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>
138 lines
3.1 KiB
Go
138 lines
3.1 KiB
Go
//go:build integration
|
|
// +build integration
|
|
|
|
package integration_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os/exec"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
|
)
|
|
|
|
// setupForkedArbitrum sets up a forked Arbitrum test environment using anvil
|
|
func setupForkedArbitrum(t testing.TB) (*ethclient.Client, func()) {
|
|
// Check if anvil is available
|
|
if _, err := exec.LookPath("anvil"); err != nil {
|
|
t.Skip("anvil not found in PATH - install Foundry to run fork tests")
|
|
}
|
|
|
|
// Start anvil with Arbitrum fork
|
|
arbitrumRPC := "https://arb1.arbitrum.io/rpc"
|
|
port := "8545"
|
|
|
|
cmd := exec.Command("anvil",
|
|
"--fork-url", arbitrumRPC,
|
|
"--port", port,
|
|
"--gas-limit", "30000000",
|
|
"--gas-price", "10000000000", // 10 gwei
|
|
"--block-time", "1", // 1 second blocks
|
|
"--accounts", "10", // 10 test accounts
|
|
"--balance", "1000", // 1000 ETH per account
|
|
)
|
|
|
|
// Start anvil in background
|
|
if err := cmd.Start(); err != nil {
|
|
t.Fatalf("Failed to start anvil: %v", err)
|
|
}
|
|
|
|
// Wait for anvil to be ready
|
|
time.Sleep(3 * time.Second)
|
|
|
|
// Connect to the forked network
|
|
client, err := ethclient.Dial(fmt.Sprintf("http://localhost:%s", port))
|
|
if err != nil {
|
|
cmd.Process.Kill()
|
|
t.Fatalf("Failed to connect to forked Arbitrum: %v", err)
|
|
}
|
|
|
|
// Verify connection by getting chain ID
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
chainID, err := client.ChainID(ctx)
|
|
if err != nil {
|
|
cmd.Process.Kill()
|
|
t.Fatalf("Failed to get chain ID: %v", err)
|
|
}
|
|
|
|
if chainID.Uint64() != 42161 {
|
|
t.Logf("Warning: Expected Arbitrum chain ID 42161, got %d", chainID.Uint64())
|
|
}
|
|
|
|
// Return cleanup function
|
|
cleanup := func() {
|
|
client.Close()
|
|
if cmd.Process != nil {
|
|
cmd.Process.Kill()
|
|
cmd.Wait()
|
|
}
|
|
}
|
|
|
|
return client, cleanup
|
|
}
|
|
|
|
// getMemStats returns current memory statistics
|
|
func getMemStats() runtime.MemStats {
|
|
var m runtime.MemStats
|
|
runtime.ReadMemStats(&m)
|
|
return m
|
|
}
|
|
|
|
// logMemoryUsage logs current memory usage for debugging
|
|
func logMemoryUsage(t testing.TB, label string) {
|
|
var m runtime.MemStats
|
|
runtime.ReadMemStats(&m)
|
|
|
|
t.Logf("%s - Memory: Alloc=%d KB, TotalAlloc=%d KB, Sys=%d KB, NumGC=%d",
|
|
label,
|
|
m.Alloc/1024,
|
|
m.TotalAlloc/1024,
|
|
m.Sys/1024,
|
|
m.NumGC,
|
|
)
|
|
}
|
|
|
|
// waitForAnvil waits for anvil to be ready and responsive
|
|
func waitForAnvil(port string, timeout time.Duration) error {
|
|
deadline := time.Now().Add(timeout)
|
|
|
|
for time.Now().Before(deadline) {
|
|
client, err := ethclient.Dial(fmt.Sprintf("http://localhost:%s", port))
|
|
if err == nil {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
_, err := client.ChainID(ctx)
|
|
cancel()
|
|
client.Close()
|
|
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
|
|
return fmt.Errorf("anvil not ready after %v", timeout)
|
|
}
|
|
|
|
// createTestLogger creates a test logger for debugging
|
|
func createTestLogger(t testing.TB) *log.Logger {
|
|
return log.New(&testWriter{t: t}, "[TEST] ", log.LstdFlags|log.Lshortfile)
|
|
}
|
|
|
|
// testWriter implements io.Writer for test logging
|
|
type testWriter struct {
|
|
t testing.TB
|
|
}
|
|
|
|
func (tw *testWriter) Write(p []byte) (n int, err error) {
|
|
tw.t.Log(string(p))
|
|
return len(p), nil
|
|
}
|