1package plugin 2 3import ( 4 "context" 5 "reflect" 6 "testing" 7 8 grpctest "github.com/hashicorp/go-plugin/test/grpc" 9 "github.com/jhump/protoreflect/grpcreflect" 10 "google.golang.org/grpc" 11 reflectpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" 12) 13 14func TestGRPCClient_App(t *testing.T) { 15 client, server := TestPluginGRPCConn(t, map[string]Plugin{ 16 "test": new(testGRPCInterfacePlugin), 17 }) 18 defer client.Close() 19 defer server.Stop() 20 21 raw, err := client.Dispense("test") 22 if err != nil { 23 t.Fatalf("err: %s", err) 24 } 25 26 impl, ok := raw.(testInterface) 27 if !ok { 28 t.Fatalf("bad: %#v", raw) 29 } 30 31 result := impl.Double(21) 32 if result != 42 { 33 t.Fatalf("bad: %#v", result) 34 } 35 36 err = impl.Bidirectional() 37 if err != nil { 38 t.Fatal(err) 39 } 40} 41 42func TestGRPCConn_BidirectionalPing(t *testing.T) { 43 conn, _ := TestGRPCConn(t, func(s *grpc.Server) { 44 grpctest.RegisterPingPongServer(s, &pingPongServer{}) 45 }) 46 defer conn.Close() 47 pingPongClient := grpctest.NewPingPongClient(conn) 48 49 pResp, err := pingPongClient.Ping(context.Background(), &grpctest.PingRequest{}) 50 if err != nil { 51 t.Fatal(err) 52 } 53 if pResp.Msg != "pong" { 54 t.Fatal("Bad PingPong") 55 } 56} 57 58func TestGRPCC_Stream(t *testing.T) { 59 client, server := TestPluginGRPCConn(t, map[string]Plugin{ 60 "test": new(testGRPCInterfacePlugin), 61 }) 62 defer client.Close() 63 defer server.Stop() 64 65 raw, err := client.Dispense("test") 66 if err != nil { 67 t.Fatalf("err: %s", err) 68 } 69 70 impl, ok := raw.(testStreamer) 71 if !ok { 72 t.Fatalf("bad: %#v", raw) 73 } 74 75 expected := []int32{21, 22, 23, 24, 25, 26} 76 result, err := impl.Stream(21, 27) 77 if err != nil { 78 t.Fatal(err) 79 } 80 81 if !reflect.DeepEqual(result, expected) { 82 t.Fatalf("expected: %v\ngot: %v", expected, result) 83 } 84} 85 86func TestGRPCClient_Ping(t *testing.T) { 87 client, server := TestPluginGRPCConn(t, map[string]Plugin{ 88 "test": new(testGRPCInterfacePlugin), 89 }) 90 defer client.Close() 91 defer server.Stop() 92 93 // Run a couple pings 94 if err := client.Ping(); err != nil { 95 t.Fatalf("err: %s", err) 96 } 97 if err := client.Ping(); err != nil { 98 t.Fatalf("err: %s", err) 99 } 100 101 // Close the remote end 102 server.server.Stop() 103 104 // Test ping fails 105 if err := client.Ping(); err == nil { 106 t.Fatal("should error") 107 } 108} 109 110func TestGRPCClient_Reflection(t *testing.T) { 111 ctx := context.Background() 112 113 client, server := TestPluginGRPCConn(t, map[string]Plugin{ 114 "test": new(testGRPCInterfacePlugin), 115 }) 116 defer client.Close() 117 defer server.Stop() 118 119 refClient := grpcreflect.NewClient(ctx, reflectpb.NewServerReflectionClient(client.Conn)) 120 121 svcs, err := refClient.ListServices() 122 if err != nil { 123 t.Fatalf("err: %s", err) 124 } 125 126 // TODO: maybe only assert some specific services here to make test more resilient 127 expectedSvcs := []string{"grpc.health.v1.Health", "grpc.reflection.v1alpha.ServerReflection", "grpctest.Test", "plugin.GRPCBroker", "plugin.GRPCController", "plugin.GRPCStdio"} 128 129 if !reflect.DeepEqual(svcs, expectedSvcs) { 130 t.Fatalf("expected: %v\ngot: %v", expectedSvcs, svcs) 131 } 132 133 healthDesc, err := refClient.ResolveService("grpc.health.v1.Health") 134 if err != nil { 135 t.Fatalf("err: %s", err) 136 } 137 138 methods := healthDesc.GetMethods() 139 var methodNames []string 140 for _, m := range methods { 141 methodNames = append(methodNames, m.GetName()) 142 } 143 144 expectedMethodNames := []string{"Check", "Watch"} 145 146 if !reflect.DeepEqual(methodNames, expectedMethodNames) { 147 t.Fatalf("expected: %v\ngot: %v", expectedMethodNames, methodNames) 148 } 149} 150