kurtosis

package
v0.0.0-...-be891b9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 13, 2026 License: MIT Imports: 21 Imported by: 0

README

Kurtosis Test Utilities

This package provides shared test utilities for managing Kurtosis networks across the ethcore test suite.

Overview

The kurtosis package centralizes Kurtosis network management to:

  • Reduce test execution time by sharing networks within test packages
  • Eliminate code duplication across test suites
  • Provide consistent test infrastructure
  • Enable easier addition of new integration tests

Usage

Basic Setup with TestMain

Each test package that needs Kurtosis should implement a TestMain function:

//go:build integration
// +build integration

package mytest

import (
    "os"
    "testing"
    "github.com/ethpandaops/ethcore/pkg/testutil/kurtosis"
)

var testFoundation *kurtosis.TestFoundation

func TestMain(m *testing.M) {
    config := kurtosis.DefaultNetworkConfig()
    config.Name = "my-test-network"
    
    foundation, err := kurtosis.GetNetwork(nil, config)
    if err != nil {
        panic(err)
    }
    testFoundation = foundation
    
    code := m.Run()
    
    if !config.KeepAlive {
        foundation.Cleanup()
    }
    
    os.Exit(code)
}
Writing Tests

Individual tests can access the shared network:

func TestMyFeature(t *testing.T) {
    require.NotNil(t, testFoundation, "TestMain must run first")
    
    // Access beacon clients
    for _, clientID := range testFoundation.BeaconClients {
        // Use the client ID to interact with beacon nodes
    }
    
    // Use helper functions
    client := kurtosis.GetRandomBeaconClient(testFoundation)
    kurtosis.AssertNetworkHealth(t, testFoundation)
}

Configuration

Environment Variables

The following environment variables control test behavior:

Variable Description Default
KURTOSIS_ENCLAVE Kurtosis enclave name "kurtosis"
KEEP_ENCLAVE Keep network after tests (true/false) false
TEST_TIMEOUT Network operation timeout (e.g., 5m) 2m
TEST_NET Use testnet configuration (true/false) false
EL_CHAIN Execution layer chain "mainnet"
Custom Configuration
config := kurtosis.NetworkConfig{
    Name:            "custom-test",
    Timeout:         5 * time.Minute,
    KurtosisEnclave: "my-enclave",
    KeepAlive:       true,
    TestNet:         false,
    ElChain:         "mainnet",
}
config.SetParticipants(8)

// Merge with environment
envConfig := kurtosis.ConfigFromEnvironment()
config = kurtosis.MergeConfigs(config, envConfig)

Helper Functions

Network Management
  • GetNetwork(t *testing.T, config NetworkConfig) - Get or create a network
  • GetNATExitIP() - Get appropriate NAT IP for Docker containers
Beacon Node Operations
  • WaitForBeaconNode(ctx, node, timeout) - Wait for node to be healthy
  • GetRandomBeaconClient(foundation) - Get random beacon client
  • GetBeaconClientByType(foundation, clientType) - Get specific client type
  • AssertNetworkHealth(t, foundation) - Assert all nodes are healthy

Best Practices

1. Use Build Tags

Always use the integration build tag for tests requiring Kurtosis:

//go:build integration
// +build integration
2. Run Tests Correctly
# Run unit tests only
make test-unit

# Run integration tests in parallel
make test-integration

# Run integration tests serially (for debugging)
make test-integration-serial
3. Network Reuse

Networks are automatically reused within a test package. To reuse across runs:

KEEP_ENCLAVE=true go test -tags=integration ./...
4. Debugging

Enable debug logging:

export KURTOSIS_LOG_LEVEL=debug

Keep the network alive for inspection:

export KEEP_ENCLAVE=true

Troubleshooting

Tests Timeout

Increase the timeout:

export TEST_TIMEOUT=10m
Network Already Exists

The package automatically handles existing networks. If issues persist:

kurtosis enclave rm ethcore-test
Docker Issues

Ensure Docker is running and has sufficient resources:

  • Memory: At least 8GB
  • CPU: At least 4 cores
  • Disk: At least 20GB free
Port Conflicts

Check for conflicting services:

lsof -i :8545  # Execution client
lsof -i :5052  # Beacon API

Performance Considerations

Parallel vs Serial Execution
  • Parallel (make test-integration): Faster but requires more resources
  • Serial (make test-integration-serial): Slower but more reliable on constrained systems
Resource Usage

Each test package spins up its own network with:

  • Multiple beacon nodes (typically 5-7)
  • Multiple execution clients
  • Supporting infrastructure

Plan resources accordingly.

Network Startup Time

Initial network creation takes 30-60 seconds. Subsequent tests in the same package reuse the network, making them much faster.

Examples

