315 lines
7.7 KiB
Go
315 lines
7.7 KiB
Go
package tests
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"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 logging during benchmarks
|
|
logger.InitGlobalLogger(logger.LevelFatal, false, false)
|
|
|
|
// Redirect standard logger output to discard
|
|
log.SetOutput(io.Discard)
|
|
|
|
// Store original stderr to restore later
|
|
originalStderr := os.Stderr
|
|
devNull, _ := os.Open(os.DevNull)
|
|
os.Stderr = devNull
|
|
|
|
// Create temp directories
|
|
tempDir, err := os.MkdirTemp("", "moonshark-bench")
|
|
if err != nil {
|
|
b.Fatalf("Failed to create temp dir: %v", err)
|
|
}
|
|
|
|
// Rest of the function remains the same...
|
|
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 stderr
|
|
cleanup := func() {
|
|
luaRunner.Close()
|
|
os.RemoveAll(tempDir)
|
|
os.Stderr = originalStderr
|
|
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_hello.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_hello.lua"), postCode, 0644)
|
|
|
|
// Computationally intensive endpoint
|
|
complexCode := []byte(`
|
|
local result = {}
|
|
for i = 1, 1000 do
|
|
table.insert(result, i * i)
|
|
end
|
|
return "Calculated " .. #result .. " squared numbers"
|
|
`)
|
|
os.WriteFile(filepath.Join(routesDir, "GET_complex.lua"), complexCode, 0644)
|
|
}
|
|
|
|
// BenchmarkRouterLookup tests route lookup performance
|
|
func BenchmarkRouterLookup(b *testing.B) {
|
|
luaRouter, _, cleanup := setupTestEnv(b)
|
|
defer cleanup()
|
|
|
|
method := "GET"
|
|
path := "/hello"
|
|
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 := "/hello"
|
|
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 := "/hello"
|
|
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 := "/hello"
|
|
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 := "/hello"
|
|
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()
|
|
}
|
|
})
|
|
}
|
|
|
|
// 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 := "/hello"
|
|
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()
|
|
}
|
|
}
|