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 }