...

Source file src/google.golang.org/grpc/xds/internal/clusterspecifier/rls/rls_test.go

Documentation: google.golang.org/grpc/xds/internal/clusterspecifier/rls

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package rls
    20  
    21  import (
    22  	"encoding/json"
    23  	"testing"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	"github.com/google/go-cmp/cmp/cmpopts"
    27  	"google.golang.org/grpc/internal/grpctest"
    28  	rlspb "google.golang.org/grpc/internal/proto/grpc_lookup_v1"
    29  	"google.golang.org/grpc/internal/testutils"
    30  	"google.golang.org/grpc/xds/internal/clusterspecifier"
    31  	"google.golang.org/protobuf/proto"
    32  	"google.golang.org/protobuf/types/known/durationpb"
    33  
    34  	_ "google.golang.org/grpc/balancer/rls"                      // Register the RLS LB policy.
    35  	_ "google.golang.org/grpc/xds/internal/balancer/cdsbalancer" // Register the CDS LB policy.
    36  )
    37  
    38  func init() {
    39  	clusterspecifier.Register(rls{})
    40  }
    41  
    42  type s struct {
    43  	grpctest.Tester
    44  }
    45  
    46  func Test(t *testing.T) {
    47  	grpctest.RunSubTests(t, s{})
    48  }
    49  
    50  // TestParseClusterSpecifierConfig tests the parsing functionality of the RLS
    51  // Cluster Specifier Plugin.
    52  func (s) TestParseClusterSpecifierConfig(t *testing.T) {
    53  	tests := []struct {
    54  		name       string
    55  		rlcs       proto.Message
    56  		wantConfig clusterspecifier.BalancerConfig
    57  		wantErr    bool
    58  	}{
    59  		{
    60  
    61  			// This will error because the required_match field is set in grpc key builder
    62  			name: "invalid-rls-cluster-specifier",
    63  			rlcs: testutils.MarshalAny(t, &rlspb.RouteLookupClusterSpecifier{
    64  				RouteLookupConfig: &rlspb.RouteLookupConfig{
    65  					GrpcKeybuilders: []*rlspb.GrpcKeyBuilder{
    66  						{
    67  							Names: []*rlspb.GrpcKeyBuilder_Name{
    68  								{
    69  									Service: "service",
    70  									Method:  "method",
    71  								},
    72  							},
    73  							Headers: []*rlspb.NameMatcher{
    74  								{
    75  									Key:           "k1",
    76  									RequiredMatch: true,
    77  									Names:         []string{"v1"},
    78  								},
    79  							},
    80  						},
    81  					},
    82  				},
    83  			}),
    84  			wantErr: true,
    85  		},
    86  		{
    87  			name: "valid-rls-cluster-specifier",
    88  			rlcs: testutils.MarshalAny(t, &rlspb.RouteLookupClusterSpecifier{
    89  				RouteLookupConfig: &rlspb.RouteLookupConfig{
    90  					GrpcKeybuilders: []*rlspb.GrpcKeyBuilder{
    91  						{
    92  							Names: []*rlspb.GrpcKeyBuilder_Name{
    93  								{
    94  									Service: "service",
    95  									Method:  "method",
    96  								},
    97  							},
    98  							Headers: []*rlspb.NameMatcher{
    99  								{
   100  									Key:   "k1",
   101  									Names: []string{"v1"},
   102  								},
   103  							},
   104  						},
   105  					},
   106  					LookupService:        "target",
   107  					LookupServiceTimeout: &durationpb.Duration{Seconds: 100},
   108  					MaxAge:               &durationpb.Duration{Seconds: 60},
   109  					StaleAge:             &durationpb.Duration{Seconds: 50},
   110  					CacheSizeBytes:       1000,
   111  					DefaultTarget:        "passthrough:///default",
   112  				},
   113  			}),
   114  			wantConfig: configWithoutTransformationsWant,
   115  		},
   116  	}
   117  	for _, test := range tests {
   118  		cs := clusterspecifier.Get("type.googleapis.com/grpc.lookup.v1.RouteLookupClusterSpecifier")
   119  		if cs == nil {
   120  			t.Fatal("Error getting cluster specifier")
   121  		}
   122  		lbCfg, err := cs.ParseClusterSpecifierConfig(test.rlcs)
   123  
   124  		if (err != nil) != test.wantErr {
   125  			t.Fatalf("ParseClusterSpecifierConfig(%+v) returned err: %v, wantErr: %v", test.rlcs, err, test.wantErr)
   126  		}
   127  		if test.wantErr { // Successfully received an error.
   128  			return
   129  		}
   130  		// Marshal and then unmarshal into any to get rid of nondeterministic
   131  		// protojson Marshaling.
   132  		lbCfgJSON, err := json.Marshal(lbCfg)
   133  		if err != nil {
   134  			t.Fatalf("json.Marshal(%+v) returned err %v", lbCfg, err)
   135  		}
   136  		var got any
   137  		err = json.Unmarshal(lbCfgJSON, got)
   138  		if err != nil {
   139  			t.Fatalf("json.Unmarshal(%+v) returned err %v", lbCfgJSON, err)
   140  		}
   141  		wantCfgJSON, err := json.Marshal(test.wantConfig)
   142  		if err != nil {
   143  			t.Fatalf("json.Marshal(%+v) returned err %v", test.wantConfig, err)
   144  		}
   145  		var want any
   146  		err = json.Unmarshal(wantCfgJSON, want)
   147  		if err != nil {
   148  			t.Fatalf("json.Unmarshal(%+v) returned err %v", lbCfgJSON, err)
   149  		}
   150  		if diff := cmp.Diff(want, got, cmpopts.EquateEmpty()); diff != "" {
   151  			t.Fatalf("ParseClusterSpecifierConfig(%+v) returned expected, diff (-want +got) %v", test.rlcs, diff)
   152  		}
   153  	}
   154  }
   155  
   156  var configWithoutTransformationsWant = clusterspecifier.BalancerConfig{{"rls_experimental": &lbConfigJSON{
   157  	RouteLookupConfig: []byte(`{"grpcKeybuilders":[{"names":[{"service":"service","method":"method"}],"headers":[{"key":"k1","names":["v1"]}]}],"lookupService":"target","lookupServiceTimeout":"100s","maxAge":"60s","staleAge":"50s","cacheSizeBytes":"1000","defaultTarget":"passthrough:///default"}`),
   158  	ChildPolicy: []map[string]json.RawMessage{
   159  		{
   160  			"cds_experimental": []byte(`{}`),
   161  		},
   162  	},
   163  	ChildPolicyConfigTargetFieldName: "cluster",
   164  }}}
   165  

View as plain text