github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/xdsclient/xdsresource/matcher_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  package xdsresource
    19  
    20  import (
    21  	"context"
    22  	"testing"
    23  
    24  	"github.com/hxx258456/ccgo/grpc/internal/grpcrand"
    25  	"github.com/hxx258456/ccgo/grpc/internal/grpcutil"
    26  	iresolver "github.com/hxx258456/ccgo/grpc/internal/resolver"
    27  	"github.com/hxx258456/ccgo/grpc/internal/xds/matcher"
    28  	"github.com/hxx258456/ccgo/grpc/metadata"
    29  )
    30  
    31  func (s) TestAndMatcherMatch(t *testing.T) {
    32  	tests := []struct {
    33  		name string
    34  		pm   pathMatcher
    35  		hm   matcher.HeaderMatcher
    36  		info iresolver.RPCInfo
    37  		want bool
    38  	}{
    39  		{
    40  			name: "both match",
    41  			pm:   newPathExactMatcher("/a/b", false),
    42  			hm:   matcher.NewHeaderExactMatcher("th", "tv", false),
    43  			info: iresolver.RPCInfo{
    44  				Method:  "/a/b",
    45  				Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("th", "tv")),
    46  			},
    47  			want: true,
    48  		},
    49  		{
    50  			name: "both match with path case insensitive",
    51  			pm:   newPathExactMatcher("/A/B", true),
    52  			hm:   matcher.NewHeaderExactMatcher("th", "tv", false),
    53  			info: iresolver.RPCInfo{
    54  				Method:  "/a/b",
    55  				Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("th", "tv")),
    56  			},
    57  			want: true,
    58  		},
    59  		{
    60  			name: "only one match",
    61  			pm:   newPathExactMatcher("/a/b", false),
    62  			hm:   matcher.NewHeaderExactMatcher("th", "tv", false),
    63  			info: iresolver.RPCInfo{
    64  				Method:  "/z/y",
    65  				Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("th", "tv")),
    66  			},
    67  			want: false,
    68  		},
    69  		{
    70  			name: "both not match",
    71  			pm:   newPathExactMatcher("/z/y", false),
    72  			hm:   matcher.NewHeaderExactMatcher("th", "abc", false),
    73  			info: iresolver.RPCInfo{
    74  				Method:  "/a/b",
    75  				Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("th", "tv")),
    76  			},
    77  			want: false,
    78  		},
    79  		{
    80  			name: "fake header",
    81  			pm:   newPathPrefixMatcher("/", false),
    82  			hm:   matcher.NewHeaderExactMatcher("content-type", "fake", false),
    83  			info: iresolver.RPCInfo{
    84  				Method: "/a/b",
    85  				Context: grpcutil.WithExtraMetadata(context.Background(), metadata.Pairs(
    86  					"content-type", "fake",
    87  				)),
    88  			},
    89  			want: true,
    90  		},
    91  		{
    92  			name: "binary header",
    93  			pm:   newPathPrefixMatcher("/", false),
    94  			hm:   matcher.NewHeaderPresentMatcher("t-bin", true, false),
    95  			info: iresolver.RPCInfo{
    96  				Method: "/a/b",
    97  				Context: grpcutil.WithExtraMetadata(
    98  					metadata.NewOutgoingContext(context.Background(), metadata.Pairs("t-bin", "123")), metadata.Pairs(
    99  						"content-type", "fake",
   100  					)),
   101  			},
   102  			// Shouldn't match binary header, even though it's in metadata.
   103  			want: false,
   104  		},
   105  	}
   106  	for _, tt := range tests {
   107  		t.Run(tt.name, func(t *testing.T) {
   108  			a := newCompositeMatcher(tt.pm, []matcher.HeaderMatcher{tt.hm}, nil)
   109  			if got := a.Match(tt.info); got != tt.want {
   110  				t.Errorf("match() = %v, want %v", got, tt.want)
   111  			}
   112  		})
   113  	}
   114  }
   115  
   116  func (s) TestFractionMatcherMatch(t *testing.T) {
   117  	const fraction = 500000
   118  	fm := newFractionMatcher(fraction)
   119  	defer func() {
   120  		RandInt63n = grpcrand.Int63n
   121  	}()
   122  
   123  	// rand > fraction, should return false.
   124  	RandInt63n = func(n int64) int64 {
   125  		return fraction + 1
   126  	}
   127  	if matched := fm.match(); matched {
   128  		t.Errorf("match() = %v, want not match", matched)
   129  	}
   130  
   131  	// rand == fraction, should return true.
   132  	RandInt63n = func(n int64) int64 {
   133  		return fraction
   134  	}
   135  	if matched := fm.match(); !matched {
   136  		t.Errorf("match() = %v, want match", matched)
   137  	}
   138  
   139  	// rand < fraction, should return true.
   140  	RandInt63n = func(n int64) int64 {
   141  		return fraction - 1
   142  	}
   143  	if matched := fm.match(); !matched {
   144  		t.Errorf("match() = %v, want match", matched)
   145  	}
   146  }
   147  
   148  func (s) TestMatchTypeForDomain(t *testing.T) {
   149  	tests := []struct {
   150  		d    string
   151  		want domainMatchType
   152  	}{
   153  		{d: "", want: domainMatchTypeInvalid},
   154  		{d: "*", want: domainMatchTypeUniversal},
   155  		{d: "bar.*", want: domainMatchTypePrefix},
   156  		{d: "*.abc.com", want: domainMatchTypeSuffix},
   157  		{d: "foo.bar.com", want: domainMatchTypeExact},
   158  		{d: "foo.*.com", want: domainMatchTypeInvalid},
   159  	}
   160  	for _, tt := range tests {
   161  		if got := matchTypeForDomain(tt.d); got != tt.want {
   162  			t.Errorf("matchTypeForDomain(%q) = %v, want %v", tt.d, got, tt.want)
   163  		}
   164  	}
   165  }
   166  
   167  func (s) TestMatch(t *testing.T) {
   168  	tests := []struct {
   169  		name        string
   170  		domain      string
   171  		host        string
   172  		wantTyp     domainMatchType
   173  		wantMatched bool
   174  	}{
   175  		{name: "invalid-empty", domain: "", host: "", wantTyp: domainMatchTypeInvalid, wantMatched: false},
   176  		{name: "invalid", domain: "a.*.b", host: "", wantTyp: domainMatchTypeInvalid, wantMatched: false},
   177  		{name: "universal", domain: "*", host: "abc.com", wantTyp: domainMatchTypeUniversal, wantMatched: true},
   178  		{name: "prefix-match", domain: "abc.*", host: "abc.123", wantTyp: domainMatchTypePrefix, wantMatched: true},
   179  		{name: "prefix-no-match", domain: "abc.*", host: "abcd.123", wantTyp: domainMatchTypePrefix, wantMatched: false},
   180  		{name: "suffix-match", domain: "*.123", host: "abc.123", wantTyp: domainMatchTypeSuffix, wantMatched: true},
   181  		{name: "suffix-no-match", domain: "*.123", host: "abc.1234", wantTyp: domainMatchTypeSuffix, wantMatched: false},
   182  		{name: "exact-match", domain: "foo.bar", host: "foo.bar", wantTyp: domainMatchTypeExact, wantMatched: true},
   183  		{name: "exact-no-match", domain: "foo.bar.com", host: "foo.bar", wantTyp: domainMatchTypeExact, wantMatched: false},
   184  	}
   185  	for _, tt := range tests {
   186  		t.Run(tt.name, func(t *testing.T) {
   187  			if gotTyp, gotMatched := match(tt.domain, tt.host); gotTyp != tt.wantTyp || gotMatched != tt.wantMatched {
   188  				t.Errorf("match() = %v, %v, want %v, %v", gotTyp, gotMatched, tt.wantTyp, tt.wantMatched)
   189  			}
   190  		})
   191  	}
   192  }