372 lines
9.2 KiB
Go
372 lines
9.2 KiB
Go
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{}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, _, _, _, _ = 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()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, _ = 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()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, _ = 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{}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
// 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{}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
// 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{}
|
|
middlewareBytecode, bytecode, scriptPath, _, _ := luaRouter.GetRouteInfo(method, path, params)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
ctx := runner.NewContext()
|
|
|
|
// Execute middleware chain
|
|
for _, mwBytecode := range middlewareBytecode {
|
|
if len(mwBytecode) > 0 {
|
|
response, _ := luaRunner.Run(mwBytecode, ctx, "middleware")
|
|
if response != nil {
|
|
runner.ReleaseResponse(response)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Execute 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)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
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 i := 0; i < b.N; i++ {
|
|
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)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
ctx := runner.NewContext()
|
|
_, _ = luaRunner.Execute(context.Background(), bytecode, ctx, scriptPath)
|
|
ctx.Release()
|
|
}
|
|
}
|