github.com/cloudwego/hertz@v0.9.3/pkg/route/routes_timing_test.go (about)

     1  /*
     2   * Copyright 2022 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   * The MIT License (MIT)
    16   *
    17   * Copyright (c) 2014 Manuel Martínez-Almeida
    18   *
    19   * Permission is hereby granted, free of charge, to any person obtaining a copy
    20   * of this software and associated documentation files (the "Software"), to deal
    21   * in the Software without restriction, including without limitation the rights
    22   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    23   * copies of the Software, and to permit persons to whom the Software is
    24   * furnished to do so, subject to the following conditions:
    25   *
    26   * The above copyright notice and this permission notice shall be included in
    27   * all copies or substantial portions of the Software.
    28   *
    29   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    30   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    31   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    32   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    33   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    34   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    35   * THE SOFTWARE.
    36   *
    37   * This file may have been modified by CloudWeGo authors. All CloudWeGo
    38   * Modifications are Copyright 2022 CloudWeGo Authors
    39   */
    40  
    41  package route
    42  
    43  import (
    44  	"context"
    45  	"testing"
    46  
    47  	"github.com/cloudwego/hertz/pkg/app"
    48  	"github.com/cloudwego/hertz/pkg/common/config"
    49  	"github.com/cloudwego/hertz/pkg/protocol"
    50  )
    51  
    52  type Route struct {
    53  	path string
    54  }
    55  
    56  func BenchmarkTree_FindStatic(b *testing.B) {
    57  	tree := &router{method: "GET", root: &node{}, hasTsrHandler: make(map[string]bool)}
    58  
    59  	static := []*Route{
    60  		{"/"},
    61  		{"/cmd.html"},
    62  		{"/code.html"},
    63  		{"/contrib.html"},
    64  		{"/contribute.html"},
    65  		{"/debugging_with_gdb.html"},
    66  		{"/docs.html"},
    67  		{"/effective_go.html"},
    68  		{"/files.log"},
    69  		{"/gccgo_contribute.html"},
    70  		{"/gccgo_install.html"},
    71  		{"/go-logo-black.png"},
    72  		{"/go-logo-blue.png"},
    73  		{"/go-logo-white.png"},
    74  		{"/go1.1.html"},
    75  		{"/go1.2.html"},
    76  		{"/go1.html"},
    77  		{"/go1compat.html"},
    78  		{"/go_faq.html"},
    79  		{"/go_mem.html"},
    80  		{"/go_spec.html"},
    81  		{"/help.html"},
    82  		{"/ie.css"},
    83  		{"/install-source.html"},
    84  		{"/install.html"},
    85  		{"/logo-153x55.png"},
    86  		{"/Makefile"},
    87  		{"/root.html"},
    88  		{"/share.png"},
    89  		{"/sieve.gif"},
    90  		{"/tos.html"},
    91  		{"/articles/"},
    92  		{"/articles/go_command.html"},
    93  		{"/articles/index.html"},
    94  		{"/articles/wiki/"},
    95  		{"/articles/wiki/edit.html"},
    96  		{"/articles/wiki/final-noclosure.go"},
    97  		{"/articles/wiki/final-noerror.go"},
    98  		{"/articles/wiki/final-parsetemplate.go"},
    99  		{"/articles/wiki/final-template.go"},
   100  		{"/articles/wiki/final.go"},
   101  		{"/articles/wiki/get.go"},
   102  		{"/articles/wiki/http-sample.go"},
   103  		{"/articles/wiki/index.html"},
   104  		{"/articles/wiki/Makefile"},
   105  		{"/articles/wiki/notemplate.go"},
   106  		{"/articles/wiki/part1-noerror.go"},
   107  		{"/articles/wiki/part1.go"},
   108  		{"/articles/wiki/part2.go"},
   109  		{"/articles/wiki/part3-errorhandling.go"},
   110  		{"/articles/wiki/part3.go"},
   111  		{"/articles/wiki/test.bash"},
   112  		{"/articles/wiki/test_edit.good"},
   113  		{"/articles/wiki/test_Test.txt.good"},
   114  		{"/articles/wiki/test_view.good"},
   115  		{"/articles/wiki/view.html"},
   116  		{"/codewalk/"},
   117  		{"/codewalk/codewalk.css"},
   118  		{"/codewalk/codewalk.js"},
   119  		{"/codewalk/codewalk.xml"},
   120  		{"/codewalk/functions.xml"},
   121  		{"/codewalk/markov.go"},
   122  		{"/codewalk/markov.xml"},
   123  		{"/codewalk/pig.go"},
   124  		{"/codewalk/popout.png"},
   125  		{"/codewalk/run"},
   126  		{"/codewalk/sharemem.xml"},
   127  		{"/codewalk/urlpoll.go"},
   128  		{"/devel/"},
   129  		{"/devel/release.html"},
   130  		{"/devel/weekly.html"},
   131  		{"/gopher/"},
   132  		{"/gopher/appenginegopher.jpg"},
   133  		{"/gopher/appenginegophercolor.jpg"},
   134  		{"/gopher/appenginelogo.gif"},
   135  		{"/gopher/bumper.png"},
   136  		{"/gopher/bumper192x108.png"},
   137  		{"/gopher/bumper320x180.png"},
   138  		{"/gopher/bumper480x270.png"},
   139  		{"/gopher/bumper640x360.png"},
   140  		{"/gopher/doc.png"},
   141  		{"/gopher/frontpage.png"},
   142  		{"/gopher/gopherbw.png"},
   143  		{"/gopher/gophercolor.png"},
   144  		{"/gopher/gophercolor16x16.png"},
   145  		{"/gopher/help.png"},
   146  		{"/gopher/pkg.png"},
   147  		{"/gopher/project.png"},
   148  		{"/gopher/ref.png"},
   149  		{"/gopher/run.png"},
   150  		{"/gopher/talks.png"},
   151  		{"/gopher/pencil/"},
   152  		{"/gopher/pencil/gopherhat.jpg"},
   153  		{"/gopher/pencil/gopherhelmet.jpg"},
   154  		{"/gopher/pencil/gophermega.jpg"},
   155  		{"/gopher/pencil/gopherrunning.jpg"},
   156  		{"/gopher/pencil/gopherswim.jpg"},
   157  		{"/gopher/pencil/gopherswrench.jpg"},
   158  		{"/play/"},
   159  		{"/play/fib.go"},
   160  		{"/play/hello.go"},
   161  		{"/play/life.go"},
   162  		{"/play/peano.go"},
   163  		{"/play/pi.go"},
   164  		{"/play/sieve.go"},
   165  		{"/play/solitaire.go"},
   166  		{"/play/tree.go"},
   167  		{"/progs/"},
   168  		{"/progs/cgo1.go"},
   169  		{"/progs/cgo2.go"},
   170  		{"/progs/cgo3.go"},
   171  		{"/progs/cgo4.go"},
   172  		{"/progs/defer.go"},
   173  		{"/progs/defer.out"},
   174  		{"/progs/defer2.go"},
   175  		{"/progs/defer2.out"},
   176  		{"/progs/eff_bytesize.go"},
   177  		{"/progs/eff_bytesize.out"},
   178  		{"/progs/eff_qr.go"},
   179  		{"/progs/eff_sequence.go"},
   180  		{"/progs/eff_sequence.out"},
   181  		{"/progs/eff_unused1.go"},
   182  		{"/progs/eff_unused2.go"},
   183  		{"/progs/error.go"},
   184  		{"/progs/error2.go"},
   185  		{"/progs/error3.go"},
   186  		{"/progs/error4.go"},
   187  		{"/progs/go1.go"},
   188  		{"/progs/gobs1.go"},
   189  		{"/progs/gobs2.go"},
   190  		{"/progs/image_draw.go"},
   191  		{"/progs/image_package1.go"},
   192  		{"/progs/image_package1.out"},
   193  		{"/progs/image_package2.go"},
   194  		{"/progs/image_package2.out"},
   195  		{"/progs/image_package3.go"},
   196  		{"/progs/image_package3.out"},
   197  		{"/progs/image_package4.go"},
   198  		{"/progs/image_package4.out"},
   199  		{"/progs/image_package5.go"},
   200  		{"/progs/image_package5.out"},
   201  		{"/progs/image_package6.go"},
   202  		{"/progs/image_package6.out"},
   203  		{"/progs/interface.go"},
   204  		{"/progs/interface2.go"},
   205  		{"/progs/interface2.out"},
   206  		{"/progs/json1.go"},
   207  		{"/progs/json2.go"},
   208  		{"/progs/json2.out"},
   209  		{"/progs/json3.go"},
   210  		{"/progs/json4.go"},
   211  		{"/progs/json5.go"},
   212  		{"/progs/run"},
   213  		{"/progs/slices.go"},
   214  		{"/progs/timeout1.go"},
   215  		{"/progs/timeout2.go"},
   216  		{"/progs/update.bash"},
   217  	}
   218  
   219  	for _, route := range static {
   220  		tree.addRoute(route.path, fakeHandler(route.path))
   221  	}
   222  	ps := getParams()
   223  
   224  	b.ResetTimer()
   225  	for i := 0; i < b.N; i++ {
   226  		for _, request := range static {
   227  			tree.find(request.path, ps, false)
   228  		}
   229  	}
   230  }
   231  
   232  func BenchmarkTree_FindGithub(b *testing.B) {
   233  	tree := &router{method: "GET", root: &node{}, hasTsrHandler: make(map[string]bool)}
   234  
   235  	static := []*Route{
   236  		// OAuth Authorizations
   237  		{"/authorizations"},
   238  		{"/authorizations/:id"},
   239  		//{"/authorizations"},
   240  		//{"/authorizations/clients/:client_id"},
   241  		//{"/authorizations/:id"},
   242  		//{"/authorizations/:id"},
   243  		{"/applications/:client_id/tokens/:access_token"},
   244  		{"/applications/:client_id/tokens"},
   245  		//{"/applications/:client_id/tokens/:access_token"},
   246  
   247  		// Activity
   248  		{"/events"},
   249  		{"/repos/:owner/:repo/events"},
   250  		{"/networks/:owner/:repo/events"},
   251  		{"/orgs/:org/events"},
   252  		{"/users/:user/received_events"},
   253  		{"/users/:user/received_events/public"},
   254  		{"/users/:user/events"},
   255  		{"/users/:user/events/public"},
   256  		{"/users/:user/events/orgs/:org"},
   257  		{"/feeds"},
   258  		//{"/notifications"},
   259  		{"/repos/:owner/:repo/notifications"},
   260  		{"/notifications"},
   261  		//{"/repos/:owner/:repo/notifications"},
   262  		{"/notifications/threads/:id"},
   263  		//{"/notifications/threads/:id"},
   264  		{"/notifications/threads/:id/subscription"},
   265  		//{"/notifications/threads/:id/subscription"},
   266  		//{"/notifications/threads/:id/subscription"},
   267  		{"/repos/:owner/:repo/stargazers"},
   268  		{"/users/:user/starred"},
   269  		{"/user/starred"},
   270  		{"/user/starred/:owner/:repo"},
   271  		//{"/user/starred/:owner/:repo"},
   272  		//{"/user/starred/:owner/:repo"},
   273  		{"/repos/:owner/:repo/subscribers"},
   274  		{"/users/:user/subscriptions"},
   275  		{"/user/subscriptions"},
   276  		{"/repos/:owner/:repo/subscription"},
   277  		//{"/repos/:owner/:repo/subscription"},
   278  		//{"/repos/:owner/:repo/subscription"},
   279  		{"/user/subscriptions/:owner/:repo"},
   280  		//{"PUT", "/user/subscriptions/:owner/:repo"},
   281  		//{"DELETE", "/user/subscriptions/:owner/:repo"},
   282  
   283  		// Gists
   284  		{"/users/:user/gists"},
   285  		{"/gists"},
   286  		//{"GET", "/gists/public"},
   287  		//{"GET", "/gists/starred"},
   288  		{"/gists/:id"},
   289  		//{"POST", "/gists"},
   290  		//{"PATCH", "/gists/:id"},
   291  		{"/gists/:id/star"},
   292  		//{"DELETE", "/gists/:id/star"},
   293  		//{"GET", "/gists/:id/star"},
   294  		{"/gists/:id/forks"},
   295  		//{"DELETE", "/gists/:id"},
   296  
   297  		// Git Data
   298  		{"/repos/:owner/:repo/git/blobs/:sha"},
   299  		{"/repos/:owner/:repo/git/blobs"},
   300  		{"/repos/:owner/:repo/git/commits/:sha"},
   301  		{"/repos/:owner/:repo/git/commits"},
   302  		//{"GET", "/repos/:owner/:repo/git/refs/*ref"},
   303  		{"/repos/:owner/:repo/git/refs"},
   304  		//{"POST", "/repos/:owner/:repo/git/refs"},
   305  		//{"PATCH", "/repos/:owner/:repo/git/refs/*ref"},
   306  		//{"DELETE", "/repos/:owner/:repo/git/refs/*ref"},
   307  		{"/repos/:owner/:repo/git/tags/:sha"},
   308  		{"/repos/:owner/:repo/git/tags"},
   309  		{"/repos/:owner/:repo/git/trees/:sha"},
   310  		{"/repos/:owner/:repo/git/trees"},
   311  
   312  		{"/issues"},
   313  		{"/user/issues"},
   314  		{"/orgs/:org/issues"},
   315  		{"/repos/:owner/:repo/issues"},
   316  		{"/repos/:owner/:repo/issues/:number"},
   317  		//{"POST", "/repos/:owner/:repo/issues"},
   318  		//{"PATCH", "/repos/:owner/:repo/issues/:number"},
   319  		{"/repos/:owner/:repo/assignees"},
   320  		{"/repos/:owner/:repo/assignees/:assignee"},
   321  		{"/repos/:owner/:repo/issues/:number/comments"},
   322  		//{"GET", "/repos/:owner/:repo/issues/comments"},
   323  		//{"GET", "/repos/:owner/:repo/issues/comments/:id"},
   324  		//{"POST", "/repos/:owner/:repo/issues/:number/comments"},
   325  		//{"PATCH", "/repos/:owner/:repo/issues/comments/:id"},
   326  		//{"DELETE", "/repos/:owner/:repo/issues/comments/:id"},
   327  		{"/repos/:owner/:repo/issues/:number/events"},
   328  		//{"GET", "/repos/:owner/:repo/issues/events"},
   329  		//{"GET", "/repos/:owner/:repo/issues/events/:id"},
   330  		{"/repos/:owner/:repo/labels"},
   331  		{"/repos/:owner/:repo/labels/:name"},
   332  		//{"POST", "/repos/:owner/:repo/labels"},
   333  		//{"PATCH", "/repos/:owner/:repo/labels/:name"},
   334  		//{"DELETE", "/repos/:owner/:repo/labels/:name"},
   335  		{"/repos/:owner/:repo/issues/:number/labels"},
   336  		//{"POST", "/repos/:owner/:repo/issues/:number/labels"},
   337  		//{"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name"},
   338  		//{"PUT", "/repos/:owner/:repo/issues/:number/labels"},
   339  		//{"DELETE", "/repos/:owner/:repo/issues/:number/labels"},
   340  		{"/repos/:owner/:repo/milestones/:number/labels"},
   341  		{"/repos/:owner/:repo/milestones"},
   342  		{"/repos/:owner/:repo/milestones/:number"},
   343  		//{"POST", "/repos/:owner/:repo/milestones"},
   344  		//{"PATCH", "/repos/:owner/:repo/milestones/:number"},
   345  		//{"DELETE", "/repos/:owner/:repo/milestones/:number"},
   346  
   347  		// Miscellaneous
   348  		{"/emojis"},
   349  		{"/gitignore/templates"},
   350  		{"/gitignore/templates/:name"},
   351  		{"/markdown"},
   352  		{"/markdown/raw"},
   353  		{"/meta"},
   354  		{"/rate_limit"},
   355  
   356  		// Organizations
   357  		{"/users/:user/orgs"},
   358  		{"/user/orgs"},
   359  		{"/orgs/:org"},
   360  		//{"PATCH", "/orgs/:org"},
   361  		{"/orgs/:org/members"},
   362  		{"/orgs/:org/members/:user"},
   363  		//{"DELETE", "/orgs/:org/members/:user"},
   364  		{"/orgs/:org/public_members"},
   365  		{"/orgs/:org/public_members/:user"},
   366  		//{"PUT", "/orgs/:org/public_members/:user"},
   367  		//{"DELETE", "/orgs/:org/public_members/:user"},
   368  		{"/orgs/:org/teams"},
   369  		{"/teams/:id"},
   370  		//{"POST", "/orgs/:org/teams"},
   371  		//{"PATCH", "/teams/:id"},
   372  		//{"DELETE", "/teams/:id"},
   373  		{"/teams/:id/members"},
   374  		{"/teams/:id/members/:user"},
   375  		//{"PUT", "/teams/:id/members/:user"},
   376  		//{"DELETE", "/teams/:id/members/:user"},
   377  		{"/teams/:id/repos"},
   378  		{"/teams/:id/repos/:owner/:repo"},
   379  		//{"PUT", "/teams/:id/repos/:owner/:repo"},
   380  		//{"DELETE", "/teams/:id/repos/:owner/:repo"},
   381  		{"/user/teams"},
   382  
   383  		// Pull Requests
   384  		{"/repos/:owner/:repo/pulls"},
   385  		{"/repos/:owner/:repo/pulls/:number"},
   386  		//{"POST", "/repos/:owner/:repo/pulls"},
   387  		//{"PATCH", "/repos/:owner/:repo/pulls/:number"},
   388  		{"/repos/:owner/:repo/pulls/:number/commits"},
   389  		{"/repos/:owner/:repo/pulls/:number/files"},
   390  		{"/repos/:owner/:repo/pulls/:number/merge"},
   391  		//{"PUT", "/repos/:owner/:repo/pulls/:number/merge"},
   392  		{"/repos/:owner/:repo/pulls/:number/comments"},
   393  		//{"GET", "/repos/:owner/:repo/pulls/comments"},
   394  		//{"GET", "/repos/:owner/:repo/pulls/comments/:number"},
   395  		//{"PUT", "/repos/:owner/:repo/pulls/:number/comments"},
   396  		//{"PATCH", "/repos/:owner/:repo/pulls/comments/:number"},
   397  		//{"DELETE", "/repos/:owner/:repo/pulls/comments/:number"},
   398  
   399  		// Repositories
   400  		{"/user/repos"},
   401  		{"/users/:user/repos"},
   402  		{"/orgs/:org/repos"},
   403  		{"/repositories"},
   404  		//{"POST", "/user/repos"},
   405  		//{"POST", "/orgs/:org/repos"},
   406  		{"/repos/:owner/:repo"},
   407  		//{"PATCH", "/repos/:owner/:repo"},
   408  		{"/repos/:owner/:repo/contributors"},
   409  		{"/repos/:owner/:repo/languages"},
   410  		{"/repos/:owner/:repo/teams"},
   411  		{"/repos/:owner/:repo/tags"},
   412  		{"/repos/:owner/:repo/branches"},
   413  		{"/repos/:owner/:repo/branches/:branch"},
   414  		//{"DELETE", "/repos/:owner/:repo"},
   415  		{"/repos/:owner/:repo/collaborators"},
   416  		{"/repos/:owner/:repo/collaborators/:user"},
   417  		//{"PUT", "/repos/:owner/:repo/collaborators/:user"},
   418  		//{"DELETE", "/repos/:owner/:repo/collaborators/:user"},
   419  		{"/repos/:owner/:repo/comments"},
   420  		{"/repos/:owner/:repo/commits/:sha/comments"},
   421  		//{"POST", "/repos/:owner/:repo/commits/:sha/comments"},
   422  		{"/repos/:owner/:repo/comments/:id"},
   423  		//{"PATCH", "/repos/:owner/:repo/comments/:id"},
   424  		//{"DELETE", "/repos/:owner/:repo/comments/:id"},
   425  		{"/repos/:owner/:repo/commits"},
   426  		{"/repos/:owner/:repo/commits/:sha"},
   427  		{"/repos/:owner/:repo/readme"},
   428  		//{"GET", "/repos/:owner/:repo/contents/*path"},
   429  		//{"PUT", "/repos/:owner/:repo/contents/*path"},
   430  		//{"DELETE", "/repos/:owner/:repo/contents/*path"},
   431  		//{"GET", "/repos/:owner/:repo/:archive_format/:ref"},
   432  		{"/repos/:owner/:repo/keys"},
   433  		{"/repos/:owner/:repo/keys/:id"},
   434  		//{"POST", "/repos/:owner/:repo/keys"},
   435  		//{"PATCH", "/repos/:owner/:repo/keys/:id"},
   436  		//{"DELETE", "/repos/:owner/:repo/keys/:id"},
   437  		{"/repos/:owner/:repo/downloads"},
   438  		{"/repos/:owner/:repo/downloads/:id"},
   439  		//{"DELETE", "/repos/:owner/:repo/downloads/:id"},
   440  		{"/repos/:owner/:repo/forks"},
   441  		//{"POST", "/repos/:owner/:repo/forks"},
   442  		{"/repos/:owner/:repo/hooks"},
   443  		{"/repos/:owner/:repo/hooks/:id"},
   444  		//{"POST", "/repos/:owner/:repo/hooks"},
   445  		//{"PATCH", "/repos/:owner/:repo/hooks/:id"},
   446  		//{"POST", "/repos/:owner/:repo/hooks/:id/tests"},
   447  		//{"DELETE", "/repos/:owner/:repo/hooks/:id"},
   448  		//{"POST", "/repos/:owner/:repo/merges"},
   449  		{"/repos/:owner/:repo/releases"},
   450  		{"/repos/:owner/:repo/releases/:id"},
   451  		//{"POST", "/repos/:owner/:repo/releases"},
   452  		//{"PATCH", "/repos/:owner/:repo/releases/:id"},
   453  		//{"DELETE", "/repos/:owner/:repo/releases/:id"},
   454  		{"/repos/:owner/:repo/releases/:id/assets"},
   455  		{"/repos/:owner/:repo/stats/contributors"},
   456  		{"/repos/:owner/:repo/stats/commit_activity"},
   457  		{"/repos/:owner/:repo/stats/code_frequency"},
   458  		{"/repos/:owner/:repo/stats/participation"},
   459  		{"/repos/:owner/:repo/stats/punch_card"},
   460  		{"/repos/:owner/:repo/statuses/:ref"},
   461  		//{"POST", "/repos/:owner/:repo/statuses/:ref"},
   462  
   463  		// Search
   464  		{"/search/repositories"},
   465  		{"/search/code"},
   466  		{"/search/issues"},
   467  		{"/search/users"},
   468  		{"/legacy/issues/search/:owner/:repository/:state/:keyword"},
   469  		{"/legacy/repos/search/:keyword"},
   470  		{"/legacy/user/search/:keyword"},
   471  		{"/legacy/user/email/:email"},
   472  
   473  		// Users
   474  		{"/users/:user"},
   475  		{"/user"},
   476  		//{"PATCH", "/user"},
   477  		{"/users"},
   478  		{"/user/emails"},
   479  		//{"POST", "/user/emails"},
   480  		//{"DELETE", "/user/emails"},
   481  		{"/users/:user/followers"},
   482  		{"/user/followers"},
   483  		{"/users/:user/following"},
   484  		{"/user/following"},
   485  		{"/user/following/:user"},
   486  		{"/users/:user/following/:target_user"},
   487  		//{"PUT", "/user/following/:user"},
   488  		//{"DELETE", "/user/following/:user"},
   489  		{"/users/:user/keys"},
   490  		{"/user/keys"},
   491  		{"/user/keys/:id"},
   492  		//{"POST", "/user/keys"},
   493  		//{"PATCH", "/user/keys/:id"},
   494  		//{"DELETE", "/user/keys/:id"},
   495  	}
   496  
   497  	for _, route := range static {
   498  		tree.addRoute(route.path, fakeHandler(route.path))
   499  	}
   500  	ps := getParams()
   501  
   502  	b.ResetTimer()
   503  	for i := 0; i < b.N; i++ {
   504  		for _, request := range static {
   505  			tree.find(request.path, ps, false)
   506  		}
   507  	}
   508  }
   509  
   510  func BenchmarkTree_FindStaticTsr(b *testing.B) {
   511  	tree := &router{method: "GET", root: &node{}, hasTsrHandler: make(map[string]bool)}
   512  
   513  	routes := [...]string{
   514  		"/doc/foo/go_faq.html/",
   515  	}
   516  	for _, route := range routes {
   517  		tree.addRoute(route, fakeHandler(route))
   518  	}
   519  	tr := testRequests{
   520  		{"/doc/foo/go_faq.html", false, "/doc/foo/go_faq.html", nil},
   521  	}
   522  	ps := getParams()
   523  
   524  	b.ResetTimer()
   525  	for i := 0; i < b.N; i++ {
   526  		for _, request := range tr {
   527  			tree.find(request.path, ps, false)
   528  		}
   529  	}
   530  }
   531  
   532  func BenchmarkTree_FindParam(b *testing.B) {
   533  	tree := &router{method: "GET", root: &node{}, hasTsrHandler: make(map[string]bool)}
   534  
   535  	routes := [...]string{
   536  		"/hi/:key1/foo/:key2",
   537  	}
   538  	for _, route := range routes {
   539  		tree.addRoute(route, fakeHandler(route))
   540  	}
   541  	tr := testRequests{
   542  		{"/hi/1/foo/2", false, "/hi", nil},
   543  	}
   544  	ps := getParams()
   545  
   546  	b.ResetTimer()
   547  	for i := 0; i < b.N; i++ {
   548  		for _, request := range tr {
   549  			tree.find(request.path, ps, false)
   550  		}
   551  	}
   552  }
   553  
   554  func BenchmarkTree_FindParamTsr(b *testing.B) {
   555  	tree := &router{method: "GET", root: &node{}, hasTsrHandler: make(map[string]bool)}
   556  
   557  	routes := [...]string{
   558  		"/hi/:key1/foo/:key2/",
   559  	}
   560  	for _, route := range routes {
   561  		tree.addRoute(route, fakeHandler(route))
   562  	}
   563  	tr := testRequests{
   564  		{"/hi/1/foo/2", false, "/hi", nil},
   565  	}
   566  	ps := getParams()
   567  
   568  	b.ResetTimer()
   569  	for i := 0; i < b.N; i++ {
   570  		for _, request := range tr {
   571  			tree.find(request.path, ps, false)
   572  		}
   573  	}
   574  }
   575  
   576  func BenchmarkTree_FindAny(b *testing.B) {
   577  	tree := &router{method: "GET", root: &node{}, hasTsrHandler: make(map[string]bool)}
   578  
   579  	routes := [...]string{
   580  		"/hi/*key1",
   581  	}
   582  	for _, route := range routes {
   583  		tree.addRoute(route, fakeHandler(route))
   584  	}
   585  	tr := testRequests{
   586  		{"/hi/foo", false, "/hi", nil},
   587  	}
   588  	ps := getParams()
   589  
   590  	b.ResetTimer()
   591  	for i := 0; i < b.N; i++ {
   592  		for _, request := range tr {
   593  			tree.find(request.path, ps, false)
   594  		}
   595  	}
   596  }
   597  
   598  func BenchmarkTree_FindAnyFallback(b *testing.B) {
   599  	tree := &router{method: "GET", root: &node{}, hasTsrHandler: make(map[string]bool)}
   600  
   601  	routes := [...]string{
   602  		"/hi/a/b/c/d/e/*key1",
   603  		"/*key2",
   604  	}
   605  	for _, route := range routes {
   606  		tree.addRoute(route, fakeHandler(route))
   607  	}
   608  	tr := testRequests{
   609  		{"/hi/a/b/c/d/f", false, "/*key2", nil},
   610  	}
   611  	ps := getParams()
   612  
   613  	b.ResetTimer()
   614  	for i := 0; i < b.N; i++ {
   615  		for _, request := range tr {
   616  			tree.find(request.path, ps, false)
   617  		}
   618  	}
   619  }
   620  
   621  func BenchmarkRouteStatic(b *testing.B) {
   622  	r := NewEngine(config.NewOptions(nil))
   623  	r.GET("/hi/foo", func(c context.Context, ctx *app.RequestContext) {})
   624  	ctx := r.NewContext()
   625  	req := protocol.NewRequest("GET", "/hi/foo", nil)
   626  	req.CopyTo(&ctx.Request)
   627  	b.ResetTimer()
   628  	for i := 0; i < b.N; i++ {
   629  		r.ServeHTTP(context.Background(), ctx)
   630  		// ctx.index = -1
   631  	}
   632  }
   633  
   634  func BenchmarkRouteParam(b *testing.B) {
   635  	r := NewEngine(config.NewOptions(nil))
   636  	r.GET("/hi/:user", func(c context.Context, ctx *app.RequestContext) {})
   637  	ctx := r.NewContext()
   638  	req := protocol.NewRequest("GET", "/hi/foo", nil)
   639  	req.CopyTo(&ctx.Request)
   640  	b.ResetTimer()
   641  	for i := 0; i < b.N; i++ {
   642  		r.ServeHTTP(context.Background(), ctx)
   643  		// ctx.index = -1
   644  	}
   645  }
   646  
   647  func BenchmarkRouteAny(b *testing.B) {
   648  	r := NewEngine(config.NewOptions(nil))
   649  	r.GET("/hi/*user", func(c context.Context, ctx *app.RequestContext) {})
   650  	ctx := r.NewContext()
   651  	req := protocol.NewRequest("GET", "/hi/foo/dy", nil)
   652  	req.CopyTo(&ctx.Request)
   653  	b.ResetTimer()
   654  	for i := 0; i < b.N; i++ {
   655  		r.ServeHTTP(context.Background(), ctx)
   656  		// ctx.index = -1
   657  	}
   658  }