goyave.dev/goyave/v4@v4.4.11/router_bench_test.go (about)

     1  package goyave
     2  
     3  import (
     4  	"net/http"
     5  	"net/http/httptest"
     6  	"runtime"
     7  	"testing"
     8  
     9  	"goyave.dev/goyave/v4/validation"
    10  )
    11  
    12  type routerDefinition struct {
    13  	prefix     string // Empty for main router
    14  	middleware []Middleware
    15  	routes     []*routeDefinition
    16  	subrouters []*routerDefinition
    17  }
    18  
    19  type routeDefinition struct {
    20  	handler Handler
    21  	rules   validation.RuleSet
    22  	uri     string
    23  	methods string
    24  	name    string
    25  }
    26  
    27  var handler Handler = func(response *Response, request *Request) {
    28  	response.Status(200)
    29  }
    30  
    31  var sampleRouteDefinition = &routerDefinition{
    32  	prefix:     "",
    33  	middleware: []Middleware{},
    34  	routes: []*routeDefinition{
    35  		{
    36  			uri:     "/hello",
    37  			methods: "GET",
    38  			name:    "hello",
    39  			handler: handler,
    40  			rules:   nil,
    41  		},
    42  		{
    43  			uri:     "/world",
    44  			methods: "POST",
    45  			name:    "post",
    46  			handler: handler,
    47  			rules:   nil,
    48  		},
    49  		{
    50  			uri:     "/{param}",
    51  			methods: "POST",
    52  			name:    "param",
    53  			handler: handler,
    54  			rules:   nil,
    55  		},
    56  	},
    57  	subrouters: []*routerDefinition{
    58  		{
    59  			prefix:     "/product",
    60  			middleware: []Middleware{},
    61  			routes: []*routeDefinition{
    62  				{
    63  					uri:     "/",
    64  					methods: "GET",
    65  					name:    "product.index",
    66  					handler: handler,
    67  					rules:   nil,
    68  				},
    69  				{
    70  					uri:     "/",
    71  					methods: "POST",
    72  					name:    "product.store",
    73  					handler: handler,
    74  					rules:   nil,
    75  				},
    76  				{
    77  					uri:     "/{id:[0-9]+}",
    78  					methods: "GET",
    79  					name:    "product.show",
    80  					handler: handler,
    81  					rules:   nil,
    82  				},
    83  				{
    84  					uri:     "/{id:[0-9]+}",
    85  					methods: "PUT|PATCH",
    86  					name:    "product.update",
    87  					handler: handler,
    88  					rules:   nil,
    89  				},
    90  				{
    91  					uri:     "/{id:[0-9]+}",
    92  					methods: "DELETE",
    93  					name:    "product.destroy",
    94  					handler: handler,
    95  					rules:   nil,
    96  				},
    97  			},
    98  			subrouters: []*routerDefinition{},
    99  		},
   100  	},
   101  }
   102  
   103  var sampleRequests = []*http.Request{
   104  	httptest.NewRequest("GET", "/", nil), // 404
   105  	httptest.NewRequest("GET", "/hello", nil),
   106  	httptest.NewRequest("POST", "/world", nil),
   107  	httptest.NewRequest("POST", "/param", nil),
   108  	httptest.NewRequest("GET", "/product", nil),
   109  	httptest.NewRequest("POST", "/product", nil),
   110  	httptest.NewRequest("GET", "/product/test", nil), // 404
   111  	httptest.NewRequest("GET", "/product/1", nil),
   112  	httptest.NewRequest("PUT", "/product/1", nil),
   113  	httptest.NewRequest("DELETE", "/product/1", nil),
   114  }
   115  
   116  func registerAll(def *routerDefinition) *Router {
   117  	main := NewRouter()
   118  	registerRouter(main, def)
   119  	return main
   120  }
   121  
   122  func registerRouter(router *Router, def *routerDefinition) {
   123  	for _, subdef := range def.subrouters {
   124  		subrouter := router.Subrouter(subdef.prefix)
   125  		registerRouter(subrouter, subdef)
   126  	}
   127  	for _, routeDef := range def.routes {
   128  		router.registerRoute(routeDef.methods, routeDef.uri, routeDef.handler).Validate(routeDef.rules).Name(routeDef.name)
   129  	}
   130  }
   131  
   132  func BenchmarkRouteRegistration(b *testing.B) {
   133  	b.ReportAllocs()
   134  	for n := 0; n < b.N; n++ {
   135  		registerAll(sampleRouteDefinition)
   136  	}
   137  }
   138  
   139  func BenchmarkRootLevelNotFound(b *testing.B) {
   140  	router := setupRouteBench(b)
   141  
   142  	for n := 0; n < b.N; n++ {
   143  		router.match(sampleRequests[0], &routeMatch{currentPath: sampleRequests[0].URL.Path})
   144  	}
   145  }
   146  
   147  func BenchmarkRootLevelMatch(b *testing.B) {
   148  	router := setupRouteBench(b)
   149  
   150  	for n := 0; n < b.N; n++ {
   151  		router.match(sampleRequests[1], &routeMatch{currentPath: sampleRequests[1].URL.Path})
   152  	}
   153  }
   154  
   155  func BenchmarkRootLevelPostMatch(b *testing.B) {
   156  	router := setupRouteBench(b)
   157  
   158  	for n := 0; n < b.N; n++ {
   159  		router.match(sampleRequests[2], &routeMatch{currentPath: sampleRequests[2].URL.Path})
   160  	}
   161  }
   162  
   163  func BenchmarkRootLevelPostParamMatch(b *testing.B) {
   164  	router := setupRouteBench(b)
   165  
   166  	for n := 0; n < b.N; n++ {
   167  		router.match(sampleRequests[3], &routeMatch{currentPath: sampleRequests[3].URL.Path})
   168  	}
   169  }
   170  
   171  func BenchmarkSubrouterMatch(b *testing.B) {
   172  	router := setupRouteBench(b)
   173  
   174  	for n := 0; n < b.N; n++ {
   175  		router.match(sampleRequests[4], &routeMatch{currentPath: sampleRequests[4].URL.Path})
   176  	}
   177  }
   178  
   179  func BenchmarkSubrouterPostMatch(b *testing.B) {
   180  	router := setupRouteBench(b)
   181  
   182  	for n := 0; n < b.N; n++ {
   183  		router.match(sampleRequests[5], &routeMatch{currentPath: sampleRequests[5].URL.Path})
   184  	}
   185  }
   186  
   187  func BenchmarkSubrouterNotFound(b *testing.B) {
   188  	router := setupRouteBench(b)
   189  
   190  	for n := 0; n < b.N; n++ {
   191  		router.match(sampleRequests[6], &routeMatch{currentPath: sampleRequests[6].URL.Path})
   192  	}
   193  }
   194  
   195  func BenchmarkParamMatch(b *testing.B) {
   196  	router := setupRouteBench(b)
   197  
   198  	for n := 0; n < b.N; n++ {
   199  		router.match(sampleRequests[7], &routeMatch{currentPath: sampleRequests[7].URL.Path})
   200  	}
   201  }
   202  
   203  func BenchmarkParamPutMatch(b *testing.B) {
   204  	router := setupRouteBench(b)
   205  
   206  	for n := 0; n < b.N; n++ {
   207  		router.match(sampleRequests[8], &routeMatch{currentPath: sampleRequests[8].URL.Path})
   208  	}
   209  }
   210  
   211  func BenchmarkParamDeleteMatch(b *testing.B) {
   212  	router := setupRouteBench(b)
   213  
   214  	for n := 0; n < b.N; n++ {
   215  		router.match(sampleRequests[9], &routeMatch{currentPath: sampleRequests[9].URL.Path})
   216  	}
   217  }
   218  
   219  func BenchmarkMatchAll(b *testing.B) {
   220  	router := setupRouteBench(b)
   221  
   222  	for n := 0; n < b.N; n++ {
   223  		for _, r := range sampleRequests {
   224  			router.match(r, &routeMatch{currentPath: r.URL.Path})
   225  		}
   226  	}
   227  }
   228  
   229  func setupRouteBench(b *testing.B) *Router {
   230  	router := registerAll(sampleRouteDefinition)
   231  	b.ReportAllocs()
   232  	runtime.GC()
   233  	defer b.ResetTimer()
   234  	return router
   235  }