Files
mev-beta/orig/test/stress/stress_test_runner.go
Administrator c54c569f30 refactor: move all remaining files to orig/ directory
Completed clean root directory structure:
- Root now contains only: .git, .env, docs/, orig/
- Moved all remaining files and directories to orig/:
  - Config files (.claude, .dockerignore, .drone.yml, etc.)
  - All .env variants (except active .env)
  - Git config (.gitconfig, .github, .gitignore, etc.)
  - Tool configs (.golangci.yml, .revive.toml, etc.)
  - Documentation (*.md files, @prompts)
  - Build files (Dockerfiles, Makefile, go.mod, go.sum)
  - Docker compose files
  - All source directories (scripts, tests, tools, etc.)
  - Runtime directories (logs, monitoring, reports)
  - Dependency files (node_modules, lib, cache)
  - Special files (--delete)

- Removed empty runtime directories (bin/, data/)

V2 structure is now clean:
- docs/planning/ - V2 planning documents
- orig/ - Complete V1 codebase preserved
- .env - Active environment config (not in git)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 10:53:05 +01:00

331 lines
9.7 KiB
Go

//go:build stress
// +build stress
package stress_test
import (
"context"
"fmt"
"math/big"
"math/rand"
"os"
"os/signal"
"sync"
"sync/atomic"
"syscall"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/holiman/uint256"
"github.com/fraktal/mev-beta/internal/logger"
"github.com/fraktal/mev-beta/pkg/arbitrum"
"github.com/fraktal/mev-beta/pkg/events"
"github.com/fraktal/mev-beta/pkg/marketdata"
"github.com/fraktal/mev-beta/pkg/pools"
"github.com/fraktal/mev-beta/pkg/profitcalc"
"github.com/fraktal/mev-beta/pkg/scanner/market"
"github.com/fraktal/mev-beta/pkg/scanner/swap"
)
// StressTestRunner runs comprehensive stress tests for the MEV bot
type StressTestRunner struct {
suite *StressTestSuite
logger *logger.Logger
wg sync.WaitGroup
ctx context.Context
cancel context.CancelFunc
shutdown chan struct{}
}
// NewStressTestRunner creates a new stress test runner
func NewStressTestRunner() *StressTestRunner {
// Initialize logger
log := logger.New("debug", "text", "logs/stress_test.log")
// Create test components
protocolRegistry := arbitrum.NewArbitrumProtocolRegistry(log)
poolCache := pools.NewPoolCache(10000, time.Hour)
marketDiscovery := market.NewMarketDiscovery(nil, log, "")
strategyEngine := arbitrum.NewMEVStrategyEngine(log, protocolRegistry)
profitCalculator := profitcalc.NewProfitCalculatorWithClient(log, nil)
marketDataLogger := marketdata.NewMarketDataLogger(log, nil)
swapAnalyzer := swap.NewSwapAnalyzer(log, marketDataLogger, profitCalculator, nil)
ctx, cancel := context.WithCancel(context.Background())
runner := &StressTestRunner{
logger: log,
ctx: ctx,
cancel: cancel,
shutdown: make(chan struct{}),
}
// Create stress test suite
runner.suite = NewStressTestSuite(
log,
protocolRegistry,
poolCache,
marketDiscovery,
strategyEngine,
profitCalculator,
nil, // mevAnalyzer
nil, // slippageProtector
nil, // capitalOptimizer
nil, // profitTracker
)
return runner
}
// RunAllStressTests runs all stress tests
func (str *StressTestRunner) RunAllStressTests() {
str.logger.Info("🚀 Starting comprehensive stress tests...")
// Set up graceful shutdown
str.setupGracefulShutdown()
// Run individual stress tests
tests := []struct {
name string
fn func() *StressTestResult
}{
{"Market Scanner Stress Test", str.suite.RunMarketScannerStressTest},
{"Swap Analyzer Stress Test", str.suite.RunSwapAnalyzerStressTest},
{"Pool Discovery Stress Test", str.suite.RunPoolDiscoveryStressTest},
{"Arbitrage Engine Stress Test", str.suite.RunArbitrageEngineStressTest},
{"Event Processing Stress Test", str.suite.RunEventProcessingStressTest},
{"Profit Calculation Stress Test", str.suite.RunProfitCalculationStressTest},
{"Concurrency Stress Test", str.suite.RunConcurrencyStressTest},
{"Memory Stress Test", str.suite.RunMemoryStressTest},
{"Performance Regression Test", str.suite.RunPerformanceRegressionTest},
}
results := make([]*StressTestResult, len(tests))
// Run tests concurrently
for i, test := range tests {
str.wg.Add(1)
go func(idx int, t struct {
name string
fn func() *StressTestResult
}) {
defer str.wg.Done()
str.logger.Info(fmt.Sprintf("🧪 Running %s...", t.name))
result := t.fn()
results[idx] = result
if result.Passed {
str.logger.Info(fmt.Sprintf("✅ %s PASSED", t.name))
} else {
str.logger.Error(fmt.Sprintf("❌ %s FAILED", t.name))
}
}(i, test)
}
// Wait for all tests to complete
str.wg.Wait()
// Generate and log summary report
str.generateSummaryReport(results)
// Close resources
close(str.shutdown)
}
// generateSummaryReport generates and logs a summary report of stress test results
func (str *StressTestRunner) generateSummaryReport(results []*StressTestResult) {
str.logger.Info("📊 STRESS TEST SUMMARY REPORT")
str.logger.Info("================================")
passed := 0
failed := 0
totalTests := len(results)
for _, result := range results {
if result.Passed {
passed++
} else {
failed++
}
status := "✅ PASS"
if !result.Passed {
status = "❌ FAIL"
}
str.logger.Info(fmt.Sprintf("%s %s - Score: %.1f%%", status, result.TestName, result.PerformanceScore))
}
str.logger.Info("================================")
str.logger.Info(fmt.Sprintf("TOTAL: %d tests, %d passed, %d failed", totalTests, passed, failed))
str.logger.Info(fmt.Sprintf("SUCCESS RATE: %.1f%%", float64(passed)/float64(totalTests)*100))
if failed == 0 {
str.logger.Info("🎉 ALL STRESS TESTS PASSED!")
} else {
str.logger.Warn(fmt.Sprintf("⚠️ %d STRESS TESTS FAILED - REVIEW RESULTS", failed))
}
}
// setupGracefulShutdown sets up signal handling for graceful shutdown
func (str *StressTestRunner) setupGracefulShutdown() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
str.logger.Info("🛑 Shutdown signal received, stopping stress tests...")
str.cancel()
close(str.shutdown)
}()
}
// generateTestLoad generates synthetic load for stress testing
func (str *StressTestRunner) generateTestLoad(duration time.Duration, transactionsPerSecond int) {
str.logger.Info(fmt.Sprintf("💥 Generating synthetic load: %d TPS for %v", transactionsPerSecond, duration))
// Calculate interval between transactions for precise TPS
interval := time.Duration(int64(time.Second) / int64(transactionsPerSecond))
if interval == 0 {
interval = time.Nanosecond // Minimum interval for very high TPS
}
ticker := time.NewTicker(interval)
defer ticker.Stop()
startTime := time.Now()
transactionCount := uint64(0)
for {
select {
case <-str.ctx.Done():
str.logger.Info(fmt.Sprintf("⏹️ Load generation stopped. Generated %d transactions in %v", transactionCount, time.Since(startTime)))
return
case <-ticker.C:
// Generate synthetic transaction
str.generateSyntheticTransaction()
atomic.AddUint64(&transactionCount, 1)
// Check if duration has elapsed
if time.Since(startTime) >= duration {
str.logger.Info(fmt.Sprintf("⏰ Load generation completed. Generated %d transactions in %v", transactionCount, time.Since(startTime)))
return
}
}
}
}
// generateSyntheticTransaction generates a synthetic transaction for stress testing
func (str *StressTestRunner) generateSyntheticTransaction() {
// Generate random transaction data
txHash := common.BigToHash(big.NewInt(rand.Int63()))
blockNumber := uint64(rand.Int63n(100000000) + 100000000)
poolAddr := common.BigToAddress(big.NewInt(rand.Int63()))
token0 := common.BigToAddress(big.NewInt(rand.Int63()))
token1 := common.BigToAddress(big.NewInt(rand.Int63()))
amount0 := big.NewInt(rand.Int63n(1000000000000000000)) // Up to 1 ETH
amount1 := big.NewInt(rand.Int63n(1000000000000000000)) // Up to 1 ETH
// Create event with random protocol
protocols := []string{"uniswap_v2", "uniswap_v3", "sushiswap", "camelot_v2", "camelot_v3", "balancer_v2", "curve", "algebra"}
protocol := protocols[rand.Intn(len(protocols))]
event := events.Event{
Timestamp: time.Now(),
BlockNumber: blockNumber,
TransactionHash: txHash,
LogIndex: uint(rand.Intn(100)),
Type: events.Swap,
Protocol: protocol,
PoolAddress: poolAddr,
Token0: token0,
Token1: token1,
Amount0: amount0,
Amount1: amount1,
Liquidity: uint256.NewInt(uint64(rand.Int63n(1000000000000000000))), // Up to 1 ETH equivalent
SqrtPriceX96: uint256.NewInt(uint64(rand.Int63n(1000000000000000000))), // Random sqrt price
Tick: int32(rand.Int31n(100000) - 50000), // Random tick between -50000 and 50000
}
// Process event through the system
// Note: In a real implementation, this would call the actual processing methods
// For stress testing, we'll just simulate the processing
time.Sleep(time.Duration(rand.Intn(5)) * time.Millisecond)
}
func main() {
fmt.Println("🚀 MEV Bot Stress Test Runner")
fmt.Println("=============================")
// Create stress test runner
runner := NewStressTestRunner()
defer runner.logger.Close()
// Parse command line arguments
args := os.Args[1:]
if len(args) == 0 {
fmt.Println("Usage: stress-test-runner [options]")
fmt.Println("Options:")
fmt.Println(" --load-test Run load generation test")
fmt.Println(" --full-suite Run full stress test suite")
fmt.Println(" --duration <sec> Set test duration (default: 60)")
fmt.Println(" --tps <count> Set transactions per second (default: 1000)")
os.Exit(1)
}
// Parse arguments
duration := 60 * time.Second
tps := 1000
runLoadTest := false
runFullSuite := false
for i := 0; i < len(args); i++ {
switch args[i] {
case "--duration":
if i+1 < len(args) {
if sec, err := fmt.Sscanf(args[i+1], "%d", &duration); err == nil && sec == 1 {
duration = time.Duration(sec) * time.Second
}
i++
}
case "--tps":
if i+1 < len(args) {
if count, err := fmt.Sscanf(args[i+1], "%d", &tps); err == nil && count == 1 {
tps = int(count)
}
i++
}
case "--load-test":
runLoadTest = true
case "--full-suite":
runFullSuite = true
}
}
// Run selected tests
if runLoadTest {
fmt.Printf("🏃 Running load test for %v at %d TPS...\n", duration, tps)
go runner.generateTestLoad(duration, tps)
// Wait for completion or shutdown
select {
case <-runner.shutdown:
fmt.Println("🛑 Load test interrupted")
case <-time.After(duration + 5*time.Second):
fmt.Println("✅ Load test completed")
}
}
if runFullSuite {
fmt.Println("🧪 Running full stress test suite...")
runner.RunAllStressTests()
fmt.Println("✅ Full stress test suite completed")
}
if !runLoadTest && !runFullSuite {
fmt.Println("❌ No test specified. Use --load-test or --full-suite")
os.Exit(1)
}
}