Moonshark/tests/basic_test.go
2025-05-24 21:50:51 -05:00

354 lines
8.7 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{}
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()
}
}