2017-08-06 12:55:42 +03:00
package integration
import (
2018-02-27 16:07:07 +03:00
"context"
2017-08-06 12:55:42 +03:00
"crypto/tls"
"crypto/x509"
2017-10-24 15:38:02 +03:00
"errors"
2018-05-23 18:48:04 +03:00
"math/rand"
2017-08-06 12:55:42 +03:00
"net"
"os"
"time"
"github.com/go-check/check"
2020-09-16 16:46:04 +03:00
"github.com/traefik/traefik/v2/integration/helloworld"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/log"
2017-08-06 12:55:42 +03:00
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
2020-07-07 15:42:03 +03:00
var (
LocalhostCert [ ] byte
LocalhostKey [ ] byte
)
2017-08-06 12:55:42 +03:00
2018-05-23 18:48:04 +03:00
const randCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
2020-05-11 13:06:07 +03:00
// GRPCSuite tests suite.
2017-08-06 12:55:42 +03:00
type GRPCSuite struct { BaseSuite }
2017-10-24 15:38:02 +03:00
type myserver struct {
stopStreamExample chan bool
}
2017-08-06 12:55:42 +03:00
2017-09-13 11:34:04 +03:00
func ( s * GRPCSuite ) SetUpSuite ( c * check . C ) {
2017-08-06 12:55:42 +03:00
var err error
2021-03-04 22:08:03 +03:00
LocalhostCert , err = os . ReadFile ( "./resources/tls/local.cert" )
2017-08-06 12:55:42 +03:00
c . Assert ( err , check . IsNil )
2021-03-04 22:08:03 +03:00
LocalhostKey , err = os . ReadFile ( "./resources/tls/local.key" )
2017-08-06 12:55:42 +03:00
c . Assert ( err , check . IsNil )
}
func ( s * myserver ) SayHello ( ctx context . Context , in * helloworld . HelloRequest ) ( * helloworld . HelloReply , error ) {
return & helloworld . HelloReply { Message : "Hello " + in . Name } , nil
}
2017-10-24 15:38:02 +03:00
func ( s * myserver ) StreamExample ( in * helloworld . StreamExampleRequest , server helloworld . Greeter_StreamExampleServer ) error {
data := make ( [ ] byte , 512 )
2018-05-23 18:48:04 +03:00
for i := range data {
data [ i ] = randCharset [ rand . Intn ( len ( randCharset ) ) ]
}
2018-08-06 21:00:03 +03:00
if err := server . Send ( & helloworld . StreamExampleReply { Data : string ( data ) } ) ; err != nil {
2019-09-13 20:28:04 +03:00
log . WithoutContext ( ) . Error ( err )
2018-08-06 21:00:03 +03:00
}
2017-10-24 15:38:02 +03:00
<- s . stopStreamExample
return nil
}
func startGRPCServer ( lis net . Listener , server * myserver ) error {
2017-08-06 12:55:42 +03:00
cert , err := tls . X509KeyPair ( LocalhostCert , LocalhostKey )
if err != nil {
return err
}
creds := credentials . NewServerTLSFromCert ( & cert )
serverOption := grpc . Creds ( creds )
2017-10-24 15:38:02 +03:00
s := grpc . NewServer ( serverOption )
2017-08-06 12:55:42 +03:00
defer s . Stop ( )
2017-10-24 15:38:02 +03:00
helloworld . RegisterGreeterServer ( s , server )
2017-08-06 12:55:42 +03:00
return s . Serve ( lis )
}
2018-05-24 11:52:04 +03:00
func starth2cGRPCServer ( lis net . Listener , server * myserver ) error {
s := grpc . NewServer ( )
defer s . Stop ( )
helloworld . RegisterGreeterServer ( s , server )
return s . Serve ( lis )
}
2017-10-24 15:38:02 +03:00
func getHelloClientGRPC ( ) ( helloworld . GreeterClient , func ( ) error , error ) {
2017-08-06 12:55:42 +03:00
roots := x509 . NewCertPool ( )
roots . AppendCertsFromPEM ( LocalhostCert )
2020-07-13 18:58:03 +03:00
credsClient := credentials . NewClientTLSFromCert ( roots , "" )
2017-08-06 12:55:42 +03:00
conn , err := grpc . Dial ( "127.0.0.1:4443" , grpc . WithTransportCredentials ( credsClient ) )
if err != nil {
2017-10-24 15:38:02 +03:00
return nil , func ( ) error { return nil } , err
2017-08-06 12:55:42 +03:00
}
2017-10-24 15:38:02 +03:00
return helloworld . NewGreeterClient ( conn ) , conn . Close , nil
}
2017-08-06 12:55:42 +03:00
2018-05-28 12:46:03 +03:00
func getHelloClientGRPCh2c ( ) ( helloworld . GreeterClient , func ( ) error , error ) {
conn , err := grpc . Dial ( "127.0.0.1:8081" , grpc . WithInsecure ( ) )
if err != nil {
return nil , func ( ) error { return nil } , err
}
return helloworld . NewGreeterClient ( conn ) , conn . Close , nil
}
func callHelloClientGRPC ( name string , secure bool ) ( string , error ) {
var client helloworld . GreeterClient
var closer func ( ) error
var err error
if secure {
client , closer , err = getHelloClientGRPC ( )
} else {
client , closer , err = getHelloClientGRPCh2c ( )
}
2021-03-04 11:02:03 +03:00
defer func ( ) { _ = closer ( ) } ( )
2018-05-28 12:46:03 +03:00
2017-10-24 15:38:02 +03:00
if err != nil {
return "" , err
}
2017-08-06 12:55:42 +03:00
r , err := client . SayHello ( context . Background ( ) , & helloworld . HelloRequest { Name : name } )
if err != nil {
return "" , err
}
return r . Message , nil
}
2017-10-24 15:38:02 +03:00
func callStreamExampleClientGRPC ( ) ( helloworld . Greeter_StreamExampleClient , func ( ) error , error ) {
client , closer , err := getHelloClientGRPC ( )
if err != nil {
return nil , closer , err
}
t , err := client . StreamExample ( context . Background ( ) , & helloworld . StreamExampleRequest { } )
if err != nil {
return nil , closer , err
}
return t , closer , nil
}
2017-09-13 11:34:04 +03:00
func ( s * GRPCSuite ) TestGRPC ( c * check . C ) {
2017-08-06 12:55:42 +03:00
lis , err := net . Listen ( "tcp" , ":0" )
2021-03-04 11:02:03 +03:00
c . Assert ( err , check . IsNil )
2017-08-06 12:55:42 +03:00
_ , port , err := net . SplitHostPort ( lis . Addr ( ) . String ( ) )
c . Assert ( err , check . IsNil )
go func ( ) {
2017-10-24 15:38:02 +03:00
err := startGRPCServer ( lis , & myserver { } )
2017-08-06 12:55:42 +03:00
c . Log ( err )
c . Assert ( err , check . IsNil )
} ( )
2017-09-13 11:34:04 +03:00
file := s . adaptFile ( c , "fixtures/grpc/config.toml" , struct {
2017-08-06 12:55:42 +03:00
CertContent string
KeyContent string
GRPCServerPort string
} {
CertContent : string ( LocalhostCert ) ,
KeyContent : string ( LocalhostKey ) ,
GRPCServerPort : port ,
} )
defer os . Remove ( file )
2017-09-13 11:34:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
2017-08-06 12:55:42 +03:00
err = cmd . Start ( )
c . Assert ( err , check . IsNil )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2017-08-06 12:55:42 +03:00
// wait for Traefik
2020-07-13 18:58:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 1 * time . Second , try . BodyContains ( "Host(`127.0.0.1`)" ) )
2017-08-06 12:55:42 +03:00
c . Assert ( err , check . IsNil )
2018-05-24 11:52:04 +03:00
2017-08-06 12:55:42 +03:00
var response string
err = try . Do ( 1 * time . Second , func ( ) error {
2018-05-28 12:46:03 +03:00
response , err = callHelloClientGRPC ( "World" , true )
2017-08-06 12:55:42 +03:00
return err
} )
2018-05-24 11:52:04 +03:00
c . Assert ( err , check . IsNil )
c . Assert ( response , check . Equals , "Hello World" )
}
func ( s * GRPCSuite ) TestGRPCh2c ( c * check . C ) {
lis , err := net . Listen ( "tcp" , ":0" )
2021-03-04 11:02:03 +03:00
c . Assert ( err , check . IsNil )
2018-05-24 11:52:04 +03:00
_ , port , err := net . SplitHostPort ( lis . Addr ( ) . String ( ) )
c . Assert ( err , check . IsNil )
go func ( ) {
err := starth2cGRPCServer ( lis , & myserver { } )
c . Log ( err )
c . Assert ( err , check . IsNil )
} ( )
file := s . adaptFile ( c , "fixtures/grpc/config_h2c.toml" , struct {
2018-05-28 12:46:03 +03:00
GRPCServerPort string
} {
GRPCServerPort : port ,
} )
defer os . Remove ( file )
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
err = cmd . Start ( )
c . Assert ( err , check . IsNil )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2018-05-28 12:46:03 +03:00
// wait for Traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 1 * time . Second , try . BodyContains ( "Host(`127.0.0.1`)" ) )
2018-05-28 12:46:03 +03:00
c . Assert ( err , check . IsNil )
var response string
err = try . Do ( 1 * time . Second , func ( ) error {
response , err = callHelloClientGRPC ( "World" , false )
return err
} )
c . Assert ( err , check . IsNil )
c . Assert ( response , check . Equals , "Hello World" )
}
func ( s * GRPCSuite ) TestGRPCh2cTermination ( c * check . C ) {
lis , err := net . Listen ( "tcp" , ":0" )
2021-03-04 11:02:03 +03:00
c . Assert ( err , check . IsNil )
2018-05-28 12:46:03 +03:00
_ , port , err := net . SplitHostPort ( lis . Addr ( ) . String ( ) )
c . Assert ( err , check . IsNil )
go func ( ) {
err := starth2cGRPCServer ( lis , & myserver { } )
c . Log ( err )
c . Assert ( err , check . IsNil )
} ( )
file := s . adaptFile ( c , "fixtures/grpc/config_h2c_termination.toml" , struct {
2018-05-24 11:52:04 +03:00
CertContent string
KeyContent string
GRPCServerPort string
} {
CertContent : string ( LocalhostCert ) ,
KeyContent : string ( LocalhostKey ) ,
GRPCServerPort : port ,
} )
defer os . Remove ( file )
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
err = cmd . Start ( )
c . Assert ( err , check . IsNil )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2018-05-24 11:52:04 +03:00
// wait for Traefik
2020-07-13 18:58:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 1 * time . Second , try . BodyContains ( "Host(`127.0.0.1`)" ) )
2018-05-24 11:52:04 +03:00
c . Assert ( err , check . IsNil )
2017-08-06 12:55:42 +03:00
2018-05-24 11:52:04 +03:00
var response string
err = try . Do ( 1 * time . Second , func ( ) error {
2018-05-28 12:46:03 +03:00
response , err = callHelloClientGRPC ( "World" , true )
2018-05-24 11:52:04 +03:00
return err
} )
2017-08-06 12:55:42 +03:00
c . Assert ( err , check . IsNil )
c . Assert ( response , check . Equals , "Hello World" )
}
2017-10-10 13:14:03 +03:00
func ( s * GRPCSuite ) TestGRPCInsecure ( c * check . C ) {
lis , err := net . Listen ( "tcp" , ":0" )
2021-03-04 11:02:03 +03:00
c . Assert ( err , check . IsNil )
2017-10-10 13:14:03 +03:00
_ , port , err := net . SplitHostPort ( lis . Addr ( ) . String ( ) )
c . Assert ( err , check . IsNil )
go func ( ) {
2017-10-24 15:38:02 +03:00
err := startGRPCServer ( lis , & myserver { } )
2017-10-10 13:14:03 +03:00
c . Log ( err )
c . Assert ( err , check . IsNil )
} ( )
file := s . adaptFile ( c , "fixtures/grpc/config_insecure.toml" , struct {
CertContent string
KeyContent string
GRPCServerPort string
} {
CertContent : string ( LocalhostCert ) ,
KeyContent : string ( LocalhostKey ) ,
GRPCServerPort : port ,
} )
defer os . Remove ( file )
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
err = cmd . Start ( )
c . Assert ( err , check . IsNil )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2017-10-10 13:14:03 +03:00
// wait for Traefik
2020-07-13 18:58:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 1 * time . Second , try . BodyContains ( "Host(`127.0.0.1`)" ) )
2017-10-10 13:14:03 +03:00
c . Assert ( err , check . IsNil )
2018-05-24 11:52:04 +03:00
2017-10-10 13:14:03 +03:00
var response string
err = try . Do ( 1 * time . Second , func ( ) error {
2018-05-28 12:46:03 +03:00
response , err = callHelloClientGRPC ( "World" , true )
2017-10-10 13:14:03 +03:00
return err
} )
c . Assert ( err , check . IsNil )
c . Assert ( response , check . Equals , "Hello World" )
}
2017-10-24 15:38:02 +03:00
func ( s * GRPCSuite ) TestGRPCBuffer ( c * check . C ) {
stopStreamExample := make ( chan bool )
defer func ( ) { stopStreamExample <- true } ( )
lis , err := net . Listen ( "tcp" , ":0" )
2017-12-04 22:04:08 +03:00
c . Assert ( err , check . IsNil )
2017-10-24 15:38:02 +03:00
_ , port , err := net . SplitHostPort ( lis . Addr ( ) . String ( ) )
c . Assert ( err , check . IsNil )
go func ( ) {
err := startGRPCServer ( lis , & myserver {
stopStreamExample : stopStreamExample ,
} )
c . Log ( err )
c . Assert ( err , check . IsNil )
} ( )
file := s . adaptFile ( c , "fixtures/grpc/config.toml" , struct {
CertContent string
KeyContent string
GRPCServerPort string
} {
CertContent : string ( LocalhostCert ) ,
KeyContent : string ( LocalhostKey ) ,
GRPCServerPort : port ,
} )
defer os . Remove ( file )
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
err = cmd . Start ( )
c . Assert ( err , check . IsNil )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2017-10-24 15:38:02 +03:00
// wait for Traefik
2020-07-13 18:58:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 1 * time . Second , try . BodyContains ( "Host(`127.0.0.1`)" ) )
2017-10-24 15:38:02 +03:00
c . Assert ( err , check . IsNil )
var client helloworld . Greeter_StreamExampleClient
client , closer , err := callStreamExampleClientGRPC ( )
2021-03-04 11:02:03 +03:00
defer func ( ) { _ = closer ( ) } ( )
2017-11-22 20:20:03 +03:00
c . Assert ( err , check . IsNil )
2017-10-24 15:38:02 +03:00
received := make ( chan bool )
go func ( ) {
2017-11-22 20:20:03 +03:00
tr , err := client . Recv ( )
c . Assert ( err , check . IsNil )
2017-10-24 15:38:02 +03:00
c . Assert ( len ( tr . Data ) , check . Equals , 512 )
received <- true
} ( )
2019-11-26 23:38:03 +03:00
err = try . Do ( 10 * time . Second , func ( ) error {
2017-10-24 15:38:02 +03:00
select {
case <- received :
return nil
default :
return errors . New ( "failed to receive stream data" )
}
} )
c . Assert ( err , check . IsNil )
}
2018-10-29 20:42:03 +03:00
func ( s * GRPCSuite ) TestGRPCBufferWithFlushInterval ( c * check . C ) {
stopStreamExample := make ( chan bool )
lis , err := net . Listen ( "tcp" , ":0" )
c . Assert ( err , check . IsNil )
_ , port , err := net . SplitHostPort ( lis . Addr ( ) . String ( ) )
c . Assert ( err , check . IsNil )
go func ( ) {
err := startGRPCServer ( lis , & myserver {
stopStreamExample : stopStreamExample ,
} )
c . Log ( err )
c . Assert ( err , check . IsNil )
} ( )
2019-05-16 11:58:06 +03:00
file := s . adaptFile ( c , "fixtures/grpc/config.toml" , struct {
2018-10-29 20:42:03 +03:00
CertContent string
KeyContent string
GRPCServerPort string
} {
CertContent : string ( LocalhostCert ) ,
KeyContent : string ( LocalhostKey ) ,
GRPCServerPort : port ,
} )
defer os . Remove ( file )
2018-11-14 12:18:03 +03:00
2018-10-29 20:42:03 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
err = cmd . Start ( )
c . Assert ( err , check . IsNil )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2018-10-29 20:42:03 +03:00
// wait for Traefik
2020-07-13 18:58:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 1 * time . Second , try . BodyContains ( "Host(`127.0.0.1`)" ) )
2018-10-29 20:42:03 +03:00
c . Assert ( err , check . IsNil )
2018-11-14 12:18:03 +03:00
2018-10-29 20:42:03 +03:00
var client helloworld . Greeter_StreamExampleClient
client , closer , err := callStreamExampleClientGRPC ( )
2021-03-04 11:02:03 +03:00
defer func ( ) {
_ = closer ( )
stopStreamExample <- true
} ( )
2018-10-29 20:42:03 +03:00
c . Assert ( err , check . IsNil )
received := make ( chan bool )
go func ( ) {
tr , err := client . Recv ( )
c . Assert ( err , check . IsNil )
c . Assert ( len ( tr . Data ) , check . Equals , 512 )
received <- true
} ( )
2018-11-14 12:18:03 +03:00
err = try . Do ( 100 * time . Millisecond , func ( ) error {
2018-10-29 20:42:03 +03:00
select {
case <- received :
return nil
default :
return errors . New ( "failed to receive stream data" )
}
} )
c . Assert ( err , check . IsNil )
}
2019-02-01 11:50:04 +03:00
func ( s * GRPCSuite ) TestGRPCWithRetry ( c * check . C ) {
lis , err := net . Listen ( "tcp" , ":0" )
2021-03-04 11:02:03 +03:00
c . Assert ( err , check . IsNil )
2019-02-01 11:50:04 +03:00
_ , port , err := net . SplitHostPort ( lis . Addr ( ) . String ( ) )
c . Assert ( err , check . IsNil )
go func ( ) {
err := startGRPCServer ( lis , & myserver { } )
c . Log ( err )
c . Assert ( err , check . IsNil )
} ( )
file := s . adaptFile ( c , "fixtures/grpc/config_retry.toml" , struct {
CertContent string
KeyContent string
GRPCServerPort string
} {
CertContent : string ( LocalhostCert ) ,
KeyContent : string ( LocalhostKey ) ,
GRPCServerPort : port ,
} )
defer os . Remove ( file )
cmd , display := s . traefikCmd ( withConfigFile ( file ) )
defer display ( c )
err = cmd . Start ( )
c . Assert ( err , check . IsNil )
2020-10-09 10:32:03 +03:00
defer s . killCmd ( cmd )
2019-02-01 11:50:04 +03:00
// wait for Traefik
2020-07-13 18:58:03 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 1 * time . Second , try . BodyContains ( "Host(`127.0.0.1`)" ) )
2019-02-01 11:50:04 +03:00
c . Assert ( err , check . IsNil )
var response string
err = try . Do ( 1 * time . Second , func ( ) error {
response , err = callHelloClientGRPC ( "World" , true )
return err
} )
c . Assert ( err , check . IsNil )
c . Assert ( response , check . Equals , "Hello World" )
}