...

Source file src/google.golang.org/grpc/xds/internal/resolver/serviceconfig_test.go

Documentation: google.golang.org/grpc/xds/internal/resolver

     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  }
   159  

View as plain text