dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/utils/matcher/string_matcher_test.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. 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 * 20 * Copyright 2020 gRPC authors. 21 * 22 */ 23 24 package matcher 25 26 import ( 27 "regexp" 28 "testing" 29 ) 30 31 import ( 32 v3matcherpb "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3" 33 34 "github.com/google/go-cmp/cmp" 35 ) 36 37 func TestStringMatcherFromProto(t *testing.T) { 38 tests := []struct { 39 desc string 40 inputProto *v3matcherpb.StringMatcher 41 wantMatcher StringMatcher 42 wantErr bool 43 }{ 44 { 45 desc: "nil proto", 46 wantErr: true, 47 }, 48 { 49 desc: "empty prefix", 50 inputProto: &v3matcherpb.StringMatcher{ 51 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: ""}, 52 }, 53 wantErr: true, 54 }, 55 { 56 desc: "empty suffix", 57 inputProto: &v3matcherpb.StringMatcher{ 58 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: ""}, 59 }, 60 wantErr: true, 61 }, 62 { 63 desc: "empty contains", 64 inputProto: &v3matcherpb.StringMatcher{ 65 MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: ""}, 66 }, 67 wantErr: true, 68 }, 69 { 70 desc: "invalid regex", 71 inputProto: &v3matcherpb.StringMatcher{ 72 MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{ 73 SafeRegex: &v3matcherpb.RegexMatcher{Regex: "??"}, 74 }, 75 }, 76 wantErr: true, 77 }, 78 { 79 desc: "happy case exact", 80 inputProto: &v3matcherpb.StringMatcher{ 81 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "exact"}, 82 }, 83 wantMatcher: StringMatcher{exactMatch: newStringP("exact")}, 84 }, 85 { 86 desc: "happy case exact ignore case", 87 inputProto: &v3matcherpb.StringMatcher{ 88 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "EXACT"}, 89 IgnoreCase: true, 90 }, 91 wantMatcher: StringMatcher{ 92 exactMatch: newStringP("exact"), 93 ignoreCase: true, 94 }, 95 }, 96 { 97 desc: "happy case prefix", 98 inputProto: &v3matcherpb.StringMatcher{ 99 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "prefix"}, 100 }, 101 wantMatcher: StringMatcher{prefixMatch: newStringP("prefix")}, 102 }, 103 { 104 desc: "happy case prefix ignore case", 105 inputProto: &v3matcherpb.StringMatcher{ 106 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "PREFIX"}, 107 IgnoreCase: true, 108 }, 109 wantMatcher: StringMatcher{ 110 prefixMatch: newStringP("prefix"), 111 ignoreCase: true, 112 }, 113 }, 114 { 115 desc: "happy case suffix", 116 inputProto: &v3matcherpb.StringMatcher{ 117 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "suffix"}, 118 }, 119 wantMatcher: StringMatcher{suffixMatch: newStringP("suffix")}, 120 }, 121 { 122 desc: "happy case suffix ignore case", 123 inputProto: &v3matcherpb.StringMatcher{ 124 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "SUFFIX"}, 125 IgnoreCase: true, 126 }, 127 wantMatcher: StringMatcher{ 128 suffixMatch: newStringP("suffix"), 129 ignoreCase: true, 130 }, 131 }, 132 { 133 desc: "happy case regex", 134 inputProto: &v3matcherpb.StringMatcher{ 135 MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{ 136 SafeRegex: &v3matcherpb.RegexMatcher{Regex: "good?regex?"}, 137 }, 138 }, 139 wantMatcher: StringMatcher{regexMatch: regexp.MustCompile("good?regex?")}, 140 }, 141 { 142 desc: "happy case contains", 143 inputProto: &v3matcherpb.StringMatcher{ 144 MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: "contains"}, 145 }, 146 wantMatcher: StringMatcher{containsMatch: newStringP("contains")}, 147 }, 148 { 149 desc: "happy case contains ignore case", 150 inputProto: &v3matcherpb.StringMatcher{ 151 MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: "CONTAINS"}, 152 IgnoreCase: true, 153 }, 154 wantMatcher: StringMatcher{ 155 containsMatch: newStringP("contains"), 156 ignoreCase: true, 157 }, 158 }, 159 } 160 161 for _, test := range tests { 162 t.Run(test.desc, func(t *testing.T) { 163 gotMatcher, err := StringMatcherFromProto(test.inputProto) 164 if (err != nil) != test.wantErr { 165 t.Fatalf("StringMatcherFromProto(%+v) returned err: %v, wantErr: %v", test.inputProto, err, test.wantErr) 166 } 167 if diff := cmp.Diff(gotMatcher, test.wantMatcher, cmp.AllowUnexported(regexp.Regexp{})); diff != "" { 168 t.Fatalf("StringMatcherFromProto(%+v) returned unexpected diff (-got, +want):\n%s", test.inputProto, diff) 169 } 170 }) 171 } 172 } 173 174 func TestMatch(t *testing.T) { 175 var ( 176 exactMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "exact"}}) 177 prefixMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "prefix"}}) 178 suffixMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "suffix"}}) 179 regexMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: "good?regex?"}}}) 180 containsMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: "contains"}}) 181 exactMatcherIgnoreCase, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{ 182 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "exact"}, 183 IgnoreCase: true, 184 }) 185 prefixMatcherIgnoreCase, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{ 186 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "prefix"}, 187 IgnoreCase: true, 188 }) 189 suffixMatcherIgnoreCase, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{ 190 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "suffix"}, 191 IgnoreCase: true, 192 }) 193 containsMatcherIgnoreCase, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{ 194 MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: "contains"}, 195 IgnoreCase: true, 196 }) 197 ) 198 199 tests := []struct { 200 desc string 201 matcher StringMatcher 202 input string 203 wantMatch bool 204 }{ 205 { 206 desc: "exact match success", 207 matcher: exactMatcher, 208 input: "exact", 209 wantMatch: true, 210 }, 211 { 212 desc: "exact match failure", 213 matcher: exactMatcher, 214 input: "not-exact", 215 }, 216 { 217 desc: "exact match success with ignore case", 218 matcher: exactMatcherIgnoreCase, 219 input: "EXACT", 220 wantMatch: true, 221 }, 222 { 223 desc: "exact match failure with ignore case", 224 matcher: exactMatcherIgnoreCase, 225 input: "not-exact", 226 }, 227 { 228 desc: "prefix match success", 229 matcher: prefixMatcher, 230 input: "prefixIsHere", 231 wantMatch: true, 232 }, 233 { 234 desc: "prefix match failure", 235 matcher: prefixMatcher, 236 input: "not-prefix", 237 }, 238 { 239 desc: "prefix match success with ignore case", 240 matcher: prefixMatcherIgnoreCase, 241 input: "PREFIXisHere", 242 wantMatch: true, 243 }, 244 { 245 desc: "prefix match failure with ignore case", 246 matcher: prefixMatcherIgnoreCase, 247 input: "not-PREFIX", 248 }, 249 { 250 desc: "suffix match success", 251 matcher: suffixMatcher, 252 input: "hereIsThesuffix", 253 wantMatch: true, 254 }, 255 { 256 desc: "suffix match failure", 257 matcher: suffixMatcher, 258 input: "suffix-is-not-here", 259 }, 260 { 261 desc: "suffix match success with ignore case", 262 matcher: suffixMatcherIgnoreCase, 263 input: "hereIsTheSuFFix", 264 wantMatch: true, 265 }, 266 { 267 desc: "suffix match failure with ignore case", 268 matcher: suffixMatcherIgnoreCase, 269 input: "SUFFIX-is-not-here", 270 }, 271 { 272 desc: "regex match success", 273 matcher: regexMatcher, 274 input: "goodregex", 275 wantMatch: true, 276 }, 277 { 278 desc: "regex match failure because only part match", 279 matcher: regexMatcher, 280 input: "goodregexa", 281 wantMatch: false, 282 }, 283 { 284 desc: "regex match failure", 285 matcher: regexMatcher, 286 input: "regex-is-not-here", 287 }, 288 { 289 desc: "contains match success", 290 matcher: containsMatcher, 291 input: "IScontainsHERE", 292 wantMatch: true, 293 }, 294 { 295 desc: "contains match failure", 296 matcher: containsMatcher, 297 input: "con-tains-is-not-here", 298 }, 299 { 300 desc: "contains match success with ignore case", 301 matcher: containsMatcherIgnoreCase, 302 input: "isCONTAINShere", 303 wantMatch: true, 304 }, 305 { 306 desc: "contains match failure with ignore case", 307 matcher: containsMatcherIgnoreCase, 308 input: "CON-TAINS-is-not-here", 309 }, 310 } 311 312 for _, test := range tests { 313 t.Run(test.desc, func(t *testing.T) { 314 if gotMatch := test.matcher.Match(test.input); gotMatch != test.wantMatch { 315 t.Errorf("StringMatcher.Match(%s) returned %v, want %v", test.input, gotMatch, test.wantMatch) 316 } 317 }) 318 } 319 } 320 321 func newStringP(s string) *string { 322 return &s 323 }