Testing Beacon Node APIs
func TestBeaconAPIs(t *testing.T) {
    require.NotNil(t, testFoundation)
    
    // Get a specific client type
    lighthouse := kurtosis.GetBeaconClientByType(testFoundation, "lighthouse")
    require.NotNil(t, lighthouse)
    
    // Create beacon node instance
    node := ethereum.NewBeaconNode(logger, &ethereum.Config{
        Name: lighthouse,
        Addr: fmt.Sprintf("http://cl-%s:5052", lighthouse),
    })
    
    // Wait for it to be ready
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()
    
    err := kurtosis.WaitForBeaconNode(ctx, node, 30*time.Second)
    require.NoError(t, err)
    
    // Use the node...
}
Testing Network Conditions
func TestNetworkPartition(t *testing.T) {
    require.NotNil(t, testFoundation)
    
    // Ensure network is healthy first
    kurtosis.AssertNetworkHealth(t, testFoundation)
    
    // Test your network partition logic...
}

Migration Guide

If you're migrating from inline Kurtosis setup:

  1. Remove SetupKurtosisEnvironment() function
  2. Remove local TestFoundation and NetworkConfig types
  3. Add //go:build integration tag
  4. Implement TestMain as shown above
  5. Update imports to use kurtosis package
  6. Replace foundation := SetupKurtosisEnvironment(t) with require.NotNil(t, testFoundation)

Contributing

When adding new helper functions:

  1. Follow ethpandaops Go coding standards
  2. Add comprehensive documentation
  3. Include error handling with wrapped errors
  4. Add unit tests where possible
  5. Update this README with usage examples

Documentation

Overview

Package kurtosis provides shared test utilities for managing Kurtosis networks across the ethcore test suite.

Usage:

func TestMain(m *testing.M) {
    config := kurtosis.DefaultNetworkConfig()
    foundation, err := kurtosis.GetNetwork(nil, config)
    if err != nil {
        log.Fatal(err)
    }
    defer foundation.Cleanup()

    os.Exit(m.Run())
}

Individual tests can then access the shared network through the foundation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AcquireTestLock

func AcquireTestLock()

AcquireTestLock acquires the global test lock for Kurtosis tests using directory creation. This should be called at the beginning of TestMain for test packages that use Kurtosis networks. Directory creation is atomic across processes.

func AssertNetworkHealth

func AssertNetworkHealth(t *testing.T, ctx context.Context, foundation *TestFoundation, epgNetwork network.Network)

AssertNetworkHealth asserts all beacon nodes in the network are healthy. This function is useful in tests to ensure the network is in a good state before proceeding with test operations.

Parameters:

  • t: Testing instance for assertions
  • ctx: Context for cancellation
  • foundation: The test foundation containing network information
  • epgNetwork: The ethereum package network instance

The function will fail the test if any beacon node is not healthy within the specified timeout period.

func ForceCleanupNetwork

func ForceCleanupNetwork(networkName string) error

ForceCleanupNetwork forcefully cleans up a network by name. This is useful in TestMain to ensure cleanup even if tests fail.

func GetBeaconClientByType

func GetBeaconClientByType(foundation *TestFoundation, epgNetwork network.Network, clientType string) (string, error)

GetBeaconClientByType finds a beacon client by its type (e.g., "lighthouse", "teku"). This is useful when tests need to interact with a specific client implementation.

Parameters:

  • foundation: The test foundation containing network information
  • epgNetwork: The ethereum package network instance
  • clientType: The type of client to find (case-insensitive)

Returns the name of the first beacon client matching the specified type, or an error if no matching client is found.

func GetEPGNetwork

func GetEPGNetwork(foundation *TestFoundation) network.Network

GetEPGNetwork returns the ethereum-package-go network from the foundation. It performs a type assertion to convert from interface{} to network.Network. Returns nil if the foundation or network is not properly initialized.

func GetNATExitIP

func GetNATExitIP() string

GetNATExitIP returns the appropriate IP address for containers to reach the host. On macOS/Windows with Docker Desktop, this is 127.0.0.1 due to automatic port forwarding. On Linux, we need to use the docker bridge gateway IP (typically 172.17.0.1).

func GetRandomBeaconClient

func GetRandomBeaconClient(foundation *TestFoundation) (string, error)

GetRandomBeaconClient returns a random beacon client from the foundation. This is useful for tests that need to interact with any beacon node without preference for a specific client type.

Parameters:

  • foundation: The test foundation containing beacon clients

Returns the name of a randomly selected beacon client, or an error if no beacon clients are available.

func ReleaseTestLock

func ReleaseTestLock()

ReleaseTestLock releases the global test lock. This should be called at the end of TestMain (or in a defer).

func WaitForBeaconNode

func WaitForBeaconNode(ctx context.Context, logger logrus.FieldLogger, beaconURL, name string, timeout time.Duration) error

WaitForBeaconNode waits for a beacon node to be healthy with context and timeout. It creates a temporary beacon node client to monitor the health of the specified beacon node URL. The function returns when the node becomes healthy or when the context is cancelled/times out.

