package tests import ( "context" "log" "os" "path/filepath" "testing" "Moonshark/routers" "Moonshark/runner" "Moonshark/utils/logger" ) // setupTestEnv initializes test components and returns cleanup function func setupTestEnv(b *testing.B) (*routers.LuaRouter, *runner.Runner, func()) { // Completely silence all logging originalStderr := os.Stderr originalStdout := os.Stdout devNull, _ := os.Open(os.DevNull) // Redirect everything to devnull os.Stderr = devNull os.Stdout = devNull log.SetOutput(devNull) // Force reinit logger to be silent logger.InitGlobalLogger(false, false) // Create temp directories tempDir, err := os.MkdirTemp("", "moonshark-bench") if err != nil { b.Fatalf("Failed to create temp dir: %v", err) } routesDir := filepath.Join(tempDir, "routes") staticDir := filepath.Join(tempDir, "static") libsDir := filepath.Join(tempDir, "libs") dataDir := filepath.Join(tempDir, "data") fsDir := filepath.Join(tempDir, "fs") os.MkdirAll(routesDir, 0755) os.MkdirAll(staticDir, 0755) os.MkdirAll(libsDir, 0755) os.MkdirAll(dataDir, 0755) os.MkdirAll(fsDir, 0755) // Create test routes createTestRoutes(routesDir) // Initialize router luaRouter, err := routers.NewLuaRouter(routesDir) if err != nil { b.Fatalf("Failed to create router: %v", err) } // Initialize runner luaRunner, err := runner.NewRunner( runner.WithPoolSize(4), runner.WithLibDirs(libsDir), runner.WithDataDir(dataDir), runner.WithFsDir(fsDir), ) if err != nil { b.Fatalf("Failed to create runner: %v", err) } // Return cleanup function that restores outputs cleanup := func() { luaRunner.Close() os.RemoveAll(tempDir) os.Stderr = originalStderr os.Stdout = originalStdout devNull.Close() } return luaRouter, luaRunner, cleanup } // createTestRoutes creates test Lua scripts for benchmarking func createTestRoutes(routesDir string) { // Simple GET endpoint getCode := []byte(`return "Hello, World!"`) os.WriteFile(filepath.Join(routesDir, "GET.lua"), getCode, 0644) // POST endpoint with form handling postCode := []byte(` local data = ctx.form or {} return "Received: " .. (data.message or "no message") `) os.WriteFile(filepath.Join(routesDir, "POST.lua"), postCode, 0644) // Computationally intensive endpoint complexDir := filepath.Join(routesDir, "complex") os.MkdirAll(complexDir, 0755) complexCode := []byte(` local result = {} for i = 1, 1000 do table.insert(result, i * i) end return "Calculated " .. #result .. " squared numbers" `) os.WriteFile(filepath.Join(complexDir, "GET.lua"), complexCode, 0644) // Create middleware for testing middlewareCode := []byte(` http.set_metadata("middleware_executed", true) return nil `) os.WriteFile(filepath.Join(routesDir, "middleware.lua"), middlewareCode, 0644) // Nested middleware nestedDir := filepath.Join(routesDir, "api") os.MkdirAll(nestedDir, 0755) nestedMiddlewareCode := []byte(` http.set_metadata("api_middleware", true) return nil `) os.WriteFile(filepath.Join(nestedDir, "middleware.lua"), nestedMiddlewareCode, 0644) // Nested endpoint nestedEndpointCode := []byte(`return "API endpoint"`) os.WriteFile(filepath.Join(nestedDir, "GET.lua"), nestedEndpointCode, 0644) } // BenchmarkRouterLookup tests route lookup performance func BenchmarkRouterLookup(b *testing.B) { luaRouter, _, cleanup := setupTestEnv(b) defer cleanup() method := "GET" path := "/" params := &routers.Params{} for b.Loop() { _, _, _, _ = luaRouter.GetRouteInfo(method, path, params) } } // BenchmarkSimpleLuaExecution tests execution of a simple Lua script func BenchmarkSimpleLuaExecution(b *testing.B) { luaRouter, luaRunner, cleanup := setupTestEnv(b) defer cleanup() method := "GET" path := "/" params := &routers.Params{} bytecode, scriptPath, _, _ := luaRouter.GetRouteInfo(method, path, params) ctx := runner.NewContext() defer ctx.Release() for b.Loop() { _, _ = luaRunner.Run(bytecode, ctx, scriptPath) } } // BenchmarkComplexLuaExecution tests execution of a computation-heavy script func BenchmarkComplexLuaExecution(b *testing.B) { luaRouter, luaRunner, cleanup := setupTestEnv(b) defer cleanup() method := "GET" path := "/complex" params := &routers.Params{} bytecode, scriptPath, _, _ := luaRouter.GetRouteInfo(method, path, params) ctx := runner.NewContext() defer ctx.Release() for b.Loop() { _, _ = luaRunner.Run(bytecode, ctx, scriptPath) } } // BenchmarkGetEndpoint tests end-to-end processing for GET endpoint func BenchmarkGetEndpoint(b *testing.B) { luaRouter, luaRunner, cleanup := setupTestEnv(b) defer cleanup() method := "GET" path := "/" params := &routers.Params{} for b.Loop() { // Route lookup bytecode, scriptPath, _, _ := luaRouter.GetRouteInfo(method, path, params) // Context setup ctx := runner.NewContext() // Script execution _, _ = luaRunner.Run(bytecode, ctx, scriptPath) // Cleanup ctx.Release() } } // BenchmarkPostEndpoint tests end-to-end processing for POST endpoint func BenchmarkPostEndpoint(b *testing.B) { luaRouter, luaRunner, cleanup := setupTestEnv(b) defer cleanup() method := "POST" path := "/" params := &routers.Params{} for b.Loop() { // Route lookup bytecode, scriptPath, _, _ := luaRouter.GetRouteInfo(method, path, params) // Context setup with form data ctx := runner.NewContext() ctx.Set("form", map[string]any{ "message": "Hello from benchmark test", }) // Script execution _, _ = luaRunner.Run(bytecode, ctx, scriptPath) // Cleanup ctx.Release() } } // BenchmarkConcurrentExecution tests parallel execution performance func BenchmarkConcurrentExecution(b *testing.B) { luaRouter, luaRunner, cleanup := setupTestEnv(b) defer cleanup() method := "GET" path := "/" params := &routers.Params{} bytecode, scriptPath, _, _ := luaRouter.GetRouteInfo(method, path, params) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { ctx := runner.NewContext() _, _ = luaRunner.Run(bytecode, ctx, scriptPath) ctx.Release() } }) } // BenchmarkConcurrentComplexExecution tests parallel execution of intensive scripts func BenchmarkConcurrentComplexExecution(b *testing.B) { luaRouter, luaRunner, cleanup := setupTestEnv(b) defer cleanup() method := "GET" path := "/complex" params := &routers.Params{} bytecode, scriptPath, _, _ := luaRouter.GetRouteInfo(method, path, params) b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { ctx := runner.NewContext() _, _ = luaRunner.Run(bytecode, ctx, scriptPath) ctx.Release() } }) } // BenchmarkMiddlewareExecution tests middleware + handler execution func BenchmarkMiddlewareExecution(b *testing.B) { luaRouter, luaRunner, cleanup := setupTestEnv(b) defer cleanup() method := "GET" path := "/api" params := &routers.Params{} bytecode, scriptPath, _, _ := luaRouter.GetRouteInfo(method, path, params) for b.Loop() { ctx := runner.NewContext() // Execute combined middleware + handler response, _ := luaRunner.Run(bytecode, ctx, scriptPath) if response != nil { runner.ReleaseResponse(response) } ctx.Release() } } // BenchmarkRouteCompilation tests the performance of route compilation func BenchmarkRouteCompilation(b *testing.B) { tempDir, err := os.MkdirTemp("", "moonshark-compile") if err != nil { b.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tempDir) routesDir := filepath.Join(tempDir, "routes") os.MkdirAll(routesDir, 0755) for b.Loop() { b.StopTimer() os.RemoveAll(routesDir) os.MkdirAll(routesDir, 0755) createTestRoutes(routesDir) b.StartTimer() // Creating router triggers compilation _, _ = routers.NewLuaRouter(routesDir) } } // BenchmarkContextCreation measures the cost of creating execution contexts func BenchmarkContextCreation(b *testing.B) { for b.Loop() { ctx := runner.NewContext() ctx.Release() } } // BenchmarkContextWithData measures context creation with realistic data func BenchmarkContextWithData(b *testing.B) { for i := 0; i < b.N; i++ { ctx := runner.NewContext() ctx.Set("method", "POST") ctx.Set("path", "/api/users") ctx.Set("host", "example.com") ctx.Set("params", map[string]any{"id": "123"}) ctx.Set("form", map[string]any{ "username": "testuser", "email": "user@example.com", "active": true, }) ctx.Release() } } // BenchmarkRunnerExecute tests the runner's Execute method with timeout func BenchmarkRunnerExecute(b *testing.B) { luaRouter, luaRunner, cleanup := setupTestEnv(b) defer cleanup() method := "GET" path := "/" params := &routers.Params{} bytecode, scriptPath, _, _ := luaRouter.GetRouteInfo(method, path, params) for b.Loop() { ctx := runner.NewContext() _, _ = luaRunner.Execute(context.Background(), bytecode, ctx, scriptPath) ctx.Release() } }