//go:build integration && legacy && forked // +build integration,legacy,forked package test_main import ( "context" "fmt" "math/big" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" "github.com/fraktal/mev-beta/internal/logger" "github.com/fraktal/mev-beta/pkg/database" "github.com/fraktal/mev-beta/pkg/events" "github.com/fraktal/mev-beta/pkg/market" "github.com/fraktal/mev-beta/pkg/marketdata" ) // TestComprehensiveMarketDataLogging tests the complete market data logging system func TestComprehensiveMarketDataLogging(t *testing.T) { // Create logger log := logger.New("info", "text", "") t.Log("=== Comprehensive Market Data Logging Test ===") // Test 1: Initialize Market Data Logger t.Log("\n--- Test 1: Market Data Logger Initialization ---") // Create mock database (in production would be real database) db := &database.Database{} // Mock database // Initialize market data logger dataLogger := marketdata.NewMarketDataLogger(log, db) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() err := dataLogger.Initialize(ctx) if err != nil { t.Errorf("Failed to initialize market data logger: %v", err) } stats := dataLogger.GetStatistics() t.Logf("Initial statistics: %+v", stats) // Verify initial state if !stats["initialized"].(bool) { t.Error("Market data logger should be initialized") } // Test 2: Token Caching and Management t.Log("\n--- Test 2: Token Caching and Management ---") // Test known tokens wethAddr := common.HexToAddress("0x82af49447d8a07e3bd95bd0d56f35241523fbab1") usdcAddr := common.HexToAddress("0xaf88d065e77c8cc2239327c5edb3a432268e5831") // Get token info wethInfo, exists := dataLogger.GetTokenInfo(wethAddr) if !exists { t.Error("WETH should be in token cache") } else { t.Logf("WETH token info: Symbol=%s, Verified=%t", wethInfo.Symbol, wethInfo.IsVerified) } usdcInfo, exists := dataLogger.GetTokenInfo(usdcAddr) if !exists { t.Error("USDC should be in token cache") } else { t.Logf("USDC token info: Symbol=%s, Verified=%t", usdcInfo.Symbol, usdcInfo.IsVerified) } // Test token lookup by symbol wethTokens := dataLogger.GetTokensBySymbol("WETH") if len(wethTokens) == 0 { t.Error("Should find WETH tokens by symbol") } else { t.Logf("Found %d WETH tokens", len(wethTokens)) } // Test 3: Swap Event Logging t.Log("\n--- Test 3: Comprehensive Swap Event Logging ---") // Create test swap event swapEvent := events.Event{ Type: events.Swap, TransactionHash: common.HexToHash("0x1234567890abcdef"), BlockNumber: 12345678, PoolAddress: common.HexToAddress("0xC6962004f452bE9203591991D15f6b388e09E8D0"), // WETH/USDC pool Protocol: "UniswapV3", Token0: wethAddr, Token1: usdcAddr, Amount0: big.NewInt(-1000000000000000000), // -1 WETH (out) Amount1: big.NewInt(2000000000), // 2000 USDC (in) SqrtPriceX96: uint256.NewInt(1771845812700481934), Liquidity: uint256.NewInt(1000000000000000000), Tick: -74959, } // Create comprehensive swap data swapData := &marketdata.SwapEventData{ TxHash: swapEvent.TransactionHash, BlockNumber: swapEvent.BlockNumber, Timestamp: time.Now(), PoolAddress: swapEvent.PoolAddress, Protocol: swapEvent.Protocol, Token0: swapEvent.Token0, Token1: swapEvent.Token1, Amount0Out: big.NewInt(1000000000000000000), // 1 WETH out Amount1In: big.NewInt(2000000000), // 2000 USDC in Amount0In: big.NewInt(0), Amount1Out: big.NewInt(0), SqrtPriceX96: swapEvent.SqrtPriceX96, Liquidity: swapEvent.Liquidity, Tick: int32(swapEvent.Tick), AmountInUSD: 2000.0, AmountOutUSD: 2000.0, } // Log the swap event err = dataLogger.LogSwapEvent(ctx, swapEvent, swapData) if err != nil { t.Errorf("Failed to log swap event: %v", err) } t.Logf("Logged swap event: %s -> %s, Amount: %s USDC -> %s WETH", swapData.Token1.Hex()[:8], swapData.Token0.Hex()[:8], swapData.Amount1In.String(), swapData.Amount0Out.String()) // Test 4: Liquidity Event Logging t.Log("\n--- Test 4: Comprehensive Liquidity Event Logging ---") // Create test liquidity event liquidityEvent := events.Event{ Type: events.AddLiquidity, TransactionHash: common.HexToHash("0xabcdef1234567890"), BlockNumber: 12345679, PoolAddress: swapEvent.PoolAddress, Protocol: "UniswapV3", Token0: wethAddr, Token1: usdcAddr, Amount0: big.NewInt(5000000000000000000), // 5 WETH Amount1: big.NewInt(10000000000), // 10000 USDC Liquidity: uint256.NewInt(7071067811865475244), // sqrt(5 * 10000) SqrtPriceX96: uint256.NewInt(1771845812700481934), Tick: -74959, } // Create comprehensive liquidity data liquidityData := &marketdata.LiquidityEventData{ TxHash: liquidityEvent.TransactionHash, BlockNumber: liquidityEvent.BlockNumber, Timestamp: time.Now(), EventType: "mint", PoolAddress: liquidityEvent.PoolAddress, Protocol: liquidityEvent.Protocol, Token0: liquidityEvent.Token0, Token1: liquidityEvent.Token1, Amount0: liquidityEvent.Amount0, Amount1: liquidityEvent.Amount1, Liquidity: liquidityEvent.Liquidity, Amount0USD: 10000.0, // 5 WETH * $2000 Amount1USD: 10000.0, // 10000 USDC TotalUSD: 20000.0, } // Log the liquidity event err = dataLogger.LogLiquidityEvent(ctx, liquidityEvent, liquidityData) if err != nil { t.Errorf("Failed to log liquidity event: %v", err) } t.Logf("Logged %s liquidity event: %s WETH + %s USDC = %s liquidity", liquidityData.EventType, liquidityData.Amount0.String(), liquidityData.Amount1.String(), liquidityData.Liquidity.ToBig().String()) // Test 5: Pool Discovery and Caching t.Log("\n--- Test 5: Pool Discovery and Caching ---") // Get pool info that should have been cached poolInfo, exists := dataLogger.GetPoolInfo(swapEvent.PoolAddress) if !exists { t.Error("Pool should be cached after swap event") } else { t.Logf("Cached pool info: Protocol=%s, SwapCount=%d, LiquidityEvents=%d", poolInfo.Protocol, poolInfo.SwapCount, poolInfo.LiquidityEvents) } // Test pools for token pair lookup pools := dataLogger.GetPoolsForTokenPair(wethAddr, usdcAddr) if len(pools) == 0 { t.Error("Should find pools for WETH/USDC pair") } else { t.Logf("Found %d pools for WETH/USDC pair", len(pools)) for i, pool := range pools { t.Logf(" Pool %d: %s (%s) - Swaps: %d, Liquidity Events: %d", i+1, pool.Address.Hex(), pool.Protocol, pool.SwapCount, pool.LiquidityEvents) } } // Test 6: Factory Management t.Log("\n--- Test 6: Factory Management ---") activeFactories := dataLogger.GetActiveFactories() if len(activeFactories) == 0 { t.Error("Should have active factories") } else { t.Logf("Found %d active factories", len(activeFactories)) for i, factory := range activeFactories { t.Logf(" Factory %d: %s (%s %s) - %d pools", i+1, factory.Address.Hex(), factory.Protocol, factory.Version, factory.PoolCount) } } // Test specific factory lookup uniV3Factory := common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984") factoryInfo, exists := dataLogger.GetFactoryInfo(uniV3Factory) if !exists { t.Error("UniswapV3 factory should be known") } else { t.Logf("UniswapV3 factory info: Protocol=%s, Version=%s, Active=%t", factoryInfo.Protocol, factoryInfo.Version, factoryInfo.IsActive) } // Test 7: Market Builder Integration t.Log("\n--- Test 7: Market Builder Integration ---") // Initialize market builder marketBuilder := market.NewMarketBuilder(log, db, nil, dataLogger) err = marketBuilder.Initialize(ctx) if err != nil { t.Errorf("Failed to initialize market builder: %v", err) } // Get market for WETH/USDC wethUsdcMarket, exists := marketBuilder.GetMarket(wethAddr, usdcAddr) if !exists { t.Log("WETH/USDC market not built yet (expected for test)") } else { t.Logf("WETH/USDC market: %d pools, Total Liquidity: %s, Spread: %.2f%%", wethUsdcMarket.PoolCount, wethUsdcMarket.TotalLiquidity.String(), wethUsdcMarket.PriceSpread) if wethUsdcMarket.BestPool != nil { t.Logf("Best pool: %s (%s) - %.2f%% liquidity share", wethUsdcMarket.BestPool.Address.Hex(), wethUsdcMarket.BestPool.Protocol, wethUsdcMarket.BestPool.LiquidityShare*100) } } // Get all markets allMarkets := marketBuilder.GetAllMarkets() t.Logf("Total markets built: %d", len(allMarkets)) // Test 8: Statistics and Performance t.Log("\n--- Test 8: Statistics and Performance ---") finalStats := dataLogger.GetStatistics() t.Logf("Final market data statistics: %+v", finalStats) builderStats := marketBuilder.GetStatistics() t.Logf("Market builder statistics: %+v", builderStats) // Validate expected statistics if finalStats["swapEvents"].(int64) < 1 { t.Error("Should have logged at least 1 swap event") } if finalStats["liquidityEvents"].(int64) < 1 { t.Error("Should have logged at least 1 liquidity event") } if finalStats["totalTokens"].(int) < 2 { t.Error("Should have at least 2 tokens cached") } // Test 9: Race Condition Safety t.Log("\n--- Test 9: Concurrent Access Safety ---") // Test concurrent access to caches done := make(chan bool, 10) // Simulate concurrent token lookups for i := 0; i < 5; i++ { go func(id int) { defer func() { done <- true }() // Rapid token lookups for j := 0; j < 100; j++ { _, _ = dataLogger.GetTokenInfo(wethAddr) _, _ = dataLogger.GetPoolInfo(swapEvent.PoolAddress) _ = dataLogger.GetPoolsForTokenPair(wethAddr, usdcAddr) } }(i) } // Simulate concurrent event logging for i := 0; i < 5; i++ { go func(id int) { defer func() { done <- true }() // Create slightly different events testEvent := swapEvent testEvent.TransactionHash = common.HexToHash(fmt.Sprintf("0x%d234567890abcdef", id)) testSwapData := *swapData testSwapData.TxHash = testEvent.TransactionHash // Log events rapidly for j := 0; j < 10; j++ { _ = dataLogger.LogSwapEvent(context.Background(), testEvent, &testSwapData) } }(i) } // Wait for all goroutines to complete for i := 0; i < 10; i++ { <-done } t.Log("Concurrent access test completed without deadlocks") // Test 10: Cleanup and Shutdown t.Log("\n--- Test 10: Cleanup and Shutdown ---") // Stop components gracefully dataLogger.Stop() marketBuilder.Stop() // Final statistics shutdownStats := dataLogger.GetStatistics() t.Logf("Shutdown statistics: %+v", shutdownStats) t.Log("\n=== Comprehensive Market Data Logging Test Complete ===") } // TestMarketDataPersistence tests database persistence of market data func TestMarketDataPersistence(t *testing.T) { t.Log("=== Market Data Persistence Test ===") // This would test actual database operations in a real implementation // For now, we'll simulate the persistence layer t.Log("Market data persistence test completed (simulation)") } // TestMarketDataRecovery tests recovery from cached data func TestMarketDataRecovery(t *testing.T) { t.Log("=== Market Data Recovery Test ===") // This would test loading existing data from database on startup // For now, we'll simulate the recovery process t.Log("Market data recovery test completed (simulation)") }