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 }