Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
Testing / vet-proto (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
163 lines
4.9 KiB
Go
163 lines
4.9 KiB
Go
/*
|
|
*
|
|
* Copyright 2021 gRPC authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
package rls
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"google.golang.org/grpc/internal/grpctest"
|
|
rlspb "google.golang.org/grpc/internal/proto/grpc_lookup_v1"
|
|
"google.golang.org/grpc/internal/testutils"
|
|
"google.golang.org/grpc/internal/xds/clusterspecifier"
|
|
"google.golang.org/protobuf/proto"
|
|
"google.golang.org/protobuf/types/known/durationpb"
|
|
|
|
_ "google.golang.org/grpc/balancer/rls" // Register the RLS LB policy.
|
|
_ "google.golang.org/grpc/internal/xds/balancer/cdsbalancer" // Register the CDS LB policy.
|
|
)
|
|
|
|
func init() {
|
|
clusterspecifier.Register(rls{})
|
|
}
|
|
|
|
type s struct {
|
|
grpctest.Tester
|
|
}
|
|
|
|
func Test(t *testing.T) {
|
|
grpctest.RunSubTests(t, s{})
|
|
}
|
|
|
|
// TestParseClusterSpecifierConfig tests the parsing functionality of the RLS
|
|
// Cluster Specifier Plugin.
|
|
func (s) TestParseClusterSpecifierConfig(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
rlcs proto.Message
|
|
wantConfig clusterspecifier.BalancerConfig
|
|
wantErr bool
|
|
}{
|
|
{
|
|
|
|
// This will error because the required_match field is set in grpc key builder
|
|
name: "invalid-rls-cluster-specifier",
|
|
rlcs: testutils.MarshalAny(t, &rlspb.RouteLookupClusterSpecifier{
|
|
RouteLookupConfig: &rlspb.RouteLookupConfig{
|
|
GrpcKeybuilders: []*rlspb.GrpcKeyBuilder{
|
|
{
|
|
Names: []*rlspb.GrpcKeyBuilder_Name{
|
|
{
|
|
Service: "service",
|
|
Method: "method",
|
|
},
|
|
},
|
|
Headers: []*rlspb.NameMatcher{
|
|
{
|
|
Key: "k1",
|
|
RequiredMatch: true,
|
|
Names: []string{"v1"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "valid-rls-cluster-specifier",
|
|
rlcs: testutils.MarshalAny(t, &rlspb.RouteLookupClusterSpecifier{
|
|
RouteLookupConfig: &rlspb.RouteLookupConfig{
|
|
GrpcKeybuilders: []*rlspb.GrpcKeyBuilder{
|
|
{
|
|
Names: []*rlspb.GrpcKeyBuilder_Name{
|
|
{
|
|
Service: "service",
|
|
Method: "method",
|
|
},
|
|
},
|
|
Headers: []*rlspb.NameMatcher{
|
|
{
|
|
Key: "k1",
|
|
Names: []string{"v1"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
LookupService: "target",
|
|
LookupServiceTimeout: &durationpb.Duration{Seconds: 100},
|
|
MaxAge: &durationpb.Duration{Seconds: 60},
|
|
StaleAge: &durationpb.Duration{Seconds: 50},
|
|
CacheSizeBytes: 1000,
|
|
DefaultTarget: "passthrough:///default",
|
|
},
|
|
}),
|
|
wantConfig: configWithoutTransformationsWant,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
cs := clusterspecifier.Get("type.googleapis.com/grpc.lookup.v1.RouteLookupClusterSpecifier")
|
|
if cs == nil {
|
|
t.Fatal("Error getting cluster specifier")
|
|
}
|
|
lbCfg, err := cs.ParseClusterSpecifierConfig(test.rlcs)
|
|
|
|
if (err != nil) != test.wantErr {
|
|
t.Fatalf("ParseClusterSpecifierConfig(%+v) returned err: %v, wantErr: %v", test.rlcs, err, test.wantErr)
|
|
}
|
|
if test.wantErr { // Successfully received an error.
|
|
continue
|
|
}
|
|
// Marshal and then unmarshal into any to get rid of nondeterministic
|
|
// protojson Marshaling.
|
|
lbCfgJSON, err := json.Marshal(lbCfg)
|
|
if err != nil {
|
|
t.Fatalf("json.Marshal(%+v) returned err %v", lbCfg, err)
|
|
}
|
|
var got any
|
|
if err := json.Unmarshal(lbCfgJSON, &got); err != nil {
|
|
t.Fatalf("json.Unmarshal(%+v) returned err %v", lbCfgJSON, err)
|
|
}
|
|
wantCfgJSON, err := json.Marshal(test.wantConfig)
|
|
if err != nil {
|
|
t.Fatalf("json.Marshal(%+v) returned err %v", test.wantConfig, err)
|
|
}
|
|
var want any
|
|
if err := json.Unmarshal(wantCfgJSON, &want); err != nil {
|
|
t.Fatalf("json.Unmarshal(%+v) returned err %v", lbCfgJSON, err)
|
|
}
|
|
if diff := cmp.Diff(want, got, cmpopts.EquateEmpty()); diff != "" {
|
|
t.Fatalf("ParseClusterSpecifierConfig(%+v) returned expected, diff (-want +got) %v", test.rlcs, diff)
|
|
}
|
|
}
|
|
}
|
|
|
|
var configWithoutTransformationsWant = clusterspecifier.BalancerConfig{{"rls_experimental": &lbConfigJSON{
|
|
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"}`),
|
|
ChildPolicy: []map[string]json.RawMessage{
|
|
{
|
|
"cds_experimental": []byte(`{"isDynamic":true}`),
|
|
},
|
|
},
|
|
ChildPolicyConfigTargetFieldName: "cluster",
|
|
}}}
|