github.com/renbou/grpcbridge@v0.0.2-0.20240416012907-bcbd8b12648a/bridgedesc/parse_test.go (about)

     1  // Package bridgedesc_test contains tests for the bridgedesc package to avoid loop cycles.
     2  package bridgedesc_test
     3  
     4  import (
     5  	"slices"
     6  	"testing"
     7  
     8  	"github.com/google/go-cmp/cmp"
     9  	"github.com/google/go-cmp/cmp/cmpopts"
    10  	"github.com/renbou/grpcbridge/bridgedesc"
    11  	"github.com/renbou/grpcbridge/internal/bridgetest/testpb"
    12  	"google.golang.org/protobuf/reflect/protoreflect"
    13  )
    14  
    15  var testSvcDesc = &bridgedesc.Target{
    16  	Name:         "testpb",
    17  	FileResolver: testpb.TestServiceFileResolver,
    18  	TypeResolver: testpb.TestServiceTypesResolver,
    19  	Services: []bridgedesc.Service{
    20  		{
    21  			Name: protoreflect.FullName(testpb.TestService_ServiceDesc.ServiceName),
    22  			Methods: []bridgedesc.Method{
    23  				{
    24  					RPCName:         testpb.TestService_UnaryUnbound_FullMethodName,
    25  					Input:           bridgedesc.ConcreteMessage[testpb.Scalars](),
    26  					Output:          bridgedesc.ConcreteMessage[testpb.Scalars](),
    27  					ClientStreaming: false,
    28  					ServerStreaming: false,
    29  				},
    30  				{
    31  					RPCName:         testpb.TestService_UnaryBound_FullMethodName,
    32  					Input:           bridgedesc.ConcreteMessage[testpb.Scalars](),
    33  					Output:          bridgedesc.ConcreteMessage[testpb.Combined](),
    34  					ClientStreaming: false,
    35  					ServerStreaming: false,
    36  					Bindings: []bridgedesc.Binding{
    37  						{
    38  							HTTPMethod:       "POST",
    39  							Pattern:          "/service/unary/{string_value}/{fixed64_value}",
    40  							RequestBodyPath:  "bytes_value",
    41  							ResponseBodyPath: "",
    42  						},
    43  					},
    44  				},
    45  				{
    46  					RPCName:         testpb.TestService_UnaryCombined_FullMethodName,
    47  					Input:           bridgedesc.ConcreteMessage[testpb.Combined](),
    48  					Output:          bridgedesc.ConcreteMessage[testpb.Combined](),
    49  					ClientStreaming: false,
    50  					ServerStreaming: false,
    51  					Bindings: []bridgedesc.Binding{{
    52  						HTTPMethod:       "POST",
    53  						Pattern:          "/service/combined/{scalars.bool_value}/{scalars.string_value}",
    54  						RequestBodyPath:  "non_scalars",
    55  						ResponseBodyPath: "non_scalars",
    56  					}},
    57  				},
    58  				{
    59  					RPCName:         testpb.TestService_BadResponsePath_FullMethodName,
    60  					Input:           bridgedesc.ConcreteMessage[testpb.Scalars](),
    61  					Output:          bridgedesc.ConcreteMessage[testpb.Combined](),
    62  					ClientStreaming: false,
    63  					ServerStreaming: false,
    64  					Bindings: []bridgedesc.Binding{{
    65  						HTTPMethod:       "POST",
    66  						Pattern:          "/service/bad-response-path",
    67  						ResponseBodyPath: "not_a_field",
    68  					}},
    69  				},
    70  				{
    71  					RPCName:         testpb.TestService_Echo_FullMethodName,
    72  					Input:           bridgedesc.ConcreteMessage[testpb.Combined](),
    73  					Output:          bridgedesc.ConcreteMessage[testpb.Combined](),
    74  					ClientStreaming: false,
    75  					ServerStreaming: false,
    76  					Bindings: []bridgedesc.Binding{{
    77  						HTTPMethod:       "POST",
    78  						Pattern:          "/service/echo",
    79  						RequestBodyPath:  "*",
    80  						ResponseBodyPath: "",
    81  					}},
    82  				},
    83  			},
    84  		},
    85  	},
    86  }
    87  
    88  func bridgedescOpts() cmp.Option {
    89  	return cmp.Options{
    90  		cmp.Transformer("MessagesToNames", func(message bridgedesc.Message) protoreflect.FullName {
    91  			return message.New().ProtoReflect().Descriptor().FullName()
    92  		}),
    93  		cmpopts.IgnoreInterfaces(struct{ bridgedesc.FileResolver }{}),
    94  		cmpopts.IgnoreInterfaces(struct{ bridgedesc.TypeResolver }{}),
    95  	}
    96  }
    97  
    98  // Test_ParseFileDescriptors_Ok tests that ParseFileDescriptors properly parses various sets of services and descriptors.
    99  func Test_ParseFileDescriptors_Ok(t *testing.T) {
   100  	t.Parallel()
   101  
   102  	tests := []struct {
   103  		name       string
   104  		services   []string
   105  		wantTarget *bridgedesc.Target
   106  	}{
   107  		{
   108  			name:       "all test services",
   109  			services:   []string{testpb.TestService_ServiceDesc.ServiceName},
   110  			wantTarget: testSvcDesc,
   111  		},
   112  		{
   113  			name:       "unknown service missing",
   114  			services:   []string{testpb.TestService_ServiceDesc.ServiceName, "unknown"},
   115  			wantTarget: &bridgedesc.Target{Name: "testpb", Services: append(slices.Clone(testSvcDesc.Services), bridgedesc.Service{Name: "unknown"})},
   116  		},
   117  		{
   118  			name:       "unrequested service ignored",
   119  			services:   []string{},
   120  			wantTarget: &bridgedesc.Target{Name: "testpb", Services: make([]bridgedesc.Service, 0)},
   121  		},
   122  	}
   123  
   124  	for _, tt := range tests {
   125  		t.Run(tt.name, func(t *testing.T) {
   126  			t.Parallel()
   127  
   128  			// Arrange
   129  			serviceNames := make([]protoreflect.FullName, len(tt.services))
   130  			for i, svc := range tt.services {
   131  				serviceNames[i] = protoreflect.FullName(svc)
   132  			}
   133  
   134  			// Act
   135  			result := bridgedesc.ParseTarget("testpb", testpb.TestServiceFileResolver, testpb.TestServiceTypesResolver, serviceNames)
   136  
   137  			// Assert
   138  			if diff := cmp.Diff(tt.wantTarget, result, bridgedescOpts()); diff != "" {
   139  				t.Errorf("ParseTarget(%s, all descriptors) returned diff (-want +got):\n%s", serviceNames, diff)
   140  			}
   141  		})
   142  	}
   143  }