1+ //nolint:errcheck
12package transports_test
23
34import (
45 "context"
6+ "net"
7+ "strconv"
8+ "strings"
59 "testing"
610
711 "github.com/stretchr/testify/assert"
812 "github.com/stretchr/testify/require"
913 "github.com/weaviate/weaviate-go-client/v6/internal/testkit"
1014 "github.com/weaviate/weaviate-go-client/v6/internal/transports"
1115 "google.golang.org/grpc"
16+ "google.golang.org/grpc/metadata"
17+ "google.golang.org/protobuf/types/known/emptypb"
1218)
1319
1420func TestNewGRPC (t * testing.T ) {
@@ -32,18 +38,18 @@ func TestNewGRPC(t *testing.T) {
3238
3339func TestGRPC_Do (t * testing.T ) {
3440 t .Run ("ok" , func (t * testing.T ) {
35- grpc , err := transports .NewGRPC (transports.GRPCConfig [any ]{
41+ gRPC , err := transports .NewGRPC (transports.GRPCConfig [any ]{
3642 NewGRPCClient : func (channel grpc.ClientConnInterface ) any {
3743 return 92
3844 },
3945 })
4046 require .NoError (t , err , "create grpc transport" )
41- require .NotNil (t , grpc , "grpc transport" )
47+ require .NotNil (t , gRPC , "grpc transport" )
4248
43- require .NoError (t , grpc .Do (t .Context (), rpcFunc ( func (_ context.Context , client any ) error {
49+ require .NoError (t , gRPC .Do (t .Context (), func (_ context.Context , client any ) error {
4450 assert .Equal (t , 92 , client , "injected client" )
4551 return nil
46- })) , "request error" )
52+ }), "request error" )
4753 })
4854
4955 t .Run ("with error" , func (t * testing.T ) {
@@ -55,17 +61,76 @@ func TestGRPC_Do(t *testing.T) {
5561 require .NoError (t , err , "create grpc transport" )
5662 require .NotNil (t , grpc , "grpc transport" )
5763
58- require .ErrorIs (t , grpc .Do (t .Context (), rpcFunc ( func (_ context.Context , client any ) error {
64+ require .ErrorIs (t , grpc .Do (t .Context (), func (_ context.Context , client any ) error {
5965 assert .Equal (t , 92 , client , "injected client" )
6066 return testkit .ErrWhaam
61- })), testkit .ErrWhaam , "request error" )
67+ }), testkit .ErrWhaam , "request error" )
68+ })
69+
70+ t .Run ("default headers" , func (t * testing.T ) {
71+ // Arrange: start a local gRPC server and register a handler with assertions.
72+ ts := startTestService (t , func (_ any , ctx context.Context , _ func (any ) error , _ grpc.UnaryServerInterceptor ) (any , error ) {
73+ md , ok := metadata .FromIncomingContext (ctx )
74+ assert .True (t , ok , "incoming context should contain metadata" )
75+ assert .Subset (t , md , metadata.MD {"x-findme" : {"foo" }}, "default headers not present in request metadata" )
76+ return nil , nil
77+ })
78+
79+ gRPC , err := transports .NewGRPC (transports.GRPCConfig [grpc.ClientConnInterface ]{
80+ Host : ts .Host (),
81+ Port : ts .Port (),
82+ Header : & metadata.MD {"X-FindMe" : {"foo" }},
83+ NewGRPCClient : func (channel grpc.ClientConnInterface ) grpc.ClientConnInterface { return channel },
84+ })
85+ require .NoError (t , err , "new grpc transport" )
86+
87+ // Act: our handled above will verify that the request included expected headers.
88+ gRPC .Do (t .Context (), func (ctx context.Context , client grpc.ClientConnInterface ) error {
89+ var empty emptypb.Empty
90+ return client .Invoke (ctx , ts .MethodName (), nil , & empty )
91+ })
6292 })
6393}
6494
65- type rpcFunc func (ctx context.Context , client any ) error
95+ type testService struct {
96+ lis net.Listener
97+ srv * grpc.Server
98+ host string
99+ port int
100+ }
101+
102+ // startTestService starts a local TCP [net.Listener] and creates a [grpc.Server]
103+ // using that listener. The mh handler can be used to make assertions about the
104+ // request or control how the requeset is processed.
105+ //
106+ // All resources are freed via [testing.T.Cleanup] hook.
107+ func startTestService (t * testing.T , mh grpc.MethodHandler ) * testService {
108+ lis , err := net .Listen ("tcp" , "localhost:0" )
109+ require .NoError (t , err )
110+ t .Cleanup (func () { lis .Close () })
111+
112+ addr := strings .Split (lis .Addr ().String (), ":" )
113+ port , _ := strconv .Atoi (addr [1 ])
114+
115+ srv := grpc .NewServer ()
116+ srv .RegisterService (& grpc.ServiceDesc {
117+ ServiceName : "testService" ,
118+ Methods : []grpc.MethodDesc {
119+ {MethodName : "Test" , Handler : mh },
120+ },
121+ }, nil )
66122
67- var _ transports.RPC [any ] = (* rpcFunc )(nil )
123+ go srv .Serve (lis )
124+ t .Cleanup (srv .Stop )
68125
69- func (f rpcFunc ) Do (ctx context.Context , client any ) error {
70- return f (ctx , client )
126+ return & testService {
127+ lis : lis ,
128+ srv : srv ,
129+ host : addr [0 ],
130+ port : port ,
131+ }
71132}
133+
134+ func (ts * testService ) Host () string { return ts .host }
135+ func (ts * testService ) Port () int { return ts .port }
136+ func (ts * testService ) MethodName () string { return "/testService/Test" }
0 commit comments