github.com/kumasuke120/mockuma@v1.1.9/internal/server/matcher_test.go (about)

     1  package server
     2  
     3  import (
     4  	"net/http/httptest"
     5  	"regexp"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/kumasuke120/mockuma/internal/mckmaps"
    10  	"github.com/kumasuke120/mockuma/internal/myhttp"
    11  	"github.com/kumasuke120/mockuma/internal/myjson"
    12  	"github.com/stretchr/testify/assert"
    13  )
    14  
    15  var emptyJSONMatcher = myjson.MakeExtJSONMatcher(myjson.Object{})
    16  var mappings = &mckmaps.MockuMappings{
    17  	Mappings: []*mckmaps.Mapping{
    18  		{
    19  			URI:      "/hello",
    20  			Method:   myhttp.MethodPost,
    21  			Policies: []*mckmaps.Policy{newJSONPolicy(myhttp.StatusOK, "OK")},
    22  		},
    23  		{
    24  			URI:    "/m",
    25  			Method: myhttp.MethodGet,
    26  			Policies: []*mckmaps.Policy{
    27  				{
    28  					When: &mckmaps.When{
    29  						Params: []*mckmaps.NameValuesPair{
    30  							{
    31  								Name:   "p1",
    32  								Values: []string{"v1"},
    33  							},
    34  							{
    35  								Name:   "p2",
    36  								Values: []string{"v2", "v1"},
    37  							},
    38  						},
    39  					},
    40  					CmdType: mckmaps.CmdTypeForwards,
    41  					Forwards: &mckmaps.Forwards{
    42  						Path: "http://localhost:8080",
    43  					},
    44  				},
    45  				{
    46  					When: &mckmaps.When{
    47  						ParamRegexps: []*mckmaps.NameRegexpPair{
    48  							{
    49  								Name:   "r1",
    50  								Regexp: regexp.MustCompile("^\\d{3}$"),
    51  							},
    52  						},
    53  					},
    54  					CmdType: mckmaps.CmdTypeReturns,
    55  					Returns: &mckmaps.Returns{
    56  						StatusCode: myhttp.StatusOK,
    57  						Body:       []byte(""),
    58  					},
    59  				},
    60  				{
    61  					When: &mckmaps.When{
    62  						ParamJSONs: []*mckmaps.NameJSONPair{
    63  							{
    64  								Name: "j",
    65  								JSON: myjson.MakeExtJSONMatcher(myjson.Object{}),
    66  							},
    67  						},
    68  					},
    69  				},
    70  				{
    71  					When: &mckmaps.When{
    72  						Headers: []*mckmaps.NameValuesPair{
    73  							{
    74  								Name:   "X-H1",
    75  								Values: []string{"v1"},
    76  							},
    77  							{
    78  								Name:   "X-H2",
    79  								Values: []string{"v2", "v1"},
    80  							},
    81  						},
    82  					},
    83  				},
    84  				{
    85  					When: &mckmaps.When{
    86  						HeaderRegexps: []*mckmaps.NameRegexpPair{
    87  							{
    88  								Name:   "X-R1",
    89  								Regexp: regexp.MustCompile("^\\d{3}$"),
    90  							},
    91  						},
    92  					},
    93  				},
    94  				{
    95  					When: &mckmaps.When{
    96  						HeaderJSONs: []*mckmaps.NameJSONPair{
    97  							{
    98  								Name: "X-J1",
    99  								JSON: myjson.MakeExtJSONMatcher(myjson.Object{}),
   100  							},
   101  						},
   102  					},
   103  				},
   104  			},
   105  		},
   106  		{
   107  			URI:    "/m",
   108  			Method: myhttp.MethodPost,
   109  			Policies: []*mckmaps.Policy{
   110  				{
   111  					When: &mckmaps.When{
   112  						Body: []byte("123"),
   113  					},
   114  				},
   115  				{
   116  					When: &mckmaps.When{
   117  						BodyRegexp: regexp.MustCompile("^\\d{3}$"),
   118  					},
   119  					CmdType: mckmaps.CmdTypeReturns,
   120  					Returns: &mckmaps.Returns{
   121  						StatusCode: myhttp.StatusOK,
   122  						Headers: []*mckmaps.NameValuesPair{
   123  							{
   124  								Name:   "Server",
   125  								Values: []string{"TEST/v1"},
   126  							},
   127  						},
   128  					},
   129  				},
   130  				{
   131  					When: &mckmaps.When{
   132  						BodyJSON: &emptyJSONMatcher,
   133  					},
   134  				},
   135  			},
   136  		},
   137  		{
   138  			URI:    "/p/{0}/m{1}",
   139  			Method: myhttp.MethodPut,
   140  			Policies: []*mckmaps.Policy{
   141  				{
   142  					When: &mckmaps.When{
   143  						PathVars: []*mckmaps.NameValuesPair{
   144  							{
   145  								Name:   "0",
   146  								Values: []string{"v0"},
   147  							},
   148  						},
   149  						PathVarRegexps: []*mckmaps.NameRegexpPair{
   150  							{
   151  								Name:   "1",
   152  								Regexp: regexp.MustCompile("^\\d+$"),
   153  							},
   154  						},
   155  					},
   156  				},
   157  			},
   158  		},
   159  	},
   160  	Config: &mckmaps.Config{
   161  		CORS: &mckmaps.CORSOptions{
   162  			Enabled: false,
   163  		},
   164  	},
   165  }
   166  
   167  var mappingsWithCORS = &mckmaps.MockuMappings{
   168  	Mappings: mappings.Mappings,
   169  	Config: &mckmaps.Config{
   170  		CORS: &mckmaps.CORSOptions{
   171  			Enabled:          true,
   172  			AllowCredentials: true,
   173  			MaxAge:           1800,
   174  			AllowedOrigins:   []string{"*"},
   175  			AllowedMethods: []myhttp.HTTPMethod{
   176  				myhttp.MethodGet,
   177  				myhttp.MethodPost,
   178  				myhttp.MethodHead,
   179  				myhttp.MethodOptions,
   180  			},
   181  			AllowedHeaders: []string{
   182  				myhttp.HeaderOrigin,
   183  				myhttp.HeaderAccept,
   184  				myhttp.HeaderXRequestWith,
   185  				myhttp.HeaderContentType,
   186  				myhttp.HeaderAccessControlRequestMethod,
   187  				myhttp.HeaderAccessControlRequestHeaders,
   188  			},
   189  			ExposedHeaders: nil,
   190  		},
   191  		MatchTrailingSlash: false,
   192  	},
   193  }
   194  
   195  func TestNewPathMatcher(t *testing.T) {
   196  	matcher := newPathMatcher(mappings)
   197  
   198  	expectedDirectPath := map[string][]*mckmaps.Mapping{
   199  		"/hello": {mappings.Mappings[0]},
   200  		"/m": {
   201  			&mckmaps.Mapping{
   202  				URI:      "/m",
   203  				Method:   myhttp.MethodGet,
   204  				Policies: mappings.Mappings[1].Policies,
   205  			},
   206  			mappings.Mappings[2],
   207  		},
   208  	}
   209  	assert.Equal(t, expectedDirectPath, matcher.directPath)
   210  	expectedPatternPath := map[*regexp.Regexp][]*mckmaps.Mapping{
   211  		regexp.MustCompile("^/p/(?P<v0>.*?)/m(?P<v1>.*?)$"): {
   212  			mappings.Mappings[3],
   213  		},
   214  	}
   215  	assert.Equal(t, formatRegexpKeyMap(expectedPatternPath), formatRegexpKeyMap(matcher.patternPath))
   216  }
   217  
   218  func formatRegexpKeyMap(m map[*regexp.Regexp][]*mckmaps.Mapping) map[string][]*mckmaps.Mapping {
   219  	result := make(map[string][]*mckmaps.Mapping, len(m))
   220  	for r, ms := range m {
   221  		result[r.String()] = ms
   222  	}
   223  	return result
   224  }
   225  
   226  func TestPathMatcher_matches(t *testing.T) {
   227  	//noinspection GoImportUsedAsName
   228  	assert := assert.New(t)
   229  
   230  	matcher := newPathMatcher(mappings)
   231  	bound := matcher.bind(httptest.NewRequest("POST", "/hello", nil))
   232  	assert.True(bound.matches())
   233  	assert.Equal(matchState(matchExact), bound.matchState)
   234  	assert.Equal(mappings.Mappings[0], bound.matchedMapping)
   235  }
   236  
   237  func TestPathMatcher_matchPolicy(t *testing.T) {
   238  	//noinspection GoImportUsedAsName
   239  	assert := assert.New(t)
   240  
   241  	matcher := newPathMatcher(mappings)
   242  
   243  	bound1 := matcher.bind(httptest.NewRequest("", "/m?p1=v1&p2=v1&p2=v2", nil))
   244  	assert.True(bound1.matches())
   245  	assert.Equal(matchState(matchExact), bound1.matchState)
   246  	assert.Equal(mappings.Mappings[1].Policies[0], bound1.matchPolicy())
   247  
   248  	bound2 := matcher.bind(httptest.NewRequest("", "/m?r1=123", nil))
   249  	assert.True(bound2.matches())
   250  	assert.Equal(matchState(matchExact), bound2.matchState)
   251  	assert.Equal(mappings.Mappings[1].Policies[1], bound2.matchPolicy())
   252  	bound2 = matcher.bind(httptest.NewRequest("", "/m?r1=12", nil))
   253  	assert.True(bound2.matches())
   254  	assert.Equal(matchState(matchExact), bound2.matchState)
   255  	assert.Equal(pNoPolicyMatched, bound2.matchPolicy())
   256  
   257  	bound3 := matcher.bind(httptest.NewRequest("", "/m?j={}", nil))
   258  	assert.True(bound3.matches())
   259  	assert.Equal(matchState(matchExact), bound3.matchState)
   260  	assert.Equal(mappings.Mappings[1].Policies[2], bound3.matchPolicy())
   261  	bound3 = matcher.bind(httptest.NewRequest("", "/m?j=120", nil))
   262  	assert.True(bound3.matches())
   263  	assert.Equal(matchState(matchExact), bound3.matchState)
   264  	assert.Equal(pNoPolicyMatched, bound3.matchPolicy())
   265  
   266  	req4 := httptest.NewRequest("", "/m", nil)
   267  	req4.Header.Add("X-H1", "v1")
   268  	req4.Header.Add("X-H2", "v1")
   269  	req4.Header.Add("X-H2", "v2")
   270  	bound4 := matcher.bind(req4)
   271  	assert.True(bound4.matches())
   272  	assert.Equal(matchState(matchExact), bound4.matchState)
   273  	assert.Equal(mappings.Mappings[1].Policies[3], bound4.matchPolicy())
   274  
   275  	req5p1 := httptest.NewRequest("", "/m", nil)
   276  	req5p1.Header.Add("X-R1", "123")
   277  	bound5 := matcher.bind(req5p1)
   278  	assert.True(bound5.matches())
   279  	assert.Equal(matchState(matchExact), bound5.matchState)
   280  	assert.Equal(mappings.Mappings[1].Policies[4], bound5.matchPolicy())
   281  	req5p2 := httptest.NewRequest("", "/m", nil)
   282  	req5p2.Header.Add("X-R1", "12")
   283  	bound5 = matcher.bind(req5p2)
   284  	assert.True(bound5.matches())
   285  	assert.Equal(matchState(matchExact), bound5.matchState)
   286  	assert.Equal(pNoPolicyMatched, bound5.matchPolicy())
   287  
   288  	req6p1 := httptest.NewRequest("", "/m", nil)
   289  	req6p1.Header.Add("X-J1", "{}")
   290  	bound6 := matcher.bind(req6p1)
   291  	assert.True(bound6.matches())
   292  	assert.Equal(matchState(matchExact), bound6.matchState)
   293  	assert.Equal(mappings.Mappings[1].Policies[5], bound6.matchPolicy())
   294  	req6p2 := httptest.NewRequest("", "/m", nil)
   295  	req6p2.Header.Add("X-J1", "120")
   296  	bound6 = matcher.bind(req6p2)
   297  	assert.True(bound6.matches())
   298  	assert.Equal(matchState(matchExact), bound6.matchState)
   299  	assert.Equal(pNoPolicyMatched, bound6.matchPolicy())
   300  
   301  	bound7 := matcher.bind(httptest.NewRequest("POST", "/m", strings.NewReader("123")))
   302  	assert.True(bound7.matches())
   303  	assert.Equal(matchState(matchExact), bound7.matchState)
   304  	assert.Equal(mappings.Mappings[2].Policies[0], bound7.matchPolicy())
   305  
   306  	bound8 := matcher.bind(httptest.NewRequest("POST", "/m", strings.NewReader("120")))
   307  	assert.True(bound8.matches())
   308  	assert.Equal(matchState(matchExact), bound8.matchState)
   309  	assert.Equal(mappings.Mappings[2].Policies[1], bound8.matchPolicy())
   310  	bound8 = matcher.bind(httptest.NewRequest("POST", "/m", strings.NewReader("95")))
   311  	assert.True(bound8.matches())
   312  	assert.Equal(matchState(matchExact), bound8.matchState)
   313  	assert.Equal(pNoPolicyMatched, bound8.matchPolicy())
   314  
   315  	bound9 := matcher.bind(httptest.NewRequest("POST", "/m", strings.NewReader("{}")))
   316  	assert.True(bound9.matches())
   317  	assert.Equal(matchState(matchExact), bound9.matchState)
   318  	assert.Equal(mappings.Mappings[2].Policies[2], bound9.matchPolicy())
   319  
   320  	bound10 := matcher.bind(httptest.NewRequest("", "/hello", nil))
   321  	assert.True(bound10.matches())
   322  	assert.Equal(matchState(matchURI), bound10.matchState)
   323  
   324  	bound11 := matcher.bind(httptest.NewRequest("PUT", "/p/v0/m1", nil))
   325  	assert.True(bound11.matches())
   326  	assert.Equal(matchState(matchExact), bound11.matchState)
   327  	assert.Equal(mappings.Mappings[3].Policies[0], bound11.matchPolicy())
   328  
   329  	bound12 := matcher.bind(httptest.NewRequest("PUT", "/p/v0/ma", nil))
   330  	assert.True(bound12.matches())
   331  	assert.Equal(matchState(matchExact), bound12.matchState)
   332  	assert.Equal(pNoPolicyMatched, bound12.matchPolicy())
   333  
   334  	bound13 := matcher.bind(httptest.NewRequest("", "/p/v0/m1", nil))
   335  	assert.True(bound13.matches())
   336  	assert.Equal(matchState(matchURI), bound13.matchState)
   337  
   338  	bound14 := matcher.bind(httptest.NewRequest("PUT", "/p/v1/m1", nil))
   339  	assert.True(bound14.matches())
   340  	assert.Equal(matchState(matchExact), bound14.matchState)
   341  	assert.Equal(pNoPolicyMatched, bound14.matchPolicy())
   342  
   343  	bound15 := matcher.bind(httptest.NewRequest("HEAD", "/m?r1=123", nil))
   344  	assert.True(bound15.matches())
   345  	assert.Equal(matchState(matchHead), bound15.matchState)
   346  	assert.Equal(mappings.Mappings[1].Policies[1], bound15.matchPolicy())
   347  }