github.com/erda-project/erda-infra@v1.0.9/providers/httpserver/path_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 package httpserver 16 17 import ( 18 libcontext "context" 19 "fmt" 20 "net/http" 21 "net/url" 22 "reflect" 23 "testing" 24 25 "github.com/erda-project/erda-infra/pkg/transport/http/runtime" 26 "github.com/erda-project/erda-infra/providers/httpserver/server" 27 ) 28 29 func Test_buildGoogleAPIsPath(t *testing.T) { 30 type args struct { 31 path string 32 url string 33 } 34 type want struct { 35 path string 36 skip bool 37 params map[string]string 38 notmatch bool 39 } 40 tests := []struct { 41 name string 42 args args 43 want want 44 }{ 45 { 46 name: "empty path", 47 args: args{}, 48 want: want{}, 49 }, 50 { 51 name: "root path", 52 args: args{path: "/"}, 53 want: want{path: "/"}, 54 }, 55 { 56 name: "static path", 57 args: args{path: "/abc/def/g"}, 58 want: want{path: "/abc/def/g"}, 59 }, 60 { 61 name: "one path param", 62 args: args{ 63 path: "/abc/{def}/g", 64 url: "/abc/123/g", 65 }, 66 want: want{ 67 path: "/abc/:def/g", 68 params: map[string]string{"def": "123"}, 69 }, 70 }, 71 { 72 name: "two path params", 73 args: args{ 74 path: "/abc/{def}/g/{xyz}", 75 url: "/abc/123/g/456", 76 }, 77 want: want{ 78 path: "/abc/:def/g/:xyz", 79 params: map[string]string{"def": "123", "xyz": "456"}, 80 }, 81 }, 82 { 83 name: "many path params", 84 args: args{ 85 path: "/abc/{def}/g/{h}/{x}/{yz}", 86 url: "/abc/123/g/4/56/7", 87 }, 88 want: want{ 89 path: "/abc/:def/g/:h/:x/:yz", 90 params: map[string]string{"def": "123", "h": "4", "x": "56", "yz": "7"}, 91 }, 92 }, 93 { 94 name: "has empty path param", 95 args: args{path: "/abc/{def}/g/{}/{x}/{yz}"}, 96 want: want{path: "/abc/:def/g/*/:x/:yz", skip: true}, 97 }, 98 { 99 name: "* path param", 100 args: args{path: "/abc/{def}/g/{*}/{x}/{yz}"}, 101 want: want{path: "/abc/:def/g/*/:x/:yz", skip: true}, 102 }, 103 { 104 args: args{path: "/abc/{def}/g/{h/{x}/{yz}"}, 105 want: want{path: "/abc/:def/g/:h%2F%7Bx/:yz", skip: true}, 106 }, 107 { 108 args: args{path: "/abc/{def}/g/{h}/{x}/{yz"}, 109 want: want{path: "/abc/:def/g/:h/:x/{yz", skip: true}, 110 }, 111 { 112 args: args{path: "/abc/{def}/g/{h=xx}/{yz"}, 113 want: want{path: "/abc/:def/g/:h/{yz", skip: true}, 114 }, 115 { 116 args: args{path: "/abc/{def}/g/{h=xx}/{yz="}, 117 want: want{path: "/abc/:def/g/:h/{yz=", skip: true}, 118 }, 119 { 120 args: args{path: "/abc/{def}/g/{h=xx/***}/{yz="}, 121 want: want{path: "/abc/:def/g/:h/***/{yz=", skip: true}, 122 }, 123 { 124 args: args{path: "/abc/{def}/g/{h=xx/**}/yz:verb"}, 125 want: want{path: "/abc/:def/g/:h/**/yz%3Averb", skip: true}, 126 }, 127 { 128 args: args{path: "/abc/{def}/g/{h=xx/**}/yz:verb1:verb2"}, 129 want: want{path: "/abc/:def/g/:h/**/yz%3Averb1%3Averb2", skip: true}, 130 }, 131 { 132 name: "query string", 133 args: args{path: "/abc/{def}/g/{h=xx/**}/yz:verb1:verb2?abc=123&def=456"}, 134 want: want{path: "/abc/:def/g/:h/**/yz%3Averb1%3Averb2", skip: true}, 135 }, 136 { 137 args: args{ 138 path: "/abc/{def}/g/{h=xx}/yz", 139 url: "/abc/123/g/xx/yz", 140 }, 141 want: want{ 142 path: "/abc/:def/g/:h/yz", 143 params: map[string]string{"def": "123", "h": "xx"}, 144 }, 145 }, 146 { 147 args: args{ 148 path: "/abc/{def}/g/{h=xx}/yz", 149 url: "/abc/123/g/xx123/yz", 150 }, 151 want: want{ 152 path: "/abc/:def/g/:h/yz", 153 notmatch: true, 154 }, 155 }, 156 { 157 args: args{ 158 path: "/abc/{def}/g/{h=xx/123/*}/yz", 159 url: "/abc/123/g/xx/123/456/yz", 160 }, 161 want: want{ 162 path: "/abc/:def/g/:h/123/*/yz", 163 params: map[string]string{"def": "123", "h": "xx/123/456"}, 164 }, 165 }, 166 { 167 args: args{ 168 path: "/abc/{def}/g/{h=xx/123/*}/yz:aaa", 169 url: "/abc/123/g/xx/123/456/yz", 170 }, 171 want: want{ 172 path: "/abc/:def/g/:h/123/*/yz%3Aaaa", 173 notmatch: true, 174 }, 175 }, 176 { 177 args: args{ 178 path: "/abc/{def}/g/{h=xx/123/*}/yz:aaa", 179 url: "/abc/123/g/xx/123/456/yz:bbb", 180 }, 181 want: want{ 182 path: "/abc/:def/g/:h/123/*/yz%3Aaaa", 183 notmatch: true, 184 }, 185 }, 186 { 187 args: args{ 188 path: "/abc/{def}/g/{h=xx/123/*}/yz:aaa", 189 url: "/abc/123/g/xx/123/456/yz:aaa", 190 }, 191 want: want{ 192 path: "/abc/:def/g/:h/123/*/yz%3Aaaa", 193 params: map[string]string{"def": "123", "h": "xx/123/456"}, 194 }, 195 }, 196 { 197 args: args{ 198 path: "/abc/{_}/d", 199 url: "/abc/123/d", 200 }, 201 want: want{ 202 path: "/abc/:_/d", 203 params: map[string]string{"_": "123"}, 204 }, 205 }, 206 } 207 for _, tt := range tests { 208 t.Run(tt.name, func(t *testing.T) { 209 if got := buildGoogleAPIsPath(tt.args.path); got != tt.want.path { 210 t.Errorf("buildGoogleAPIsPath() = %v, want %v", got, tt.want.path) 211 return 212 } 213 if tt.want.skip { 214 return 215 } 216 matcher, err := runtime.Compile(tt.args.path) 217 if err != nil { 218 t.Errorf("runtime.Compile() return %s", err) 219 return 220 } 221 if len(tt.args.url) > 0 { 222 vars, err := matcher.Match(tt.args.url) 223 if err != nil { 224 if !tt.want.notmatch { 225 t.Errorf("not match %q by %q", tt.args.url, tt.args.path) 226 return 227 } 228 return 229 } 230 if len(vars) == 0 && len(tt.want.params) == 0 { 231 return 232 } 233 if !reflect.DeepEqual(vars, tt.want.params) { 234 t.Errorf("params not match, got %v, want %v", vars, tt.want.params) 235 return 236 } 237 } 238 }) 239 } 240 } 241 242 func Test_buildEchoPath(t *testing.T) { 243 tests := []struct { 244 path string 245 want string 246 }{ 247 { 248 path: "/abc/def", 249 want: "/abc/def", 250 }, 251 { 252 path: "/abc/:def/g", 253 want: "/abc/:def/g", 254 }, 255 } 256 for _, tt := range tests { 257 t.Run("", func(t *testing.T) { 258 if got := buildEchoPath(tt.path); got != tt.want { 259 t.Errorf("buildEchoPath() = %v, want %v", got, tt.want) 260 } 261 }) 262 } 263 } 264 265 func Test_googleAPIsPathParamsInterceptor(t *testing.T) { 266 handler := func(c server.Context) error { return nil } 267 type args struct { 268 path string 269 handler server.HandlerFunc 270 } 271 tests := []struct { 272 name string 273 args args 274 static bool 275 }{ 276 { 277 name: "static", 278 args: args{ 279 path: "/abc/def", 280 handler: handler, 281 }, 282 static: true, 283 }, 284 { 285 name: "params", 286 args: args{ 287 path: "/abc/{def}/g", 288 handler: handler, 289 }, 290 static: false, 291 }, 292 } 293 for _, tt := range tests { 294 t.Run(tt.name, func(t *testing.T) { 295 handler := googleAPIsPathParamsInterceptor(tt.args.path)(tt.args.handler) 296 if tt.static { 297 if fmt.Sprint(handler) != fmt.Sprint(tt.args.handler) { 298 t.Errorf("googleAPIsPathParamsInterceptor()(handler) get non static handler") 299 } 300 } else { 301 if fmt.Sprint(handler) == fmt.Sprint(tt.args.handler) { 302 t.Errorf("googleAPIsPathParamsInterceptor()(handler) got wrapped handler") 303 } 304 } 305 }) 306 } 307 } 308 309 func TestWithPathFormat(t *testing.T) { 310 tests := []struct { 311 name string 312 format PathFormat 313 want *pathFormater 314 }{ 315 { 316 name: "googleapis", 317 format: PathFormatGoogleAPIs, 318 want: &pathFormater{ 319 typ: PathFormatGoogleAPIs, 320 format: buildGoogleAPIsPath, 321 parser: googleAPIsPathParamsInterceptor, 322 }, 323 }, 324 { 325 name: "echo path", 326 format: PathFormatEcho, 327 want: &pathFormater{ 328 typ: PathFormatEcho, 329 format: buildEchoPath, 330 }, 331 }, 332 } 333 for _, tt := range tests { 334 335 t.Run(tt.name, func(t *testing.T) { 336 if got, ok := WithPathFormat(tt.format).(*pathFormater); !ok || fmt.Sprint(*got) != fmt.Sprint(*tt.want) { 337 t.Errorf("WithPathFormat() = %v, want %v", got, tt.want) 338 } 339 }) 340 } 341 } 342 343 func TestAddVarsToRequest(t *testing.T) { 344 type args struct { 345 req *http.Request 346 vars map[string]string 347 } 348 tests := []struct { 349 name string 350 args args 351 }{ 352 { 353 name: "add vars", 354 args: args{ 355 req: &http.Request{ 356 URL: &url.URL{ 357 Path: "/abc/def", 358 }, 359 }, 360 vars: map[string]string{"def": "123"}, 361 }, 362 }, 363 } 364 for _, tt := range tests { 365 t.Run(tt.name, func(t *testing.T) { 366 ctx := libcontext.Background() 367 ctxWithVars := makeCtxWithVars(ctx, tt.args.vars) 368 if !reflect.DeepEqual(tt.args.vars, ctxWithVars.Value(varsKey).(map[string]string)) { 369 t.Errorf("makeCtxWithVars() = %v, want %v", ctxWithVars.Value(varsKey).(map[string]string), tt.args.vars) 370 } 371 }) 372 } 373 }