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  }