Moonshark/tests/basic_test.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()
}
}