From 36ea63fe56af6c37fb9d3d6f169e98515803fa69 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 17:53:48 +0200 Subject: [PATCH 01/18] benchmark: remove obsolete files --- bench_test.go | 788 --------------------------- gplus_test.go | 571 -------------------- parse_test.go | 591 -------------------- routers.go | 1370 ----------------------------------------------- routers_test.go | 85 --- 5 files changed, 3405 deletions(-) delete mode 100644 bench_test.go delete mode 100644 gplus_test.go delete mode 100644 parse_test.go delete mode 100644 routers.go delete mode 100644 routers_test.go diff --git a/bench_test.go b/bench_test.go deleted file mode 100644 index 3dd46557..00000000 --- a/bench_test.go +++ /dev/null @@ -1,788 +0,0 @@ -// Copyright 2013 Julien Schmidt. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -package main - -import ( - "net/http" - "os" - "regexp" - "runtime" - "strings" - "testing" -) - -var benchRe *regexp.Regexp - -func isTested(name string) bool { - if benchRe == nil { - // Get -test.bench flag value (not accessible via flag package) - bench := "" - for _, arg := range os.Args { - if strings.HasPrefix(arg, "-test.bench=") { - // ignore the benchmark name after an underscore - bench = strings.SplitN(arg[12:], "_", 2)[0] - break - } - } - - // Compile RegExp to match Benchmark names - var err error - benchRe, err = regexp.Compile(bench) - if err != nil { - panic(err.Error()) - } - } - return benchRe.MatchString(name) -} - -func calcMem(name string, load func()) { - if !isTested(name) { - return - } - - m := new(runtime.MemStats) - - // before - runtime.GC() - runtime.ReadMemStats(m) - before := m.HeapAlloc - - load() - - // after - runtime.GC() - runtime.ReadMemStats(m) - after := m.HeapAlloc - println(" "+name+":", after-before, "Bytes") -} - -func benchRequest(b *testing.B, router http.Handler, r *http.Request) { - w := new(mockResponseWriter) - u := r.URL - rq := u.RawQuery - r.RequestURI = u.RequestURI() - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - u.RawQuery = rq - router.ServeHTTP(w, r) - } -} - -func benchRoutes(b *testing.B, router http.Handler, routes []route) { - w := new(mockResponseWriter) - r, _ := http.NewRequest("GET", "/", nil) - u := r.URL - rq := u.RawQuery - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - for _, route := range routes { - r.Method = route.method - r.RequestURI = route.path - u.Path = route.path - u.RawQuery = rq - router.ServeHTTP(w, r) - } - } -} - -// Micro Benchmarks - -// Route with Param (no write) -func BenchmarkAce_Param(b *testing.B) { - router := loadAceSingle("GET", "/user/:name", aceHandle) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkBear_Param(b *testing.B) { - router := loadBearSingle("GET", "/user/{name}", bearHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkBeego_Param(b *testing.B) { - router := loadBeegoSingle("GET", "/user/:name", beegoHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkBone_Param(b *testing.B) { - router := loadBoneSingle("GET", "/user/:name", http.HandlerFunc(httpHandlerFunc)) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkDenco_Param(b *testing.B) { - router := loadDencoSingle("GET", "/user/:name", dencoHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkEcho_Param(b *testing.B) { - router := loadEchoSingle("GET", "/user/:name", echoHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGin_Param(b *testing.B) { - router := loadGinSingle("GET", "/user/:name", ginHandle) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGocraftWeb_Param(b *testing.B) { - router := loadGocraftWebSingle("GET", "/user/:name", gocraftWebHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGoji_Param(b *testing.B) { - router := loadGojiSingle("GET", "/user/:name", httpHandlerFunc) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGoJsonRest_Param(b *testing.B) { - router := loadGoJsonRestSingle("GET", "/user/:name", goJsonRestHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGoRestful_Param(b *testing.B) { - router := loadGoRestfulSingle("GET", "/user/{name}", goRestfulHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGorillaMux_Param(b *testing.B) { - router := loadGorillaMuxSingle("GET", "/user/{name}", httpHandlerFunc) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkHttpRouter_Param(b *testing.B) { - router := loadHttpRouterSingle("GET", "/user/:name", httpRouterHandle) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkHttpTreeMux_Param(b *testing.B) { - router := loadHttpTreeMuxSingle("GET", "/user/:name", httpTreeMuxHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkKocha_Param(b *testing.B) { - handler := new(kochaHandler) - router := loadKochaSingle( - "GET", "/user/:name", - handler, http.HandlerFunc(handler.Get), - ) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkMacaron_Param(b *testing.B) { - router := loadMacaronSingle("GET", "/user/:name", macaronHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkMartini_Param(b *testing.B) { - router := loadMartiniSingle("GET", "/user/:name", martiniHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkPat_Param(b *testing.B) { - router := loadPatSingle("GET", "/user/:name", http.HandlerFunc(httpHandlerFunc)) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} - -func BenchmarkPossum_Param(b *testing.B) { - router := loadPossumSingle("GET", "/user/:name", possumHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkR2router_Param(b *testing.B) { - router := loadR2routerSingle("GET", "/user/:name", r2routerHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} - -func BenchmarkRevel_Param(b *testing.B) { - router := loadRevelSingle("GET", "/user/:name", "RevelController.Handle") - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkRivet_Param(b *testing.B) { - router := loadRivetSingle("GET", "/user/:name", rivetHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkTango_Param(b *testing.B) { - router := loadTangoSingle("GET", "/user/:name", tangoHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkTigerTonic_Param(b *testing.B) { - router := loadTigerTonicSingle("GET", "/user/{name}", httpHandlerFunc) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkTraffic_Param(b *testing.B) { - router := loadTrafficSingle("GET", "/user/:name", trafficHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkVulcan_Param(b *testing.B) { - router := loadVulcanSingle("GET", "/user/:name", vulcanHandler) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} - -// func BenchmarkZeus_Param(b *testing.B) { -// router := loadZeusSingle("GET", "/user/:name", http.HandlerFunc(httpHandlerFunc)) - -// r, _ := http.NewRequest("GET", "/user/gordon", nil) -// benchRequest(b, router, r) -// } - -// Route with 5 Params (no write) -const fiveColon = "/:a/:b/:c/:d/:e" -const fiveBrace = "/{a}/{b}/{c}/{d}/{e}" -const fiveRoute = "/test/test/test/test/test" - -func BenchmarkAce_Param5(b *testing.B) { - router := loadAceSingle("GET", fiveColon, aceHandle) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkBear_Param5(b *testing.B) { - router := loadBearSingle("GET", fiveBrace, bearHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkBeego_Param5(b *testing.B) { - router := loadBeegoSingle("GET", fiveColon, beegoHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkBone_Param5(b *testing.B) { - router := loadBoneSingle("GET", fiveColon, http.HandlerFunc(httpHandlerFunc)) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkDenco_Param5(b *testing.B) { - router := loadDencoSingle("GET", fiveColon, dencoHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkEcho_Param5(b *testing.B) { - router := loadEchoSingle("GET", fiveColon, echoHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkGin_Param5(b *testing.B) { - router := loadGinSingle("GET", fiveColon, ginHandle) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkGocraftWeb_Param5(b *testing.B) { - router := loadGocraftWebSingle("GET", fiveColon, gocraftWebHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkGoji_Param5(b *testing.B) { - router := loadGojiSingle("GET", fiveColon, httpHandlerFunc) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkGoJsonRest_Param5(b *testing.B) { - handler := loadGoJsonRestSingle("GET", fiveColon, goJsonRestHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, handler, r) -} -func BenchmarkGoRestful_Param5(b *testing.B) { - router := loadGoRestfulSingle("GET", fiveBrace, goRestfulHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkGorillaMux_Param5(b *testing.B) { - router := loadGorillaMuxSingle("GET", fiveBrace, httpHandlerFunc) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkHttpRouter_Param5(b *testing.B) { - router := loadHttpRouterSingle("GET", fiveColon, httpRouterHandle) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkHttpTreeMux_Param5(b *testing.B) { - router := loadHttpTreeMuxSingle("GET", fiveColon, httpTreeMuxHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkKocha_Param5(b *testing.B) { - handler := new(kochaHandler) - router := loadKochaSingle( - "GET", fiveColon, - handler, http.HandlerFunc(handler.Get), - ) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkMacaron_Param5(b *testing.B) { - router := loadMacaronSingle("GET", fiveColon, macaronHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkMartini_Param5(b *testing.B) { - router := loadMartiniSingle("GET", fiveColon, martiniHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkPat_Param5(b *testing.B) { - router := loadPatSingle("GET", fiveColon, http.HandlerFunc(httpHandlerFunc)) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkPossum_Param5(b *testing.B) { - router := loadPossumSingle("GET", fiveColon, possumHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkR2router_Param5(b *testing.B) { - router := loadR2routerSingle("GET", fiveColon, r2routerHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} - -func BenchmarkRevel_Param5(b *testing.B) { - router := loadRevelSingle("GET", fiveColon, "RevelController.Handle") - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkRivet_Param5(b *testing.B) { - router := loadRivetSingle("GET", fiveColon, rivetHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkTango_Param5(b *testing.B) { - router := loadTangoSingle("GET", fiveColon, tangoHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkTigerTonic_Param5(b *testing.B) { - router := loadTigerTonicSingle("GET", fiveBrace, httpHandlerFunc) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkTraffic_Param5(b *testing.B) { - router := loadTrafficSingle("GET", fiveColon, trafficHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkVulcan_Param5(b *testing.B) { - router := loadVulcanSingle("GET", fiveColon, vulcanHandler) - - r, _ := http.NewRequest("GET", fiveRoute, nil) - benchRequest(b, router, r) -} - -// func BenchmarkZeus_Param5(b *testing.B) { -// router := loadZeusSingle("GET", fiveColon, http.HandlerFunc(httpHandlerFunc)) - -// r, _ := http.NewRequest("GET", fiveRoute, nil) -// benchRequest(b, router, r) -// } - -// Route with 20 Params (no write) -const twentyColon = "/:a/:b/:c/:d/:e/:f/:g/:h/:i/:j/:k/:l/:m/:n/:o/:p/:q/:r/:s/:t" -const twentyBrace = "/{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}/{i}/{j}/{k}/{l}/{m}/{n}/{o}/{p}/{q}/{r}/{s}/{t}" -const twentyRoute = "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t" - -func BenchmarkAce_Param20(b *testing.B) { - router := loadAceSingle("GET", twentyColon, aceHandle) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkBear_Param20(b *testing.B) { - router := loadBearSingle("GET", twentyBrace, bearHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkBeego_Param20(b *testing.B) { - router := loadBeegoSingle("GET", twentyColon, beegoHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkBone_Param20(b *testing.B) { - router := loadBoneSingle("GET", twentyColon, http.HandlerFunc(httpHandlerFunc)) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkDenco_Param20(b *testing.B) { - router := loadDencoSingle("GET", twentyColon, dencoHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkEcho_Param20(b *testing.B) { - router := loadEchoSingle("GET", twentyColon, echoHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkGin_Param20(b *testing.B) { - router := loadGinSingle("GET", twentyColon, ginHandle) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkGocraftWeb_Param20(b *testing.B) { - router := loadGocraftWebSingle("GET", twentyColon, gocraftWebHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkGoji_Param20(b *testing.B) { - router := loadGojiSingle("GET", twentyColon, httpHandlerFunc) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkGoJsonRest_Param20(b *testing.B) { - handler := loadGoJsonRestSingle("GET", twentyColon, goJsonRestHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, handler, r) -} -func BenchmarkGoRestful_Param20(b *testing.B) { - handler := loadGoRestfulSingle("GET", twentyBrace, goRestfulHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, handler, r) -} -func BenchmarkGorillaMux_Param20(b *testing.B) { - router := loadGorillaMuxSingle("GET", twentyBrace, httpHandlerFunc) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkHttpRouter_Param20(b *testing.B) { - router := loadHttpRouterSingle("GET", twentyColon, httpRouterHandle) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkHttpTreeMux_Param20(b *testing.B) { - router := loadHttpTreeMuxSingle("GET", twentyColon, httpTreeMuxHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkKocha_Param20(b *testing.B) { - handler := new(kochaHandler) - router := loadKochaSingle( - "GET", twentyColon, - handler, http.HandlerFunc(handler.Get), - ) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkMacaron_Param20(b *testing.B) { - router := loadMacaronSingle("GET", twentyColon, macaronHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkMartini_Param20(b *testing.B) { - router := loadMartiniSingle("GET", twentyColon, martiniHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkPat_Param20(b *testing.B) { - router := loadPatSingle("GET", twentyColon, http.HandlerFunc(httpHandlerFunc)) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkPossum_Param20(b *testing.B) { - router := loadPossumSingle("GET", twentyColon, possumHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkR2router_Param20(b *testing.B) { - router := loadR2routerSingle("GET", twentyColon, r2routerHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} - -func BenchmarkRevel_Param20(b *testing.B) { - router := loadRevelSingle("GET", twentyColon, "RevelController.Handle") - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkRivet_Param20(b *testing.B) { - router := loadRivetSingle("GET", twentyColon, rivetHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkTango_Param20(b *testing.B) { - router := loadTangoSingle("GET", twentyColon, tangoHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkTigerTonic_Param20(b *testing.B) { - router := loadTigerTonicSingle("GET", twentyBrace, httpHandlerFunc) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkTraffic_Param20(b *testing.B) { - router := loadTrafficSingle("GET", twentyColon, trafficHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} -func BenchmarkVulcan_Param20(b *testing.B) { - router := loadVulcanSingle("GET", twentyColon, vulcanHandler) - - r, _ := http.NewRequest("GET", twentyRoute, nil) - benchRequest(b, router, r) -} - -// func BenchmarkZeus_Param20(b *testing.B) { -// router := loadZeusSingle("GET", twentyColon, http.HandlerFunc(httpHandlerFunc)) - -// r, _ := http.NewRequest("GET", twentyRoute, nil) -// benchRequest(b, router, r) -// } - -// Route with Param and write -func BenchmarkAce_ParamWrite(b *testing.B) { - router := loadAceSingle("GET", "/user/:name", aceHandleWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkBear_ParamWrite(b *testing.B) { - router := loadBearSingle("GET", "/user/{name}", bearHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkBeego_ParamWrite(b *testing.B) { - router := loadBeegoSingle("GET", "/user/:name", beegoHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkBone_ParamWrite(b *testing.B) { - router := loadBoneSingle("GET", "/user/:name", http.HandlerFunc(boneHandlerWrite)) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkDenco_ParamWrite(b *testing.B) { - router := loadDencoSingle("GET", "/user/:name", dencoHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkEcho_ParamWrite(b *testing.B) { - router := loadEchoSingle("GET", "/user/:name", echoHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGin_ParamWrite(b *testing.B) { - router := loadGinSingle("GET", "/user/:name", ginHandleWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGocraftWeb_ParamWrite(b *testing.B) { - router := loadGocraftWebSingle("GET", "/user/:name", gocraftWebHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGoji_ParamWrite(b *testing.B) { - router := loadGojiSingle("GET", "/user/:name", gojiFuncWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkGoJsonRest_ParamWrite(b *testing.B) { - handler := loadGoJsonRestSingle("GET", "/user/:name", goJsonRestHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, handler, r) -} -func BenchmarkGoRestful_ParamWrite(b *testing.B) { - handler := loadGoRestfulSingle("GET", "/user/{name}", goRestfulHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, handler, r) -} -func BenchmarkGorillaMux_ParamWrite(b *testing.B) { - router := loadGorillaMuxSingle("GET", "/user/{name}", gorillaHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkHttpRouter_ParamWrite(b *testing.B) { - router := loadHttpRouterSingle("GET", "/user/:name", httpRouterHandleWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkHttpTreeMux_ParamWrite(b *testing.B) { - router := loadHttpTreeMuxSingle("GET", "/user/:name", httpTreeMuxHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkKocha_ParamWrite(b *testing.B) { - handler := new(kochaHandler) - router := loadKochaSingle( - "GET", "/user/:name", - handler, http.HandlerFunc(handler.kochaHandlerWrite), - ) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkMacaron_ParamWrite(b *testing.B) { - router := loadMacaronSingle("GET", "/user/:name", macaronHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkMartini_ParamWrite(b *testing.B) { - router := loadMartiniSingle("GET", "/user/:name", martiniHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkPat_ParamWrite(b *testing.B) { - router := loadPatSingle("GET", "/user/:name", http.HandlerFunc(patHandlerWrite)) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkPossum_ParamWrite(b *testing.B) { - router := loadPossumSingle("GET", "/user/:name", possumHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkR2router_ParamWrite(b *testing.B) { - router := loadR2routerSingle("GET", "/user/:name", r2routerHandleWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} - -func BenchmarkRevel_ParamWrite(b *testing.B) { - router := loadRevelSingle("GET", "/user/:name", "RevelController.HandleWrite") - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkRivet_ParamWrite(b *testing.B) { - router := loadRivetSingle("GET", "/user/:name", rivetHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkTango_ParamWrite(b *testing.B) { - router := loadTangoSingle("GET", "/user/:name", tangoHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkTigerTonic_ParamWrite(b *testing.B) { - router := loadTigerTonicSingle( - "GET", "/user/{name}", - http.HandlerFunc(tigerTonicHandlerWrite), - ) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkTraffic_ParamWrite(b *testing.B) { - router := loadTrafficSingle("GET", "/user/:name", trafficHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} -func BenchmarkVulcan_ParamWrite(b *testing.B) { - router := loadVulcanSingle("GET", "/user/:name", vulcanHandlerWrite) - - r, _ := http.NewRequest("GET", "/user/gordon", nil) - benchRequest(b, router, r) -} - -// func BenchmarkZeus_ParamWrite(b *testing.B) { -// router := loadZeusSingle("GET", "/user/:name", zeusHandlerWrite) - -// r, _ := http.NewRequest("GET", "/user/gordon", nil) -// benchRequest(b, router, r) -// } diff --git a/gplus_test.go b/gplus_test.go deleted file mode 100644 index af5da63d..00000000 --- a/gplus_test.go +++ /dev/null @@ -1,571 +0,0 @@ -// Copyright 2013 Julien Schmidt. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -package main - -import ( - "net/http" - "testing" -) - -// Google+ -// https://developers.google.com/+/api/latest/ -// (in reality this is just a subset of a much larger API) -var gplusAPI = []route{ - // People - {"GET", "/people/:userId"}, - {"GET", "/people"}, - {"GET", "/activities/:activityId/people/:collection"}, - {"GET", "/people/:userId/people/:collection"}, - {"GET", "/people/:userId/openIdConnect"}, - - // Activities - {"GET", "/people/:userId/activities/:collection"}, - {"GET", "/activities/:activityId"}, - {"GET", "/activities"}, - - // Comments - {"GET", "/activities/:activityId/comments"}, - {"GET", "/comments/:commentId"}, - - // Moments - {"POST", "/people/:userId/moments/:collection"}, - {"GET", "/people/:userId/moments/:collection"}, - {"DELETE", "/moments/:id"}, -} - -var ( - gplusAce http.Handler - gplusBear http.Handler - gplusBeego http.Handler - gplusBone http.Handler - gplusDenco http.Handler - gplusEcho http.Handler - gplusGin http.Handler - gplusGocraftWeb http.Handler - gplusGoji http.Handler - gplusGoJsonRest http.Handler - gplusGoRestful http.Handler - gplusGorillaMux http.Handler - gplusHttpRouter http.Handler - gplusHttpTreeMux http.Handler - gplusKocha http.Handler - gplusMacaron http.Handler - gplusMartini http.Handler - gplusPat http.Handler - gplusPossum http.Handler - gplusR2router http.Handler - gplusRevel http.Handler - gplusRivet http.Handler - gplusTango http.Handler - gplusTigerTonic http.Handler - gplusTraffic http.Handler - gplusVulcan http.Handler - // gplusZeus http.Handler -) - -func init() { - println("#GPlusAPI Routes:", len(gplusAPI)) - - calcMem("Ace", func() { - gplusAce = loadAce(gplusAPI) - }) - calcMem("Bear", func() { - gplusBear = loadBear(gplusAPI) - }) - calcMem("Beego", func() { - gplusBeego = loadBeego(gplusAPI) - }) - calcMem("Bone", func() { - gplusBone = loadBone(gplusAPI) - }) - calcMem("Denco", func() { - gplusDenco = loadDenco(gplusAPI) - }) - calcMem("Echo", func() { - gplusEcho = loadEcho(gplusAPI) - }) - calcMem("Gin", func() { - gplusGin = loadGin(gplusAPI) - }) - calcMem("GocraftWeb", func() { - gplusGocraftWeb = loadGocraftWeb(gplusAPI) - }) - calcMem("Goji", func() { - gplusGoji = loadGoji(gplusAPI) - }) - calcMem("GoJsonRest", func() { - gplusGoJsonRest = loadGoJsonRest(gplusAPI) - }) - calcMem("GoRestful", func() { - gplusGoRestful = loadGoRestful(gplusAPI) - }) - calcMem("GorillaMux", func() { - gplusGorillaMux = loadGorillaMux(gplusAPI) - }) - calcMem("HttpRouter", func() { - gplusHttpRouter = loadHttpRouter(gplusAPI) - }) - calcMem("HttpTreeMux", func() { - gplusHttpTreeMux = loadHttpTreeMux(gplusAPI) - }) - calcMem("Kocha", func() { - gplusKocha = loadKocha(gplusAPI) - }) - calcMem("Macaron", func() { - gplusMacaron = loadMacaron(gplusAPI) - }) - calcMem("Martini", func() { - gplusMartini = loadMartini(gplusAPI) - }) - calcMem("Pat", func() { - gplusPat = loadPat(gplusAPI) - }) - calcMem("Possum", func() { - gplusPossum = loadPossum(gplusAPI) - }) - calcMem("R2router", func() { - gplusR2router = loadR2router(gplusAPI) - }) - calcMem("Revel", func() { - gplusRevel = loadRevel(gplusAPI) - }) - calcMem("Rivet", func() { - gplusRivet = loadRivet(gplusAPI) - }) - calcMem("Tango", func() { - gplusTango = loadTango(gplusAPI) - }) - calcMem("TigerTonic", func() { - gplusTigerTonic = loadTigerTonic(gplusAPI) - }) - calcMem("Traffic", func() { - gplusTraffic = loadTraffic(gplusAPI) - }) - calcMem("Vulcan", func() { - gplusVulcan = loadVulcan(gplusAPI) - }) - // calcMem("Zeus", func() { - // gplusZeus = loadZeus(gplusAPI) - // }) - - println() -} - -// Static -func BenchmarkAce_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusAce, req) -} -func BenchmarkBear_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusBear, req) -} -func BenchmarkBeego_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusBeego, req) -} -func BenchmarkBone_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusBone, req) -} -func BenchmarkDenco_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusDenco, req) -} -func BenchmarkEcho_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusEcho, req) -} -func BenchmarkGin_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusGin, req) -} -func BenchmarkGocraftWeb_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusGocraftWeb, req) -} -func BenchmarkGoji_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusGoji, req) -} -func BenchmarkGoJsonRest_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusGoJsonRest, req) -} -func BenchmarkGoRestful_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusGoRestful, req) -} -func BenchmarkGorillaMux_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusGorillaMux, req) -} -func BenchmarkHttpRouter_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusHttpRouter, req) -} -func BenchmarkHttpTreeMux_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusHttpTreeMux, req) -} -func BenchmarkKocha_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusKocha, req) -} -func BenchmarkMacaron_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusMacaron, req) -} -func BenchmarkMartini_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusMartini, req) -} -func BenchmarkPat_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusPat, req) -} -func BenchmarkPossum_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusPossum, req) -} -func BenchmarkR2router_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusR2router, req) -} -func BenchmarkRevel_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusRevel, req) -} -func BenchmarkRivet_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusRivet, req) -} -func BenchmarkTango_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusTango, req) -} -func BenchmarkTigerTonic_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusTigerTonic, req) -} -func BenchmarkTraffic_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusTraffic, req) -} -func BenchmarkVulcan_GPlusStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/people", nil) - benchRequest(b, gplusVulcan, req) -} - -// func BenchmarkZeus_GPlusStatic(b *testing.B) { -// req, _ := http.NewRequest("GET", "/people", nil) -// benchRequest(b, gplusZeus, req) -// } - -// One Param -func BenchmarkAce_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusAce, req) -} -func BenchmarkBear_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusBear, req) -} -func BenchmarkBeego_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusBeego, req) -} -func BenchmarkBone_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusBone, req) -} -func BenchmarkDenco_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusDenco, req) -} -func BenchmarkEcho_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusEcho, req) -} -func BenchmarkGin_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusGin, req) -} -func BenchmarkGocraftWeb_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusGocraftWeb, req) -} -func BenchmarkGoji_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusGoji, req) -} -func BenchmarkGoJsonRest_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusGoJsonRest, req) -} -func BenchmarkGoRestful_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusGoRestful, req) -} -func BenchmarkGorillaMux_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusGorillaMux, req) -} -func BenchmarkHttpRouter_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusHttpRouter, req) -} -func BenchmarkHttpTreeMux_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusHttpTreeMux, req) -} -func BenchmarkKocha_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusKocha, req) -} -func BenchmarkMacaron_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusMacaron, req) -} -func BenchmarkMartini_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusMartini, req) -} -func BenchmarkPat_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusPat, req) -} -func BenchmarkPossum_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusPossum, req) -} -func BenchmarkR2router_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusR2router, req) -} -func BenchmarkRevel_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusRevel, req) -} -func BenchmarkRivet_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusRivet, req) -} -func BenchmarkTango_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusTango, req) -} -func BenchmarkTigerTonic_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusTigerTonic, req) -} -func BenchmarkTraffic_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusTraffic, req) -} -func BenchmarkVulcan_GPlusParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) - benchRequest(b, gplusVulcan, req) -} - -// func BenchmarkZeus_GPlusParam(b *testing.B) { -// req, _ := http.NewRequest("GET", "/people/118051310819094153327", nil) -// benchRequest(b, gplusZeus, req) -// } - -// Two Params -func BenchmarkAce_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusAce, req) -} -func BenchmarkBear_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusBear, req) -} -func BenchmarkBeego_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusBeego, req) -} -func BenchmarkBone_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusBone, req) -} -func BenchmarkDenco_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusDenco, req) -} -func BenchmarkEcho_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusEcho, req) -} -func BenchmarkGin_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusGin, req) -} -func BenchmarkGocraftWeb_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusGocraftWeb, req) -} -func BenchmarkGoji_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusGoji, req) -} -func BenchmarkGoJsonRest_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusGoJsonRest, req) -} -func BenchmarkGoRestful_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusGoRestful, req) -} -func BenchmarkGorillaMux_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusGorillaMux, req) -} -func BenchmarkHttpRouter_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusHttpRouter, req) -} -func BenchmarkHttpTreeMux_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusHttpTreeMux, req) -} -func BenchmarkKocha_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusKocha, req) -} -func BenchmarkMacaron_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusMacaron, req) -} -func BenchmarkMartini_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusMartini, req) -} -func BenchmarkPat_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusPat, req) -} -func BenchmarkPossum_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusPossum, req) -} -func BenchmarkR2router_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusR2router, req) -} -func BenchmarkRevel_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusRevel, req) -} -func BenchmarkRivet_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusRivet, req) -} -func BenchmarkTango_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusTango, req) -} -func BenchmarkTigerTonic_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusTigerTonic, req) -} -func BenchmarkTraffic_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusTraffic, req) -} -func BenchmarkVulcan_GPlus2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) - benchRequest(b, gplusVulcan, req) -} - -// func BenchmarkZeus_GPlus2Params(b *testing.B) { -// req, _ := http.NewRequest("GET", "/people/118051310819094153327/activities/123456789", nil) -// benchRequest(b, gplusZeus, req) -// } - -// All Routes -func BenchmarkAce_GPlusAll(b *testing.B) { - benchRoutes(b, gplusAce, gplusAPI) -} -func BenchmarkBear_GPlusAll(b *testing.B) { - benchRoutes(b, gplusBear, gplusAPI) -} -func BenchmarkBeego_GPlusAll(b *testing.B) { - benchRoutes(b, gplusBeego, gplusAPI) -} -func BenchmarkBone_GPlusAll(b *testing.B) { - benchRoutes(b, gplusBone, gplusAPI) -} -func BenchmarkDenco_GPlusAll(b *testing.B) { - benchRoutes(b, gplusDenco, gplusAPI) -} -func BenchmarkEcho_GPlusAll(b *testing.B) { - benchRoutes(b, gplusEcho, gplusAPI) -} -func BenchmarkGin_GPlusAll(b *testing.B) { - benchRoutes(b, gplusGin, gplusAPI) -} -func BenchmarkGocraftWeb_GPlusAll(b *testing.B) { - benchRoutes(b, gplusGocraftWeb, gplusAPI) -} -func BenchmarkGoji_GPlusAll(b *testing.B) { - benchRoutes(b, gplusGoji, gplusAPI) -} -func BenchmarkGoJsonRest_GPlusAll(b *testing.B) { - benchRoutes(b, gplusGoJsonRest, gplusAPI) -} -func BenchmarkGoRestful_GPlusAll(b *testing.B) { - benchRoutes(b, gplusGoRestful, gplusAPI) -} -func BenchmarkGorillaMux_GPlusAll(b *testing.B) { - benchRoutes(b, gplusGorillaMux, gplusAPI) -} -func BenchmarkHttpRouter_GPlusAll(b *testing.B) { - benchRoutes(b, gplusHttpRouter, gplusAPI) -} -func BenchmarkHttpTreeMux_GPlusAll(b *testing.B) { - benchRoutes(b, gplusHttpTreeMux, gplusAPI) -} -func BenchmarkKocha_GPlusAll(b *testing.B) { - benchRoutes(b, gplusKocha, gplusAPI) -} -func BenchmarkMacaron_GPlusAll(b *testing.B) { - benchRoutes(b, gplusMacaron, gplusAPI) -} -func BenchmarkMartini_GPlusAll(b *testing.B) { - benchRoutes(b, gplusMartini, gplusAPI) -} -func BenchmarkPat_GPlusAll(b *testing.B) { - benchRoutes(b, gplusPat, gplusAPI) -} -func BenchmarkPossum_GPlusAll(b *testing.B) { - benchRoutes(b, gplusPossum, gplusAPI) -} -func BenchmarkR2router_GPlusAll(b *testing.B) { - benchRoutes(b, gplusR2router, gplusAPI) -} -func BenchmarkRevel_GPlusAll(b *testing.B) { - benchRoutes(b, gplusRevel, gplusAPI) -} -func BenchmarkRivet_GPlusAll(b *testing.B) { - benchRoutes(b, gplusRivet, gplusAPI) -} -func BenchmarkTango_GPlusAll(b *testing.B) { - benchRoutes(b, gplusTango, gplusAPI) -} -func BenchmarkTigerTonic_GPlusAll(b *testing.B) { - benchRoutes(b, gplusTigerTonic, gplusAPI) -} -func BenchmarkTraffic_GPlusAll(b *testing.B) { - benchRoutes(b, gplusTraffic, gplusAPI) -} -func BenchmarkVulcan_GPlusAll(b *testing.B) { - benchRoutes(b, gplusVulcan, gplusAPI) -} - -// func BenchmarkZeus_GPlusAll(b *testing.B) { -// benchRoutes(b, gplusZeus, gplusAPI) -// } diff --git a/parse_test.go b/parse_test.go deleted file mode 100644 index c54046c6..00000000 --- a/parse_test.go +++ /dev/null @@ -1,591 +0,0 @@ -// Copyright 2013 Julien Schmidt. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -package main - -import ( - "net/http" - "testing" -) - -// Parse -// https://parse.com/docs/rest#summary -var parseAPI = []route{ - // Objects - {"POST", "/1/classes/:className"}, - {"GET", "/1/classes/:className/:objectId"}, - {"PUT", "/1/classes/:className/:objectId"}, - {"GET", "/1/classes/:className"}, - {"DELETE", "/1/classes/:className/:objectId"}, - - // Users - {"POST", "/1/users"}, - {"GET", "/1/login"}, - {"GET", "/1/users/:objectId"}, - {"PUT", "/1/users/:objectId"}, - {"GET", "/1/users"}, - {"DELETE", "/1/users/:objectId"}, - {"POST", "/1/requestPasswordReset"}, - - // Roles - {"POST", "/1/roles"}, - {"GET", "/1/roles/:objectId"}, - {"PUT", "/1/roles/:objectId"}, - {"GET", "/1/roles"}, - {"DELETE", "/1/roles/:objectId"}, - - // Files - {"POST", "/1/files/:fileName"}, - - // Analytics - {"POST", "/1/events/:eventName"}, - - // Push Notifications - {"POST", "/1/push"}, - - // Installations - {"POST", "/1/installations"}, - {"GET", "/1/installations/:objectId"}, - {"PUT", "/1/installations/:objectId"}, - {"GET", "/1/installations"}, - {"DELETE", "/1/installations/:objectId"}, - - // Cloud Functions - {"POST", "/1/functions"}, -} - -var ( - parseAce http.Handler - parseBear http.Handler - parseBeego http.Handler - parseBone http.Handler - parseDenco http.Handler - parseEcho http.Handler - parseGin http.Handler - parseGocraftWeb http.Handler - parseGoji http.Handler - parseGoJsonRest http.Handler - parseGoRestful http.Handler - parseGorillaMux http.Handler - parseHttpRouter http.Handler - parseHttpTreeMux http.Handler - parseKocha http.Handler - parseMacaron http.Handler - parseMartini http.Handler - parsePat http.Handler - parsePossum http.Handler - parseR2router http.Handler - parseRevel http.Handler - parseRivet http.Handler - parseTango http.Handler - parseTigerTonic http.Handler - parseTraffic http.Handler - parseVulcan http.Handler - // parseZeus http.Handler -) - -func init() { - println("#ParseAPI Routes:", len(parseAPI)) - - calcMem("Ace", func() { - parseAce = loadAce(parseAPI) - }) - calcMem("Bear", func() { - parseBear = loadBear(parseAPI) - }) - calcMem("Beego", func() { - parseBeego = loadBeego(parseAPI) - }) - calcMem("Bone", func() { - parseBone = loadBone(parseAPI) - }) - calcMem("Denco", func() { - parseDenco = loadDenco(parseAPI) - }) - calcMem("Echo", func() { - parseEcho = loadEcho(parseAPI) - }) - calcMem("Gin", func() { - parseGin = loadGin(parseAPI) - }) - calcMem("GocraftWeb", func() { - parseGocraftWeb = loadGocraftWeb(parseAPI) - }) - calcMem("Goji", func() { - parseGoji = loadGoji(parseAPI) - }) - calcMem("GoJsonRest", func() { - parseGoJsonRest = loadGoJsonRest(parseAPI) - }) - calcMem("GoRestful", func() { - parseGoRestful = loadGoRestful(parseAPI) - }) - calcMem("GorillaMux", func() { - parseGorillaMux = loadGorillaMux(parseAPI) - }) - calcMem("HttpRouter", func() { - parseHttpRouter = loadHttpRouter(parseAPI) - }) - calcMem("HttpTreeMux", func() { - parseHttpTreeMux = loadHttpTreeMux(parseAPI) - }) - calcMem("Kocha", func() { - parseKocha = loadKocha(parseAPI) - }) - calcMem("Macaron", func() { - parseMacaron = loadMacaron(parseAPI) - }) - calcMem("Martini", func() { - parseMartini = loadMartini(parseAPI) - }) - calcMem("Pat", func() { - parsePat = loadPat(parseAPI) - }) - calcMem("Possum", func() { - parsePossum = loadPossum(parseAPI) - }) - calcMem("R2router", func() { - parseR2router = loadR2router(parseAPI) - }) - calcMem("Revel", func() { - parseRevel = loadRevel(parseAPI) - }) - calcMem("Rivet", func() { - parseRivet = loadRivet(parseAPI) - }) - calcMem("Tango", func() { - parseTango = loadTango(parseAPI) - }) - calcMem("TigerTonic", func() { - parseTigerTonic = loadTigerTonic(parseAPI) - }) - calcMem("Traffic", func() { - parseTraffic = loadTraffic(parseAPI) - }) - calcMem("Vulcan", func() { - parseVulcan = loadVulcan(parseAPI) - }) - // calcMem("Zeus", func() { - // parseZeus = loadZeus(parseAPI) - // }) - - println() -} - -// Static -func BenchmarkAce_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseAce, req) -} -func BenchmarkBear_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseBear, req) -} -func BenchmarkBeego_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseBeego, req) -} -func BenchmarkBone_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseBone, req) -} -func BenchmarkDenco_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseDenco, req) -} -func BenchmarkEcho_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseEcho, req) -} -func BenchmarkGin_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseGin, req) -} -func BenchmarkGocraftWeb_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseGocraftWeb, req) -} -func BenchmarkGoji_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseGoji, req) -} -func BenchmarkGoJsonRest_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseGoJsonRest, req) -} -func BenchmarkGoRestful_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseGoRestful, req) -} -func BenchmarkGorillaMux_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseGorillaMux, req) -} -func BenchmarkHttpRouter_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseHttpRouter, req) -} -func BenchmarkHttpTreeMux_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseHttpTreeMux, req) -} -func BenchmarkKocha_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseKocha, req) -} -func BenchmarkMacaron_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseMacaron, req) -} -func BenchmarkMartini_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseMartini, req) -} -func BenchmarkPat_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parsePat, req) -} -func BenchmarkPossum_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parsePossum, req) -} -func BenchmarkR2router_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseR2router, req) -} -func BenchmarkRevel_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseRevel, req) -} -func BenchmarkRivet_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseRivet, req) -} -func BenchmarkTango_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseTango, req) -} -func BenchmarkTigerTonic_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseTigerTonic, req) -} -func BenchmarkTraffic_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseTraffic, req) -} -func BenchmarkVulcan_ParseStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/users", nil) - benchRequest(b, parseVulcan, req) -} - -// func BenchmarkZeus_ParseStatic(b *testing.B) { -// req, _ := http.NewRequest("GET", "/1/users", nil) -// benchRequest(b, parseZeus, req) -// } - -// One Param -func BenchmarkAce_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseAce, req) -} -func BenchmarkBear_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseBear, req) -} -func BenchmarkBeego_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseBeego, req) -} -func BenchmarkBone_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseBone, req) -} -func BenchmarkDenco_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseDenco, req) -} -func BenchmarkEcho_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseEcho, req) -} -func BenchmarkGin_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseGin, req) -} -func BenchmarkGocraftWeb_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseGocraftWeb, req) -} -func BenchmarkGoji_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseGoji, req) -} -func BenchmarkGoJsonRest_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseGoJsonRest, req) -} -func BenchmarkGoRestful_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseGoRestful, req) -} -func BenchmarkGorillaMux_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseGorillaMux, req) -} -func BenchmarkHttpRouter_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseHttpRouter, req) -} -func BenchmarkHttpTreeMux_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseHttpTreeMux, req) -} -func BenchmarkKocha_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseKocha, req) -} -func BenchmarkMacaron_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseMacaron, req) -} -func BenchmarkMartini_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseMartini, req) -} -func BenchmarkPat_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parsePat, req) -} -func BenchmarkPossum_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parsePossum, req) -} -func BenchmarkR2router_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseR2router, req) -} -func BenchmarkRevel_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseRevel, req) -} -func BenchmarkRivet_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseRivet, req) -} -func BenchmarkTango_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseTango, req) -} -func BenchmarkTigerTonic_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseTigerTonic, req) -} -func BenchmarkTraffic_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseTraffic, req) -} -func BenchmarkVulcan_ParseParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go", nil) - benchRequest(b, parseVulcan, req) -} - -// func BenchmarkZeus_ParseParam(b *testing.B) { -// req, _ := http.NewRequest("GET", "/1/classes/go", nil) -// benchRequest(b, parseZeus, req) -// } - -// Two Params -func BenchmarkAce_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseAce, req) -} -func BenchmarkBear_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseBear, req) -} -func BenchmarkBeego_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseBeego, req) -} -func BenchmarkBone_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseBone, req) -} -func BenchmarkDenco_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseDenco, req) -} -func BenchmarkEcho_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseEcho, req) -} -func BenchmarkGin_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseGin, req) -} -func BenchmarkGocraftWeb_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseGocraftWeb, req) -} -func BenchmarkGoji_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseGoji, req) -} -func BenchmarkGoJsonRest_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseGoJsonRest, req) -} -func BenchmarkGoRestful_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseGoRestful, req) -} -func BenchmarkGorillaMux_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseGorillaMux, req) -} -func BenchmarkHttpRouter_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseHttpRouter, req) -} -func BenchmarkHttpTreeMux_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseHttpTreeMux, req) -} -func BenchmarkKocha_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseKocha, req) -} -func BenchmarkMacaron_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseMacaron, req) -} -func BenchmarkMartini_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseMartini, req) -} -func BenchmarkPat_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parsePat, req) -} -func BenchmarkPossum_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parsePossum, req) -} -func BenchmarkR2router_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseR2router, req) -} -func BenchmarkRevel_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseRevel, req) -} -func BenchmarkRivet_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseRivet, req) -} -func BenchmarkTango_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseTango, req) -} -func BenchmarkTigerTonic_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseTigerTonic, req) -} -func BenchmarkTraffic_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseTraffic, req) -} -func BenchmarkVulcan_Parse2Params(b *testing.B) { - req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) - benchRequest(b, parseVulcan, req) -} - -// func BenchmarkZeus_Parse2Params(b *testing.B) { -// req, _ := http.NewRequest("GET", "/1/classes/go/123456789", nil) -// benchRequest(b, parseZeus, req) -// } - -// All Routes -func BenchmarkAce_ParseAll(b *testing.B) { - benchRoutes(b, parseAce, parseAPI) -} -func BenchmarkBear_ParseAll(b *testing.B) { - benchRoutes(b, parseBeego, parseAPI) -} -func BenchmarkBeego_ParseAll(b *testing.B) { - benchRoutes(b, parseBeego, parseAPI) -} -func BenchmarkBone_ParseAll(b *testing.B) { - benchRoutes(b, parseBone, parseAPI) -} -func BenchmarkDenco_ParseAll(b *testing.B) { - benchRoutes(b, parseDenco, parseAPI) -} -func BenchmarkEcho_ParseAll(b *testing.B) { - benchRoutes(b, parseEcho, parseAPI) -} -func BenchmarkGin_ParseAll(b *testing.B) { - benchRoutes(b, parseGin, parseAPI) -} -func BenchmarkGocraftWeb_ParseAll(b *testing.B) { - benchRoutes(b, parseGocraftWeb, parseAPI) -} -func BenchmarkGoji_ParseAll(b *testing.B) { - benchRoutes(b, parseGoji, parseAPI) -} -func BenchmarkGoJsonRest_ParseAll(b *testing.B) { - benchRoutes(b, parseGoJsonRest, parseAPI) -} -func BenchmarkGoRestful_ParseAll(b *testing.B) { - benchRoutes(b, parseGoRestful, parseAPI) -} -func BenchmarkGorillaMux_ParseAll(b *testing.B) { - benchRoutes(b, parseGorillaMux, parseAPI) -} -func BenchmarkHttpRouter_ParseAll(b *testing.B) { - benchRoutes(b, parseHttpRouter, parseAPI) -} -func BenchmarkHttpTreeMux_ParseAll(b *testing.B) { - benchRoutes(b, parseHttpTreeMux, parseAPI) -} -func BenchmarkKocha_ParseAll(b *testing.B) { - benchRoutes(b, parseKocha, parseAPI) -} -func BenchmarkMacaron_ParseAll(b *testing.B) { - benchRoutes(b, parseMacaron, parseAPI) -} -func BenchmarkMartini_ParseAll(b *testing.B) { - benchRoutes(b, parseMartini, parseAPI) -} -func BenchmarkPat_ParseAll(b *testing.B) { - benchRoutes(b, parsePat, parseAPI) -} -func BenchmarkPossum_ParseAll(b *testing.B) { - benchRoutes(b, parsePossum, parseAPI) -} -func BenchmarkR2router_ParseAll(b *testing.B) { - benchRoutes(b, parseR2router, parseAPI) -} -func BenchmarkRevel_ParseAll(b *testing.B) { - benchRoutes(b, parseRevel, parseAPI) -} -func BenchmarkRivet_ParseAll(b *testing.B) { - benchRoutes(b, parseRivet, parseAPI) -} -func BenchmarkTango_ParseAll(b *testing.B) { - benchRoutes(b, parseTango, parseAPI) -} -func BenchmarkTigerTonic_ParseAll(b *testing.B) { - benchRoutes(b, parseTigerTonic, parseAPI) -} -func BenchmarkTraffic_ParseAll(b *testing.B) { - benchRoutes(b, parseTraffic, parseAPI) -} -func BenchmarkVulcan_ParseAll(b *testing.B) { - benchRoutes(b, parseVulcan, parseAPI) -} - -// func BenchmarkZeus_ParseAll(b *testing.B) { -// benchRoutes(b, parseZeus, parseAPI) -// } diff --git a/routers.go b/routers.go deleted file mode 100644 index ecb7a97c..00000000 --- a/routers.go +++ /dev/null @@ -1,1370 +0,0 @@ -// Copyright 2014 Julien Schmidt. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -package main - -import ( - "fmt" - "io" - "log" - "net/http" - "os" - "regexp" - "runtime" - - // If you add new routers please: - // - Keep the benchmark functions etc. alphabetically sorted - // - Make a pull request (without benchmark results) at - // https://github.com/julienschmidt/go-http-routing-benchmark - "github.com/Unknwon/macaron" - "github.com/ant0ine/go-json-rest/rest" - "github.com/astaxie/beego" - "github.com/astaxie/beego/context" - "github.com/bmizerany/pat" - // "github.com/daryl/zeus" - "github.com/dimfeld/httptreemux" - "github.com/emicklei/go-restful" - "github.com/gin-gonic/gin" - "github.com/go-martini/martini" - "github.com/go-zoo/bone" - "github.com/gocraft/web" - "github.com/gorilla/mux" - "github.com/julienschmidt/httprouter" - "github.com/labstack/echo" - llog "github.com/lunny/log" - "github.com/lunny/tango" - vulcan "github.com/mailgun/route" - "github.com/mikespook/possum" - possumrouter "github.com/mikespook/possum/router" - possumview "github.com/mikespook/possum/view" - "github.com/naoina/denco" - "github.com/naoina/kocha-urlrouter" - _ "github.com/naoina/kocha-urlrouter/doublearray" - "github.com/pilu/traffic" - "github.com/plimble/ace" - "github.com/rcrowley/go-tigertonic" - "github.com/revel/revel" - "github.com/robfig/pathtree" - "github.com/typepress/rivet" - "github.com/ursiform/bear" - "github.com/vanng822/r2router" - goji "github.com/zenazn/goji/web" -) - -type route struct { - method string - path string -} - -type mockResponseWriter struct{} - -func (m *mockResponseWriter) Header() (h http.Header) { - return http.Header{} -} - -func (m *mockResponseWriter) Write(p []byte) (n int, err error) { - return len(p), nil -} - -func (m *mockResponseWriter) WriteString(s string) (n int, err error) { - return len(s), nil -} - -func (m *mockResponseWriter) WriteHeader(int) {} - -var nullLogger *log.Logger - -// flag indicating if the normal or the test handler should be loaded -var loadTestHandler = false - -func init() { - // beego sets it to runtime.NumCPU() - // Currently none of the contesters does concurrent routing - runtime.GOMAXPROCS(1) - - // makes logging 'webscale' (ignores them) - log.SetOutput(new(mockResponseWriter)) - nullLogger = log.New(new(mockResponseWriter), "", 0) - - initBeego() - initGin() - initMartini() - initRevel() - initTango() - initTraffic() -} - -// Common -func httpHandlerFunc(w http.ResponseWriter, r *http.Request) {} - -func httpHandlerFuncTest(w http.ResponseWriter, r *http.Request) { - io.WriteString(w, r.RequestURI) -} - -// Ace -func aceHandle(_ *ace.C) {} - -func aceHandleWrite(c *ace.C) { - io.WriteString(c.Writer, c.Param("name")) -} - -func aceHandleTest(c *ace.C) { - io.WriteString(c.Writer, c.Request.RequestURI) -} - -func loadAce(routes []route) http.Handler { - h := []ace.HandlerFunc{aceHandle} - if loadTestHandler { - h = []ace.HandlerFunc{aceHandleTest} - } - - router := ace.New() - for _, route := range routes { - router.Handle(route.method, route.path, h) - } - return router -} - -func loadAceSingle(method, path string, handle ace.HandlerFunc) http.Handler { - router := ace.New() - router.Handle(method, path, []ace.HandlerFunc{handle}) - return router -} - -// bear -func bearHandler(_ http.ResponseWriter, _ *http.Request, _ *bear.Context) {} - -func bearHandlerWrite(w http.ResponseWriter, _ *http.Request, ctx *bear.Context) { - io.WriteString(w, ctx.Params["name"]) -} - -func bearHandlerTest(w http.ResponseWriter, r *http.Request, _ *bear.Context) { - io.WriteString(w, r.RequestURI) -} - -func loadBear(routes []route) http.Handler { - h := bearHandler - if loadTestHandler { - h = bearHandlerTest - } - - router := bear.New() - re := regexp.MustCompile(":([^/]*)") - for _, route := range routes { - switch route.method { - case "GET", "POST", "PUT", "PATCH", "DELETE": - router.On(route.method, re.ReplaceAllString(route.path, "{$1}"), h) - default: - panic("Unknown HTTP method: " + route.method) - } - } - return router -} - -func loadBearSingle(method string, path string, handler bear.HandlerFunc) http.Handler { - router := bear.New() - switch method { - case "GET", "POST", "PUT", "PATCH", "DELETE": - router.On(method, path, handler) - default: - panic("Unknown HTTP method: " + method) - } - return router -} - -// beego -func beegoHandler(ctx *context.Context) {} - -func beegoHandlerWrite(ctx *context.Context) { - ctx.WriteString(ctx.Input.Param(":name")) -} - -func beegoHandlerTest(ctx *context.Context) { - ctx.WriteString(ctx.Request.RequestURI) -} - -func initBeego() { - beego.RunMode = "prod" - beego.BeeLogger.Close() -} - -func loadBeego(routes []route) http.Handler { - h := beegoHandler - if loadTestHandler { - h = beegoHandlerTest - } - - re := regexp.MustCompile(":([^/]*)") - app := beego.NewControllerRegister() - for _, route := range routes { - route.path = re.ReplaceAllString(route.path, ":$1") - switch route.method { - case "GET": - app.Get(route.path, h) - case "POST": - app.Post(route.path, h) - case "PUT": - app.Put(route.path, h) - case "PATCH": - app.Patch(route.path, h) - case "DELETE": - app.Delete(route.path, h) - default: - panic("Unknow HTTP method: " + route.method) - } - } - return app -} - -func loadBeegoSingle(method, path string, handler beego.FilterFunc) http.Handler { - app := beego.NewControllerRegister() - switch method { - case "GET": - app.Get(path, handler) - case "POST": - app.Post(path, handler) - case "PUT": - app.Put(path, handler) - case "PATCH": - app.Patch(path, handler) - case "DELETE": - app.Delete(path, handler) - default: - panic("Unknow HTTP method: " + method) - } - return app -} - -// bone -func boneHandlerWrite(rw http.ResponseWriter, req *http.Request) { - io.WriteString(rw, bone.GetValue(req, "name")) -} - -func loadBone(routes []route) http.Handler { - h := http.HandlerFunc(httpHandlerFunc) - if loadTestHandler { - h = http.HandlerFunc(httpHandlerFuncTest) - } - - router := bone.New() - for _, route := range routes { - switch route.method { - case "GET": - router.Get(route.path, h) - case "POST": - router.Post(route.path, h) - case "PUT": - router.Put(route.path, h) - case "PATCH": - router.Patch(route.path, h) - case "DELETE": - router.Delete(route.path, h) - default: - panic("Unknow HTTP method: " + route.method) - } - } - return router -} - -func loadBoneSingle(method, path string, handler http.Handler) http.Handler { - router := bone.New() - switch method { - case "GET": - router.Get(path, handler) - case "POST": - router.Post(path, handler) - case "PUT": - router.Put(path, handler) - case "PATCH": - router.Patch(path, handler) - case "DELETE": - router.Delete(path, handler) - default: - panic("Unknow HTTP method: " + method) - } - return router -} - -// Denco -func dencoHandler(w http.ResponseWriter, r *http.Request, params denco.Params) {} - -func dencoHandlerWrite(w http.ResponseWriter, r *http.Request, params denco.Params) { - io.WriteString(w, params.Get("name")) -} - -func dencoHandlerTest(w http.ResponseWriter, r *http.Request, params denco.Params) { - io.WriteString(w, r.RequestURI) -} - -func loadDenco(routes []route) http.Handler { - h := dencoHandler - if loadTestHandler { - h = dencoHandlerTest - } - - mux := denco.NewMux() - handlers := make([]denco.Handler, 0, len(routes)) - for _, route := range routes { - handler := mux.Handler(route.method, route.path, h) - handlers = append(handlers, handler) - } - handler, err := mux.Build(handlers) - if err != nil { - panic(err) - } - return handler -} - -func loadDencoSingle(method, path string, h denco.HandlerFunc) http.Handler { - mux := denco.NewMux() - handler, err := mux.Build([]denco.Handler{mux.Handler(method, path, h)}) - if err != nil { - panic(err) - } - return handler -} - -// Echo -func echoHandler(c *echo.Context) error { - return nil -} - -func echoHandlerWrite(c *echo.Context) error { - io.WriteString(c.Response(), c.Param("name")) - return nil -} - -func echoHandlerTest(c *echo.Context) error { - io.WriteString(c.Response(), c.Request().RequestURI) - return nil -} - -func loadEcho(routes []route) http.Handler { - var h interface{} = echoHandler - if loadTestHandler { - h = echoHandlerTest - } - - e := echo.New() - for _, r := range routes { - switch r.method { - case "GET": - e.Get(r.path, h) - case "POST": - e.Post(r.path, h) - case "PUT": - e.Put(r.path, h) - case "PATCH": - e.Patch(r.path, h) - case "DELETE": - e.Delete(r.path, h) - default: - panic("Unknow HTTP method: " + r.method) - } - } - return e -} - -func loadEchoSingle(method, path string, h interface{}) http.Handler { - e := echo.New() - switch method { - case "GET": - e.Get(path, h) - case "POST": - e.Post(path, h) - case "PUT": - e.Put(path, h) - case "PATCH": - e.Patch(path, h) - case "DELETE": - e.Delete(path, h) - default: - panic("Unknow HTTP method: " + method) - } - return e -} - -// Gin -func ginHandle(_ *gin.Context) {} - -func ginHandleWrite(c *gin.Context) { - io.WriteString(c.Writer, c.Params.ByName("name")) -} - -func ginHandleTest(c *gin.Context) { - io.WriteString(c.Writer, c.Request.RequestURI) -} - -func initGin() { - gin.SetMode(gin.ReleaseMode) -} - -func loadGin(routes []route) http.Handler { - h := ginHandle - if loadTestHandler { - h = ginHandleTest - } - - router := gin.New() - for _, route := range routes { - router.Handle(route.method, route.path, h) - } - return router -} - -func loadGinSingle(method, path string, handle gin.HandlerFunc) http.Handler { - router := gin.New() - router.Handle(method, path, handle) - return router -} - -// gocraft/web -type gocraftWebContext struct{} - -func gocraftWebHandler(w web.ResponseWriter, r *web.Request) {} - -func gocraftWebHandlerWrite(w web.ResponseWriter, r *web.Request) { - io.WriteString(w, r.PathParams["name"]) -} - -func gocraftWebHandlerTest(w web.ResponseWriter, r *web.Request) { - io.WriteString(w, r.RequestURI) -} - -func loadGocraftWeb(routes []route) http.Handler { - h := gocraftWebHandler - if loadTestHandler { - h = gocraftWebHandlerTest - } - - router := web.New(gocraftWebContext{}) - for _, route := range routes { - switch route.method { - case "GET": - router.Get(route.path, h) - case "POST": - router.Post(route.path, h) - case "PUT": - router.Put(route.path, h) - case "PATCH": - router.Patch(route.path, h) - case "DELETE": - router.Delete(route.path, h) - default: - panic("Unknow HTTP method: " + route.method) - } - } - return router -} - -func loadGocraftWebSingle(method, path string, handler interface{}) http.Handler { - router := web.New(gocraftWebContext{}) - switch method { - case "GET": - router.Get(path, handler) - case "POST": - router.Post(path, handler) - case "PUT": - router.Put(path, handler) - case "PATCH": - router.Patch(path, handler) - case "DELETE": - router.Delete(path, handler) - default: - panic("Unknow HTTP method: " + method) - } - return router -} - -// goji -func gojiFuncWrite(c goji.C, w http.ResponseWriter, r *http.Request) { - io.WriteString(w, c.URLParams["name"]) -} - -func loadGoji(routes []route) http.Handler { - h := httpHandlerFunc - if loadTestHandler { - h = httpHandlerFuncTest - } - - mux := goji.New() - for _, route := range routes { - switch route.method { - case "GET": - mux.Get(route.path, h) - case "POST": - mux.Post(route.path, h) - case "PUT": - mux.Put(route.path, h) - case "PATCH": - mux.Patch(route.path, h) - case "DELETE": - mux.Delete(route.path, h) - default: - panic("Unknown HTTP method: " + route.method) - } - } - return mux -} - -func loadGojiSingle(method, path string, handler interface{}) http.Handler { - mux := goji.New() - switch method { - case "GET": - mux.Get(path, handler) - case "POST": - mux.Post(path, handler) - case "PUT": - mux.Put(path, handler) - case "PATCH": - mux.Patch(path, handler) - case "DELETE": - mux.Delete(path, handler) - default: - panic("Unknow HTTP method: " + method) - } - return mux -} - -// go-json-rest/rest -func goJsonRestHandler(w rest.ResponseWriter, req *rest.Request) {} - -func goJsonRestHandlerWrite(w rest.ResponseWriter, req *rest.Request) { - io.WriteString(w.(io.Writer), req.PathParam("name")) -} - -func goJsonRestHandlerTest(w rest.ResponseWriter, req *rest.Request) { - io.WriteString(w.(io.Writer), req.RequestURI) -} - -func loadGoJsonRest(routes []route) http.Handler { - h := goJsonRestHandler - if loadTestHandler { - h = goJsonRestHandlerTest - } - - api := rest.NewApi() - restRoutes := make([]*rest.Route, 0, len(routes)) - for _, route := range routes { - restRoutes = append(restRoutes, - &rest.Route{route.method, route.path, h}, - ) - } - router, err := rest.MakeRouter(restRoutes...) - if err != nil { - log.Fatal(err) - } - api.SetApp(router) - return api.MakeHandler() -} - -func loadGoJsonRestSingle(method, path string, hfunc rest.HandlerFunc) http.Handler { - api := rest.NewApi() - router, err := rest.MakeRouter( - &rest.Route{method, path, hfunc}, - ) - if err != nil { - log.Fatal(err) - } - api.SetApp(router) - return api.MakeHandler() -} - -// go-restful -func goRestfulHandler(r *restful.Request, w *restful.Response) {} - -func goRestfulHandlerWrite(r *restful.Request, w *restful.Response) { - io.WriteString(w, r.PathParameter("name")) -} - -func goRestfulHandlerTest(r *restful.Request, w *restful.Response) { - io.WriteString(w, r.Request.RequestURI) -} - -func loadGoRestful(routes []route) http.Handler { - h := goRestfulHandler - if loadTestHandler { - h = goRestfulHandlerTest - } - - re := regexp.MustCompile(":([^/]*)") - - wsContainer := restful.NewContainer() - ws := new(restful.WebService) - - for _, route := range routes { - path := re.ReplaceAllString(route.path, "{$1}") - - switch route.method { - case "GET": - ws.Route(ws.GET(path).To(h)) - case "POST": - ws.Route(ws.POST(path).To(h)) - case "PUT": - ws.Route(ws.PUT(path).To(h)) - case "PATCH": - ws.Route(ws.PATCH(path).To(h)) - case "DELETE": - ws.Route(ws.DELETE(path).To(h)) - default: - panic("Unknow HTTP method: " + route.method) - } - } - wsContainer.Add(ws) - return wsContainer -} - -func loadGoRestfulSingle(method, path string, handler restful.RouteFunction) http.Handler { - wsContainer := restful.NewContainer() - ws := new(restful.WebService) - switch method { - case "GET": - ws.Route(ws.GET(path).To(handler)) - case "POST": - ws.Route(ws.POST(path).To(handler)) - case "PUT": - ws.Route(ws.PUT(path).To(handler)) - case "PATCH": - ws.Route(ws.PATCH(path).To(handler)) - case "DELETE": - ws.Route(ws.DELETE(path).To(handler)) - default: - panic("Unknow HTTP method: " + method) - } - wsContainer.Add(ws) - return wsContainer -} - -// gorilla/mux -func gorillaHandlerWrite(w http.ResponseWriter, r *http.Request) { - params := mux.Vars(r) - io.WriteString(w, params["name"]) -} - -func loadGorillaMux(routes []route) http.Handler { - h := httpHandlerFunc - if loadTestHandler { - h = httpHandlerFuncTest - } - - re := regexp.MustCompile(":([^/]*)") - m := mux.NewRouter() - for _, route := range routes { - m.HandleFunc( - re.ReplaceAllString(route.path, "{$1}"), - h, - ).Methods(route.method) - } - return m -} - -func loadGorillaMuxSingle(method, path string, handler http.HandlerFunc) http.Handler { - m := mux.NewRouter() - m.HandleFunc(path, handler).Methods(method) - return m -} - -// HttpRouter -func httpRouterHandle(_ http.ResponseWriter, _ *http.Request, _ httprouter.Params) {} - -func httpRouterHandleWrite(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) { - io.WriteString(w, ps.ByName("name")) -} - -func httpRouterHandleTest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - io.WriteString(w, r.RequestURI) -} - -func loadHttpRouter(routes []route) http.Handler { - h := httpRouterHandle - if loadTestHandler { - h = httpRouterHandleTest - } - - router := httprouter.New() - for _, route := range routes { - router.Handle(route.method, route.path, h) - } - return router -} - -func loadHttpRouterSingle(method, path string, handle httprouter.Handle) http.Handler { - router := httprouter.New() - router.Handle(method, path, handle) - return router -} - -// httpTreeMux -func httpTreeMuxHandler(_ http.ResponseWriter, _ *http.Request, _ map[string]string) {} - -func httpTreeMuxHandlerWrite(w http.ResponseWriter, _ *http.Request, vars map[string]string) { - io.WriteString(w, vars["name"]) -} - -func httpTreeMuxHandlerTest(w http.ResponseWriter, r *http.Request, _ map[string]string) { - io.WriteString(w, r.RequestURI) -} - -func loadHttpTreeMux(routes []route) http.Handler { - h := httpTreeMuxHandler - if loadTestHandler { - h = httpTreeMuxHandlerTest - } - - router := httptreemux.New() - for _, route := range routes { - router.Handle(route.method, route.path, h) - } - return router -} - -func loadHttpTreeMuxSingle(method, path string, handler httptreemux.HandlerFunc) http.Handler { - router := httptreemux.New() - router.Handle(method, path, handler) - return router -} - -// Kocha-urlrouter -type kochaHandler struct { - routerMap map[string]urlrouter.URLRouter - params []urlrouter.Param -} - -func (h *kochaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - meth, params := h.routerMap[r.Method].Lookup(r.URL.Path) - h.params = params - meth.(http.HandlerFunc).ServeHTTP(w, r) -} - -func (h *kochaHandler) Get(w http.ResponseWriter, r *http.Request) {} -func (h *kochaHandler) Post(w http.ResponseWriter, r *http.Request) {} -func (h *kochaHandler) Put(w http.ResponseWriter, r *http.Request) {} -func (h *kochaHandler) Patch(w http.ResponseWriter, r *http.Request) {} -func (h *kochaHandler) Delete(w http.ResponseWriter, r *http.Request) {} -func (h *kochaHandler) kochaHandlerWrite(w http.ResponseWriter, r *http.Request) { - var name string - for _, param := range h.params { - if param.Name == "name" { - name = param.Value - break - } - } - io.WriteString(w, name) -} - -func loadKocha(routes []route) http.Handler { - /*h := httpRouterHandle - if loadTestHandler { - h = httpRouterHandleTest - }*/ - - handler := &kochaHandler{routerMap: map[string]urlrouter.URLRouter{ - "GET": urlrouter.NewURLRouter("doublearray"), - "POST": urlrouter.NewURLRouter("doublearray"), - "PUT": urlrouter.NewURLRouter("doublearray"), - "PATCH": urlrouter.NewURLRouter("doublearray"), - "DELETE": urlrouter.NewURLRouter("doublearray"), - }} - recordMap := make(map[string][]urlrouter.Record) - for _, route := range routes { - var f http.HandlerFunc - switch route.method { - case "GET": - f = handler.Get - case "POST": - f = handler.Post - case "PUT": - f = handler.Put - case "PATCH": - f = handler.Patch - case "DELETE": - f = handler.Delete - } - recordMap[route.method] = append( - recordMap[route.method], - urlrouter.NewRecord(route.path, f), - ) - } - for method, records := range recordMap { - if err := handler.routerMap[method].Build(records); err != nil { - panic(err) - } - } - return handler -} - -func loadKochaSingle(method, path string, handler *kochaHandler, hfunc http.HandlerFunc) http.Handler { - handler.routerMap = map[string]urlrouter.URLRouter{ - method: urlrouter.NewURLRouter("doublearray"), - } - - if err := handler.routerMap[method].Build([]urlrouter.Record{ - urlrouter.NewRecord(path, hfunc), - }); err != nil { - panic(err) - } - return handler -} - -// Macaron -func macaronHandler() {} - -func macaronHandlerWrite(c *macaron.Context) string { - return c.Params("name") -} - -func macaronHandlerTest(c *macaron.Context) string { - return c.Req.RequestURI -} - -func loadMacaron(routes []route) http.Handler { - var h = []macaron.Handler{macaronHandler} - if loadTestHandler { - h[0] = macaronHandlerTest - } - - m := macaron.New() - for _, route := range routes { - m.Handle(route.method, route.path, h) - } - return m -} - -func loadMacaronSingle(method, path string, handler interface{}) http.Handler { - m := macaron.New() - m.Handle(method, path, []macaron.Handler{handler}) - return m -} - -// Martini -func martiniHandler() {} - -func martiniHandlerWrite(params martini.Params) string { - return params["name"] -} - -func initMartini() { - martini.Env = martini.Prod -} - -func loadMartini(routes []route) http.Handler { - var h interface{} = martiniHandler - if loadTestHandler { - h = httpHandlerFuncTest - } - - router := martini.NewRouter() - for _, route := range routes { - switch route.method { - case "GET": - router.Get(route.path, h) - case "POST": - router.Post(route.path, h) - case "PUT": - router.Put(route.path, h) - case "PATCH": - router.Patch(route.path, h) - case "DELETE": - router.Delete(route.path, h) - default: - panic("Unknow HTTP method: " + route.method) - } - } - martini := martini.New() - martini.Action(router.Handle) - return martini -} - -func loadMartiniSingle(method, path string, handler interface{}) http.Handler { - router := martini.NewRouter() - switch method { - case "GET": - router.Get(path, handler) - case "POST": - router.Post(path, handler) - case "PUT": - router.Put(path, handler) - case "PATCH": - router.Patch(path, handler) - case "DELETE": - router.Delete(path, handler) - default: - panic("Unknow HTTP method: " + method) - } - - martini := martini.New() - martini.Action(router.Handle) - return martini -} - -// pat -func patHandlerWrite(w http.ResponseWriter, r *http.Request) { - io.WriteString(w, r.URL.Query().Get(":name")) -} - -func loadPat(routes []route) http.Handler { - h := http.HandlerFunc(httpHandlerFunc) - if loadTestHandler { - h = http.HandlerFunc(httpHandlerFuncTest) - } - - m := pat.New() - for _, route := range routes { - switch route.method { - case "GET": - m.Get(route.path, h) - case "POST": - m.Post(route.path, h) - case "PUT": - m.Put(route.path, h) - case "DELETE": - m.Del(route.path, h) - default: - panic("Unknow HTTP method: " + route.method) - } - } - return m -} - -func loadPatSingle(method, path string, handler http.Handler) http.Handler { - m := pat.New() - switch method { - case "GET": - m.Get(path, handler) - case "POST": - m.Post(path, handler) - case "PUT": - m.Put(path, handler) - case "DELETE": - m.Del(path, handler) - default: - panic("Unknow HTTP method: " + method) - } - return m -} - -// Possum -func possumHandler(c *possum.Context) error { - return nil -} - -func possumHandlerWrite(c *possum.Context) error { - io.WriteString(c.Response, c.Request.URL.Query().Get("name")) - return nil -} - -func possumHandlerTest(c *possum.Context) error { - io.WriteString(c.Response, c.Request.RequestURI) - return nil -} - -func loadPossum(routes []route) http.Handler { - h := possumHandler - if loadTestHandler { - h = possumHandlerTest - } - - router := possum.NewServerMux() - for _, route := range routes { - router.HandleFunc(possumrouter.Simple(route.path), h, possumview.Simple("text/html", "utf-8")) - } - return router -} - -func loadPossumSingle(method, path string, handler possum.HandlerFunc) http.Handler { - router := possum.NewServerMux() - router.HandleFunc(possumrouter.Simple(path), handler, possumview.Simple("text/html", "utf-8")) - return router -} - -// R2router -func r2routerHandler(w http.ResponseWriter, req *http.Request, _ r2router.Params) {} - -func r2routerHandleWrite(w http.ResponseWriter, req *http.Request, params r2router.Params) { - io.WriteString(w, params.Get("name")) -} - -func r2routerHandleTest(w http.ResponseWriter, req *http.Request, _ r2router.Params) { - io.WriteString(w, req.RequestURI) -} - -func loadR2router(routes []route) http.Handler { - h := r2routerHandler - if loadTestHandler { - h = r2routerHandleTest - } - - router := r2router.NewRouter() - for _, r := range routes { - router.AddHandler(r.method, r.path, h) - } - return router -} - -func loadR2routerSingle(method, path string, handler r2router.HandlerFunc) http.Handler { - router := r2router.NewRouter() - router.AddHandler(method, path, handler) - return router -} - -// Revel (Router only) -// In the following code some Revel internals are modelled. -// The original revel code is copyrighted by Rob Figueiredo. -// See https://github.com/revel/revel/blob/master/LICENSE -type RevelController struct { - *revel.Controller - router *revel.Router -} - -func (rc *RevelController) Handle() revel.Result { - return revelResult{} -} - -func (rc *RevelController) HandleWrite() revel.Result { - return rc.RenderText(rc.Params.Get("name")) -} - -func (rc *RevelController) HandleTest() revel.Result { - return rc.RenderText(rc.Request.RequestURI) -} - -type revelResult struct{} - -func (rr revelResult) Apply(req *revel.Request, resp *revel.Response) {} - -func (rc *RevelController) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // Dirty hacks, do NOT copy! - revel.MainRouter = rc.router - - upgrade := r.Header.Get("Upgrade") - if upgrade == "websocket" || upgrade == "Websocket" { - panic("Not implemented") - } else { - var ( - req = revel.NewRequest(r) - resp = revel.NewResponse(w) - c = revel.NewController(req, resp) - ) - req.Websocket = nil - revel.Filters[0](c, revel.Filters[1:]) - if c.Result != nil { - c.Result.Apply(req, resp) - } else if c.Response.Status != 0 { - panic("Not implemented") - } - // Close the Writer if we can - if w, ok := resp.Out.(io.Closer); ok { - w.Close() - } - } -} - -func initRevel() { - // Only use the Revel filters required for this benchmark - revel.Filters = []revel.Filter{ - revel.RouterFilter, - revel.ParamsFilter, - revel.ActionInvoker, - } - - revel.RegisterController((*RevelController)(nil), - []*revel.MethodType{ - &revel.MethodType{ - Name: "Handle", - }, - &revel.MethodType{ - Name: "HandleWrite", - }, - &revel.MethodType{ - Name: "HandleTest", - }, - }) -} - -func loadRevel(routes []route) http.Handler { - h := "RevelController.Handle" - if loadTestHandler { - h = "RevelController.HandleTest" - } - - router := revel.NewRouter("") - - // parseRoutes - var rs []*revel.Route - for _, r := range routes { - rs = append(rs, revel.NewRoute(r.method, r.path, h, "", "", 0)) - } - router.Routes = rs - - // updateTree - router.Tree = pathtree.New() - for _, r := range router.Routes { - err := router.Tree.Add(r.TreePath, r) - // Allow GETs to respond to HEAD requests. - if err == nil && r.Method == "GET" { - err = router.Tree.Add("/HEAD"+r.Path, r) - } - // Error adding a route to the pathtree. - if err != nil { - panic(err) - } - } - - rc := new(RevelController) - rc.router = router - return rc -} - -func loadRevelSingle(method, path, action string) http.Handler { - router := revel.NewRouter("") - - route := revel.NewRoute(method, path, action, "", "", 0) - if err := router.Tree.Add(route.TreePath, route); err != nil { - panic(err) - } - - rc := new(RevelController) - rc.router = router - return rc -} - -// Rivet -func rivetHandler() {} - -func rivetHandlerWrite(c rivet.Context) { - c.WriteString(c.GetParams().Get("name")) -} - -func rivetHandlerTest(c rivet.Context) { - c.WriteString(c.Request().RequestURI) -} - -func loadRivet(routes []route) http.Handler { - var h interface{} = rivetHandler - if loadTestHandler { - h = rivetHandlerTest - } - - router := rivet.NewRouter(nil) - for _, route := range routes { - router.Handle(route.method, route.path, h) - } - return router -} - -func loadRivetSingle(method, path string, handler interface{}) http.Handler { - router := rivet.NewRouter(nil) - - router.Handle(method, path, handler) - - return router -} - -// Tango -func tangoHandler(ctx *tango.Context) {} - -func tangoHandlerWrite(ctx *tango.Context) { - ctx.Write([]byte(ctx.Params().Get(":name"))) -} - -func tangoHandlerTest(ctx *tango.Context) { - ctx.Write([]byte(ctx.Req().RequestURI)) -} - -func initTango() { - llog.SetOutput(new(mockResponseWriter)) - llog.SetOutputLevel(llog.Lnone) -} - -func loadTango(routes []route) http.Handler { - h := tangoHandler - if loadTestHandler { - h = tangoHandlerTest - } - - tg := tango.NewWithLog(llog.Std) - for _, route := range routes { - tg.Route(route.method, route.path, h) - } - return tg -} - -func loadTangoSingle(method, path string, handler func(*tango.Context)) http.Handler { - tg := tango.NewWithLog(llog.Std) - tg.Route(method, path, handler) - return tg -} - -// Tiger Tonic -func tigerTonicHandlerWrite(w http.ResponseWriter, r *http.Request) { - io.WriteString(w, r.URL.Query().Get("name")) -} - -func loadTigerTonic(routes []route) http.Handler { - h := httpHandlerFunc - if loadTestHandler { - h = httpHandlerFuncTest - } - - re := regexp.MustCompile(":([^/]*)") - mux := tigertonic.NewTrieServeMux() - for _, route := range routes { - mux.HandleFunc(route.method, re.ReplaceAllString(route.path, "{$1}"), h) - } - return mux -} - -func loadTigerTonicSingle(method, path string, handler http.HandlerFunc) http.Handler { - mux := tigertonic.NewTrieServeMux() - mux.HandleFunc(method, path, handler) - return mux -} - -// Traffic -func trafficHandler(w traffic.ResponseWriter, r *traffic.Request) {} - -func trafficHandlerWrite(w traffic.ResponseWriter, r *traffic.Request) { - io.WriteString(w, r.URL.Query().Get("name")) -} - -func trafficHandlerTest(w traffic.ResponseWriter, r *traffic.Request) { - io.WriteString(w, r.RequestURI) -} - -func initTraffic() { - traffic.SetVar("env", "bench") -} - -func loadTraffic(routes []route) http.Handler { - h := trafficHandler - if loadTestHandler { - h = trafficHandlerTest - } - - router := traffic.New() - for _, route := range routes { - switch route.method { - case "GET": - router.Get(route.path, h) - case "POST": - router.Post(route.path, h) - case "PUT": - router.Put(route.path, h) - case "PATCH": - router.Patch(route.path, h) - case "DELETE": - router.Delete(route.path, h) - default: - panic("Unknow HTTP method: " + route.method) - } - } - return router -} - -func loadTrafficSingle(method, path string, handler traffic.HttpHandleFunc) http.Handler { - router := traffic.New() - switch method { - case "GET": - router.Get(path, handler) - case "POST": - router.Post(path, handler) - case "PUT": - router.Put(path, handler) - case "PATCH": - router.Patch(path, handler) - case "DELETE": - router.Delete(path, handler) - default: - panic("Unknow HTTP method: " + method) - } - return router -} - -// Mailgun Vulcan -func vulcanHandler(w http.ResponseWriter, r *http.Request) {} - -func vulcanHandlerWrite(w http.ResponseWriter, r *http.Request) { - io.WriteString(w, r.URL.Query().Get("name")) -} - -func loadVulcan(routes []route) http.Handler { - h := httpHandlerFunc - if loadTestHandler { - h = httpHandlerFuncTest - } - - re := regexp.MustCompile(":([^/]*)") - mux := vulcan.NewMux() - for _, route := range routes { - path := re.ReplaceAllString(route.path, "<$1>") - expr := fmt.Sprintf(`Method("%s") && Path("%s")`, route.method, path) - if err := mux.HandleFunc(expr, h); err != nil { - panic(err) - } - } - return mux -} - -func loadVulcanSingle(method, path string, handler http.HandlerFunc) http.Handler { - re := regexp.MustCompile(":([^/]*)") - mux := vulcan.NewMux() - path = re.ReplaceAllString(path, "<$1>") - expr := fmt.Sprintf(`Method("%s") && Path("%s")`, method, path) - if err := mux.HandleFunc(expr, httpHandlerFunc); err != nil { - panic(err) - } - return mux -} - -// Zeus -// func zeusHandlerWrite(w http.ResponseWriter, r *http.Request) { -// io.WriteString(w, zeus.Var(r, "name")) -// } - -// func loadZeus(routes []route) http.Handler { -// h := http.HandlerFunc(httpHandlerFunc) -// if loadTestHandler { -// h = http.HandlerFunc(httpHandlerFuncTest) -// } - -// m := zeus.New() -// for _, route := range routes { -// switch route.method { -// case "GET": -// m.GET(route.path, h) -// case "POST": -// m.POST(route.path, h) -// case "PUT": -// m.PUT(route.path, h) -// case "DELETE": -// m.DELETE(route.path, h) -// default: -// panic("Unknow HTTP method: " + route.method) -// } -// } -// return m -// } - -// func loadZeusSingle(method, path string, handler http.HandlerFunc) http.Handler { -// m := zeus.New() -// switch method { -// case "GET": -// m.GET(path, handler) -// case "POST": -// m.POST(path, handler) -// case "PUT": -// m.PUT(path, handler) -// case "DELETE": -// m.DELETE(path, handler) -// default: -// panic("Unknow HTTP method: " + method) -// } -// return m -// } - -// Usage notice -func main() { - fmt.Println("Usage: go test -bench=. -timeout=20m") - os.Exit(1) -} diff --git a/routers_test.go b/routers_test.go deleted file mode 100644 index b5f1aec3..00000000 --- a/routers_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "net/http" - "net/http/httptest" - "testing" -) - -var ( - // load functions of all routers - routers = []struct { - name string - load func(routes []route) http.Handler - }{ - {"Ace", loadAce}, - {"Bear", loadBear}, - {"Beego", loadBeego}, - {"Bone", loadBone}, - {"Denco", loadDenco}, - {"Echo", loadEcho}, - {"Gin", loadGin}, - {"GocraftWeb", loadGocraftWeb}, - {"Goji", loadGoji}, - {"GoJsonRest", loadGoJsonRest}, - {"GoRestful", loadGoRestful}, - {"GorillaMux", loadGorillaMux}, - {"HttpRouter", loadHttpRouter}, - {"HttpTreeMux", loadHttpTreeMux}, - //{"Kocha", loadKocha}, - {"Macaron", loadMacaron}, - {"Martini", loadMartini}, - {"Pat", loadPat}, - {"Possum", loadPossum}, - {"R2router", loadR2router}, - {"Revel", loadRevel}, - {"Rivet", loadRivet}, - {"Tango", loadTango}, - {"TigerTonic", loadTigerTonic}, - {"Traffic", loadTraffic}, - {"Vulcan", loadVulcan}, - // {"Zeus", loadZeus}, - } - - // all APIs - apis = []struct { - name string - routes []route - }{ - {"GitHub", githubAPI}, - {"GPlus", gplusAPI}, - {"Parse", parseAPI}, - {"Static", staticRoutes}, - } -) - -func TestRouters(t *testing.T) { - loadTestHandler = true - - for _, router := range routers { - req, _ := http.NewRequest("GET", "/", nil) - u := req.URL - rq := u.RawQuery - - for _, api := range apis { - r := router.load(api.routes) - - for _, route := range api.routes { - w := httptest.NewRecorder() - req.Method = route.method - req.RequestURI = route.path - u.Path = route.path - u.RawQuery = rq - r.ServeHTTP(w, req) - if w.Code != 200 || w.Body.String() != route.path { - t.Errorf( - "%s in API %s: %d - %s; expected %s %s\n", - router.name, api.name, w.Code, w.Body.String(), route.method, route.path, - ) - } - } - } - } - - loadTestHandler = false -} From 212594d662ad1ed0cf75c35d09f876ab12d689f8 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 17:54:13 +0200 Subject: [PATCH 02/18] runner: add basic benchmark runner implementation The runner.go file is the new benchmark entry point. The implementation is currently neither feature complete nor completely correct, which will be fixed and refactored in a following commit. --- runner.go | 647 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 647 insertions(+) create mode 100644 runner.go diff --git a/runner.go b/runner.go new file mode 100644 index 00000000..4d179964 --- /dev/null +++ b/runner.go @@ -0,0 +1,647 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "flag" + "fmt" + "log" + "os" + "runtime" + "sort" + "strings" + "time" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/julienschmidt/go-http-routing-benchmark/driver/ui" + + _ "github.com/julienschmidt/go-http-routing-benchmark/router" + _ "github.com/julienschmidt/go-http-routing-benchmark/suite" +) + +const highlight = 3 + +var ( + std = flag.Bool("std", false, "use default benchmark output") + test = flag.Bool("test", false, "only run tests and not benchmarks") + list = flag.Bool("list", false, "print the names of all registered Routers") + markdown = flag.String("markdown", "", "write the benchmark output in markdown format to a file") + color = flag.String("color", "on", "colorize output, valid options are 'on', 'off' and 'ansi'") + duration = flag.Duration("time", 5*time.Second, "approximate run time for each benchmark") +) + +var ( + mdfile *os.File + mdbuf *bytes.Buffer +) + +func init() { + // beego sets it to runtime.NumCPU() and as of Go1.5 the default + // value may change anyway. Currently none of the contesters does + // concurrent routing. + runtime.GOMAXPROCS(1) + + // Disable log output + log.SetOutput(&driver.ResponseStub{}) +} + +func main() { + flag.Parse() + flag.Set("test.benchtime", duration.String()) + + isvalid := false + for _, op := range []string{"on", "off", "ansi"} { + if *color == op { + isvalid = true + } + } + if !isvalid { + fmt.Fprint(os.Stderr, "error: test: no packages registered\n") + os.Exit(1) + } + + if *list { + fmt.Print(strings.Join(driver.PackageNames(), "\n") + "\n") + os.Exit(0) + } + + console := ui.Console(*color) + console.Print("Running Tests...\n\n") + tests := driver.RunTests() + if tests != nil { + RenderTest(console, tests) + os.Exit(2) + } + + if *test { + os.Exit(0) + } + + if *markdown != "" { + f, err := os.Create(*markdown) + if err != nil { + fmt.Fprintf(os.Stderr, "error: %s\n", err.Error()) + os.Exit(1) + } + + mdfile = f + mdbuf = &bytes.Buffer{} + } + + length := driver.NumPackages() + renderer := &Renderer{ + span: &Span{ + Names: make([]string, length), + Homepages: make([]string, length), + + HeapMemory: &markUint64{marker: &marker{marked: make([]int, length)}}, + + NsPerOp: &markInt64{marker: &marker{marked: make([]int, length)}}, + AllocsPerOp: &markInt64{marker: &marker{marked: make([]int, length)}}, + BytesPerOp: &markInt64{marker: &marker{marked: make([]int, length)}}, + }, + + NsPerOp: make([]int64, length), + BytesPerOp: make([]int64, length), + AllocsPerOp: make([]int64, length), + } + + br := &BenchmarkRenderer{ + mark: console.Green, + color: console.Yellow, + } + renderer.Add(br.Render) + + if *std { + br.std = true + br.mark = console.Print + } + + console.Print("Running Benchmarks...\n\n") + benchmarks := driver.RunBenchmarks() + + if *markdown != "" { + mdbuf.WriteString("Results\n=======\n\n\n") + RenderMemoryTable(benchmarks) + renderer.Add(RenderMarkdown) + } + + for _, result := range benchmarks { + renderer.Render(result) + } + + if mdfile != nil { + // Create router name links + urls := make(map[string]string) + for _, result := range benchmarks { + for _, pkg := range result.Packages() { + urls[pkg.Name] = pkg.Homepage + } + } + for name, url := range urls { + if url != "" { + fmt.Fprintf(mdbuf, "[%s]: %s\n", name, url) + } + } + + mdfile.Write(mdbuf.Bytes()) + mdfile.Close() + } +} + +func RenderMemoryTable(b []*driver.Result) { + tcw := []int{4} // We'll add 2 later anyway + thd := []string{"Router"} + num := driver.NumPackages() + rts := driver.PackageNames() + col := make([]*markUint64, num) + + for i, name := range rts { + col[i] = &markUint64{ + zero: true, + data: make([]uint64, len(b)), + marker: &marker{marked: make([]int, len(b))}, + } + + if tcw[0] < len(name) { + tcw[0] = len(name) + } + } + + for _, r := range b { + bname := r.Name() + if !strings.HasSuffix(bname, "All") { + continue + } + + x := len(bname) - 3 + thd = append(thd, bname[:x]) + if x < 9 { + x = 9 + } + tcw = append(tcw, x) + + for i, name := range rts { + pkgs := r.Packages() + mems := r.RouterMemory() + + for x, pkg := range pkgs { + if pkg.Name == name { + col[i].data[len(thd)-2] = mems[x] + } + } + } + } + + fmt.Fprint(mdbuf, "### Memory Consumption\n\n\n") + + for _, m := range col { + m.Set(m.data[:]) + } + + var header string + for i, cell := range thd { + tcw[i] += 2 + header += fmt.Sprintf("| %-*s ", tcw[i], cell) + } + header += "|\n" + for i, x := range tcw { + if i == 0 { + header += fmt.Sprintf("|:%s-", strings.Repeat("-", x)) + } else { + header += fmt.Sprintf("|-%s:", strings.Repeat("-", x)) + } + } + fmt.Fprint(mdbuf, header+"|\n") + + for i, name := range rts { + fmt.Fprintf(mdbuf, "| %-*s ", tcw[0], "["+name+"]") + + for x, width := range tcw[1:] { + var memory string + if col[i].data[x] == 0 { + memory = "- " + } else { + if col[i].IsMarked(x) { + memory = fmt.Sprintf("__%d__", col[i].data[x]) + } else { + memory = fmt.Sprintf("%d ", col[i].data[x]) + } + } + + fmt.Fprintf(mdbuf, "| %*s", width+1, memory) + } + + fmt.Fprint(mdbuf, "|\n") + } + + fmt.Fprint(mdbuf, "\n\n") +} + +type Renderer struct { + span *Span + funcs []func(*driver.Result, *Span) + + // Slice cache + NsPerOp []int64 + BytesPerOp []int64 + AllocsPerOp []int64 +} + +func (r *Renderer) Add(fn func(*driver.Result, *Span)) { + r.funcs = append(r.funcs, fn) +} + +func (r *Renderer) Render(result *driver.Result) { + span := r.span + pkgs := result.Packages() + slen := len(pkgs) + + for i, pkg := range pkgs { + span.Names[i] = pkg.Name + span.Homepages[i] = pkg.Homepage + } + + benchmarks := result.Results() + for i, b := range benchmarks { + r.NsPerOp[i] = b.NsPerOp() + r.AllocsPerOp[i] = b.AllocsPerOp() + r.BytesPerOp[i] = b.AllocedBytesPerOp() + } + + span.length = slen + span.NsPerOp.Set(r.NsPerOp[:slen]) + span.BytesPerOp.Set(r.BytesPerOp[:slen]) + span.AllocsPerOp.Set(r.AllocsPerOp[:slen]) + span.HeapMemory.Set(result.RouterMemory()) + + for _, fn := range r.funcs { + fn(result, span) + } +} + +type BenchmarkRenderer struct { + std bool + mark func(string) + color func(string) +} + +func (b *BenchmarkRenderer) Render(r *driver.Result, s *Span) { + if !b.std { + b.color(fmt.Sprintf("%s:\n%s\n\n", r.Name(), r.Description())) + } + + packages := r.Packages() + benchmarks := r.Results() + + colum := 0 + for _, pkg := range packages { + if colum < len(pkg.Name) { + colum = len(pkg.Name) + } + } + + if b.std { + colum += 9 + len(r.Name()) + } + + for i := 0; i < s.length; i++ { + var mwd int + + name := packages[i].Name + if b.std { + name = "Benchmark" + name + r.Name() + "\t" + } + + if b.std { + fmt.Printf("%-*s %8d ", colum, name, benchmarks[i].N) + } else { + fmt.Printf("%-*s ", colum, name) + + if s.BytesPerOp.IsMarked(i) { + b.mark(fmt.Sprintf("%8d", s.HeapMemory.data[i])) + } else { + fmt.Printf("%8d", s.HeapMemory.data[i]) + } + fmt.Print(" B ") + } + + var nsopstr string + nsop := s.NsPerOp.data[i] + if benchmarks[i].N > 0 && nsop < 100 { + if nsop < 10 { + mwd = 3 + nsopstr = fmt.Sprintf("%13.2f", float64(benchmarks[i].T.Nanoseconds())/float64(benchmarks[i].N)) + } else { + mwd = 2 + nsopstr = fmt.Sprintf("%12.1f", float64(benchmarks[i].T.Nanoseconds())/float64(benchmarks[i].N)) + } + } else { + nsopstr = fmt.Sprintf("%10d", nsop) + } + + if s.NsPerOp.IsMarked(i) { + b.mark(nsopstr) + } else { + fmt.Print(nsopstr) + } + fmt.Print(" ns/op ") + + if s.BytesPerOp.IsMarked(i) { + b.mark(fmt.Sprintf("%*d", 10-mwd, s.BytesPerOp.data[i])) + } else { + fmt.Printf("%*d", 10-mwd, s.BytesPerOp.data[i]) + } + fmt.Print(" B/op ") + + if s.AllocsPerOp.IsMarked(i) { + b.mark(fmt.Sprintf("%8d", s.AllocsPerOp.data[i])) + } else { + fmt.Printf("%8d", s.AllocsPerOp.data[i]) + } + fmt.Print(" allocs/op\n") + } + + if !b.std { + fmt.Print("\n\n") + } +} + +var widths = []int{9 /*Memory*/, 10 /*Iterations*/, 10 /*Ns*/, 8 /*B*/, 10 /*Allocs*/} + +func RenderMarkdown(r *driver.Result, s *Span) { + fmt.Fprintf(mdbuf, "#### %s\n\n%s\n\n", r.Name(), r.Description()) + + packages := r.Packages() + benchmarks := r.Results() + + c := 4 // We'll add 2 later anyway + w := widths + for _, pkg := range packages { + if c < len(pkg.Name) { + c = len(pkg.Name) + } + } + c += 2 + + fmt.Fprintf(mdbuf, "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s |\n", + c, "Router", w[0], "Memory", w[1], "Iterations", w[2], "Ns/Op", w[3], "Bytes/Op", w[4], "Allocs/Op", + ) + fmt.Fprintf(mdbuf, "|:%s-|-%s-:|-%s:|-%s-:|-%s-:|-%s-:|\n", + strings.Repeat("-", c), strings.Repeat("-", w[0]), strings.Repeat("-", w[1]), + strings.Repeat("-", w[2]), strings.Repeat("-", w[3]), strings.Repeat("-", w[4]), + ) + + for i := 0; i < s.length; i++ { + + var ( + nw int + name string + memory string + nsop string + bop string + allocs string + ) + + if packages[i].Homepage != "" { + nw = c + name = "[" + packages[i].Name + "]" + } else { + nw = c + 2 + name = packages[i].Name + } + + if s.BytesPerOp.IsMarked(i) { + memory = fmt.Sprintf("__%d__", s.HeapMemory.data[i]) + } else { + memory = fmt.Sprintf("%d ", s.HeapMemory.data[i]) + } + + ns := s.NsPerOp.data[i] + if benchmarks[i].N > 0 && ns < 100 { + if ns < 10 { + nsop = fmt.Sprintf("%.2f", float64(benchmarks[i].T.Nanoseconds())/float64(benchmarks[i].N)) + } else { + nsop = fmt.Sprintf("%.1f", float64(benchmarks[i].T.Nanoseconds())/float64(benchmarks[i].N)) + } + } else { + nsop = fmt.Sprintf("%d", ns) + } + if s.NsPerOp.IsMarked(i) { + nsop = fmt.Sprintf("__%s__", nsop) + } else { + nsop = fmt.Sprintf("%s ", nsop) + } + + if s.BytesPerOp.IsMarked(i) { + bop = fmt.Sprintf("__%d__", s.BytesPerOp.data[i]) + } else { + bop = fmt.Sprintf("%d ", s.BytesPerOp.data[i]) + } + + if s.AllocsPerOp.IsMarked(i) { + allocs = fmt.Sprintf("__%d__", s.AllocsPerOp.data[i]) + } else { + allocs = fmt.Sprintf("%d ", s.AllocsPerOp.data[i]) + } + + fmt.Fprintf(mdbuf, "| %-*s | %*s| %*d | %*s| %*s| %*s|\n", + nw, name, w[0]+2, memory, w[1], benchmarks[i].N, w[2]+2, nsop, w[3]+2, bop, w[4]+2, allocs, + ) + } + + mdbuf.WriteString("\n\n\n") +} + +func RenderTest(ui ui.ConsoleAdapter, tests []*driver.Assertion) { + // TODO: Improve dedup suppression implementation. + var l *driver.Assertion + + for i, t := range tests { + n := i + 1 + + if l == nil || l.Benchmark() != t.Benchmark() { + l = nil + print("\n\n", t.Benchmark(), "\n\n", ui.Print, ui.Yellow) + } + + if l == nil { + print("Test: ", t.Description(), "\n", ui.Print, ui.Print) + + if t.Error != "" { + if len(tests) > n { + if tests[n].Benchmark() != t.Benchmark() || tests[n].Error != t.Error { + print("Error: ", t.Error, "\n", ui.Print, ui.Red) + } + } else { + print("Error: ", t.Error, "\n", ui.Print, ui.Red) + } + + print("Router: ", t.Router(), "\n", ui.Print, ui.Yellow) + } else { + print("Expect: ", t.Expect, "\n", ui.Print, ui.Green) + print("Router: ", t.Router(), "\n", ui.Print, ui.Yellow) + + if len(tests) > n { + if tests[n].Benchmark() != t.Benchmark() || tests[n].Actual != t.Actual { + print("Actual: ", t.Actual, "\n", ui.Print, ui.Red) + } + } else { + print("Actual: ", t.Actual, "\n", ui.Print, ui.Red) + } + } + } else if len(tests) == n { + if t.Error != "" { + print("Error: ", t.Error, "\n", ui.Print, ui.Red) + } else { + print("Actual: ", t.Actual, "\n", ui.Print, ui.Red) + } + } else { + if l.Description() != t.Description() { + print("Test: ", t.Description(), "\n", ui.Print, ui.Print) + } + if l.Router() != t.Router() { + print("Router: ", t.Router(), "\n", ui.Print, ui.Yellow) + } + if t.Error != "" && l.Error != t.Error { + print("Error: ", t.Error, "\n", ui.Print, ui.Red) + } + if l.Expect != t.Expect { + print("Expect: ", t.Expect, "\n", ui.Print, ui.Green) + } + if l.Actual != t.Actual { + print("Actual: ", t.Actual, "\n", ui.Print, ui.Red) + } + } + + l = t + } +} + +type Span struct { + length int + + Names []string // Package names + Homepages []string // Package homepage URLs + + HeapMemory *markUint64 // Heap memory allocated for the router object + + NsPerOp *markInt64 // testing.B NsPerOp + AllocsPerOp *markInt64 // testing.B AllocsPerOp + BytesPerOp *markInt64 // testing.B AllocBytesPerOp +} + +type markInt64 struct { + *marker + data []int64 +} + +func (m *markInt64) Less(i, j int) bool { return m.data[i] < m.data[j] } +func (m *markInt64) cmp(i, j int) bool { return m.data[i] != m.data[j] } +func (m *markInt64) IsMarked(i int) bool { return m.marker.isMarked(m.cmp, i) } + +func (m *markInt64) Set(data []int64) { + m.data = data + m.marker.length = len(data) + m.marker.set() + sort.Sort(m) +} + +type markUint64 struct { + *marker + zero bool // Ignore zero values + data []uint64 +} + +func (m *markUint64) cmp(i, j int) bool { return m.data[i] != m.data[j] } +func (m *markUint64) IsMarked(i int) bool { return m.marker.isMarked(m.cmp, i) } + +func (m *markUint64) Less(i, j int) bool { + if m.zero { + return true + } + + return m.data[i] < m.data[j] +} + +func (m *markUint64) Set(data []uint64) { + m.data = data + m.marker.length = len(data) + m.marker.set() + sort.Sort(m) +} + +type marker struct { + number int + length int + marked []int +} + +func (m *marker) Len() int { return m.length } +func (m *marker) Swap(i, j int) { m.marked[i], m.marked[j] = m.marked[j], m.marked[i] } + +func (m *marker) set() { + m.number = -1 + + if m.length > len(m.marked) { + m.marked = make([]int, m.length) + } + + for i := 0; i < m.length; i++ { + m.marked[i] = i + } +} + +func (m *marker) isMarked(cmp func(int, int) bool, i int) bool { + if m.number == -1 { + m.markable(cmp, i) + } + + for x := 0; x < m.number; x++ { + if m.marked[x] == i { + return true + } + } + + return false +} + +func (m *marker) markable(cmp func(int, int) bool, i int) { + m.number = highlight + + if m.length < highlight { + m.number = int(m.length / 2) + } + + if m.number <= 1 { + if m.length > 1 && !cmp(0, 1) { + m.number = 0 + } + return + } + + n := m.number + c := m.number - 1 + + for { + ni := m.marked[n] + ci := m.marked[c] + + if cmp(ci, ni) { + break + } + + n++ + c++ + m.number++ + } +} + +func print(p, m, s string, w, c func(string)) { + w(p) + c(m) + w(s) +} From 674ab00b450f093fa7954beef53262edb40f1c42 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 17:55:00 +0200 Subject: [PATCH 03/18] driver: add driver and ui progress bar implementation The new benchmark and test drivers allow for better extendability. Benchmarks are split into different types of benchmarks, e.g. ParameterReadWrite which benchmarks the reading and writing of a named path segment. These types are the only shared information between benchmarks and Router implementations. A Router implementor specifies the types of benchmarks a Router can run as well as other metadata, such as Router name and homepage URL, during registration. Further allows the new driver implementation to run tests for each benchmark, which uncovered more errors than the current test implementation. --- driver/driver.go | 294 ++++++++++++++++++++++++++ driver/extern.go | 481 +++++++++++++++++++++++++++++++++++++++++++ driver/ui/console.go | 114 ++++++++++ driver/ui/text.go | 106 ++++++++++ 4 files changed, 995 insertions(+) create mode 100644 driver/driver.go create mode 100644 driver/extern.go create mode 100644 driver/ui/console.go create mode 100644 driver/ui/text.go diff --git a/driver/driver.go b/driver/driver.go new file mode 100644 index 00000000..ffe6c56e --- /dev/null +++ b/driver/driver.go @@ -0,0 +1,294 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package driver + +import ( + "fmt" + "log" + "net/http" + "os" + "runtime" + "strings" + "testing" + + "github.com/julienschmidt/go-http-routing-benchmark/driver/ui" +) + +// RunTests runs all registerd tests against all registerd packages. +func RunTests() []*Assertion { + pn, bn := len(packages), len(benchmarks) + + if pn == 0 { + fmt.Fprint(os.Stderr, "error: test: no packages registered\n") + os.Exit(1) + } + if bn == 0 { + fmt.Fprint(os.Stderr, "error: test: no benchmarks registered\n") + os.Exit(1) + } + + var runs int + var errs []*Assertion + + // Calculate the number of tests we have to run + for _, b := range benchmarks { + var rs, qs, ps int + + for _, t := range b.tests { + if t.Route != nil { + rs += len(b.routes) + } + if t.Request != nil { + qs += len(b.requests) + } + } + for _, p := range packages { + if p.Supports.isset(b.Type) { + ps++ + } + } + + runs += ((rs + qs) * ps) + (len(packages) - ps) + } + + rw := &Response{} + ui := ui.NewText(runs) + + defer func() { + if rerr := recover(); rerr != nil { + ui.Error() + stack := make([]byte, 10000) + runtime.Stack(stack, false) + fmt.Fprintf(os.Stderr, "\n\n%s\n\n%s", rerr, stack) + os.Exit(2) + } + }() + + for _, b := range benchmarks { + for _, p := range packages { + if !p.Supports.isset(b.Type) { + ui.Skip() + continue + } + + h := p.Router(b.Type, normalize(b.routes, p.Normalizer)) + + for _, t := range b.tests { + rt := t.Route + if rt != nil { + for _, r := range b.routes { + x := verify(rt(r)) + + if x != nil { + ui.Error() + x.pkg = p + x.test = t + x.bench = b + errs = append(errs, x) + } else { + ui.Success() + } + } + } + + qt := t.Request + if qt != nil { + for _, r := range b.requests { + rw.Reset() + h.ServeHTTP(rw, r) + x := verify(qt(r, rw)) + + if x != nil { + if x.Error == "" && x.Expect == x.Actual { + ui.Success() + continue + } + + ui.Error() + x.pkg = p + x.test = t + x.bench = b + errs = append(errs, x) + } else { + ui.Success() + } + } + } + } + } + } + + return errs +} + +// RunBenchmarks runs all registerd benchmarks against all registerd packages. +func RunBenchmarks() []*Result { + pn, bn := len(packages), len(benchmarks) + + if pn == 0 { + fmt.Fprint(os.Stderr, "error: benchmark: no packages registered\n") + os.Exit(1) + } + if bn == 0 { + fmt.Fprint(os.Stderr, "error: benchmark: no benchmarks registered\n") + os.Exit(1) + } + + var ( + results []*Result + memory runtime.MemStats + ) + + ui := ui.NewText(pn * bn) + + for _, b := range benchmarks { + r := &Result{ + benchmark: b, + } + + for _, p := range packages { + if !p.Supports.isset(b.Type) { + ui.Skip() + continue + } + + f := normalize(b.routes, p.Normalizer) + + runtime.GC() + runtime.ReadMemStats(&memory) + m := memory.HeapAlloc + + h := p.Router(b.Type, f) + + runtime.GC() + runtime.ReadMemStats(&memory) + m = memory.HeapAlloc - m + + x := testing.Benchmark(benchmarkify(h, b.requests)) + + r.pkgs = append(r.pkgs, p) + r.alloc = append(r.alloc, m) + r.results = append(r.results, &x) + + ui.Success() + } + + if r.pkgs != nil && r.alloc != nil && r.results != nil { + results = append(results, r) + } + + } + + return results +} + +// benchmarkify wraps a http.Handler in a benchmarkable closure. +func benchmarkify(h http.Handler, rs []*http.Request) func(*testing.B) { + rw := &ResponseStub{} + + if len(rs) > 1 { + r := rs[0] + + return func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + h.ServeHTTP(rw, r) + } + } + } + + return func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, r := range rs { + h.ServeHTTP(rw, r) + } + } + } +} + +var ncache = make(map[nkey]Fixtures) + +type nkey struct { + f *Fixtures + n *Normalizer +} + +// normalize's and caches normalized Fixtures. +func normalize(f Fixtures, n Normalizer) Fixtures { + if n == nil { + return f + } + + k := nkey{&f, &n} + x, ok := ncache[k] + + if ok { + return x + } + + o := n(f) + ncache[k] = o + + return o +} + +// verify checks that the Assertion is valid or nil. A Assertion is only valid +// if Error is set and Expect and Actual are empty or vice versa. See Assertion. +func verify(a *Assertion) *Assertion { + if a == nil { + return a + } + + var errors []string + + if a.Error != "" { + if a.Expect != "" { + panic("Expect must be empty if Error is set") + } + if a.Actual != "" { + errors = append(errors, "Actual must be empty if Error is set") + } + } else { + if a.Expect == "" { + errors = append(errors, "Expect must be set") + } + if a.Actual == "" { + errors = append(errors, "Actual must be set") + } + } + + if errors != nil { + panic(strings.Join(errors, ", ")) + } + + return a +} + +type ResponseStub struct{} + +func (r *ResponseStub) Header() http.Header { + return http.Header{} +} + +func (r *ResponseStub) Write(p []byte) (int, error) { + return len(p), nil +} + +func (r *ResponseStub) WriteString(p string) (int, error) { + return len(p), nil +} + +func (r *ResponseStub) WriteHeader(int) {} + +var LoggerStub *log.Logger + +func init() { + LoggerStub = log.New(&ResponseStub{}, "", 0) +} diff --git a/driver/extern.go b/driver/extern.go new file mode 100644 index 00000000..40cc94e6 --- /dev/null +++ b/driver/extern.go @@ -0,0 +1,481 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package driver + +import ( + "bytes" + "fmt" + "net/http" + "net/url" + "regexp" + "strings" + "testing" +) + +// Type defines a benchmark type +type Type uint + +// isset determines wether b is set. +func (t Type) isset(b Type) bool { + return t&b != 0 +} + +const ( + // Benchmark route with a static path. This benchmark must only contain + // static routes. + // + // Route: GET /test/example + // Request: GET /test/example + Static Type = 1 << 0 + + // Benchmark routes with one or more dynamic path segments. This benchmark + // may also contain static routes. + // + // Route: GET /test/:example + // Request: GET /test/benchmark + // Parameter: example=benchmark + Parameterized Type = 1 << 1 + + // Benchmark a route with multiple dynamic path segments where one parameter + // (dynamicparam, see ParamNameReadWrite) is read and written to /dev/null. + // This benchmark must not contain other types of benchmarks. + // + // Route: GET /test/:one/:two/:three/:dynamicparam + // Request: GET /test/one/two/three/benchmark + // Parameter: one=one, two=two, three=three, dynamicparam=benchmark + // Response: benchmark + ParameterReadWrite Type = 1 << 2 + + // ParameterReadWrite benchmark expects a parameter named dynamicparam. + ParamNameReadWrite = "dynamicparam" +) + +// Fixture is used to benchmark and test Router implementations. +type Fixture struct { + // Method used for routing and requesting the endpoint. + Method string + + // Path used for routing and requesting the endpoint. + Path string +} + +// Fixtures is a list of Fixture objects. +type Fixtures []*Fixture + +// Router initializes and returns a http.Handler used to route requests. +type Router func(Type, Fixtures) http.Handler + +// Normalizer normalizes parameterized routes before they get passed to the Router. +// Route normalization is importatnt for Routers that differ in the way they +// indicate a parameter (e.g. not prefixing it with a colon). +type Normalizer func(Fixtures) Fixtures + +var nre = regexp.MustCompile(":([^/]*)") + +// CurlyBracesNormalizer replaces colon (:param) parameters with curly braces +// (i.e. {param}). +func CurlyBracesNormalizer(f Fixtures) Fixtures { + s := make(Fixtures, len(f)) + + for i, r := range f { + s[i] = &Fixture{r.Method, nre.ReplaceAllString(r.Path, "{$1}")} + } + + return s +} + +// XThanSignNormalizer replaces colon (:param) parameters with greater- and +// less-than sign (i.e. ). +func XThanSignNormalizer(f Fixtures) Fixtures { + s := make(Fixtures, len(f)) + + for i, r := range f { + s[i] = &Fixture{r.Method, nre.ReplaceAllString(r.Path, "<$1>")} + } + + return s +} + +// RegExAllNormalizer replaces colon (:param) parameters with a regular expression +// which matches everything.except a slash +func RegExAllNormalizer(f Fixtures) Fixtures { + s := make(Fixtures, len(f)) + + for i, r := range f { + s[i] = &Fixture{r.Method, nre.ReplaceAllString(r.Path, "(?P<$1>[^/]*)")} + } + + return s +} + +// Benchmark describes a benchmark. A benchmark may only cover one benchmark type. +type Benchmark struct { + Type Type + Name string + Description string + tests []*Test + routes Fixtures + requests []*http.Request +} + +var benchmarks []*Benchmark + +// NewBenchmark registers and returns a new benchmark object. This function +// panics on error. +func NewBenchmark(t Type, name, desc string) *Benchmark { + var errors []string + + if t == Type(0) { + errors = append(errors, "Benchmark type cannot be zero") + } + if t&(t-Type(1)) != Type(0) { + errors = append(errors, "Benchmark cannot cover multiple types") + } + if name == "" { + errors = append(errors, "Benchmark name cannot be empty") + } + if desc == "" { + errors = append(errors, "Benchmark description cannot be empty") + } + + if errors != nil { + panic(strings.Join(errors, ", ")) + } + + b := &Benchmark{ + Type: t, + Name: name, + Description: desc, + } + benchmarks = append(benchmarks, b) + + return b +} + +// AddTest registers a new test case which will be run against a Router +// implementation. This function panics on error. +func (b *Benchmark) AddTest(t *Test) { + var errors []string + + if t.Description == "" { + errors = append(errors, "Test.Description cannot be empty") + } + if t.Route == nil && t.Request == nil { + errors = append(errors, "Test.Route or Test.Request must be set") + } + + if errors != nil { + panic(strings.Join(errors, ", ")) + } + + b.tests = append(b.tests, t) +} + +// AddRoute registers a new route which will be registered with a Router. +// This function panics on error. +func (b *Benchmark) AddRoute(method, path string) { + var errors []string + + if method == "" { + errors = append(errors, "Method cannot be empty") + } + if path == "" { + errors = append(errors, "Path cannot be empty") + } + + if errors != nil { + panic(strings.Join(errors, ", ")) + } + + b.routes = append(b.routes, &Fixture{method, path}) +} + +// AddRoutes registers routes based on Fixtures which will be registered with a Router. +// This function panics on error. +func (b *Benchmark) AddRoutes(fs Fixtures) { + var errors []string + + for i, f := range fs { + if f.Method == "" { + errors = append(errors, fmt.Sprintf("Fixture #%d: Method cannot be empty", i)) + } + if f.Path == "" { + errors = append(errors, fmt.Sprintf("Fixture #%d: Path cannot be empty", i)) + } + + b.routes = append(b.routes, f) + } + + if errors != nil { + panic(strings.Join(errors, ", ")) + } +} + +var request = strings.NewReplacer("/:", "/") + +// AddRoute registers a new route which will be registered with a Router. +// This function panics on error. +func (b *Benchmark) AddRequest(method, path string) { + var errors []string + r, err := http.NewRequest(method, request.Replace(path), nil) + + if err != nil { + errors = append(errors, err.Error()) + } + if method == "" { + errors = append(errors, "Method cannot be empty") + } + if path == "" { + errors = append(errors, "Path cannot be empty") + } + + if errors != nil { + panic(strings.Join(errors, ", ")) + } + + b.requests = append(b.requests, r) +} + +// AddRequests generates requests based on Fixtures. The paths will be striped +// of parameters (/:). // This function panics on error. +func (b *Benchmark) AddRequests(fs Fixtures) { + var errors []string + + for i, f := range fs { + r, err := http.NewRequest(f.Method, request.Replace(f.Path), nil) + + if err != nil { + errors = append(errors, err.Error()) + } + if f.Method == "" { + errors = append(errors, fmt.Sprintf("Fixture #%d: Method cannot be empty", i)) + } + if f.Path == "" { + errors = append(errors, fmt.Sprintf("Fixture #%d: Path cannot be empty", i)) + } + + b.requests = append(b.requests, r) + } + + if errors != nil { + panic(strings.Join(errors, ", ")) + } +} + +// Package describes a router or framework. Every field except for Normalizer +// is required. +type Package struct { + Name string // Name of the Router + Homepage string // Homepage or repository URL for the router/framework + Router Router // Router to initialize a http.Handler + Supports Type // Bitmask of supported benchmark Type's + Normalizer Normalizer // Normalizer to run before routes get passed to the Router +} + +var packages []*Package + +// Returns the number of registered packages. +func NumPackages() int { + return len(packages) +} + +// Returns the names of registered packages. +func PackageNames() []string { + r := make([]string, len(packages)) + for i, pkg := range packages { + r[i] = pkg.Name + } + + return r +} + +// RegisterPackage registers router/framework package. +func RegisterPackage(p *Package) { + var errors []string + + if p == nil { + errors = append(errors, "Package cannot be nil") + } else { + if p.Name == "" { + errors = append(errors, "Package.Name cannot be empty") + } + if p.Homepage == "" { + errors = append(errors, "Package.Homepage cannot be empty") + } else if _, err := url.Parse(p.Homepage); p != nil && err != nil { + errors = append(errors, err.Error()) + } + if p.Router == nil { + errors = append(errors, "Package.Router cannot be nil") + } + if p.Supports == Type(0) { + errors = append(errors, "Package.Supports cannot be zero") + } + } + + if errors != nil { + panic(strings.Join(errors, ", ")) + } + + packages = append(packages, p) +} + +// Test describes a test case used to test that benchmarks are configured correctly. +// A Test function may return a pointer to a Assertion object or nil, depending whether +// the test was successful or not. +type Test struct { + // Description for the test case. + Description string + + // Tests the raw, not normalized routes. + Route func(*Fixture) *Assertion + + // Tests the http.Request or Response object. + Request func(*http.Request, *Response) *Assertion +} + +// Assertion is used in test cases to indicate that an error occured or to compare +// the expected output is equal to the actual output. If the Error property is +// set, Actual and Expect must be empty and vice versa. The comparison of the expected +// and actual output is not part of the test and will be handled externaly. +type Assertion struct { + test *Test + pkg *Package + bench *Benchmark + Error string + Actual string + Expect string +} + +// Returns the description of the test that failed. +func (a *Assertion) Description() string { + if a.test == nil { + return "" + } + + return a.test.Description +} + +// Returns the router name of the test that failed. +func (a *Assertion) Router() string { + if a.pkg == nil { + return "" + } + + return a.pkg.Name +} + +// Returns the benchmark description of the test that failed. +func (a *Assertion) Benchmark() string { + if a.bench == nil { + return "" + } + + return a.bench.Name + ": " + a.bench.Description +} + +// Result is a benchmark result. +type Result struct { + benchmark *Benchmark + alloc []uint64 + pkgs []*Package + results []*testing.BenchmarkResult +} + +// Name returns the name of the benchmark. +func (r *Result) Name() string { + if r.benchmark == nil { + panic("benchmark is nil") + } + + return r.benchmark.Name +} + +// Description returns the description of the benchmark. +func (r *Result) Description() string { + if r.benchmark == nil { + panic("benchmark is nil") + } + + return r.benchmark.Description +} + +// Package returns all packages which were benchmarked. +func (r *Result) Packages() []*Package { + if len(r.pkgs) != len(r.results) && len(r.pkgs) != len(r.alloc) { + panic("Package, BenchmarkResult and HeapMemory mismatch") + } + + return r.pkgs +} + +// RouterMemory returns the heap memory used for the router object. +func (r *Result) RouterMemory() []uint64 { + if len(r.pkgs) != len(r.results) && len(r.pkgs) != len(r.alloc) { + panic("Package, BenchmarkResult and HeapMemory mismatch") + } + + return r.alloc +} + +// Result returns the benchmarks result of all benchmarked packages. +func (r *Result) Results() []*testing.BenchmarkResult { + if len(r.pkgs) != len(r.results) && len(r.pkgs) != len(r.alloc) { + panic("Package, BenchmarkResult and HeapMemory mismatch") + } + + return r.results +} + +// Response is used in during tests and captures the written response. +type Response struct { + flushed bool + status int + output bytes.Buffer + header http.Header +} + +// Reset's the captured status code and output. +func (r *Response) Reset() { + r.status = 0 + r.header = nil + r.flushed = false + r.output.Reset() +} + +// StatusCode returns the written status code. +func (r *Response) Status() int { + return r.status +} + +// Output returns the written output. +func (r *Response) Output() []byte { + return r.output.Bytes() +} + +// Header returns the header map that will be sent by WriteHeader. +func (r *Response) Header() http.Header { + if r.header == nil { + r.header = http.Header{} + } + + return r.header +} + +// Write's the data to the connection as part of an HTTP reply. +func (r *Response) Write(b []byte) (int, error) { + if !r.flushed { + r.WriteHeader(http.StatusOK) + } + + return r.output.Write(b) +} + +// WriteHeader sends an HTTP response header with status code. +func (r *Response) WriteHeader(c int) { + if !r.flushed { + r.status = c + r.flushed = true + } +} diff --git a/driver/ui/console.go b/driver/ui/console.go new file mode 100644 index 00000000..391ff3c3 --- /dev/null +++ b/driver/ui/console.go @@ -0,0 +1,114 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package ui + +import ( + "fmt" + "runtime" + "strings" +) + +var defaultConsole ConsoleAdapter + +// Console sets the default console and returns it. +func Console(style string) ConsoleAdapter { + var stylizer Colorizer + + switch style { + case "on": + stylizer = color{} + case "ansi": + stylizer = ansiColor{} + case "off": + stylizer = nullColor{} + default: + panic("Unknown color option") + } + + switch runtime.GOOS { + case "windows": + defaultConsole = windowsConsole{baseConsole{stylizer}} + default: + defaultConsole = posixConsole{baseConsole{stylizer}} + } + + return defaultConsole +} + +type ConsoleAdapter interface { + Reset() + Width() int + Height() int + Red(string) + Green(string) + Yellow(string) + Print(string) + Printf(string, ...interface{}) + Color() Colorizer +} + +type baseConsole struct { + style Colorizer +} + +func (c baseConsole) Width() int { return 80 } +func (c baseConsole) Height() int { return 25 } +func (c baseConsole) Color() Colorizer { return c.style } +func (c baseConsole) Reset() { fmt.Print("\f") } +func (c baseConsole) Red(b string) { fmt.Print(c.style.Red(b)) } +func (c baseConsole) Green(b string) { fmt.Print(c.style.Green(b)) } +func (c baseConsole) Yellow(b string) { fmt.Print(c.style.Yellow(b)) } +func (c baseConsole) Print(p string) { fmt.Print(p) } +func (c baseConsole) Printf(f string, args ...interface{}) { fmt.Printf(f, args...) } + +type posixConsole struct { + baseConsole +} + +type windowsConsole struct { + baseConsole +} + +func (c windowsConsole) Reset() { fmt.Print(strings.Repeat("\r\n", c.Height())) } + +type Colorizer interface { + Red(string) string + Green(string) string + Yellow(string) string +} + +type nullColor struct{} + +func (c nullColor) Red(b string) string { return b } +func (c nullColor) Green(b string) string { return b } +func (c nullColor) Yellow(b string) string { return b } + +type color struct{} + +func (c color) Red(b string) string { + return "\033[1;31m" + b + "\033[0m" +} + +func (c color) Green(b string) string { + return "\033[1;32m" + b + "\033[0m" +} + +func (c color) Yellow(b string) string { + return "\033[1;33m" + b + "\033[0m" +} + +type ansiColor struct{} + +func (c ansiColor) Red(b string) string { + return "\x1b[1;31m" + b + "\x1b[0m" +} + +func (c ansiColor) Green(b string) string { + return "\x1b[1;32m" + b + "\x1b[0m" +} + +func (c ansiColor) Yellow(b string) string { + return "\x1b[1;33m" + b + "\x1b[0m" +} diff --git a/driver/ui/text.go b/driver/ui/text.go new file mode 100644 index 00000000..f002bcaa --- /dev/null +++ b/driver/ui/text.go @@ -0,0 +1,106 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package ui + +import ( + "bytes" + "strconv" + "strings" + "time" +) + +// Text describes a text runner user interface. +type Text struct { + errors int + skipped int + + max int // Maximum steps to take + step int // Steps already taken + colum int // Right colum width + width int // Current width without the colum + digits int // Digits of max steps + + start time.Time + line bytes.Buffer + console ConsoleAdapter +} + +// NewText returns a new text user interface which can be called steps times. +// After steps calls it prints stats. This function captures the default colorizer +// at instantiation. +func NewText(steps int) *Text { + d := len(strconv.Itoa(steps)) + + return &Text{ + digits: d, + max: steps, + start: time.Now(), + console: defaultConsole, + colum: 6 + d + 1 + d, // " 000% " d "/" d, + } +} + +// Success marks the current step as successful. +func (t *Text) Success() { + t.write(".") +} + +// Error marks the current step as failed. +func (t *Text) Error() { + t.errors++ + t.write(t.console.Color().Red("E")) +} + +// Skip marks the current step as skipped. +func (t *Text) Skip() { + t.skipped++ + t.write(t.console.Color().Yellow("S")) +} + +func (t *Text) write(b string) { + t.step++ + t.width++ + t.line.WriteString(b) + + pd := strings.Repeat(" ", t.console.Width()-(t.width+t.colum)) + + if t.max < t.step { + panic("Maximum steps already reached") + } + + pc := int(100 * float64(t.step) / float64(t.max)) + t.console.Printf("\r%s%s %3d%% %*d/%*d", t.line.String(), pd, pc, t.digits, t.step, t.digits, t.max) + + if (t.width + t.colum) >= t.console.Width() { + t.width = 0 + t.line.Reset() + t.console.Print("\n") + } + + if t.max == t.step { + t.console.Print("\n\n") + + t.console.Printf("Total: %d", t.max) + if t.errors > 0 { + t.console.Printf(", %d failed", t.errors) + } + if t.skipped > 0 { + t.console.Printf(", %d skipped", t.skipped) + } + + d := time.Since(t.start) + h := int(d.Hours()) + m := int(d.Minutes()) % 60 + s := int(d.Seconds()) % 60 + + t.console.Print("; Time: ") + if h > 0 { + t.console.Printf("%d:", h) + } + t.console.Printf("%02d:%02d", m, s) + + t.console.Print("\n\n\n") + } +} From 8c8ae3f62e80a80448716481eb09694f0fbc4f44 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 17:56:57 +0200 Subject: [PATCH 04/18] suite: refactor fixtures to use the new driver Refactored benchmark fixtures to use the new driver and implemented test cases for each benchmark. --- github_test.go | 698 -------------------------------------------- static_test.go | 386 ------------------------ suite/github.go | 309 ++++++++++++++++++++ suite/googleplus.go | 80 +++++ suite/params.go | 77 +++++ suite/parsecom.go | 100 +++++++ suite/static.go | 192 ++++++++++++ suite/tests.go | 102 +++++++ 8 files changed, 860 insertions(+), 1084 deletions(-) delete mode 100644 github_test.go delete mode 100644 static_test.go create mode 100644 suite/github.go create mode 100644 suite/googleplus.go create mode 100644 suite/params.go create mode 100644 suite/parsecom.go create mode 100644 suite/static.go create mode 100644 suite/tests.go diff --git a/github_test.go b/github_test.go deleted file mode 100644 index c744447d..00000000 --- a/github_test.go +++ /dev/null @@ -1,698 +0,0 @@ -// Copyright 2013 Julien Schmidt. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -package main - -import ( - "net/http" - "testing" -) - -// http://developer.github.com/v3/ -var githubAPI = []route{ - // OAuth Authorizations - {"GET", "/authorizations"}, - {"GET", "/authorizations/:id"}, - {"POST", "/authorizations"}, - //{"PUT", "/authorizations/clients/:client_id"}, - //{"PATCH", "/authorizations/:id"}, - {"DELETE", "/authorizations/:id"}, - {"GET", "/applications/:client_id/tokens/:access_token"}, - {"DELETE", "/applications/:client_id/tokens"}, - {"DELETE", "/applications/:client_id/tokens/:access_token"}, - - // Activity - {"GET", "/events"}, - {"GET", "/repos/:owner/:repo/events"}, - {"GET", "/networks/:owner/:repo/events"}, - {"GET", "/orgs/:org/events"}, - {"GET", "/users/:user/received_events"}, - {"GET", "/users/:user/received_events/public"}, - {"GET", "/users/:user/events"}, - {"GET", "/users/:user/events/public"}, - {"GET", "/users/:user/events/orgs/:org"}, - {"GET", "/feeds"}, - {"GET", "/notifications"}, - {"GET", "/repos/:owner/:repo/notifications"}, - {"PUT", "/notifications"}, - {"PUT", "/repos/:owner/:repo/notifications"}, - {"GET", "/notifications/threads/:id"}, - //{"PATCH", "/notifications/threads/:id"}, - {"GET", "/notifications/threads/:id/subscription"}, - {"PUT", "/notifications/threads/:id/subscription"}, - {"DELETE", "/notifications/threads/:id/subscription"}, - {"GET", "/repos/:owner/:repo/stargazers"}, - {"GET", "/users/:user/starred"}, - {"GET", "/user/starred"}, - {"GET", "/user/starred/:owner/:repo"}, - {"PUT", "/user/starred/:owner/:repo"}, - {"DELETE", "/user/starred/:owner/:repo"}, - {"GET", "/repos/:owner/:repo/subscribers"}, - {"GET", "/users/:user/subscriptions"}, - {"GET", "/user/subscriptions"}, - {"GET", "/repos/:owner/:repo/subscription"}, - {"PUT", "/repos/:owner/:repo/subscription"}, - {"DELETE", "/repos/:owner/:repo/subscription"}, - {"GET", "/user/subscriptions/:owner/:repo"}, - {"PUT", "/user/subscriptions/:owner/:repo"}, - {"DELETE", "/user/subscriptions/:owner/:repo"}, - - // Gists - {"GET", "/users/:user/gists"}, - {"GET", "/gists"}, - //{"GET", "/gists/public"}, - //{"GET", "/gists/starred"}, - {"GET", "/gists/:id"}, - {"POST", "/gists"}, - //{"PATCH", "/gists/:id"}, - {"PUT", "/gists/:id/star"}, - {"DELETE", "/gists/:id/star"}, - {"GET", "/gists/:id/star"}, - {"POST", "/gists/:id/forks"}, - {"DELETE", "/gists/:id"}, - - // Git Data - {"GET", "/repos/:owner/:repo/git/blobs/:sha"}, - {"POST", "/repos/:owner/:repo/git/blobs"}, - {"GET", "/repos/:owner/:repo/git/commits/:sha"}, - {"POST", "/repos/:owner/:repo/git/commits"}, - //{"GET", "/repos/:owner/:repo/git/refs/*ref"}, - {"GET", "/repos/:owner/:repo/git/refs"}, - {"POST", "/repos/:owner/:repo/git/refs"}, - //{"PATCH", "/repos/:owner/:repo/git/refs/*ref"}, - //{"DELETE", "/repos/:owner/:repo/git/refs/*ref"}, - {"GET", "/repos/:owner/:repo/git/tags/:sha"}, - {"POST", "/repos/:owner/:repo/git/tags"}, - {"GET", "/repos/:owner/:repo/git/trees/:sha"}, - {"POST", "/repos/:owner/:repo/git/trees"}, - - // Issues - {"GET", "/issues"}, - {"GET", "/user/issues"}, - {"GET", "/orgs/:org/issues"}, - {"GET", "/repos/:owner/:repo/issues"}, - {"GET", "/repos/:owner/:repo/issues/:number"}, - {"POST", "/repos/:owner/:repo/issues"}, - //{"PATCH", "/repos/:owner/:repo/issues/:number"}, - {"GET", "/repos/:owner/:repo/assignees"}, - {"GET", "/repos/:owner/:repo/assignees/:assignee"}, - {"GET", "/repos/:owner/:repo/issues/:number/comments"}, - //{"GET", "/repos/:owner/:repo/issues/comments"}, - //{"GET", "/repos/:owner/:repo/issues/comments/:id"}, - {"POST", "/repos/:owner/:repo/issues/:number/comments"}, - //{"PATCH", "/repos/:owner/:repo/issues/comments/:id"}, - //{"DELETE", "/repos/:owner/:repo/issues/comments/:id"}, - {"GET", "/repos/:owner/:repo/issues/:number/events"}, - //{"GET", "/repos/:owner/:repo/issues/events"}, - //{"GET", "/repos/:owner/:repo/issues/events/:id"}, - {"GET", "/repos/:owner/:repo/labels"}, - {"GET", "/repos/:owner/:repo/labels/:name"}, - {"POST", "/repos/:owner/:repo/labels"}, - //{"PATCH", "/repos/:owner/:repo/labels/:name"}, - {"DELETE", "/repos/:owner/:repo/labels/:name"}, - {"GET", "/repos/:owner/:repo/issues/:number/labels"}, - {"POST", "/repos/:owner/:repo/issues/:number/labels"}, - {"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name"}, - {"PUT", "/repos/:owner/:repo/issues/:number/labels"}, - {"DELETE", "/repos/:owner/:repo/issues/:number/labels"}, - {"GET", "/repos/:owner/:repo/milestones/:number/labels"}, - {"GET", "/repos/:owner/:repo/milestones"}, - {"GET", "/repos/:owner/:repo/milestones/:number"}, - {"POST", "/repos/:owner/:repo/milestones"}, - //{"PATCH", "/repos/:owner/:repo/milestones/:number"}, - {"DELETE", "/repos/:owner/:repo/milestones/:number"}, - - // Miscellaneous - {"GET", "/emojis"}, - {"GET", "/gitignore/templates"}, - {"GET", "/gitignore/templates/:name"}, - {"POST", "/markdown"}, - {"POST", "/markdown/raw"}, - {"GET", "/meta"}, - {"GET", "/rate_limit"}, - - // Organizations - {"GET", "/users/:user/orgs"}, - {"GET", "/user/orgs"}, - {"GET", "/orgs/:org"}, - //{"PATCH", "/orgs/:org"}, - {"GET", "/orgs/:org/members"}, - {"GET", "/orgs/:org/members/:user"}, - {"DELETE", "/orgs/:org/members/:user"}, - {"GET", "/orgs/:org/public_members"}, - {"GET", "/orgs/:org/public_members/:user"}, - {"PUT", "/orgs/:org/public_members/:user"}, - {"DELETE", "/orgs/:org/public_members/:user"}, - {"GET", "/orgs/:org/teams"}, - {"GET", "/teams/:id"}, - {"POST", "/orgs/:org/teams"}, - //{"PATCH", "/teams/:id"}, - {"DELETE", "/teams/:id"}, - {"GET", "/teams/:id/members"}, - {"GET", "/teams/:id/members/:user"}, - {"PUT", "/teams/:id/members/:user"}, - {"DELETE", "/teams/:id/members/:user"}, - {"GET", "/teams/:id/repos"}, - {"GET", "/teams/:id/repos/:owner/:repo"}, - {"PUT", "/teams/:id/repos/:owner/:repo"}, - {"DELETE", "/teams/:id/repos/:owner/:repo"}, - {"GET", "/user/teams"}, - - // Pull Requests - {"GET", "/repos/:owner/:repo/pulls"}, - {"GET", "/repos/:owner/:repo/pulls/:number"}, - {"POST", "/repos/:owner/:repo/pulls"}, - //{"PATCH", "/repos/:owner/:repo/pulls/:number"}, - {"GET", "/repos/:owner/:repo/pulls/:number/commits"}, - {"GET", "/repos/:owner/:repo/pulls/:number/files"}, - {"GET", "/repos/:owner/:repo/pulls/:number/merge"}, - {"PUT", "/repos/:owner/:repo/pulls/:number/merge"}, - {"GET", "/repos/:owner/:repo/pulls/:number/comments"}, - //{"GET", "/repos/:owner/:repo/pulls/comments"}, - //{"GET", "/repos/:owner/:repo/pulls/comments/:number"}, - {"PUT", "/repos/:owner/:repo/pulls/:number/comments"}, - //{"PATCH", "/repos/:owner/:repo/pulls/comments/:number"}, - //{"DELETE", "/repos/:owner/:repo/pulls/comments/:number"}, - - // Repositories - {"GET", "/user/repos"}, - {"GET", "/users/:user/repos"}, - {"GET", "/orgs/:org/repos"}, - {"GET", "/repositories"}, - {"POST", "/user/repos"}, - {"POST", "/orgs/:org/repos"}, - {"GET", "/repos/:owner/:repo"}, - //{"PATCH", "/repos/:owner/:repo"}, - {"GET", "/repos/:owner/:repo/contributors"}, - {"GET", "/repos/:owner/:repo/languages"}, - {"GET", "/repos/:owner/:repo/teams"}, - {"GET", "/repos/:owner/:repo/tags"}, - {"GET", "/repos/:owner/:repo/branches"}, - {"GET", "/repos/:owner/:repo/branches/:branch"}, - {"DELETE", "/repos/:owner/:repo"}, - {"GET", "/repos/:owner/:repo/collaborators"}, - {"GET", "/repos/:owner/:repo/collaborators/:user"}, - {"PUT", "/repos/:owner/:repo/collaborators/:user"}, - {"DELETE", "/repos/:owner/:repo/collaborators/:user"}, - {"GET", "/repos/:owner/:repo/comments"}, - {"GET", "/repos/:owner/:repo/commits/:sha/comments"}, - {"POST", "/repos/:owner/:repo/commits/:sha/comments"}, - {"GET", "/repos/:owner/:repo/comments/:id"}, - //{"PATCH", "/repos/:owner/:repo/comments/:id"}, - {"DELETE", "/repos/:owner/:repo/comments/:id"}, - {"GET", "/repos/:owner/:repo/commits"}, - {"GET", "/repos/:owner/:repo/commits/:sha"}, - {"GET", "/repos/:owner/:repo/readme"}, - //{"GET", "/repos/:owner/:repo/contents/*path"}, - //{"PUT", "/repos/:owner/:repo/contents/*path"}, - //{"DELETE", "/repos/:owner/:repo/contents/*path"}, - //{"GET", "/repos/:owner/:repo/:archive_format/:ref"}, - {"GET", "/repos/:owner/:repo/keys"}, - {"GET", "/repos/:owner/:repo/keys/:id"}, - {"POST", "/repos/:owner/:repo/keys"}, - //{"PATCH", "/repos/:owner/:repo/keys/:id"}, - {"DELETE", "/repos/:owner/:repo/keys/:id"}, - {"GET", "/repos/:owner/:repo/downloads"}, - {"GET", "/repos/:owner/:repo/downloads/:id"}, - {"DELETE", "/repos/:owner/:repo/downloads/:id"}, - {"GET", "/repos/:owner/:repo/forks"}, - {"POST", "/repos/:owner/:repo/forks"}, - {"GET", "/repos/:owner/:repo/hooks"}, - {"GET", "/repos/:owner/:repo/hooks/:id"}, - {"POST", "/repos/:owner/:repo/hooks"}, - //{"PATCH", "/repos/:owner/:repo/hooks/:id"}, - {"POST", "/repos/:owner/:repo/hooks/:id/tests"}, - {"DELETE", "/repos/:owner/:repo/hooks/:id"}, - {"POST", "/repos/:owner/:repo/merges"}, - {"GET", "/repos/:owner/:repo/releases"}, - {"GET", "/repos/:owner/:repo/releases/:id"}, - {"POST", "/repos/:owner/:repo/releases"}, - //{"PATCH", "/repos/:owner/:repo/releases/:id"}, - {"DELETE", "/repos/:owner/:repo/releases/:id"}, - {"GET", "/repos/:owner/:repo/releases/:id/assets"}, - {"GET", "/repos/:owner/:repo/stats/contributors"}, - {"GET", "/repos/:owner/:repo/stats/commit_activity"}, - {"GET", "/repos/:owner/:repo/stats/code_frequency"}, - {"GET", "/repos/:owner/:repo/stats/participation"}, - {"GET", "/repos/:owner/:repo/stats/punch_card"}, - {"GET", "/repos/:owner/:repo/statuses/:ref"}, - {"POST", "/repos/:owner/:repo/statuses/:ref"}, - - // Search - {"GET", "/search/repositories"}, - {"GET", "/search/code"}, - {"GET", "/search/issues"}, - {"GET", "/search/users"}, - {"GET", "/legacy/issues/search/:owner/:repository/:state/:keyword"}, - {"GET", "/legacy/repos/search/:keyword"}, - {"GET", "/legacy/user/search/:keyword"}, - {"GET", "/legacy/user/email/:email"}, - - // Users - {"GET", "/users/:user"}, - {"GET", "/user"}, - //{"PATCH", "/user"}, - {"GET", "/users"}, - {"GET", "/user/emails"}, - {"POST", "/user/emails"}, - {"DELETE", "/user/emails"}, - {"GET", "/users/:user/followers"}, - {"GET", "/user/followers"}, - {"GET", "/users/:user/following"}, - {"GET", "/user/following"}, - {"GET", "/user/following/:user"}, - {"GET", "/users/:user/following/:target_user"}, - {"PUT", "/user/following/:user"}, - {"DELETE", "/user/following/:user"}, - {"GET", "/users/:user/keys"}, - {"GET", "/user/keys"}, - {"GET", "/user/keys/:id"}, - {"POST", "/user/keys"}, - //{"PATCH", "/user/keys/:id"}, - {"DELETE", "/user/keys/:id"}, -} - -var ( - githubAce http.Handler - githubBear http.Handler - githubBeego http.Handler - githubBone http.Handler - githubDenco http.Handler - githubEcho http.Handler - githubGin http.Handler - githubGocraftWeb http.Handler - githubGoji http.Handler - githubGoJsonRest http.Handler - githubGoRestful http.Handler - githubGorillaMux http.Handler - githubHttpRouter http.Handler - githubHttpTreeMux http.Handler - githubKocha http.Handler - githubMacaron http.Handler - githubMartini http.Handler - githubPat http.Handler - githubPossum http.Handler - githubR2router http.Handler - githubRevel http.Handler - githubRivet http.Handler - githubTango http.Handler - githubTigerTonic http.Handler - githubTraffic http.Handler - githubVulcan http.Handler - // githubZeus http.Handler -) - -func init() { - println("#GithubAPI Routes:", len(githubAPI)) - - calcMem("Ace", func() { - githubAce = loadAce(githubAPI) - }) - calcMem("Bear", func() { - githubBear = loadBear(githubAPI) - }) - calcMem("Beego", func() { - githubBeego = loadBeego(githubAPI) - }) - calcMem("Bone", func() { - githubBone = loadBone(githubAPI) - }) - calcMem("Denco", func() { - githubDenco = loadDenco(githubAPI) - }) - calcMem("Echo", func() { - githubEcho = loadEcho(githubAPI) - }) - calcMem("Gin", func() { - githubGin = loadGin(githubAPI) - }) - calcMem("GocraftWeb", func() { - githubGocraftWeb = loadGocraftWeb(githubAPI) - }) - calcMem("Goji", func() { - githubGoji = loadGoji(githubAPI) - }) - calcMem("GoJsonRest", func() { - githubGoJsonRest = loadGoJsonRest(githubAPI) - }) - calcMem("GoRestful", func() { - githubGoRestful = loadGoRestful(githubAPI) - }) - calcMem("GorillaMux", func() { - githubGorillaMux = loadGorillaMux(githubAPI) - }) - calcMem("HttpRouter", func() { - githubHttpRouter = loadHttpRouter(githubAPI) - }) - calcMem("HttpTreeMux", func() { - githubHttpTreeMux = loadHttpTreeMux(githubAPI) - }) - calcMem("Kocha", func() { - githubKocha = loadKocha(githubAPI) - }) - calcMem("Macaron", func() { - githubMacaron = loadMacaron(githubAPI) - }) - calcMem("Martini", func() { - githubMartini = loadMartini(githubAPI) - }) - calcMem("Pat", func() { - githubPat = loadPat(githubAPI) - }) - calcMem("Possum", func() { - githubPossum = loadPossum(githubAPI) - }) - calcMem("R2router", func() { - githubR2router = loadR2router(githubAPI) - }) - calcMem("Revel", func() { - githubRevel = loadRevel(githubAPI) - }) - calcMem("Rivet", func() { - githubRivet = loadRivet(githubAPI) - }) - calcMem("Tango", func() { - githubTango = loadTango(githubAPI) - }) - calcMem("TigerTonic", func() { - githubTigerTonic = loadTigerTonic(githubAPI) - }) - calcMem("Traffic", func() { - githubTraffic = loadTraffic(githubAPI) - }) - calcMem("Vulcan", func() { - githubVulcan = loadVulcan(githubAPI) - }) - // calcMem("Zeus", func() { - // githubZeus = loadZeus(githubAPI) - // }) - - println() -} - -// Static -func BenchmarkAce_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubAce, req) -} -func BenchmarkBear_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubBear, req) -} -func BenchmarkBeego_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubBeego, req) -} -func BenchmarkBone_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubBone, req) -} -func BenchmarkDenco_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubDenco, req) -} -func BenchmarkEcho_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubEcho, req) -} -func BenchmarkGin_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubGin, req) -} -func BenchmarkGocraftWeb_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubGocraftWeb, req) -} -func BenchmarkGoji_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubGoji, req) -} -func BenchmarkGoRestful_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubGoRestful, req) -} -func BenchmarkGoJsonRest_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubGoJsonRest, req) -} -func BenchmarkGorillaMux_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubGorillaMux, req) -} -func BenchmarkHttpRouter_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubHttpRouter, req) -} -func BenchmarkHttpTreeMux_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubHttpTreeMux, req) -} -func BenchmarkKocha_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubKocha, req) -} -func BenchmarkMacaron_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubMacaron, req) -} -func BenchmarkMartini_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubMartini, req) -} -func BenchmarkPat_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubPat, req) -} -func BenchmarkPossum_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubPossum, req) -} -func BenchmarkR2router_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubR2router, req) -} -func BenchmarkRevel_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubRevel, req) -} -func BenchmarkRivet_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubRivet, req) -} -func BenchmarkTango_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubTango, req) -} -func BenchmarkTigerTonic_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubTigerTonic, req) -} -func BenchmarkTraffic_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubTraffic, req) -} -func BenchmarkVulcan_GithubStatic(b *testing.B) { - req, _ := http.NewRequest("GET", "/user/repos", nil) - benchRequest(b, githubVulcan, req) -} - -// func BenchmarkZeus_GithubStatic(b *testing.B) { -// req, _ := http.NewRequest("GET", "/user/repos", nil) -// benchRequest(b, githubZeus, req) -// } - -// Param -func BenchmarkAce_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubAce, req) -} -func BenchmarkBear_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubBear, req) -} -func BenchmarkBeego_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubBeego, req) -} -func BenchmarkBone_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubBone, req) -} -func BenchmarkDenco_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubDenco, req) -} -func BenchmarkEcho_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubEcho, req) -} -func BenchmarkGin_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubGin, req) -} -func BenchmarkGocraftWeb_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubGocraftWeb, req) -} -func BenchmarkGoji_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubGoji, req) -} -func BenchmarkGoJsonRest_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubGoJsonRest, req) -} -func BenchmarkGoRestful_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubGoRestful, req) -} -func BenchmarkGorillaMux_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubGorillaMux, req) -} -func BenchmarkHttpRouter_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubHttpRouter, req) -} -func BenchmarkHttpTreeMux_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubHttpTreeMux, req) -} -func BenchmarkKocha_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubKocha, req) -} -func BenchmarkMacaron_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubMacaron, req) -} -func BenchmarkMartini_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubMartini, req) -} -func BenchmarkPat_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubPat, req) -} -func BenchmarkPossum_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubPossum, req) -} -func BenchmarkR2router_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubR2router, req) -} -func BenchmarkRevel_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubRevel, req) -} -func BenchmarkRivet_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubRivet, req) -} -func BenchmarkTango_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubTango, req) -} -func BenchmarkTigerTonic_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubTigerTonic, req) -} -func BenchmarkTraffic_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubTraffic, req) -} -func BenchmarkVulcan_GithubParam(b *testing.B) { - req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) - benchRequest(b, githubVulcan, req) -} - -// func BenchmarkZeus_GithubParam(b *testing.B) { -// req, _ := http.NewRequest("GET", "/repos/julienschmidt/httprouter/stargazers", nil) -// benchRequest(b, githubZeus, req) -// } - -// All routes -func BenchmarkAce_GithubAll(b *testing.B) { - benchRoutes(b, githubAce, githubAPI) -} -func BenchmarkBear_GithubAll(b *testing.B) { - benchRoutes(b, githubBear, githubAPI) -} -func BenchmarkBeego_GithubAll(b *testing.B) { - benchRoutes(b, githubBeego, githubAPI) -} -func BenchmarkBone_GithubAll(b *testing.B) { - benchRoutes(b, githubBone, githubAPI) -} -func BenchmarkDenco_GithubAll(b *testing.B) { - benchRoutes(b, githubDenco, githubAPI) -} -func BenchmarkEcho_GithubAll(b *testing.B) { - benchRoutes(b, githubEcho, githubAPI) -} -func BenchmarkGin_GithubAll(b *testing.B) { - benchRoutes(b, githubGin, githubAPI) -} -func BenchmarkGocraftWeb_GithubAll(b *testing.B) { - benchRoutes(b, githubGocraftWeb, githubAPI) -} -func BenchmarkGoji_GithubAll(b *testing.B) { - benchRoutes(b, githubGoji, githubAPI) -} -func BenchmarkGoJsonRest_GithubAll(b *testing.B) { - benchRoutes(b, githubGoJsonRest, githubAPI) -} -func BenchmarkGoRestful_GithubAll(b *testing.B) { - benchRoutes(b, githubGoRestful, githubAPI) -} -func BenchmarkGorillaMux_GithubAll(b *testing.B) { - benchRoutes(b, githubGorillaMux, githubAPI) -} -func BenchmarkHttpRouter_GithubAll(b *testing.B) { - benchRoutes(b, githubHttpRouter, githubAPI) -} -func BenchmarkHttpTreeMux_GithubAll(b *testing.B) { - benchRoutes(b, githubHttpTreeMux, githubAPI) -} -func BenchmarkKocha_GithubAll(b *testing.B) { - benchRoutes(b, githubKocha, githubAPI) -} -func BenchmarkMacaron_GithubAll(b *testing.B) { - benchRoutes(b, githubMacaron, githubAPI) -} -func BenchmarkMartini_GithubAll(b *testing.B) { - benchRoutes(b, githubMartini, githubAPI) -} -func BenchmarkPat_GithubAll(b *testing.B) { - benchRoutes(b, githubPat, githubAPI) -} -func BenchmarkPossum_GithubAll(b *testing.B) { - benchRoutes(b, githubPossum, githubAPI) -} -func BenchmarkR2router_GithubAll(b *testing.B) { - benchRoutes(b, githubR2router, githubAPI) -} -func BenchmarkRevel_GithubAll(b *testing.B) { - benchRoutes(b, githubRevel, githubAPI) -} -func BenchmarkRivet_GithubAll(b *testing.B) { - benchRoutes(b, githubRivet, githubAPI) -} -func BenchmarkTango_GithubAll(b *testing.B) { - benchRoutes(b, githubTango, githubAPI) -} -func BenchmarkTigerTonic_GithubAll(b *testing.B) { - benchRoutes(b, githubTigerTonic, githubAPI) -} -func BenchmarkTraffic_GithubAll(b *testing.B) { - benchRoutes(b, githubTraffic, githubAPI) -} -func BenchmarkVulcan_GithubAll(b *testing.B) { - benchRoutes(b, githubVulcan, githubAPI) -} - -// func BenchmarkZeus_GithubAll(b *testing.B) { -// benchRoutes(b, githubZeus, githubAPI) -// } diff --git a/static_test.go b/static_test.go deleted file mode 100644 index f7a5f85a..00000000 --- a/static_test.go +++ /dev/null @@ -1,386 +0,0 @@ -// Copyright 2013 Julien Schmidt. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. - -package main - -import ( - "net/http" - "testing" -) - -var staticRoutes = []route{ - {"GET", "/"}, - {"GET", "/cmd.html"}, - {"GET", "/code.html"}, - {"GET", "/contrib.html"}, - {"GET", "/contribute.html"}, - {"GET", "/debugging_with_gdb.html"}, - {"GET", "/docs.html"}, - {"GET", "/effective_go.html"}, - {"GET", "/files.log"}, - {"GET", "/gccgo_contribute.html"}, - {"GET", "/gccgo_install.html"}, - {"GET", "/go-logo-black.png"}, - {"GET", "/go-logo-blue.png"}, - {"GET", "/go-logo-white.png"}, - {"GET", "/go1.1.html"}, - {"GET", "/go1.2.html"}, - {"GET", "/go1.html"}, - {"GET", "/go1compat.html"}, - {"GET", "/go_faq.html"}, - {"GET", "/go_mem.html"}, - {"GET", "/go_spec.html"}, - {"GET", "/help.html"}, - {"GET", "/ie.css"}, - {"GET", "/install-source.html"}, - {"GET", "/install.html"}, - {"GET", "/logo-153x55.png"}, - {"GET", "/Makefile"}, - {"GET", "/root.html"}, - {"GET", "/share.png"}, - {"GET", "/sieve.gif"}, - {"GET", "/tos.html"}, - {"GET", "/articles/"}, - {"GET", "/articles/go_command.html"}, - {"GET", "/articles/index.html"}, - {"GET", "/articles/wiki/"}, - {"GET", "/articles/wiki/edit.html"}, - {"GET", "/articles/wiki/final-noclosure.go"}, - {"GET", "/articles/wiki/final-noerror.go"}, - {"GET", "/articles/wiki/final-parsetemplate.go"}, - {"GET", "/articles/wiki/final-template.go"}, - {"GET", "/articles/wiki/final.go"}, - {"GET", "/articles/wiki/get.go"}, - {"GET", "/articles/wiki/http-sample.go"}, - {"GET", "/articles/wiki/index.html"}, - {"GET", "/articles/wiki/Makefile"}, - {"GET", "/articles/wiki/notemplate.go"}, - {"GET", "/articles/wiki/part1-noerror.go"}, - {"GET", "/articles/wiki/part1.go"}, - {"GET", "/articles/wiki/part2.go"}, - {"GET", "/articles/wiki/part3-errorhandling.go"}, - {"GET", "/articles/wiki/part3.go"}, - {"GET", "/articles/wiki/test.bash"}, - {"GET", "/articles/wiki/test_edit.good"}, - {"GET", "/articles/wiki/test_Test.txt.good"}, - {"GET", "/articles/wiki/test_view.good"}, - {"GET", "/articles/wiki/view.html"}, - {"GET", "/codewalk/"}, - {"GET", "/codewalk/codewalk.css"}, - {"GET", "/codewalk/codewalk.js"}, - {"GET", "/codewalk/codewalk.xml"}, - {"GET", "/codewalk/functions.xml"}, - {"GET", "/codewalk/markov.go"}, - {"GET", "/codewalk/markov.xml"}, - {"GET", "/codewalk/pig.go"}, - {"GET", "/codewalk/popout.png"}, - {"GET", "/codewalk/run"}, - {"GET", "/codewalk/sharemem.xml"}, - {"GET", "/codewalk/urlpoll.go"}, - {"GET", "/devel/"}, - {"GET", "/devel/release.html"}, - {"GET", "/devel/weekly.html"}, - {"GET", "/gopher/"}, - {"GET", "/gopher/appenginegopher.jpg"}, - {"GET", "/gopher/appenginegophercolor.jpg"}, - {"GET", "/gopher/appenginelogo.gif"}, - {"GET", "/gopher/bumper.png"}, - {"GET", "/gopher/bumper192x108.png"}, - {"GET", "/gopher/bumper320x180.png"}, - {"GET", "/gopher/bumper480x270.png"}, - {"GET", "/gopher/bumper640x360.png"}, - {"GET", "/gopher/doc.png"}, - {"GET", "/gopher/frontpage.png"}, - {"GET", "/gopher/gopherbw.png"}, - {"GET", "/gopher/gophercolor.png"}, - {"GET", "/gopher/gophercolor16x16.png"}, - {"GET", "/gopher/help.png"}, - {"GET", "/gopher/pkg.png"}, - {"GET", "/gopher/project.png"}, - {"GET", "/gopher/ref.png"}, - {"GET", "/gopher/run.png"}, - {"GET", "/gopher/talks.png"}, - {"GET", "/gopher/pencil/"}, - {"GET", "/gopher/pencil/gopherhat.jpg"}, - {"GET", "/gopher/pencil/gopherhelmet.jpg"}, - {"GET", "/gopher/pencil/gophermega.jpg"}, - {"GET", "/gopher/pencil/gopherrunning.jpg"}, - {"GET", "/gopher/pencil/gopherswim.jpg"}, - {"GET", "/gopher/pencil/gopherswrench.jpg"}, - {"GET", "/play/"}, - {"GET", "/play/fib.go"}, - {"GET", "/play/hello.go"}, - {"GET", "/play/life.go"}, - {"GET", "/play/peano.go"}, - {"GET", "/play/pi.go"}, - {"GET", "/play/sieve.go"}, - {"GET", "/play/solitaire.go"}, - {"GET", "/play/tree.go"}, - {"GET", "/progs/"}, - {"GET", "/progs/cgo1.go"}, - {"GET", "/progs/cgo2.go"}, - {"GET", "/progs/cgo3.go"}, - {"GET", "/progs/cgo4.go"}, - {"GET", "/progs/defer.go"}, - {"GET", "/progs/defer.out"}, - {"GET", "/progs/defer2.go"}, - {"GET", "/progs/defer2.out"}, - {"GET", "/progs/eff_bytesize.go"}, - {"GET", "/progs/eff_bytesize.out"}, - {"GET", "/progs/eff_qr.go"}, - {"GET", "/progs/eff_sequence.go"}, - {"GET", "/progs/eff_sequence.out"}, - {"GET", "/progs/eff_unused1.go"}, - {"GET", "/progs/eff_unused2.go"}, - {"GET", "/progs/error.go"}, - {"GET", "/progs/error2.go"}, - {"GET", "/progs/error3.go"}, - {"GET", "/progs/error4.go"}, - {"GET", "/progs/go1.go"}, - {"GET", "/progs/gobs1.go"}, - {"GET", "/progs/gobs2.go"}, - {"GET", "/progs/image_draw.go"}, - {"GET", "/progs/image_package1.go"}, - {"GET", "/progs/image_package1.out"}, - {"GET", "/progs/image_package2.go"}, - {"GET", "/progs/image_package2.out"}, - {"GET", "/progs/image_package3.go"}, - {"GET", "/progs/image_package3.out"}, - {"GET", "/progs/image_package4.go"}, - {"GET", "/progs/image_package4.out"}, - {"GET", "/progs/image_package5.go"}, - {"GET", "/progs/image_package5.out"}, - {"GET", "/progs/image_package6.go"}, - {"GET", "/progs/image_package6.out"}, - {"GET", "/progs/interface.go"}, - {"GET", "/progs/interface2.go"}, - {"GET", "/progs/interface2.out"}, - {"GET", "/progs/json1.go"}, - {"GET", "/progs/json2.go"}, - {"GET", "/progs/json2.out"}, - {"GET", "/progs/json3.go"}, - {"GET", "/progs/json4.go"}, - {"GET", "/progs/json5.go"}, - {"GET", "/progs/run"}, - {"GET", "/progs/slices.go"}, - {"GET", "/progs/timeout1.go"}, - {"GET", "/progs/timeout2.go"}, - {"GET", "/progs/update.bash"}, -} - -var ( - staticHttpServeMux http.Handler - - staticAce http.Handler - staticBear http.Handler - staticBeego http.Handler - staticBone http.Handler - staticDenco http.Handler - staticEcho http.Handler - staticGin http.Handler - staticGocraftWeb http.Handler - staticGoji http.Handler - staticGoJsonRest http.Handler - staticGoRestful http.Handler - staticGorillaMux http.Handler - staticHttpRouter http.Handler - staticHttpTreeMux http.Handler - staticKocha http.Handler - staticMacaron http.Handler - staticMartini http.Handler - staticPat http.Handler - staticPossum http.Handler - staticR2router http.Handler - staticRevel http.Handler - staticRivet http.Handler - staticTango http.Handler - staticTigerTonic http.Handler - staticTraffic http.Handler - staticVulcan http.Handler - // staticZeus http.Handler -) - -func init() { - println("#Static Routes:", len(staticRoutes)) - - calcMem("HttpServeMux", func() { - serveMux := http.NewServeMux() - for _, route := range staticRoutes { - serveMux.HandleFunc(route.path, httpHandlerFunc) - } - staticHttpServeMux = serveMux - }) - - calcMem("Ace", func() { - staticAce = loadAce(staticRoutes) - }) - calcMem("Bear", func() { - staticBear = loadBear(staticRoutes) - }) - calcMem("Beego", func() { - staticBeego = loadBeego(staticRoutes) - }) - calcMem("Bone", func() { - staticBone = loadBone(staticRoutes) - }) - calcMem("Denco", func() { - staticDenco = loadDenco(staticRoutes) - }) - calcMem("Echo", func() { - staticEcho = loadEcho(staticRoutes) - }) - calcMem("Gin", func() { - staticGin = loadGin(staticRoutes) - }) - calcMem("GocraftWeb", func() { - staticGocraftWeb = loadGocraftWeb(staticRoutes) - }) - calcMem("Goji", func() { - staticGoji = loadGoji(staticRoutes) - }) - calcMem("GoJsonRest", func() { - staticGoJsonRest = loadGoJsonRest(staticRoutes) - }) - calcMem("GoRestful", func() { - staticGoRestful = loadGoRestful(staticRoutes) - }) - calcMem("GorillaMux", func() { - staticGorillaMux = loadGorillaMux(staticRoutes) - }) - calcMem("HttpRouter", func() { - staticHttpRouter = loadHttpRouter(staticRoutes) - }) - calcMem("HttpTreeMux", func() { - staticHttpTreeMux = loadHttpTreeMux(staticRoutes) - }) - calcMem("Kocha", func() { - staticKocha = loadKocha(staticRoutes) - }) - calcMem("Macaron", func() { - staticMacaron = loadMacaron(staticRoutes) - }) - calcMem("Martini", func() { - staticMartini = loadMartini(staticRoutes) - }) - calcMem("Pat", func() { - staticPat = loadPat(staticRoutes) - }) - calcMem("Possum", func() { - staticPossum = loadPossum(staticRoutes) - }) - calcMem("R2router", func() { - staticR2router = loadR2router(staticRoutes) - }) - calcMem("Revel", func() { - staticRevel = loadRevel(staticRoutes) - }) - calcMem("Rivet", func() { - staticRivet = loadRivet(staticRoutes) - }) - calcMem("Tango", func() { - staticTango = loadTango(staticRoutes) - }) - calcMem("TigerTonic", func() { - staticTigerTonic = loadTigerTonic(staticRoutes) - }) - calcMem("Traffic", func() { - staticTraffic = loadTraffic(staticRoutes) - }) - calcMem("Vulcan", func() { - staticVulcan = loadVulcan(staticRoutes) - }) - // calcMem("Zeus", func() { - // staticZeus = loadZeus(staticRoutes) - // }) - - println() -} - -// All routes - -func BenchmarkAce_StaticAll(b *testing.B) { - benchRoutes(b, staticAce, staticRoutes) -} -func BenchmarkHttpServeMux_StaticAll(b *testing.B) { - benchRoutes(b, staticHttpServeMux, staticRoutes) -} -func BenchmarkBeego_StaticAll(b *testing.B) { - benchRoutes(b, staticBeego, staticRoutes) -} -func BenchmarkBear_StaticAll(b *testing.B) { - benchRoutes(b, staticBear, staticRoutes) -} -func BenchmarkBone_StaticAll(b *testing.B) { - benchRoutes(b, staticBone, staticRoutes) -} -func BenchmarkDenco_StaticAll(b *testing.B) { - benchRoutes(b, staticDenco, staticRoutes) -} -func BenchmarkEcho_StaticAll(b *testing.B) { - benchRoutes(b, staticEcho, staticRoutes) -} -func BenchmarkGin_StaticAll(b *testing.B) { - benchRoutes(b, staticGin, staticRoutes) -} -func BenchmarkGocraftWeb_StaticAll(b *testing.B) { - benchRoutes(b, staticGocraftWeb, staticRoutes) -} -func BenchmarkGoji_StaticAll(b *testing.B) { - benchRoutes(b, staticGoji, staticRoutes) -} -func BenchmarkGoJsonRest_StaticAll(b *testing.B) { - benchRoutes(b, staticGoJsonRest, staticRoutes) -} -func BenchmarkGoRestful_StaticAll(b *testing.B) { - benchRoutes(b, staticGoRestful, staticRoutes) -} -func BenchmarkGorillaMux_StaticAll(b *testing.B) { - benchRoutes(b, staticGorillaMux, staticRoutes) -} -func BenchmarkHttpRouter_StaticAll(b *testing.B) { - benchRoutes(b, staticHttpRouter, staticRoutes) -} -func BenchmarkHttpTreeMux_StaticAll(b *testing.B) { - benchRoutes(b, staticHttpRouter, staticRoutes) -} -func BenchmarkKocha_StaticAll(b *testing.B) { - benchRoutes(b, staticKocha, staticRoutes) -} -func BenchmarkMacaron_StaticAll(b *testing.B) { - benchRoutes(b, staticMacaron, staticRoutes) -} -func BenchmarkMartini_StaticAll(b *testing.B) { - benchRoutes(b, staticMartini, staticRoutes) -} -func BenchmarkPat_StaticAll(b *testing.B) { - benchRoutes(b, staticPat, staticRoutes) -} -func BenchmarkPossum_StaticAll(b *testing.B) { - benchRoutes(b, staticPossum, staticRoutes) -} -func BenchmarkR2router_StaticAll(b *testing.B) { - benchRoutes(b, staticR2router, staticRoutes) -} -func BenchmarkRevel_StaticAll(b *testing.B) { - benchRoutes(b, staticRevel, staticRoutes) -} -func BenchmarkRivet_StaticAll(b *testing.B) { - benchRoutes(b, staticRivet, staticRoutes) -} -func BenchmarkTango_StaticAll(b *testing.B) { - benchRoutes(b, staticTango, staticRoutes) -} -func BenchmarkTigerTonic_StaticAll(b *testing.B) { - benchRoutes(b, staticTigerTonic, staticRoutes) -} -func BenchmarkTraffic_StaticAll(b *testing.B) { - benchRoutes(b, staticTraffic, staticRoutes) -} -func BenchmarkVulcan_StaticAll(b *testing.B) { - benchRoutes(b, staticVulcan, staticRoutes) -} - -// func BenchmarkZeus_StaticAll(b *testing.B) { -// benchRoutes(b, staticZeus, staticRoutes) -// } diff --git a/suite/github.go b/suite/github.go new file mode 100644 index 00000000..a8b26dee --- /dev/null +++ b/suite/github.go @@ -0,0 +1,309 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package suite + +import "github.com/julienschmidt/go-http-routing-benchmark/driver" + +func init() { + gh1 := driver.NewBenchmark( + driver.Parameterized, + "GitHubStatic", + "Request one static GitHub endpoint with two segments", + ) + gh1.AddRoutes(githubRoutes) + gh1.AddTest(TestResponseOkWithoutOutput) + gh1.AddRequest("GET", "/user/repos") + + gh2 := driver.NewBenchmark( + driver.Parameterized, + "GitHub2Params", + "Request one parameterized GitHub endpoint with four segments, two of which are parameters", + ) + gh2.AddRoutes(githubRoutes) + gh2.AddTest(TestResponseOkWithoutOutput) + gh2.AddRequest("GET", "/repos/julienschmidt/httprouter/stargazers") + + gh3 := driver.NewBenchmark( + driver.Parameterized, + "GitHubNotFound", + "Request one unavailable GitHub endpoint", + ) + gh3.AddRoutes(githubRoutes) + gh3.AddTest(TestResponseNotFound) + gh3.AddRequest("GET", "/notfound/this-path-is-unavailable") // Without trailing slash! + + gh4 := driver.NewBenchmark( + driver.Parameterized, + "GitHubAll", + "Request all GitHub endpoints", + ) + gh4.AddRoutes(githubRoutes) + gh4.AddRequests(githubRoutes) + gh4.AddTest(TestResponseOkWithoutOutput) +} + +// http://developer.github.com/v3/ +var githubRoutes = driver.Fixtures{ + // OAuth Authorizations + {"GET", "/authorizations"}, + {"GET", "/authorizations/:id"}, + {"POST", "/authorizations"}, + //{"PUT", "/authorizations/clients/:client_id"}, + //{"PATCH", "/authorizations/:id"}, + {"DELETE", "/authorizations/:id"}, + {"GET", "/applications/:client_id/tokens/:access_token"}, + {"DELETE", "/applications/:client_id/tokens"}, + {"DELETE", "/applications/:client_id/tokens/:access_token"}, + + // Activity + {"GET", "/events"}, + {"GET", "/repos/:owner/:repo/events"}, + {"GET", "/networks/:owner/:repo/events"}, + {"GET", "/orgs/:org/events"}, + {"GET", "/users/:user/received_events"}, + {"GET", "/users/:user/received_events/public"}, + {"GET", "/users/:user/events"}, + {"GET", "/users/:user/events/public"}, + {"GET", "/users/:user/events/orgs/:org"}, + {"GET", "/feeds"}, + {"GET", "/notifications"}, + {"GET", "/repos/:owner/:repo/notifications"}, + {"PUT", "/notifications"}, + {"PUT", "/repos/:owner/:repo/notifications"}, + {"GET", "/notifications/threads/:id"}, + //{"PATCH", "/notifications/threads/:id"}, + {"GET", "/notifications/threads/:id/subscription"}, + {"PUT", "/notifications/threads/:id/subscription"}, + {"DELETE", "/notifications/threads/:id/subscription"}, + {"GET", "/repos/:owner/:repo/stargazers"}, + {"GET", "/users/:user/starred"}, + {"GET", "/user/starred"}, + {"GET", "/user/starred/:owner/:repo"}, + {"PUT", "/user/starred/:owner/:repo"}, + {"DELETE", "/user/starred/:owner/:repo"}, + {"GET", "/repos/:owner/:repo/subscribers"}, + {"GET", "/users/:user/subscriptions"}, + {"GET", "/user/subscriptions"}, + {"GET", "/repos/:owner/:repo/subscription"}, + {"PUT", "/repos/:owner/:repo/subscription"}, + {"DELETE", "/repos/:owner/:repo/subscription"}, + {"GET", "/user/subscriptions/:owner/:repo"}, + {"PUT", "/user/subscriptions/:owner/:repo"}, + {"DELETE", "/user/subscriptions/:owner/:repo"}, + + // Gists + {"GET", "/users/:user/gists"}, + {"GET", "/gists"}, + //{"GET", "/gists/public"}, + //{"GET", "/gists/starred"}, + {"GET", "/gists/:id"}, + {"POST", "/gists"}, + //{"PATCH", "/gists/:id"}, + {"PUT", "/gists/:id/star"}, + {"DELETE", "/gists/:id/star"}, + {"GET", "/gists/:id/star"}, + {"POST", "/gists/:id/forks"}, + {"DELETE", "/gists/:id"}, + + // Git Data + {"GET", "/repos/:owner/:repo/git/blobs/:sha"}, + {"POST", "/repos/:owner/:repo/git/blobs"}, + {"GET", "/repos/:owner/:repo/git/commits/:sha"}, + {"POST", "/repos/:owner/:repo/git/commits"}, + //{"GET", "/repos/:owner/:repo/git/refs/*ref"}, + {"GET", "/repos/:owner/:repo/git/refs"}, + {"POST", "/repos/:owner/:repo/git/refs"}, + //{"PATCH", "/repos/:owner/:repo/git/refs/*ref"}, + //{"DELETE", "/repos/:owner/:repo/git/refs/*ref"}, + {"GET", "/repos/:owner/:repo/git/tags/:sha"}, + {"POST", "/repos/:owner/:repo/git/tags"}, + {"GET", "/repos/:owner/:repo/git/trees/:sha"}, + {"POST", "/repos/:owner/:repo/git/trees"}, + + // Issues + {"GET", "/issues"}, + {"GET", "/user/issues"}, + {"GET", "/orgs/:org/issues"}, + {"GET", "/repos/:owner/:repo/issues"}, + {"GET", "/repos/:owner/:repo/issues/:number"}, + {"POST", "/repos/:owner/:repo/issues"}, + //{"PATCH", "/repos/:owner/:repo/issues/:number"}, + {"GET", "/repos/:owner/:repo/assignees"}, + {"GET", "/repos/:owner/:repo/assignees/:assignee"}, + {"GET", "/repos/:owner/:repo/issues/:number/comments"}, + //{"GET", "/repos/:owner/:repo/issues/comments"}, + //{"GET", "/repos/:owner/:repo/issues/comments/:id"}, + {"POST", "/repos/:owner/:repo/issues/:number/comments"}, + //{"PATCH", "/repos/:owner/:repo/issues/comments/:id"}, + //{"DELETE", "/repos/:owner/:repo/issues/comments/:id"}, + {"GET", "/repos/:owner/:repo/issues/:number/events"}, + //{"GET", "/repos/:owner/:repo/issues/events"}, + //{"GET", "/repos/:owner/:repo/issues/events/:id"}, + {"GET", "/repos/:owner/:repo/labels"}, + {"GET", "/repos/:owner/:repo/labels/:name"}, + {"POST", "/repos/:owner/:repo/labels"}, + //{"PATCH", "/repos/:owner/:repo/labels/:name"}, + {"DELETE", "/repos/:owner/:repo/labels/:name"}, + {"GET", "/repos/:owner/:repo/issues/:number/labels"}, + {"POST", "/repos/:owner/:repo/issues/:number/labels"}, + {"DELETE", "/repos/:owner/:repo/issues/:number/labels/:name"}, + {"PUT", "/repos/:owner/:repo/issues/:number/labels"}, + {"DELETE", "/repos/:owner/:repo/issues/:number/labels"}, + {"GET", "/repos/:owner/:repo/milestones/:number/labels"}, + {"GET", "/repos/:owner/:repo/milestones"}, + {"GET", "/repos/:owner/:repo/milestones/:number"}, + {"POST", "/repos/:owner/:repo/milestones"}, + //{"PATCH", "/repos/:owner/:repo/milestones/:number"}, + {"DELETE", "/repos/:owner/:repo/milestones/:number"}, + + // Miscellaneous + {"GET", "/emojis"}, + {"GET", "/gitignore/templates"}, + {"GET", "/gitignore/templates/:name"}, + {"POST", "/markdown"}, + {"POST", "/markdown/raw"}, + {"GET", "/meta"}, + {"GET", "/rate_limit"}, + + // Organizations + {"GET", "/users/:user/orgs"}, + {"GET", "/user/orgs"}, + {"GET", "/orgs/:org"}, + //{"PATCH", "/orgs/:org"}, + {"GET", "/orgs/:org/members"}, + {"GET", "/orgs/:org/members/:user"}, + {"DELETE", "/orgs/:org/members/:user"}, + {"GET", "/orgs/:org/public_members"}, + {"GET", "/orgs/:org/public_members/:user"}, + {"PUT", "/orgs/:org/public_members/:user"}, + {"DELETE", "/orgs/:org/public_members/:user"}, + {"GET", "/orgs/:org/teams"}, + {"GET", "/teams/:id"}, + {"POST", "/orgs/:org/teams"}, + //{"PATCH", "/teams/:id"}, + {"DELETE", "/teams/:id"}, + {"GET", "/teams/:id/members"}, + {"GET", "/teams/:id/members/:user"}, + {"PUT", "/teams/:id/members/:user"}, + {"DELETE", "/teams/:id/members/:user"}, + {"GET", "/teams/:id/repos"}, + {"GET", "/teams/:id/repos/:owner/:repo"}, + {"PUT", "/teams/:id/repos/:owner/:repo"}, + {"DELETE", "/teams/:id/repos/:owner/:repo"}, + {"GET", "/user/teams"}, + + // Pull Requests + {"GET", "/repos/:owner/:repo/pulls"}, + {"GET", "/repos/:owner/:repo/pulls/:number"}, + {"POST", "/repos/:owner/:repo/pulls"}, + //{"PATCH", "/repos/:owner/:repo/pulls/:number"}, + {"GET", "/repos/:owner/:repo/pulls/:number/commits"}, + {"GET", "/repos/:owner/:repo/pulls/:number/files"}, + {"GET", "/repos/:owner/:repo/pulls/:number/merge"}, + {"PUT", "/repos/:owner/:repo/pulls/:number/merge"}, + {"GET", "/repos/:owner/:repo/pulls/:number/comments"}, + //{"GET", "/repos/:owner/:repo/pulls/comments"}, + //{"GET", "/repos/:owner/:repo/pulls/comments/:number"}, + {"PUT", "/repos/:owner/:repo/pulls/:number/comments"}, + //{"PATCH", "/repos/:owner/:repo/pulls/comments/:number"}, + //{"DELETE", "/repos/:owner/:repo/pulls/comments/:number"}, + + // Repositories + {"GET", "/user/repos"}, + {"GET", "/users/:user/repos"}, + {"GET", "/orgs/:org/repos"}, + {"GET", "/repositories"}, + {"POST", "/user/repos"}, + {"POST", "/orgs/:org/repos"}, + {"GET", "/repos/:owner/:repo"}, + //{"PATCH", "/repos/:owner/:repo"}, + {"GET", "/repos/:owner/:repo/contributors"}, + {"GET", "/repos/:owner/:repo/languages"}, + {"GET", "/repos/:owner/:repo/teams"}, + {"GET", "/repos/:owner/:repo/tags"}, + {"GET", "/repos/:owner/:repo/branches"}, + {"GET", "/repos/:owner/:repo/branches/:branch"}, + {"DELETE", "/repos/:owner/:repo"}, + {"GET", "/repos/:owner/:repo/collaborators"}, + {"GET", "/repos/:owner/:repo/collaborators/:user"}, + {"PUT", "/repos/:owner/:repo/collaborators/:user"}, + {"DELETE", "/repos/:owner/:repo/collaborators/:user"}, + {"GET", "/repos/:owner/:repo/comments"}, + {"GET", "/repos/:owner/:repo/commits/:sha/comments"}, + {"POST", "/repos/:owner/:repo/commits/:sha/comments"}, + {"GET", "/repos/:owner/:repo/comments/:id"}, + //{"PATCH", "/repos/:owner/:repo/comments/:id"}, + {"DELETE", "/repos/:owner/:repo/comments/:id"}, + {"GET", "/repos/:owner/:repo/commits"}, + {"GET", "/repos/:owner/:repo/commits/:sha"}, + {"GET", "/repos/:owner/:repo/readme"}, + //{"GET", "/repos/:owner/:repo/contents/*path"}, + //{"PUT", "/repos/:owner/:repo/contents/*path"}, + //{"DELETE", "/repos/:owner/:repo/contents/*path"}, + //{"GET", "/repos/:owner/:repo/:archive_format/:ref"}, + {"GET", "/repos/:owner/:repo/keys"}, + {"GET", "/repos/:owner/:repo/keys/:id"}, + {"POST", "/repos/:owner/:repo/keys"}, + //{"PATCH", "/repos/:owner/:repo/keys/:id"}, + {"DELETE", "/repos/:owner/:repo/keys/:id"}, + {"GET", "/repos/:owner/:repo/downloads"}, + {"GET", "/repos/:owner/:repo/downloads/:id"}, + {"DELETE", "/repos/:owner/:repo/downloads/:id"}, + {"GET", "/repos/:owner/:repo/forks"}, + {"POST", "/repos/:owner/:repo/forks"}, + {"GET", "/repos/:owner/:repo/hooks"}, + {"GET", "/repos/:owner/:repo/hooks/:id"}, + {"POST", "/repos/:owner/:repo/hooks"}, + //{"PATCH", "/repos/:owner/:repo/hooks/:id"}, + {"POST", "/repos/:owner/:repo/hooks/:id/tests"}, + {"DELETE", "/repos/:owner/:repo/hooks/:id"}, + {"POST", "/repos/:owner/:repo/merges"}, + {"GET", "/repos/:owner/:repo/releases"}, + {"GET", "/repos/:owner/:repo/releases/:id"}, + {"POST", "/repos/:owner/:repo/releases"}, + //{"PATCH", "/repos/:owner/:repo/releases/:id"}, + {"DELETE", "/repos/:owner/:repo/releases/:id"}, + {"GET", "/repos/:owner/:repo/releases/:id/assets"}, + {"GET", "/repos/:owner/:repo/stats/contributors"}, + {"GET", "/repos/:owner/:repo/stats/commit_activity"}, + {"GET", "/repos/:owner/:repo/stats/code_frequency"}, + {"GET", "/repos/:owner/:repo/stats/participation"}, + {"GET", "/repos/:owner/:repo/stats/punch_card"}, + {"GET", "/repos/:owner/:repo/statuses/:ref"}, + {"POST", "/repos/:owner/:repo/statuses/:ref"}, + + // Search + {"GET", "/search/repositories"}, + {"GET", "/search/code"}, + {"GET", "/search/issues"}, + {"GET", "/search/users"}, + {"GET", "/legacy/issues/search/:owner/:repository/:state/:keyword"}, + {"GET", "/legacy/repos/search/:keyword"}, + {"GET", "/legacy/user/search/:keyword"}, + {"GET", "/legacy/user/email/:email"}, + + // Users + {"GET", "/users/:user"}, + {"GET", "/user"}, + //{"PATCH", "/user"}, + {"GET", "/users"}, + {"GET", "/user/emails"}, + {"POST", "/user/emails"}, + {"DELETE", "/user/emails"}, + {"GET", "/users/:user/followers"}, + {"GET", "/user/followers"}, + {"GET", "/users/:user/following"}, + {"GET", "/user/following"}, + {"GET", "/user/following/:user"}, + {"GET", "/users/:user/following/:target_user"}, + {"PUT", "/user/following/:user"}, + {"DELETE", "/user/following/:user"}, + {"GET", "/users/:user/keys"}, + {"GET", "/user/keys"}, + {"GET", "/user/keys/:id"}, + {"POST", "/user/keys"}, + //{"PATCH", "/user/keys/:id"}, + {"DELETE", "/user/keys/:id"}, +} diff --git a/suite/googleplus.go b/suite/googleplus.go new file mode 100644 index 00000000..1aec2449 --- /dev/null +++ b/suite/googleplus.go @@ -0,0 +1,80 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package suite + +import "github.com/julienschmidt/go-http-routing-benchmark/driver" + +func init() { + gp1 := driver.NewBenchmark( + driver.Parameterized, + "GooglePlusStatic", + "Request one static Google+ endpoint with one segment", + ) + gp1.AddRoutes(googleplusRoutes) + gp1.AddTest(TestResponseOkWithoutOutput) + gp1.AddRequest("GET", "/people") + + gp2 := driver.NewBenchmark( + driver.Parameterized, + "GooglePlusParam", + "Request one parameterized Google+ endpoint with two segments, one of which is a parameter", + ) + gp2.AddRoutes(googleplusRoutes) + gp2.AddTest(TestResponseOkWithoutOutput) + gp2.AddRequest("GET", "/people/118051310819094153327") + + gp3 := driver.NewBenchmark( + driver.Parameterized, + "GooglePlus2Params", + "Request one parameterized Google+ endpoint with four segments, two of which are parameters", + ) + gp3.AddRoutes(googleplusRoutes) + gp3.AddTest(TestResponseOkWithoutOutput) + gp3.AddRequest("GET", "/people/118051310819094153327/activities/123456789") + + gp4 := driver.NewBenchmark( + driver.Parameterized, + "GooglePlusNotFound", + "Request one unavailable Google+ endpoint", + ) + gp4.AddRoutes(googleplusRoutes) + gp4.AddTest(TestResponseNotFound) + gp4.AddRequest("GET", "/notfound/this-path-is-unavailable") // Without trailing slash! + + gp5 := driver.NewBenchmark( + driver.Parameterized, + "GooglePlusAll", + "Request all Google+ endpoints", + ) + gp5.AddRoutes(googleplusRoutes) + gp5.AddRequests(googleplusRoutes) + gp5.AddTest(TestResponseOkWithoutOutput) +} + +// Google+ +// https://developers.google.com/+/api/latest/ +// (in reality this is just a subset of a much larger API) +var googleplusRoutes = driver.Fixtures{ + // People + {"GET", "/people/:userId"}, + {"GET", "/people"}, + {"GET", "/activities/:activityId/people/:collection"}, + {"GET", "/people/:userId/people/:collection"}, + {"GET", "/people/:userId/openIdConnect"}, + + // Activities + {"GET", "/people/:userId/activities/:collection"}, + {"GET", "/activities/:activityId"}, + {"GET", "/activities"}, + + // Comments + {"GET", "/activities/:activityId/comments"}, + {"GET", "/comments/:commentId"}, + + // Moments + {"POST", "/people/:userId/moments/:collection"}, + {"GET", "/people/:userId/moments/:collection"}, + {"DELETE", "/moments/:id"}, +} diff --git a/suite/params.go b/suite/params.go new file mode 100644 index 00000000..734b5673 --- /dev/null +++ b/suite/params.go @@ -0,0 +1,77 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package suite + +import "github.com/julienschmidt/go-http-routing-benchmark/driver" + +func init() { + p1 := driver.NewBenchmark( + driver.ParameterReadWrite, + "OneParam", + "Request one parameterized endpoint with two segments, one of which is a parameter", + ) + p1.AddRoute("GET", "/user/:name") + p1.AddRequest("GET", "/user/gordon") + p1.AddTest(TestResponseOkWithoutOutput) + p1.AddTest(TestParameterizedRoutesContainsNParams(1)) + + p2 := driver.NewBenchmark( + driver.ParameterReadWrite, + "FiveParams", + "Request one parameterized endpoint with five segments, all of which are parameters", + ) + p2.AddRoute("GET", "/:a/:b/:c/:d/:e") + p2.AddRequest("GET", "/test/test/test/test/test") + p2.AddTest(TestResponseOkWithoutOutput) + p2.AddTest(TestParameterizedRoutesContainsNParams(5)) + + p3 := driver.NewBenchmark( + driver.ParameterReadWrite, + "TwentyParams", + "Request one parameterized endpoint with twenty segments, all of which are parameters", + ) + p3.AddTest(TestResponseOkWithoutOutput) + p3.AddTest(TestParameterizedRoutesContainsNParams(20)) + p3.AddRequest("GET", "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t") + p3.AddRoute("GET", "/:a/:b/:c/:d/:e/:f/:g/:h/:i/:j/:k/:l/:m/:n/:o/:p/:q/:r/:s/:t") +} + +func init() { + rwp1 := driver.NewBenchmark( + driver.ParameterReadWrite, + "ReadWriteOneParam", + "Request one parameterized endpoint with two segments, one of which is a "+ + "parameter and respond with the value of the last parameter", + ) + rwp1.AddTest(TestParameterReadWriteName) + rwp1.AddTest(TestResponseOkParameterReadWrite) + rwp1.AddTest(TestParameterizedRoutesContainsNParams(1)) + rwp1.AddRoute("GET", "/user/:"+driver.ParamNameReadWrite) + rwp1.AddRequest("GET", "/user/"+driver.ParamNameReadWrite) + + rwp2 := driver.NewBenchmark( + driver.ParameterReadWrite, + "ReadWriteFiveParams", + "Request one parameterized endpoint with five segments, all of which "+ + "are parameters and respond with the value of the last parameter", + ) + rwp2.AddTest(TestParameterReadWriteName) + rwp2.AddTest(TestResponseOkParameterReadWrite) + rwp2.AddTest(TestParameterizedRoutesContainsNParams(5)) + rwp2.AddRoute("GET", "/:a/:b/:c/:d/:"+driver.ParamNameReadWrite) + rwp2.AddRequest("GET", "/test/test/test/test/"+driver.ParamNameReadWrite) + + rwp3 := driver.NewBenchmark( + driver.ParameterReadWrite, + "ReadWriteTwentyParams", + "Request one parameterized endpoint with twenty segments, all of which "+ + "are parameters and respond with the value of the last parameter", + ) + rwp3.AddTest(TestParameterReadWriteName) + rwp3.AddTest(TestResponseOkParameterReadWrite) + rwp3.AddTest(TestParameterizedRoutesContainsNParams(20)) + rwp3.AddRequest("GET", "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/"+driver.ParamNameReadWrite) + rwp3.AddRoute("GET", "/:a/:b/:c/:d/:e/:f/:g/:h/:i/:j/:k/:l/:m/:n/:o/:p/:q/:r/:s/:"+driver.ParamNameReadWrite) +} diff --git a/suite/parsecom.go b/suite/parsecom.go new file mode 100644 index 00000000..e517e3a7 --- /dev/null +++ b/suite/parsecom.go @@ -0,0 +1,100 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package suite + +import "github.com/julienschmidt/go-http-routing-benchmark/driver" + +func init() { + pc1 := driver.NewBenchmark( + driver.Parameterized, + "ParseComStatic", + "Request one static parse.com endpoint with two segments", + ) + pc1.AddRoutes(parsecomRoutes) + pc1.AddTest(TestResponseOkWithoutOutput) + pc1.AddRequest("GET", "/1/users") + + pc2 := driver.NewBenchmark( + driver.Parameterized, + "ParseComParam", + "Request one parameterized parse.com endpoint with three segments, one of which is a parameter", + ) + pc2.AddRoutes(parsecomRoutes) + pc2.AddTest(TestResponseOkWithoutOutput) + pc2.AddRequest("GET", "/1/classes/go") + + pc3 := driver.NewBenchmark( + driver.Parameterized, + "ParseCom2Params", + "Request one parameterized parse.com endpoint with four segments, two of which are parameters", + ) + pc3.AddRoutes(parsecomRoutes) + pc3.AddTest(TestResponseOkWithoutOutput) + pc3.AddRequest("GET", "/1/classes/go/123456789") + + pc4 := driver.NewBenchmark( + driver.Parameterized, + "ParseComNotFound", + "Request one unavailable parse.com endpoint", + ) + pc4.AddRoutes(parsecomRoutes) + pc4.AddTest(TestResponseNotFound) + pc4.AddRequest("GET", "/notfound/this-path-is-unavailable") // Without trailing slash! + + pc5 := driver.NewBenchmark( + driver.Parameterized, + "ParseComAll", + "Request all parse.com endpoints", + ) + pc5.AddRoutes(parsecomRoutes) + pc5.AddRequests(parsecomRoutes) + pc5.AddTest(TestResponseOkWithoutOutput) +} + +// Parse +// https://parse.com/docs/rest#summary +var parsecomRoutes = driver.Fixtures{ + // Objects + {"POST", "/1/classes/:className"}, + {"GET", "/1/classes/:className/:objectId"}, + {"PUT", "/1/classes/:className/:objectId"}, + {"GET", "/1/classes/:className"}, + {"DELETE", "/1/classes/:className/:objectId"}, + + // Users + {"POST", "/1/users"}, + {"GET", "/1/login"}, + {"GET", "/1/users/:objectId"}, + {"PUT", "/1/users/:objectId"}, + {"GET", "/1/users"}, + {"DELETE", "/1/users/:objectId"}, + {"POST", "/1/requestPasswordReset"}, + + // Roles + {"POST", "/1/roles"}, + {"GET", "/1/roles/:objectId"}, + {"PUT", "/1/roles/:objectId"}, + {"GET", "/1/roles"}, + {"DELETE", "/1/roles/:objectId"}, + + // Files + {"POST", "/1/files/:fileName"}, + + // Analytics + {"POST", "/1/events/:eventName"}, + + // Push Notifications + {"POST", "/1/push"}, + + // Installations + {"POST", "/1/installations"}, + {"GET", "/1/installations/:objectId"}, + {"PUT", "/1/installations/:objectId"}, + {"GET", "/1/installations"}, + {"DELETE", "/1/installations/:objectId"}, + + // Cloud Functions + {"POST", "/1/functions"}, +} diff --git a/suite/static.go b/suite/static.go new file mode 100644 index 00000000..95be8d80 --- /dev/null +++ b/suite/static.go @@ -0,0 +1,192 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package suite + +import "github.com/julienschmidt/go-http-routing-benchmark/driver" + +func init() { + s1 := driver.NewBenchmark( + driver.Static, + "StaticNotFound", + "Request one unavailable static endpoint", + ) + s1.AddRoutes(staticRoutes) + s1.AddTest(TestResponseNotFound) + s1.AddTest(TestStaticRoutesAreStatic) + s1.AddRequest("GET", "/notfound/this-path-is-unavailable") // Without trailing slash! + + s2 := driver.NewBenchmark( + driver.Static, + "StaticAll", + "Request all static endpoints", + ) + s2.AddRoutes(staticRoutes) + s2.AddRequests(staticRoutes) + s2.AddTest(TestStaticRoutesAreStatic) + s2.AddTest(TestResponseOkWithoutOutput) +} + +var staticRoutes = driver.Fixtures{ + // Cannot register root path handler because of the way http.ServeMux + // handles unknown paths (fallback to last known directory). + // {"GET", "/"}, + + {"GET", "/cmd.html"}, + {"GET", "/code.html"}, + {"GET", "/contrib.html"}, + {"GET", "/contribute.html"}, + {"GET", "/debugging_with_gdb.html"}, + {"GET", "/docs.html"}, + {"GET", "/effective_go.html"}, + {"GET", "/files.log"}, + {"GET", "/gccgo_contribute.html"}, + {"GET", "/gccgo_install.html"}, + {"GET", "/go-logo-black.png"}, + {"GET", "/go-logo-blue.png"}, + {"GET", "/go-logo-white.png"}, + {"GET", "/go1.1.html"}, + {"GET", "/go1.2.html"}, + {"GET", "/go1.html"}, + {"GET", "/go1compat.html"}, + {"GET", "/go_faq.html"}, + {"GET", "/go_mem.html"}, + {"GET", "/go_spec.html"}, + {"GET", "/help.html"}, + {"GET", "/ie.css"}, + {"GET", "/install-source.html"}, + {"GET", "/install.html"}, + {"GET", "/logo-153x55.png"}, + {"GET", "/Makefile"}, + {"GET", "/root.html"}, + {"GET", "/share.png"}, + {"GET", "/sieve.gif"}, + {"GET", "/tos.html"}, + {"GET", "/articles/"}, + {"GET", "/articles/go_command.html"}, + {"GET", "/articles/index.html"}, + {"GET", "/articles/wiki/"}, + {"GET", "/articles/wiki/edit.html"}, + {"GET", "/articles/wiki/final-noclosure.go"}, + {"GET", "/articles/wiki/final-noerror.go"}, + {"GET", "/articles/wiki/final-parsetemplate.go"}, + {"GET", "/articles/wiki/final-template.go"}, + {"GET", "/articles/wiki/final.go"}, + {"GET", "/articles/wiki/get.go"}, + {"GET", "/articles/wiki/http-sample.go"}, + {"GET", "/articles/wiki/index.html"}, + {"GET", "/articles/wiki/Makefile"}, + {"GET", "/articles/wiki/notemplate.go"}, + {"GET", "/articles/wiki/part1-noerror.go"}, + {"GET", "/articles/wiki/part1.go"}, + {"GET", "/articles/wiki/part2.go"}, + {"GET", "/articles/wiki/part3-errorhandling.go"}, + {"GET", "/articles/wiki/part3.go"}, + {"GET", "/articles/wiki/test.bash"}, + {"GET", "/articles/wiki/test_edit.good"}, + {"GET", "/articles/wiki/test_Test.txt.good"}, + {"GET", "/articles/wiki/test_view.good"}, + {"GET", "/articles/wiki/view.html"}, + {"GET", "/codewalk/"}, + {"GET", "/codewalk/codewalk.css"}, + {"GET", "/codewalk/codewalk.js"}, + {"GET", "/codewalk/codewalk.xml"}, + {"GET", "/codewalk/functions.xml"}, + {"GET", "/codewalk/markov.go"}, + {"GET", "/codewalk/markov.xml"}, + {"GET", "/codewalk/pig.go"}, + {"GET", "/codewalk/popout.png"}, + {"GET", "/codewalk/run"}, + {"GET", "/codewalk/sharemem.xml"}, + {"GET", "/codewalk/urlpoll.go"}, + {"GET", "/devel/"}, + {"GET", "/devel/release.html"}, + {"GET", "/devel/weekly.html"}, + {"GET", "/gopher/"}, + {"GET", "/gopher/appenginegopher.jpg"}, + {"GET", "/gopher/appenginegophercolor.jpg"}, + {"GET", "/gopher/appenginelogo.gif"}, + {"GET", "/gopher/bumper.png"}, + {"GET", "/gopher/bumper192x108.png"}, + {"GET", "/gopher/bumper320x180.png"}, + {"GET", "/gopher/bumper480x270.png"}, + {"GET", "/gopher/bumper640x360.png"}, + {"GET", "/gopher/doc.png"}, + {"GET", "/gopher/frontpage.png"}, + {"GET", "/gopher/gopherbw.png"}, + {"GET", "/gopher/gophercolor.png"}, + {"GET", "/gopher/gophercolor16x16.png"}, + {"GET", "/gopher/help.png"}, + {"GET", "/gopher/pkg.png"}, + {"GET", "/gopher/project.png"}, + {"GET", "/gopher/ref.png"}, + {"GET", "/gopher/run.png"}, + {"GET", "/gopher/talks.png"}, + {"GET", "/gopher/pencil/"}, + {"GET", "/gopher/pencil/gopherhat.jpg"}, + {"GET", "/gopher/pencil/gopherhelmet.jpg"}, + {"GET", "/gopher/pencil/gophermega.jpg"}, + {"GET", "/gopher/pencil/gopherrunning.jpg"}, + {"GET", "/gopher/pencil/gopherswim.jpg"}, + {"GET", "/gopher/pencil/gopherswrench.jpg"}, + {"GET", "/play/"}, + {"GET", "/play/fib.go"}, + {"GET", "/play/hello.go"}, + {"GET", "/play/life.go"}, + {"GET", "/play/peano.go"}, + {"GET", "/play/pi.go"}, + {"GET", "/play/sieve.go"}, + {"GET", "/play/solitaire.go"}, + {"GET", "/play/tree.go"}, + {"GET", "/progs/"}, + {"GET", "/progs/cgo1.go"}, + {"GET", "/progs/cgo2.go"}, + {"GET", "/progs/cgo3.go"}, + {"GET", "/progs/cgo4.go"}, + {"GET", "/progs/defer.go"}, + {"GET", "/progs/defer.out"}, + {"GET", "/progs/defer2.go"}, + {"GET", "/progs/defer2.out"}, + {"GET", "/progs/eff_bytesize.go"}, + {"GET", "/progs/eff_bytesize.out"}, + {"GET", "/progs/eff_qr.go"}, + {"GET", "/progs/eff_sequence.go"}, + {"GET", "/progs/eff_sequence.out"}, + {"GET", "/progs/eff_unused1.go"}, + {"GET", "/progs/eff_unused2.go"}, + {"GET", "/progs/error.go"}, + {"GET", "/progs/error2.go"}, + {"GET", "/progs/error3.go"}, + {"GET", "/progs/error4.go"}, + {"GET", "/progs/go1.go"}, + {"GET", "/progs/gobs1.go"}, + {"GET", "/progs/gobs2.go"}, + {"GET", "/progs/image_draw.go"}, + {"GET", "/progs/image_package1.go"}, + {"GET", "/progs/image_package1.out"}, + {"GET", "/progs/image_package2.go"}, + {"GET", "/progs/image_package2.out"}, + {"GET", "/progs/image_package3.go"}, + {"GET", "/progs/image_package3.out"}, + {"GET", "/progs/image_package4.go"}, + {"GET", "/progs/image_package4.out"}, + {"GET", "/progs/image_package5.go"}, + {"GET", "/progs/image_package5.out"}, + {"GET", "/progs/image_package6.go"}, + {"GET", "/progs/image_package6.out"}, + {"GET", "/progs/interface.go"}, + {"GET", "/progs/interface2.go"}, + {"GET", "/progs/interface2.out"}, + {"GET", "/progs/json1.go"}, + {"GET", "/progs/json2.go"}, + {"GET", "/progs/json2.out"}, + {"GET", "/progs/json3.go"}, + {"GET", "/progs/json4.go"}, + {"GET", "/progs/json5.go"}, + {"GET", "/progs/run"}, + {"GET", "/progs/slices.go"}, + {"GET", "/progs/timeout1.go"}, + {"GET", "/progs/timeout2.go"}, + {"GET", "/progs/update.bash"}, +} diff --git a/suite/tests.go b/suite/tests.go new file mode 100644 index 00000000..83a7df98 --- /dev/null +++ b/suite/tests.go @@ -0,0 +1,102 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package suite + +import ( + "fmt" + "net/http" + "strings" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +// TestStaticRoutesAreStatic ensures that static routes contain no parameterized segment. +var TestStaticRoutesAreStatic = &driver.Test{ + Description: "Test that the read/write parameter exists", + Route: func(f *driver.Fixture) *driver.Assertion { + x := strings.Count(f.Path, "/:") + if x > 0 { + return &driver.Assertion{ + Error: "Static routes must not contain parameters: " + f.Path, + } + } + + return nil + }, +} + +// TestParameterizedRoutesContainsNParams ensures that parameterized routes +// contain n parameterized segments. +func TestParameterizedRoutesContainsNParams(n int) *driver.Test { + return &driver.Test{ + Description: "Test that the read/write parameter exists", + Route: func(f *driver.Fixture) *driver.Assertion { + x := strings.Count(f.Path, "/:") + if x != n { + return &driver.Assertion{ + Error: fmt.Sprintf("Parameterized route must contain %d parameter(s), has %d", n, x), + } + } + + return nil + }, + } +} + +// TestParameterReadWriteName tests that the route contains the parameter +// name used to benchmark ParameterReadWrite. +var TestParameterReadWriteName = &driver.Test{ + Description: "Test that the read/write parameter exists", + Route: func(f *driver.Fixture) *driver.Assertion { + x := strings.Count(f.Path, "/:"+driver.ParamNameReadWrite) + if x == 0 { + return &driver.Assertion{ + Error: "The route contains no parameter named " + driver.ParamNameReadWrite, + } + } else if x > 1 { + return &driver.Assertion{ + Error: "The route contains too many parameters named " + driver.ParamNameReadWrite, + } + } + + return nil + }, +} + +// TestResponseOkParameterReadWrite is a test case that tests that the response status +// code is 200 and the response body is equal to the value of ParameterReadWrite name. +var TestResponseOkParameterReadWrite = &driver.Test{ + Description: "Test that the response status is 200 ok without output written", + Request: func(r *http.Request, w *driver.Response) *driver.Assertion { + return &driver.Assertion{ + Expect: fmt.Sprintf("Status code: 200, Output: \"%s\"", driver.ParamNameReadWrite), + Actual: fmt.Sprintf("Status code: %d, Output: \"%s\"", w.Status(), string(w.Output())), + } + }, +} + +// TestResponseNotFound is a test case that tests that the response status +// code is 404 with or without output. +var TestResponseNotFound = &driver.Test{ + Description: "Test that the response status is 404 not found", + Request: func(r *http.Request, w *driver.Response) *driver.Assertion { + return &driver.Assertion{ + Expect: "Status code: 404", + Actual: fmt.Sprintf("Status code: %d", w.Status()), + } + }, +} + +// TestResponseOkWithoutOutput is a test case that tests that the response status +// code is 0 and the response body is empty. +var TestResponseOkWithoutOutput = &driver.Test{ + Description: "Test that the response status is 200 without output written", + Request: func(r *http.Request, w *driver.Response) *driver.Assertion { + return &driver.Assertion{ + Expect: "Status code: 200, Output: \"\"", + Actual: fmt.Sprintf("Status code: %d, Output: \"%s\"", w.Status(), string(w.Output())), + } + }, +} From 2b2d6e6af5016aba9497f14ac29194d0ed063811 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 17:58:48 +0200 Subject: [PATCH 05/18] router: add ace --- router/ace.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 router/ace.go diff --git a/router/ace.go b/router/ace.go new file mode 100644 index 00000000..b9fb4014 --- /dev/null +++ b/router/ace.go @@ -0,0 +1,56 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !ace + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/plimble/ace" +) + +func aceHandler(c *ace.C) { + c.Writer.WriteHeader(http.StatusOK) +} + +func aceHandlerReadWrite(c *ace.C) { + io.WriteString(c.Writer, c.Param(driver.ParamNameReadWrite)) +} + +func aceFactory(t driver.Type) []ace.HandlerFunc { + switch t { + case driver.Static: + return []ace.HandlerFunc{aceHandler} + case driver.Parameterized: + return []ace.HandlerFunc{aceHandler} + case driver.ParameterReadWrite: + return []ace.HandlerFunc{aceHandlerReadWrite} + default: + panic("Unknown benchmark type passed") + } +} + +func aceRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := ace.New() + h := aceFactory(t) + + for _, r := range f { + m.Handle(r.Method, r.Path, h) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Ace", + Router: aceRouter, + Homepage: "http://github.com/plimble/ace", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From 4ccd04e3088b805943f38136ac5ff2f4bf28623d Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 17:59:09 +0200 Subject: [PATCH 06/18] router: add bear, beego and bone --- router/bear.go | 62 +++++++++++++++++++++++++++++++++++++++++ router/beego.go | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ router/bone.go | 69 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 router/bear.go create mode 100644 router/beego.go create mode 100644 router/bone.go diff --git a/router/bear.go b/router/bear.go new file mode 100644 index 00000000..896b3bc1 --- /dev/null +++ b/router/bear.go @@ -0,0 +1,62 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !bear + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/ursiform/bear" +) + +func bearHandler(w http.ResponseWriter, _ *http.Request, _ *bear.Context) { + w.WriteHeader(http.StatusOK) +} + +func bearHandlerReadWrite(w http.ResponseWriter, _ *http.Request, ctx *bear.Context) { + io.WriteString(w, ctx.Params[driver.ParamNameReadWrite]) +} + +func bearFactory(t driver.Type) func(http.ResponseWriter, *http.Request, *bear.Context) { + switch t { + case driver.Static: + return bearHandler + case driver.Parameterized: + return bearHandler + case driver.ParameterReadWrite: + return bearHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func bearRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := bear.New() + h := bearFactory(t) + + for _, r := range f { + switch r.Method { + case "GET", "POST", "PUT", "PATCH", "DELETE": + m.On(r.Method, r.Path, h) + default: + panic("Unknown HTTP method: " + r.Method) + } + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Bear", + Router: bearRouter, + Normalizer: driver.CurlyBracesNormalizer, + Homepage: "http://github.com/ursiform/bear", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/beego.go b/router/beego.go new file mode 100644 index 00000000..14068701 --- /dev/null +++ b/router/beego.go @@ -0,0 +1,74 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !beego + +package router + +import ( + "net/http" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/context" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +const beegoRWP = ":" + driver.ParamNameReadWrite + +func beegoHandler(ctx *context.Context) { + ctx.ResponseWriter.WriteHeader(http.StatusOK) +} + +func beegoHandlerReadWrite(ctx *context.Context) { + ctx.WriteString(ctx.Input.Param(beegoRWP)) +} + +func beegoFactory(t driver.Type) func(ctx *context.Context) { + switch t { + case driver.Static: + return beegoHandler + case driver.Parameterized: + return beegoHandler + case driver.ParameterReadWrite: + return beegoHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func beegoRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := beegoFactory(t) + m := beego.NewControllerRegister() + + for _, r := range f { + switch r.Method { + case "GET": + m.Get(r.Path, h) + case "POST": + m.Post(r.Path, h) + case "PUT": + m.Put(r.Path, h) + case "PATCH": + m.Patch(r.Path, h) + case "DELETE": + m.Delete(r.Path, h) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + return m +} + +func init() { + beego.RunMode = "prod" + beego.BeeLogger.Close() + + driver.RegisterPackage(&driver.Package{ + Name: "Beego", + Router: beegoRouter, + Homepage: "http://beego.me/", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/bone.go b/router/bone.go new file mode 100644 index 00000000..abed18f6 --- /dev/null +++ b/router/bone.go @@ -0,0 +1,69 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !bone + +package router + +import ( + "io" + "net/http" + + "github.com/go-zoo/bone" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +func boneHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func boneHandlerReadWrite(w http.ResponseWriter, req *http.Request) { + io.WriteString(w, bone.GetValue(req, driver.ParamNameReadWrite)) +} + +func boneFactory(t driver.Type) http.Handler { + switch t { + case driver.Static: + return http.HandlerFunc(boneHandler) + case driver.Parameterized: + return http.HandlerFunc(boneHandler) + case driver.ParameterReadWrite: + return http.HandlerFunc(boneHandlerReadWrite) + default: + panic("Unknown benchmark type passed") + } +} + +func boneRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := bone.New() + h := boneFactory(t) + + for _, r := range f { + switch r.Method { + case "GET": + m.Get(r.Path, h) + case "POST": + m.Post(r.Path, h) + case "PUT": + m.Put(r.Path, h) + case "PATCH": + m.Patch(r.Path, h) + case "DELETE": + m.Delete(r.Path, h) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Bone", + Router: boneRouter, + Homepage: "http://github.com/go-zoo/bone", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From 1a82fc7a53e35c5ae288d76304eacece1897c955 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 17:59:19 +0200 Subject: [PATCH 07/18] router: add denco --- router/denco.go | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 router/denco.go diff --git a/router/denco.go b/router/denco.go new file mode 100644 index 00000000..21a8f2d8 --- /dev/null +++ b/router/denco.go @@ -0,0 +1,65 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !denco + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/naoina/denco" +) + +func dencoHandler(w http.ResponseWriter, _ *http.Request, params denco.Params) { + w.WriteHeader(http.StatusOK) +} + +func dencoHandlerReadWrite(w http.ResponseWriter, req *http.Request, params denco.Params) { + io.WriteString(w, params.Get(driver.ParamNameReadWrite)) +} + +func dencoFactory(t driver.Type) func(http.ResponseWriter, *http.Request, denco.Params) { + switch t { + case driver.Static: + return dencoHandler + case driver.Parameterized: + return dencoHandler + case driver.ParameterReadWrite: + return dencoHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func dencoRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := denco.NewMux() + h := dencoFactory(t) + + handlers := make([]denco.Handler, 0, len(f)) + + for _, r := range f { + handler := m.Handler(r.Method, r.Path, h) + handlers = append(handlers, handler) + } + + handler, err := m.Build(handlers) + + if err != nil { + panic(err) + } + + return handler +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Denco", + Router: dencoRouter, + Homepage: "http://github.com/naoina/denco", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From ed5018268e1a3b342f6c0897c72655dc577b4c27 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 17:59:38 +0200 Subject: [PATCH 08/18] router: add echo --- router/echo.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 router/echo.go diff --git a/router/echo.go b/router/echo.go new file mode 100644 index 00000000..4a290004 --- /dev/null +++ b/router/echo.go @@ -0,0 +1,71 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !echo + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/labstack/echo" +) + +func echoHandler(c *echo.Context) error { + c.Response().WriteHeader(http.StatusOK) + return nil +} + +func echoHandlerReadWrite(c *echo.Context) error { + io.WriteString(c.Response(), c.Param(driver.ParamNameReadWrite)) + return nil +} + +func echoFactory(t driver.Type) func(*echo.Context) error { + switch t { + case driver.Static: + return echoHandler + case driver.Parameterized: + return echoHandler + case driver.ParameterReadWrite: + return echoHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func echoRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := echo.New() + h := echoFactory(t) + + for _, r := range f { + switch r.Method { + case "GET": + m.Get(r.Path, h) + case "POST": + m.Post(r.Path, h) + case "PUT": + m.Put(r.Path, h) + case "PATCH": + m.Patch(r.Path, h) + case "DELETE": + m.Delete(r.Path, h) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Echo", + Router: echoRouter, + Homepage: "http://github.com/labstack/echo", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From ddec05cfeb273430f1aa8b9a5d446df166e27d35 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:00:29 +0200 Subject: [PATCH 09/18] router: add gin, gocraftweb, goji, gojsonrest, go restful and gorilla mux --- router/gin.go | 58 +++++++++++++++++++++++++++++++++ router/gocraftweb.go | 71 +++++++++++++++++++++++++++++++++++++++++ router/goji.go | 69 ++++++++++++++++++++++++++++++++++++++++ router/gojsonrest.go | 67 +++++++++++++++++++++++++++++++++++++++ router/gorestful.go | 74 +++++++++++++++++++++++++++++++++++++++++++ router/gorilla_mux.go | 58 +++++++++++++++++++++++++++++++++ 6 files changed, 397 insertions(+) create mode 100644 router/gin.go create mode 100644 router/gocraftweb.go create mode 100644 router/goji.go create mode 100644 router/gojsonrest.go create mode 100644 router/gorestful.go create mode 100644 router/gorilla_mux.go diff --git a/router/gin.go b/router/gin.go new file mode 100644 index 00000000..bdc0bfbd --- /dev/null +++ b/router/gin.go @@ -0,0 +1,58 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !gin + +package router + +import ( + "io" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +func ginHandler(c *gin.Context) { + c.Writer.WriteHeader(http.StatusOK) +} + +func ginHandlerReadWrite(c *gin.Context) { + io.WriteString(c.Writer, c.Params.ByName(driver.ParamNameReadWrite)) +} + +func ginFactory(t driver.Type) func(*gin.Context) { + switch t { + case driver.Static: + return ginHandler + case driver.Parameterized: + return ginHandler + case driver.ParameterReadWrite: + return ginHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func ginRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := gin.New() + h := ginFactory(t) + + for _, r := range f { + m.Handle(r.Method, r.Path, h) + } + + return m +} + +func init() { + gin.SetMode(gin.ReleaseMode) + + driver.RegisterPackage(&driver.Package{ + Name: "Gin", + Router: ginRouter, + Homepage: "http://github.com/gin-gonic/gin", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/gocraftweb.go b/router/gocraftweb.go new file mode 100644 index 00000000..7da5f0de --- /dev/null +++ b/router/gocraftweb.go @@ -0,0 +1,71 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !gocraftweb + +package router + +import ( + "io" + "net/http" + + "github.com/gocraft/web" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +type gocraftWebContext struct{} + +func gocraftWebHandler(w web.ResponseWriter, _ *web.Request) { + w.WriteHeader(http.StatusOK) +} + +func gocraftWebHandlerReadWrite(w web.ResponseWriter, r *web.Request) { + io.WriteString(w, r.PathParams[driver.ParamNameReadWrite]) +} + +func gocraftWebFactory(t driver.Type) func(web.ResponseWriter, *web.Request) { + switch t { + case driver.Static: + return gocraftWebHandler + case driver.Parameterized: + return gocraftWebHandler + case driver.ParameterReadWrite: + return gocraftWebHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func gocraftWebRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := gocraftWebFactory(t) + m := web.New(gocraftWebContext{}) + + for _, r := range f { + switch r.Method { + case "GET": + m.Get(r.Path, h) + case "POST": + m.Post(r.Path, h) + case "PUT": + m.Put(r.Path, h) + case "PATCH": + m.Patch(r.Path, h) + case "DELETE": + m.Delete(r.Path, h) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "GoCraft Web", + Router: gocraftWebRouter, + Homepage: "http://github.com/gocraft/web", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/goji.go b/router/goji.go new file mode 100644 index 00000000..3efa7558 --- /dev/null +++ b/router/goji.go @@ -0,0 +1,69 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !goji + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/zenazn/goji/web" +) + +func gojiHandler(_ web.C, w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func gojiHandlerReadWrite(c web.C, w http.ResponseWriter, _ *http.Request) { + io.WriteString(w, c.URLParams[driver.ParamNameReadWrite]) +} + +func gojiFactory(t driver.Type) func(web.C, http.ResponseWriter, *http.Request) { + switch t { + case driver.Static: + return gojiHandler + case driver.Parameterized: + return gojiHandler + case driver.ParameterReadWrite: + return gojiHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func gojiRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := web.New() + h := gojiFactory(t) + + for _, r := range f { + switch r.Method { + case "GET": + m.Get(r.Path, h) + case "POST": + m.Post(r.Path, h) + case "PUT": + m.Put(r.Path, h) + case "PATCH": + m.Patch(r.Path, h) + case "DELETE": + m.Delete(r.Path, h) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Goji", + Router: gojiRouter, + Homepage: "http://github.com/zenazn/goji/web", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/gojsonrest.go b/router/gojsonrest.go new file mode 100644 index 00000000..18c1f674 --- /dev/null +++ b/router/gojsonrest.go @@ -0,0 +1,67 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !gojsonrest + +package router + +import ( + "io" + "log" + "net/http" + + "github.com/ant0ine/go-json-rest/rest" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +func goJsonRestHandler(w rest.ResponseWriter, _ *rest.Request) { + w.WriteHeader(http.StatusOK) +} + +func goJsonRestHandlerReadWrite(w rest.ResponseWriter, r *rest.Request) { + io.WriteString(w.(io.Writer), r.PathParam(driver.ParamNameReadWrite)) +} + +func goJsonRestFactory(t driver.Type) func(rest.ResponseWriter, *rest.Request) { + switch t { + case driver.Static: + return goJsonRestHandler + case driver.Parameterized: + return goJsonRestHandler + case driver.ParameterReadWrite: + return goJsonRestHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func goJsonRestRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := rest.NewApi() + h := goJsonRestFactory(t) + + restRoutes := make([]*rest.Route, 0, len(f)) + + for _, r := range f { + restRoutes = append(restRoutes, + &rest.Route{r.Method, r.Path, h}, + ) + } + + router, err := rest.MakeRouter(restRoutes...) + if err != nil { + log.Fatal(err) + } + + m.SetApp(router) + return m.MakeHandler() +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Go Json Rest", + Router: goJsonRestRouter, + Homepage: "http://github.com/ant0ine/go-json-rest/rest", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/gorestful.go b/router/gorestful.go new file mode 100644 index 00000000..f2ad5c5a --- /dev/null +++ b/router/gorestful.go @@ -0,0 +1,74 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !gorestful + +package router + +import ( + "io" + "net/http" + + "github.com/emicklei/go-restful" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +func goRestfulHandler(_ *restful.Request, w *restful.Response) { + // Cannot use w.WriteHeader for some reason + w.ResponseWriter.WriteHeader(http.StatusOK) +} + +func goRestfulHandlerReadWrite(r *restful.Request, w *restful.Response) { + io.WriteString(w, r.PathParameter(driver.ParamNameReadWrite)) +} + +func goRestfulFactory(t driver.Type) func(*restful.Request, *restful.Response) { + switch t { + case driver.Static: + return goRestfulHandler + case driver.Parameterized: + return goRestfulHandler + case driver.ParameterReadWrite: + return goRestfulHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func goRestfulRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := goRestfulFactory(t) + s := &restful.WebService{} + m := restful.NewContainer() + + for _, r := range f { + switch r.Method { + case "GET": + s.Route(s.GET(r.Path).To(h)) + case "POST": + s.Route(s.POST(r.Path).To(h)) + case "PUT": + s.Route(s.PUT(r.Path).To(h)) + case "PATCH": + s.Route(s.PATCH(r.Path).To(h)) + case "DELETE": + s.Route(s.DELETE(r.Path).To(h)) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + m.Add(s) + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Go Restful", + Router: goRestfulRouter, + Normalizer: driver.CurlyBracesNormalizer, + Homepage: "http://github.com/emicklei/go-restful", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/gorilla_mux.go b/router/gorilla_mux.go new file mode 100644 index 00000000..f9341a03 --- /dev/null +++ b/router/gorilla_mux.go @@ -0,0 +1,58 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !gorilla_mux + +package router + +import ( + "io" + "net/http" + + "github.com/gorilla/mux" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +func gorillaHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func gorillaHandlerReadWrite(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + io.WriteString(w, params[driver.ParamNameReadWrite]) +} + +func gorillaFactory(t driver.Type) func(http.ResponseWriter, *http.Request) { + switch t { + case driver.Static: + return gorillaHandler + case driver.Parameterized: + return gorillaHandler + case driver.ParameterReadWrite: + return gorillaHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func gorillaRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := mux.NewRouter() + h := gorillaFactory(t) + + for _, r := range f { + m.HandleFunc(r.Path, h).Methods(r.Method) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Gorilla Mux", + Router: gorillaRouter, + Normalizer: driver.CurlyBracesNormalizer, + Homepage: "http://github.com/gorilla/mux", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From 7f411172594b116189ac63049b0ca2b5d2a00199 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:01:34 +0200 Subject: [PATCH 10/18] router: add http.ServeMux, HttpRouter and HttpTreeMux --- router/http_servemux.go | 48 +++++++++++++++++++++++++++++++++++ router/httprouter.go | 56 +++++++++++++++++++++++++++++++++++++++++ router/httptreemux.go | 56 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 router/http_servemux.go create mode 100644 router/httprouter.go create mode 100644 router/httptreemux.go diff --git a/router/http_servemux.go b/router/http_servemux.go new file mode 100644 index 00000000..c44619b1 --- /dev/null +++ b/router/http_servemux.go @@ -0,0 +1,48 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !http_servemux + +package router + +import ( + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +type httpServeMuxHandler struct{} + +func (h *httpServeMuxHandler) ServeHTTP(r http.ResponseWriter, _ *http.Request) { + r.WriteHeader(http.StatusOK) +} + +func httpServeMuxFactory(t driver.Type) http.Handler { + switch t { + case driver.Static: + return &httpServeMuxHandler{} + default: + panic("Unknown benchmark type passed") + } +} + +func httpServeMuxRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := httpServeMuxFactory(t) + m := http.NewServeMux() + + for _, r := range f { + m.Handle(r.Path, h) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "http.ServeMux", + Router: httpServeMuxRouter, + Homepage: "http://golang.org/pkg/net/http/#ServeMux", + Supports: driver.Static, + }) +} diff --git a/router/httprouter.go b/router/httprouter.go new file mode 100644 index 00000000..05b18468 --- /dev/null +++ b/router/httprouter.go @@ -0,0 +1,56 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !httprouter + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/julienschmidt/httprouter" +) + +func httpRouterHandler(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { + w.WriteHeader(http.StatusOK) +} + +func httpRouterHandlerReadWrite(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + io.WriteString(w, p.ByName(driver.ParamNameReadWrite)) +} + +func httpRouterFactory(t driver.Type) func(http.ResponseWriter, *http.Request, httprouter.Params) { + switch t { + case driver.Static: + return httpRouterHandler + case driver.Parameterized: + return httpRouterHandler + case driver.ParameterReadWrite: + return httpRouterHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func httpRouterRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := httprouter.New() + h := httpRouterFactory(t) + + for _, r := range f { + m.Handle(r.Method, r.Path, h) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "HTTP Router", + Router: httpRouterRouter, + Homepage: "http://github.com/julienschmidt/httprouter", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/httptreemux.go b/router/httptreemux.go new file mode 100644 index 00000000..9197913d --- /dev/null +++ b/router/httptreemux.go @@ -0,0 +1,56 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !httptreemux + +package router + +import ( + "io" + "net/http" + + "github.com/dimfeld/httptreemux" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +func httpTreeMuxHandler(w http.ResponseWriter, _ *http.Request, _ map[string]string) { + w.WriteHeader(http.StatusOK) +} + +func httpTreeMuxHandlerReadWrite(w http.ResponseWriter, r *http.Request, p map[string]string) { + io.WriteString(w, p[driver.ParamNameReadWrite]) +} + +func httpTreeMuxFactory(t driver.Type) func(http.ResponseWriter, *http.Request, map[string]string) { + switch t { + case driver.Static: + return httpTreeMuxHandler + case driver.Parameterized: + return httpTreeMuxHandler + case driver.ParameterReadWrite: + return httpTreeMuxHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func httpTreeMuxRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := httptreemux.New() + h := httpTreeMuxFactory(t) + + for _, r := range f { + m.Handle(r.Method, r.Path, h) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "HTTP Tree Mux", + Router: httpTreeMuxRouter, + Homepage: "http://github.com/dimfeld/httptreemux", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From f1978f303c30485b474b277d6ac216fc14a0f408 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:01:51 +0200 Subject: [PATCH 11/18] router: add mocha --- router/kocha.go | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 router/kocha.go diff --git a/router/kocha.go b/router/kocha.go new file mode 100644 index 00000000..da3e0de6 --- /dev/null +++ b/router/kocha.go @@ -0,0 +1,177 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !kocha + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/naoina/kocha-urlrouter" + _ "github.com/naoina/kocha-urlrouter/doublearray" +) + +type kochaController interface { + http.Handler + Get(http.ResponseWriter, *http.Request) + Post(http.ResponseWriter, *http.Request) + Put(http.ResponseWriter, *http.Request) + Patch(http.ResponseWriter, *http.Request) + Delete(http.ResponseWriter, *http.Request) + RouterMap() map[string]urlrouter.URLRouter +} + +type kochaHandler struct { + routerMap map[string]urlrouter.URLRouter + params []urlrouter.Param +} + +func (h *kochaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + method, params := h.routerMap[r.Method].Lookup(r.URL.Path) + h.params = params + + if method == nil { + w.WriteHeader(http.StatusNotFound) + } else { + method.(http.HandlerFunc).ServeHTTP(w, r) + } +} + +func (h *kochaHandler) Get(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h *kochaHandler) Post(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h *kochaHandler) Put(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h *kochaHandler) Patch(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h *kochaHandler) Delete(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h *kochaHandler) RouterMap() map[string]urlrouter.URLRouter { + return h.routerMap +} + +type kochaHandlerReadWrite struct { + routerMap map[string]urlrouter.URLRouter + params []urlrouter.Param +} + +func (h *kochaHandlerReadWrite) ServeHTTP(w http.ResponseWriter, r *http.Request) { + method, params := h.routerMap[r.Method].Lookup(r.URL.Path) + h.params = params + + if method == nil { + w.WriteHeader(http.StatusNotFound) + } else { + method.(http.HandlerFunc).ServeHTTP(w, r) + } +} + +func (h *kochaHandlerReadWrite) Post(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h *kochaHandlerReadWrite) Put(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h *kochaHandlerReadWrite) Patch(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h *kochaHandlerReadWrite) Delete(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func (h *kochaHandlerReadWrite) RouterMap() map[string]urlrouter.URLRouter { + return h.routerMap +} + +func (h *kochaHandlerReadWrite) Get(w http.ResponseWriter, r *http.Request) { + var name string + for _, param := range h.params { + if param.Name == driver.ParamNameReadWrite { + name = param.Value + break + } + } + io.WriteString(w, name) +} + +func kochaFactory(t driver.Type) kochaController { + switch t { + case driver.Static, driver.Parameterized: + return &kochaHandler{routerMap: map[string]urlrouter.URLRouter{ + "GET": urlrouter.NewURLRouter("doublearray"), + "POST": urlrouter.NewURLRouter("doublearray"), + "PUT": urlrouter.NewURLRouter("doublearray"), + "PATCH": urlrouter.NewURLRouter("doublearray"), + "DELETE": urlrouter.NewURLRouter("doublearray"), + }} + case driver.ParameterReadWrite: + return &kochaHandlerReadWrite{routerMap: map[string]urlrouter.URLRouter{ + "GET": urlrouter.NewURLRouter("doublearray"), + "POST": urlrouter.NewURLRouter("doublearray"), + "PUT": urlrouter.NewURLRouter("doublearray"), + "PATCH": urlrouter.NewURLRouter("doublearray"), + "DELETE": urlrouter.NewURLRouter("doublearray"), + }} + default: + panic("Unknown benchmark type passed") + } +} + +func kochaRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := kochaFactory(t) + h := make(map[string][]urlrouter.Record) + + for _, r := range f { + var ch http.HandlerFunc + + switch r.Method { + case "GET": + ch = m.Get + case "POST": + ch = m.Post + case "PUT": + ch = m.Put + case "PATCH": + ch = m.Patch + case "DELETE": + ch = m.Delete + } + + h[r.Method] = append(h[r.Method], urlrouter.NewRecord(r.Path, ch)) + } + + for method, records := range h { + if err := m.RouterMap()[method].Build(records); err != nil { + panic(err) + } + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Kocha", + Router: kochaRouter, + Homepage: "http://github.com/naoina/kocha-urlrouter", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From 8f0eba73bde16d64ca3a8d394c6c46d5244140a8 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:02:08 +0200 Subject: [PATCH 12/18] router: add macaron and martini --- router/macaron.go | 55 ++++++++++++++++++++++++++++++++++++ router/martini.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 router/macaron.go create mode 100644 router/martini.go diff --git a/router/macaron.go b/router/macaron.go new file mode 100644 index 00000000..0ee53319 --- /dev/null +++ b/router/macaron.go @@ -0,0 +1,55 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !macaron + +package router + +import ( + "net/http" + + "github.com/Unknwon/macaron" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +func macaronHandler(c *macaron.Context) { + c.Resp.WriteHeader(http.StatusOK) +} + +func macaronHandlerReadWrite(c *macaron.Context) string { + return c.Params(driver.ParamNameReadWrite) +} + +func macaronFactory(t driver.Type) interface{} { + switch t { + case driver.Static: + return macaronHandler + case driver.Parameterized: + return macaronHandler + case driver.ParameterReadWrite: + return macaronHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func macaronRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := macaron.New() + h := macaronFactory(t) + + for _, r := range f { + m.Handle(r.Method, r.Path, []macaron.Handler{h}) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Macaron", + Router: macaronRouter, + Homepage: "http://github.com/Unknwon/macaron", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/martini.go b/router/martini.go new file mode 100644 index 00000000..700260f3 --- /dev/null +++ b/router/martini.go @@ -0,0 +1,71 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !martini + +package router + +import ( + "net/http" + + "github.com/go-martini/martini" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +func martiniHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func martiniHandlerReadWrite(p martini.Params) string { + return p[driver.ParamNameReadWrite] +} + +func martiniFactory(t driver.Type) interface{} { + switch t { + case driver.Static: + return martiniHandler + case driver.Parameterized: + return martiniHandler + case driver.ParameterReadWrite: + return martiniHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func martiniRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := martiniFactory(t) + m := martini.NewRouter() + + for _, r := range f { + switch r.Method { + case "GET": + m.Get(r.Path, h) + case "POST": + m.Post(r.Path, h) + case "PUT": + m.Put(r.Path, h) + case "PATCH": + m.Patch(r.Path, h) + case "DELETE": + m.Delete(r.Path, h) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + martini := martini.New() + martini.Action(m.Handle) + + return martini +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Martini", + Router: martiniRouter, + Homepage: "http://github.com/go-martini/martini", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From 39931e5b82f063c9b742f2b59e4221696ee61892 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:07:21 +0200 Subject: [PATCH 13/18] router: add pat and possum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Possum implementation was previously broken. Possum’s router.Simple is not sufficient for dynamic path segment routing. Further makes Possum’s current implementation of router.RegEx it impossible to benchmark ParameterReadWrite. ParameterReadWrite should be re-enabled once Possum implements named RegEx groups. --- router/pat.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ router/possum.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 router/pat.go create mode 100644 router/possum.go diff --git a/router/pat.go b/router/pat.go new file mode 100644 index 00000000..2d792fca --- /dev/null +++ b/router/pat.go @@ -0,0 +1,69 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !martini + +package router + +import ( + "io" + "net/http" + + "github.com/bmizerany/pat" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +const patRWP = ":" + driver.ParamNameReadWrite + +func patHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func patHandlerReadWrite(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, r.URL.Query().Get(patRWP)) +} + +func patFactory(t driver.Type) http.Handler { + switch t { + case driver.Static: + return http.HandlerFunc(patHandler) + case driver.Parameterized: + return http.HandlerFunc(patHandler) + case driver.ParameterReadWrite: + return http.HandlerFunc(patHandlerReadWrite) + default: + panic("Unknown benchmark type passed") + } +} + +func patRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := pat.New() + h := patFactory(t) + + for _, r := range f { + switch r.Method { + case "GET": + m.Get(r.Path, h) + case "POST": + m.Post(r.Path, h) + case "PUT": + m.Put(r.Path, h) + case "DELETE": + m.Del(r.Path, h) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Pat", + Router: patRouter, + Homepage: "http://github.com/bmizerany/pat", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/possum.go b/router/possum.go new file mode 100644 index 00000000..26a5c4fe --- /dev/null +++ b/router/possum.go @@ -0,0 +1,68 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !possum + +package router + +import ( + "io" + "net/http" + "strings" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/mikespook/possum" + "github.com/mikespook/possum/router" + "github.com/mikespook/possum/view" +) + +func possumHandler(c *possum.Context) error { + c.Response.WriteHeader(http.StatusOK) + return nil +} + +func possumHandlerReadWrite(c *possum.Context) error { + io.WriteString(c.Response, c.Request.URL.Query().Get(driver.ParamNameReadWrite)) + return nil +} + +func possumFactory(t driver.Type) func(*possum.Context) error { + switch t { + case driver.Static: + return possumHandler + case driver.Parameterized: + return possumHandler + case driver.ParameterReadWrite: + return possumHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func possumRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := possumFactory(t) + m := possum.NewServerMux() + + for _, r := range f { + var routable router.Router = router.Simple(r.Path) + + if strings.Contains(r.Path, "[^/]*)") { + routable = router.RegEx(r.Path) + } + + m.HandleFunc(routable, h, view.Simple("text/html", "utf-8")) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Possum", + Router: possumRouter, + Normalizer: driver.RegExAllNormalizer, + Homepage: "http://github.com/mikespook/possum", + Supports: driver.Static | driver.Parameterized, /* | driver.ParameterReadWrite */ + }) +} From 2e2a83271495b1bd86d196bfd14ae07a64fcbaa5 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:10:34 +0200 Subject: [PATCH 14/18] router: add R2Router, Revel and Rivet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revels implementation contains now more internals directly copied from the source code because without it the tests fail constantly with „nil pointer dereference“ errors. --- router/r2router.go | 56 ++++++++++++ router/revel.go | 216 +++++++++++++++++++++++++++++++++++++++++++++ router/rivet.go | 55 ++++++++++++ 3 files changed, 327 insertions(+) create mode 100644 router/r2router.go create mode 100644 router/revel.go create mode 100644 router/rivet.go diff --git a/router/r2router.go b/router/r2router.go new file mode 100644 index 00000000..fc06c510 --- /dev/null +++ b/router/r2router.go @@ -0,0 +1,56 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !r2router + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/vanng822/r2router" +) + +func r2RouterHandler(w http.ResponseWriter, _ *http.Request, _ r2router.Params) { + w.WriteHeader(http.StatusOK) +} + +func r2RouterHandlerReadWrite(w http.ResponseWriter, _ *http.Request, p r2router.Params) { + io.WriteString(w, p.Get(driver.ParamNameReadWrite)) +} + +func r2RouterFactory(t driver.Type) func(http.ResponseWriter, *http.Request, r2router.Params) { + switch t { + case driver.Static: + return r2RouterHandler + case driver.Parameterized: + return r2RouterHandler + case driver.ParameterReadWrite: + return r2RouterHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func r2RouterRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := r2RouterFactory(t) + m := r2router.NewRouter() + + for _, r := range f { + m.AddHandler(r.Method, r.Path, h) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "R2 Router", + Router: r2RouterRouter, + Homepage: "http://github.com/vanng822/r2router", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/revel.go b/router/revel.go new file mode 100644 index 00000000..7892f7bd --- /dev/null +++ b/router/revel.go @@ -0,0 +1,216 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !revel + +package router + +import ( + "fmt" + "io" + "net/http" + "path" + "path/filepath" + + "go/build" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/revel/revel" + "github.com/robfig/pathtree" +) + +// In the following code some Revel internals are modelled. +// The original revel code is copyrighted by Rob Figueiredo. +// See https://github.com/revel/revel/blob/master/LICENSE +type RevelController struct { + *revel.Controller + router *revel.Router +} + +func (rc *RevelController) Handle() revel.Result { + return revelResult{} +} + +func (rc *RevelController) HandleReadWrite() revel.Result { + return rc.RenderText(rc.Params.Get(driver.ParamNameReadWrite)) +} + +func (rc *RevelController) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // Dirty hacks, do NOT copy! + revel.MainRouter = rc.router + + upgrade := r.Header.Get("Upgrade") + if upgrade == "websocket" || upgrade == "Websocket" { + panic("Not implemented") + } + + var ( + req = revel.NewRequest(r) + resp = revel.NewResponse(w) + c = revel.NewController(req, resp) + ) + req.Websocket = nil + + revel.Filters[0](c, revel.Filters[1:]) + + if c.Result != nil { + c.Result.Apply(req, resp) + } else if c.Response.Status != 0 { + c.Response.Out.WriteHeader(c.Response.Status) + } else { + panic("Result is empty") + } + // Close the Writer if we can + if w, ok := resp.Out.(io.Closer); ok { + w.Close() + } +} + +type revelResult struct{} + +func (rr revelResult) Apply(req *revel.Request, resp *revel.Response) { + resp.Out.WriteHeader(http.StatusOK) +} + +func revelFactory(t driver.Type) string { + switch t { + case driver.Static: + return "RevelController.Handle" + case driver.Parameterized: + return "RevelController.Handle" + case driver.ParameterReadWrite: + return "RevelController.HandleReadWrite" + default: + panic("Unknown benchmark type passed") + } +} + +func revelRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := revelFactory(t) + m := revel.NewRouter("") + + rs := make([]*revel.Route, 0, len(f)) + for _, r := range f { + rs = append(rs, revel.NewRoute(r.Method, r.Path, h, "", "", 0)) + } + m.Routes = rs + + m.Tree = pathtree.New() + for _, r := range m.Routes { + err := m.Tree.Add(r.TreePath, r) + + // Allow GETs to respond to HEAD requests. + if err == nil && r.Method == "GET" { + err = m.Tree.Add("/HEAD"+r.Path, r) + } + + // Error adding a route to the pathtree. + if err != nil { + panic(err) + } + } + + rc := &RevelController{} + rc.router = m + + return rc +} + +// findSrcPaths uses the "go/build" package to find the source root for Revel +// and the app. +// +// Directly copied from revel/revel.go. +// The original revel code is copyrighted by Rob Figueiredo. +// See https://github.com/revel/revel/blob/master/LICENSE +func revelFindSrcPaths(importPath string) (revelSourcePath, appSourcePath string) { + var ( + gopaths = filepath.SplitList(build.Default.GOPATH) + goroot = build.Default.GOROOT + ) + + if len(gopaths) == 0 { + panic("GOPATH environment variable is not set. " + + "Please refer to http://golang.org/doc/code.html to configure your Go environment.") + } + + if revelContainsString(gopaths, goroot) { + panic(fmt.Sprintf("GOPATH (%s) must not include your GOROOT (%s). "+ + "Please refer to http://golang.org/doc/code.html to configure your Go environment.", + gopaths, goroot)) + } + + appPkg, err := build.Import(importPath, "", build.FindOnly) + if err != nil { + panic("Failed to import" + importPath + "with error:" + err.Error()) + } + + revelPkg, err := build.Import(revel.REVEL_IMPORT_PATH, "", build.FindOnly) + if err != nil { + panic("Failed to find Revel with error:" + err.Error()) + } + + return revelPkg.SrcRoot, appPkg.SrcRoot +} + +// Directly copied from revel/utils.go. +// The original revel code is copyrighted by Rob Figueiredo. +// See https://github.com/revel/revel/blob/master/LICENSE +func revelContainsString(list []string, target string) bool { + for _, el := range list { + if el == target { + return true + } + } + return false +} + +func revelInit() { + // Only use the Revel filters required for this benchmark + revel.Filters = []revel.Filter{ + revel.RouterFilter, + revel.ParamsFilter, + revel.ActionInvoker, + } + + revel.RegisterController( + (*RevelController)(nil), + []*revel.MethodType{ + &revel.MethodType{ + Name: "Handle", + }, + &revel.MethodType{ + Name: "HandleReadWrite", + }, + }, + ) + + // Load mime config from revel, otherwise revel panics (nil pointer dereference) + srcPath, _ := revelFindSrcPaths(revel.REVEL_IMPORT_PATH) + revel.ConfPaths = []string{path.Join( + srcPath, + filepath.FromSlash(revel.REVEL_IMPORT_PATH), + "conf"), + } + revel.LoadMimeConfig() + + // Must be set before instantiationg the TemplateLoader object to avoid panics. + revel.RevelPath = path.Join(srcPath, filepath.FromSlash(revel.REVEL_IMPORT_PATH)) + revel.TemplatePaths = []string{path.Join(revel.RevelPath, "templates")} + + // Otherwise revel panics (nil pointer dereference) in revel/results.go:47 + // ErrorResult.Apply: tmpl, err := MainTemplateLoader.Template(templatePath) + revel.MainTemplateLoader = revel.NewTemplateLoader(revel.TemplatePaths) + revel.MainTemplateLoader.Refresh() +} + +func init() { + revelInit() + + driver.RegisterPackage(&driver.Package{ + Name: "Revel", + Router: revelRouter, + Homepage: "http://github.com/revel/revel", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/rivet.go b/router/rivet.go new file mode 100644 index 00000000..088f9956 --- /dev/null +++ b/router/rivet.go @@ -0,0 +1,55 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !rivet + +package router + +import ( + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/typepress/rivet" +) + +func rivetHandler(c rivet.Context) { + c.Response().WriteHeader(http.StatusOK) +} + +func rivetHandlerReadWrite(c rivet.Context) { + c.WriteString(c.GetParams().Get(driver.ParamNameReadWrite)) +} + +func rivetFactory(t driver.Type) func(rivet.Context) { + switch t { + case driver.Static: + return rivetHandler + case driver.Parameterized: + return rivetHandler + case driver.ParameterReadWrite: + return rivetHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func rivetRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := rivetFactory(t) + m := rivet.NewRouter(nil) + + for _, r := range f { + m.Handle(r.Method, r.Path, h) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Rivet", + Router: rivetRouter, + Homepage: "http://github.com/typepress/rivet", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From 86360ac9c3ba06d753747fcfef8e9e74054e42d7 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:11:10 +0200 Subject: [PATCH 15/18] router: add Tango, TigerTonic and Traffic --- router/tango.go | 61 +++++++++++++++++++++++++++++++++++++ router/tigertonic.go | 59 ++++++++++++++++++++++++++++++++++++ router/traffic.go | 71 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 router/tango.go create mode 100644 router/tigertonic.go create mode 100644 router/traffic.go diff --git a/router/tango.go b/router/tango.go new file mode 100644 index 00000000..fbe64fe3 --- /dev/null +++ b/router/tango.go @@ -0,0 +1,61 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !tango + +package router + +import ( + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + llog "github.com/lunny/log" + "github.com/lunny/tango" +) + +const tangoRWP = ":" + driver.ParamNameReadWrite + +func tangoHandler(c *tango.Context) { + c.ResponseWriter.WriteHeader(http.StatusOK) +} + +func tangoHandlerReadWrite(c *tango.Context) { + c.Write([]byte(c.Params().Get(tangoRWP))) +} + +func tangoFactory(t driver.Type) func(*tango.Context) { + switch t { + case driver.Static: + return tangoHandler + case driver.Parameterized: + return tangoHandler + case driver.ParameterReadWrite: + return tangoHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func tangoRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := tangoFactory(t) + m := tango.NewWithLog(llog.Std) + + for _, r := range f { + m.Route(r.Method, r.Path, h) + } + + return m +} + +func init() { + llog.SetOutputLevel(llog.Lnone) + llog.SetOutput(&driver.ResponseStub{}) + + driver.RegisterPackage(&driver.Package{ + Name: "Tango", + Router: tangoRouter, + Homepage: "http://github.com/lunny/tango", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/tigertonic.go b/router/tigertonic.go new file mode 100644 index 00000000..4795160e --- /dev/null +++ b/router/tigertonic.go @@ -0,0 +1,59 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !tigertonic + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/rcrowley/go-tigertonic" +) + +const tigerTonicRWP = ":" + driver.ParamNameReadWrite + +func tigerTonicHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func tigerTonicHandlerReadWrite(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, r.URL.Query().Get(tigerTonicRWP)) +} + +func tigerTonicFactory(t driver.Type) func(http.ResponseWriter, *http.Request) { + switch t { + case driver.Static: + return tigerTonicHandler + case driver.Parameterized: + return tigerTonicHandler + case driver.ParameterReadWrite: + return tigerTonicHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func tigerTonicRouter(t driver.Type, f driver.Fixtures) http.Handler { + h := tigerTonicFactory(t) + m := tigertonic.NewTrieServeMux() + + for _, r := range f { + m.HandleFunc(r.Method, r.Path, h) + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Tiger Tonic", + Router: tigerTonicRouter, + Normalizer: driver.CurlyBracesNormalizer, + Homepage: "http://github.com/rcrowley/go-tigertonic", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} diff --git a/router/traffic.go b/router/traffic.go new file mode 100644 index 00000000..dc220afa --- /dev/null +++ b/router/traffic.go @@ -0,0 +1,71 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !traffic + +package router + +import ( + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/pilu/traffic" +) + +func trafficHandler(w traffic.ResponseWriter, _ *traffic.Request) { + w.WriteHeader(http.StatusOK) +} + +func trafficHandlerReadWrite(w traffic.ResponseWriter, r *traffic.Request) { + io.WriteString(w, r.URL.Query().Get(driver.ParamNameReadWrite)) +} + +func trafficFactory(t driver.Type) func(traffic.ResponseWriter, *traffic.Request) { + switch t { + case driver.Static: + return trafficHandler + case driver.Parameterized: + return trafficHandler + case driver.ParameterReadWrite: + return trafficHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func trafficRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := traffic.New() + h := trafficFactory(t) + + for _, r := range f { + switch r.Method { + case "GET": + m.Get(r.Path, h) + case "POST": + m.Post(r.Path, h) + case "PUT": + m.Put(r.Path, h) + case "PATCH": + m.Patch(r.Path, h) + case "DELETE": + m.Delete(r.Path, h) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + return m +} + +func init() { + traffic.SetVar("env", "bench") + + driver.RegisterPackage(&driver.Package{ + Name: "Traffic", + Router: trafficRouter, + Homepage: "http://github.com/pilu/traffic", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From 8ed7bae277d17417c87bc1b3d45e39339e3767aa Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:11:39 +0200 Subject: [PATCH 16/18] router: add Vulcan --- router/vulcan.go | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 router/vulcan.go diff --git a/router/vulcan.go b/router/vulcan.go new file mode 100644 index 00000000..afd149a9 --- /dev/null +++ b/router/vulcan.go @@ -0,0 +1,62 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build !vulcan + +package router + +import ( + "fmt" + "io" + "net/http" + + "github.com/julienschmidt/go-http-routing-benchmark/driver" + "github.com/mailgun/route" +) + +func vulcanHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func vulcanHandlerReadWrite(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, r.URL.Query().Get(driver.ParamNameReadWrite)) +} + +func vulcanFactory(t driver.Type) func(http.ResponseWriter, *http.Request) { + switch t { + case driver.Static: + return vulcanHandler + case driver.Parameterized: + return vulcanHandler + case driver.ParameterReadWrite: + return vulcanHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func vulcanRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := route.NewMux() + h := vulcanFactory(t) + + for _, r := range f { + expr := fmt.Sprintf(`Method("%s") && Path("%s")`, r.Method, r.Path) + + if err := m.HandleFunc(expr, h); err != nil { + panic(err) + } + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Mailgun Vulcan", + Router: vulcanRouter, + Normalizer: driver.XThanSignNormalizer, + Homepage: "http://github.com/mailgun/route", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From 62dc0d27a55b9cbe52e5375d499f0e89df1423db Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:12:26 +0200 Subject: [PATCH 17/18] router: add Zeus Zeus is currently disabled. Enable again once daryl/zeus#2 is fixed. --- router/zeus.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 router/zeus.go diff --git a/router/zeus.go b/router/zeus.go new file mode 100644 index 00000000..f0bf9810 --- /dev/null +++ b/router/zeus.go @@ -0,0 +1,67 @@ +// Copyright 2014-2015 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// +build ignore,!zeus + +package router + +import ( + "io" + "net/http" + + "github.com/daryl/zeus" + "github.com/julienschmidt/go-http-routing-benchmark/driver" +) + +func zeusHandler(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func zeusHandlerReadWrite(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, zeus.Var(r, driver.ParamNameReadWrite)) +} + +func zeusFactory(t driver.Type) func(http.ResponseWriter, *http.Request) { + switch t { + case driver.Static: + return zeusHandler + case driver.Parameterized: + return zeusHandler + case driver.ParameterReadWrite: + return zeusHandlerReadWrite + default: + panic("Unknown benchmark type passed") + } +} + +func zeusRouter(t driver.Type, f driver.Fixtures) http.Handler { + m := zeus.New() + h := zeusFactory(t) + + for _, r := range f { + switch r.Method { + case "GET": + m.GET(r.Path, h) + case "POST": + m.POST(r.Path, h) + case "PUT": + m.PUT(r.Path, h) + case "DELETE": + m.DELETE(r.Path, h) + default: + panic("Unknow HTTP method: " + r.Method) + } + } + + return m +} + +func init() { + driver.RegisterPackage(&driver.Package{ + Name: "Zeus", + Router: zeusRouter, + Homepage: "http://github.com/daryl/zeus", + Supports: driver.Static | driver.Parameterized | driver.ParameterReadWrite, + }) +} From 1df382252d8dd7f5ddd7bc611411107502072179 Mon Sep 17 00:00:00 2001 From: Eric Boh Date: Fri, 12 Jun 2015 18:16:44 +0200 Subject: [PATCH 18/18] ci: use runner.go --test instead of go test --- .travis.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9573daa6..edd60b79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,10 @@ sudo: false + language: go + go: - - 1.4 - - tip + - 1.4 + - tip + +script: + - go run runner.go --test