Parameters:

  • ctx: Context for cancellation and timeout control
  • logger: Logger instance for diagnostic output
  • beaconURL: The URL of the beacon node to monitor
  • name: A descriptive name for the beacon node (used in logs)
  • timeout: Maximum duration to wait for the node to become healthy

Returns an error if the node doesn't become healthy within the timeout period or if the context is cancelled.

Types

type NetworkConfig

type NetworkConfig struct {
	// Name is the unique identifier for the test network
	Name string

	// Timeout specifies the maximum duration for network operations
	Timeout time.Duration

	// KurtosisEnclave represents the Kurtosis enclave configuration
	KurtosisEnclave string

	// KeepAlive determines whether the network should persist after the test completes
	KeepAlive bool

	// TestNet indicates whether this is a test network configuration
	TestNet bool

	// ElChain specifies the execution layer chain configuration
	ElChain string

	// PortOffset specifies the port offset for avoiding conflicts between test packages
	// For example, if PortOffset is 1000, EL ports start at 33000 and CL ports at 34000
	PortOffset int
	// contains filtered or unexported fields
}

NetworkConfig defines the configuration parameters for a Kurtosis test network. It specifies how the network should be created, managed, and torn down during testing.

func ConfigFromEnvironment

func ConfigFromEnvironment() (*NetworkConfig, error)

ConfigFromEnvironment reads configuration values from environment variables and returns a NetworkConfig. It returns an error if any environment variable contains an invalid value.

The following environment variables are supported:

  • KURTOSIS_ENCLAVE: The Kurtosis enclave name (default: "kurtosis")
  • KEEP_ENCLAVE: Whether to keep the enclave alive after tests (default: false)
  • TEST_TIMEOUT: Duration for test timeout (e.g., "5m", "30s") (default: 2m)
  • TEST_NET: Whether this is a test network (default: false)
  • EL_CHAIN: The execution layer chain configuration (default: "mainnet")

func DefaultNetworkConfig

func DefaultNetworkConfig() *NetworkConfig

DefaultNetworkConfig returns a NetworkConfig with sensible default values for testing Ethereum networks with Kurtosis.

func MergeConfigs

func MergeConfigs(base, override *NetworkConfig) *NetworkConfig

MergeConfigs merges two NetworkConfig instances, with values from the override configuration taking precedence over the base configuration for non-zero values. This allows for layering configurations, such as defaults with environment-specific overrides.

The merge rules are:

  • String fields: override value is used if not empty
  • Duration fields: override value is used if not zero
  • Boolean fields: override value is always used
  • Private fields: override value is used if not zero

func (*NetworkConfig) GetParticipants

func (nc *NetworkConfig) GetParticipants() int

GetParticipants returns the number of participants configured for the network.

func (*NetworkConfig) SetParticipants

func (nc *NetworkConfig) SetParticipants(count int) error

SetParticipants sets the number of participants for the network. It returns an error if the participant count is invalid (less than 1).

type NetworkManager

type NetworkManager interface {
	// GetNetwork retrieves or creates a Kurtosis network based on the provided configuration.
	// It returns an enclave context that can be used to interact with the network,
	// or an error if the network cannot be obtained.
	GetNetwork(t *testing.T, config *NetworkConfig) (*enclaves.EnclaveContext, error)

	// ReleaseNetwork releases the resources associated with a test network.
	// It should be called when the test is complete to ensure proper cleanup.
	// Returns an error if the network cannot be properly released.
	ReleaseNetwork(t *testing.T, config *NetworkConfig) error
}

NetworkManager defines the interface for managing Kurtosis test networks. It provides methods to acquire and release network resources for testing.

type TestFoundation

type TestFoundation struct {
	// Config holds the network configuration for the test
	Config *NetworkConfig

	// Network represents the active Kurtosis network instance
	Network *enclaves.EnclaveContext

	// EPGNetwork is the ethereum-package-go network instance.
	// This is stored as interface{} to avoid circular dependencies,
	// but should be cast to network.Network when used.
	EPGNetwork interface{}

	// BeaconClients contains the list of beacon client identifiers used in the test
	BeaconClients []string

	// NAT specifies whether NAT (Network Address Translation) is enabled for the test network
	NAT bool

	// Logger provides structured logging for test operations
	Logger *logrus.Logger
	// contains filtered or unexported fields
}

TestFoundation represents the foundational structure for Kurtosis-based tests. It provides the core components needed to set up and manage test networks, including configuration, network management, beacon clients, NAT settings, and thread-safe access to shared resources.

func GetNetwork

func GetNetwork(t *testing.T, config *NetworkConfig) (*TestFoundation, error)

GetNetwork retrieves or creates a Kurtosis network based on the provided configuration. It reuses existing networks when possible to improve test performance. Note: This returns a TestFoundation, not just an EnclaveContext, because ethereum-package-go doesn't directly provide access to the underlying Kurtosis enclave.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL