google.golang.org/grpc@v1.62.1/xds/internal/resolver/serviceconfig_test.go (about) 1 /* 2 * 3 * Copyright 2020 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 resolver 20 21 import ( 22 "context" 23 "regexp" 24 "testing" 25 26 xxhash "github.com/cespare/xxhash/v2" 27 "github.com/google/go-cmp/cmp" 28 "google.golang.org/grpc/internal/grpctest" 29 "google.golang.org/grpc/internal/grpcutil" 30 iresolver "google.golang.org/grpc/internal/resolver" 31 "google.golang.org/grpc/internal/testutils" 32 "google.golang.org/grpc/metadata" 33 _ "google.golang.org/grpc/xds/internal/balancer/cdsbalancer" // To parse LB config 34 "google.golang.org/grpc/xds/internal/xdsclient/xdsresource" 35 ) 36 37 type s struct { 38 grpctest.Tester 39 } 40 41 func Test(t *testing.T) { 42 grpctest.RunSubTests(t, s{}) 43 } 44 45 func (s) TestPruneActiveClusters(t *testing.T) { 46 r := &xdsResolver{activeClusters: map[string]*clusterInfo{ 47 "zero": {refCount: 0}, 48 "one": {refCount: 1}, 49 "two": {refCount: 2}, 50 "anotherzero": {refCount: 0}, 51 }} 52 want := map[string]*clusterInfo{ 53 "one": {refCount: 1}, 54 "two": {refCount: 2}, 55 } 56 r.pruneActiveClusters() 57 if d := cmp.Diff(r.activeClusters, want, cmp.AllowUnexported(clusterInfo{})); d != "" { 58 t.Fatalf("r.activeClusters = %v; want %v\nDiffs: %v", r.activeClusters, want, d) 59 } 60 } 61 62 func (s) TestGenerateRequestHash(t *testing.T) { 63 const channelID = 12378921 64 cs := &configSelector{ 65 r: &xdsResolver{ 66 cc: &testutils.ResolverClientConn{Logger: t}, 67 channelID: channelID, 68 }, 69 } 70 tests := []struct { 71 name string 72 hashPolicies []*xdsresource.HashPolicy 73 requestHashWant uint64 74 rpcInfo iresolver.RPCInfo 75 }{ 76 // TestGenerateRequestHashHeaders tests generating request hashes for 77 // hash policies that specify to hash headers. 78 { 79 name: "test-generate-request-hash-headers", 80 hashPolicies: []*xdsresource.HashPolicy{{ 81 HashPolicyType: xdsresource.HashPolicyTypeHeader, 82 HeaderName: ":path", 83 Regex: func() *regexp.Regexp { return regexp.MustCompile("/products") }(), // Will replace /products with /new-products, to test find and replace functionality. 84 RegexSubstitution: "/new-products", 85 }}, 86 requestHashWant: xxhash.Sum64String("/new-products"), 87 rpcInfo: iresolver.RPCInfo{ 88 Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs(":path", "/products")), 89 Method: "/some-method", 90 }, 91 }, 92 // TestGenerateHashChannelID tests generating request hashes for hash 93 // policies that specify to hash something that uniquely identifies the 94 // ClientConn (the pointer). 95 { 96 name: "test-generate-request-hash-channel-id", 97 hashPolicies: []*xdsresource.HashPolicy{{ 98 HashPolicyType: xdsresource.HashPolicyTypeChannelID, 99 }}, 100 requestHashWant: channelID, 101 rpcInfo: iresolver.RPCInfo{}, 102 }, 103 // TestGenerateRequestHashEmptyString tests generating request hashes 104 // for hash policies that specify to hash headers and replace empty 105 // strings in the headers. 106 { 107 name: "test-generate-request-hash-empty-string", 108 hashPolicies: []*xdsresource.HashPolicy{{ 109 HashPolicyType: xdsresource.HashPolicyTypeHeader, 110 HeaderName: ":path", 111 Regex: func() *regexp.Regexp { return regexp.MustCompile("") }(), 112 RegexSubstitution: "e", 113 }}, 114 requestHashWant: xxhash.Sum64String("eaebece"), 115 rpcInfo: iresolver.RPCInfo{ 116 Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs(":path", "abc")), 117 Method: "/some-method", 118 }, 119 }, 120 // Tests that bin headers are skipped. 121 { 122 name: "skip-bin", 123 hashPolicies: []*xdsresource.HashPolicy{{ 124 HashPolicyType: xdsresource.HashPolicyTypeHeader, 125 HeaderName: "something-bin", 126 }, { 127 HashPolicyType: xdsresource.HashPolicyTypeChannelID, 128 }}, 129 requestHashWant: channelID, 130 rpcInfo: iresolver.RPCInfo{ 131 Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("something-bin", "xyz")), 132 }, 133 }, 134 // Tests that extra metadata takes precedence over the user's metadata. 135 { 136 name: "extra-metadata", 137 hashPolicies: []*xdsresource.HashPolicy{{ 138 HashPolicyType: xdsresource.HashPolicyTypeHeader, 139 HeaderName: "content-type", 140 }}, 141 requestHashWant: xxhash.Sum64String("grpc value"), 142 rpcInfo: iresolver.RPCInfo{ 143 Context: grpcutil.WithExtraMetadata( 144 metadata.NewOutgoingContext(context.Background(), metadata.Pairs("content-type", "user value")), 145 metadata.Pairs("content-type", "grpc value"), 146 ), 147 }, 148 }, 149 } 150 for _, test := range tests { 151 t.Run(test.name, func(t *testing.T) { 152 requestHashGot := cs.generateHash(test.rpcInfo, test.hashPolicies) 153 if requestHashGot != test.requestHashWant { 154 t.Fatalf("requestHashGot = %v, requestHashWant = %v", requestHashGot, test.requestHashWant) 155 } 156 }) 157 } 158 }