github.com/erda-project/erda-infra@v1.0.10-0.20240327085753-f3a249292aeb/pkg/transport/http/httprule/parse_test.go (about) 1 // Copyright (c) 2021 Terminus, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Reference: https://github.com/grpc-ecosystem/grpc-gateway/blob/v2.3.0/internal/httprule/parse_test.go 16 17 package httprule 18 19 import ( 20 "fmt" 21 "reflect" 22 "testing" 23 ) 24 25 func TestTokenize(t *testing.T) { 26 for _, spec := range []struct { 27 src string 28 tokens []string 29 verb string 30 }{ 31 { 32 src: "", 33 tokens: []string{eof}, 34 }, 35 { 36 src: "v1", 37 tokens: []string{"v1", eof}, 38 }, 39 { 40 src: "v1/b", 41 tokens: []string{"v1", "/", "b", eof}, 42 }, 43 { 44 src: "v1/endpoint/*", 45 tokens: []string{"v1", "/", "endpoint", "/", "*", eof}, 46 }, 47 { 48 src: "v1/endpoint/**", 49 tokens: []string{"v1", "/", "endpoint", "/", "**", eof}, 50 }, 51 { 52 src: "v1/b/{bucket_name=*}", 53 tokens: []string{ 54 "v1", "/", 55 "b", "/", 56 "{", "bucket_name", "=", "*", "}", 57 eof, 58 }, 59 }, 60 { 61 src: "v1/b/{bucket_name=buckets/*}", 62 tokens: []string{ 63 "v1", "/", 64 "b", "/", 65 "{", "bucket_name", "=", "buckets", "/", "*", "}", 66 eof, 67 }, 68 }, 69 { 70 src: "v1/b/{bucket_name=buckets/*}/o", 71 tokens: []string{ 72 "v1", "/", 73 "b", "/", 74 "{", "bucket_name", "=", "buckets", "/", "*", "}", "/", 75 "o", 76 eof, 77 }, 78 }, 79 { 80 src: "v1/b/{bucket_name=buckets/*}/o/{name}", 81 tokens: []string{ 82 "v1", "/", 83 "b", "/", 84 "{", "bucket_name", "=", "buckets", "/", "*", "}", "/", 85 "o", "/", "{", "name", "}", 86 eof, 87 }, 88 }, 89 { 90 src: "v1/a=b&c=d;e=f:g/endpoint.rdf", 91 tokens: []string{ 92 "v1", "/", 93 "a=b&c=d;e=f:g", "/", 94 "endpoint.rdf", 95 eof, 96 }, 97 }, 98 { 99 src: "v1/a/{endpoint}:a", 100 tokens: []string{ 101 "v1", "/", 102 "a", "/", 103 "{", "endpoint", "}", 104 eof, 105 }, 106 verb: "a", 107 }, 108 { 109 src: "v1/a/{endpoint}:b:c", 110 tokens: []string{ 111 "v1", "/", 112 "a", "/", 113 "{", "endpoint", "}", 114 eof, 115 }, 116 verb: "b:c", 117 }, 118 } { 119 tokens, verb := tokenize(spec.src) 120 if got, want := tokens, spec.tokens; !reflect.DeepEqual(got, want) { 121 t.Errorf("tokenize(%q) = %q, _; want %q, _", spec.src, got, want) 122 } 123 124 switch { 125 case spec.verb != "": 126 if got, want := verb, spec.verb; !reflect.DeepEqual(got, want) { 127 t.Errorf("tokenize(%q) = %q, _; want %q, _", spec.src, got, want) 128 } 129 130 default: 131 if got, want := verb, ""; got != want { 132 t.Errorf("tokenize(%q) = _, %q; want _, %q", spec.src, got, want) 133 } 134 135 src := fmt.Sprintf("%s:%s", spec.src, "LOCK") 136 tokens, verb = tokenize(src) 137 if got, want := tokens, spec.tokens; !reflect.DeepEqual(got, want) { 138 t.Errorf("tokenize(%q) = %q, _; want %q, _", src, got, want) 139 } 140 if got, want := verb, "LOCK"; got != want { 141 t.Errorf("tokenize(%q) = _, %q; want _, %q", src, got, want) 142 } 143 } 144 } 145 } 146 147 func TestParseSegments(t *testing.T) { 148 for _, spec := range []struct { 149 tokens []string 150 want []segment 151 }{ 152 { 153 tokens: []string{"v1", eof}, 154 want: []segment{ 155 literal("v1"), 156 }, 157 }, 158 { 159 tokens: []string{"/", eof}, 160 want: []segment{ 161 wildcard{}, 162 }, 163 }, 164 { 165 tokens: []string{"-._~!$&'()*+,;=:@", eof}, 166 want: []segment{ 167 literal("-._~!$&'()*+,;=:@"), 168 }, 169 }, 170 { 171 tokens: []string{"%e7%ac%ac%e4%b8%80%e7%89%88", eof}, 172 want: []segment{ 173 literal("%e7%ac%ac%e4%b8%80%e7%89%88"), 174 }, 175 }, 176 { 177 tokens: []string{"v1", "/", "*", eof}, 178 want: []segment{ 179 literal("v1"), 180 wildcard{}, 181 }, 182 }, 183 { 184 tokens: []string{"v1", "/", "**", eof}, 185 want: []segment{ 186 literal("v1"), 187 deepWildcard{}, 188 }, 189 }, 190 { 191 tokens: []string{"{", "name", "}", eof}, 192 want: []segment{ 193 variable{ 194 path: "name", 195 segments: []segment{ 196 wildcard{}, 197 }, 198 }, 199 }, 200 }, 201 { 202 tokens: []string{"{", "name", "=", "*", "}", eof}, 203 want: []segment{ 204 variable{ 205 path: "name", 206 segments: []segment{ 207 wildcard{}, 208 }, 209 }, 210 }, 211 }, 212 { 213 tokens: []string{"{", "field", ".", "nested", ".", "nested2", "=", "*", "}", eof}, 214 want: []segment{ 215 variable{ 216 path: "field.nested.nested2", 217 segments: []segment{ 218 wildcard{}, 219 }, 220 }, 221 }, 222 }, 223 { 224 tokens: []string{"{", "name", "=", "a", "/", "b", "/", "*", "}", eof}, 225 want: []segment{ 226 variable{ 227 path: "name", 228 segments: []segment{ 229 literal("a"), 230 literal("b"), 231 wildcard{}, 232 }, 233 }, 234 }, 235 }, 236 { 237 tokens: []string{ 238 "v1", "/", 239 "{", 240 "name", ".", "nested", ".", "nested2", 241 "=", 242 "a", "/", "b", "/", "*", 243 "}", "/", 244 "o", "/", 245 "{", 246 "another_name", 247 "=", 248 "a", "/", "b", "/", "*", "/", "c", 249 "}", "/", 250 "**", 251 eof, 252 }, 253 want: []segment{ 254 literal("v1"), 255 variable{ 256 path: "name.nested.nested2", 257 segments: []segment{ 258 literal("a"), 259 literal("b"), 260 wildcard{}, 261 }, 262 }, 263 literal("o"), 264 variable{ 265 path: "another_name", 266 segments: []segment{ 267 literal("a"), 268 literal("b"), 269 wildcard{}, 270 literal("c"), 271 }, 272 }, 273 deepWildcard{}, 274 }, 275 }, 276 } { 277 p := parser{tokens: spec.tokens} 278 segs, err := p.topLevelSegments() 279 if err != nil { 280 t.Errorf("parser{%q}.segments() failed with %v; want success", spec.tokens, err) 281 continue 282 } 283 if got, want := segs, spec.want; !reflect.DeepEqual(got, want) { 284 t.Errorf("parser{%q}.segments() = %#v; want %#v", spec.tokens, got, want) 285 } 286 if got := p.tokens; len(got) > 0 { 287 t.Errorf("p.tokens = %q; want []; spec.tokens=%q", got, spec.tokens) 288 } 289 } 290 } 291 292 func TestParseSegmentsWithErrors(t *testing.T) { 293 for _, spec := range []struct { 294 tokens []string 295 }{ 296 { 297 // double slash 298 tokens: []string{"//", eof}, 299 }, 300 { 301 // invalid literal 302 tokens: []string{"a?b", eof}, 303 }, 304 { 305 // invalid percent-encoding 306 tokens: []string{"%", eof}, 307 }, 308 { 309 // invalid percent-encoding 310 tokens: []string{"%2", eof}, 311 }, 312 { 313 // invalid percent-encoding 314 tokens: []string{"a%2z", eof}, 315 }, 316 { 317 // empty segments 318 tokens: []string{eof}, 319 }, 320 { 321 // unterminated variable 322 tokens: []string{"{", "name", eof}, 323 }, 324 { 325 // unterminated variable 326 tokens: []string{"{", "name", "=", eof}, 327 }, 328 { 329 // unterminated variable 330 tokens: []string{"{", "name", "=", "*", eof}, 331 }, 332 { 333 // empty component in field path 334 tokens: []string{"{", "name", ".", "}", eof}, 335 }, 336 { 337 // empty component in field path 338 tokens: []string{"{", "name", ".", ".", "nested", "}", eof}, 339 }, 340 { 341 // invalid character in identifier 342 tokens: []string{"{", "field-name", "}", eof}, 343 }, 344 { 345 // no slash between segments 346 tokens: []string{"v1", "endpoint", eof}, 347 }, 348 { 349 // no slash between segments 350 tokens: []string{"v1", "{", "name", "}", eof}, 351 }, 352 } { 353 p := parser{tokens: spec.tokens} 354 segs, err := p.topLevelSegments() 355 if err == nil { 356 t.Errorf("parser{%q}.segments() succeeded; want InvalidTemplateError; accepted %#v", spec.tokens, segs) 357 continue 358 } 359 t.Log(err) 360 } 361 }