Skip to content

TERANODE Testing Framework Technical Reference

Framework Components

TeranodeTestEnv Structure

type TeranodeTestEnv struct {
    TConfig              tconfig.TConfig       // Test configuration
    Context              context.Context      // Test context
    Compose              tc.ComposeStack      // Docker compose stack
    ComposeSharedStorage tstore.TStoreClient  // Shared storage client
    Nodes                []TeranodeTestClient // Array of test nodes
    LegacyNodes          []SVNodeTestClient   // Array of legacy nodes
    Logger               ulogger.Logger       // Framework logger
    Cancel               context.CancelFunc   // Context cancellation
    Daemon               daemon.Daemon        // Daemon instance
}

TeranodeTestClient Structure

type TeranodeTestClient struct {
    Name                string                  // Node identifier
    SettingsContext     string                  // Configuration context
    BlockchainClient    bc.ClientI              // Blockchain service client
    BlockassemblyClient ba.Client               // Block assembly client
    DistributorClient   distributor.Distributor // Distribution service client
    ClientBlockstore    *bhttp.HTTPStore        // HTTP client for block storage
    ClientSubtreestore  *bhttp.HTTPStore        // HTTP client for subtree storage
    UtxoStore           *utxostore.Store        // UTXO storage
    CoinbaseClient      *stubs.CoinbaseClient   // Coinbase service client stub
    AssetURL            string                  // Asset service URL
    RPCURL              string                  // RPC service URL
    IPAddress           string                  // Node IP address
    SVNodeIPAddress     string                  // Legacy node IP address
    Settings            *settings.Settings      // Node settings
    BlockChainDB        bcs.Store               // Blockchain storage
}

SVNodeTestClient Structure

type SVNodeTestClient struct {
    Name      string // Node identifier
    IPAddress string // Node IP address
}

Framework Setup and Usage

Creating a Test Environment

The test environment is created using the NewTeraNodeTestEnv function, which accepts a test configuration:

func NewTeraNodeTestEnv(c tconfig.TConfig) *TeranodeTestEnv {
    logger := ulogger.New("e2eTestRun", ulogger.WithLevel(c.Suite.LogLevel))
    ctx, cancel := context.WithCancel(context.Background())

    return &TeranodeTestEnv{
        TConfig: c,
        Context: ctx,
        Logger:  logger,
        Cancel:  cancel,
    }
}

Setting Up Docker Nodes

The SetupDockerNodes method initializes the Docker Compose environment with the provided settings:

func (t *TeranodeTestEnv) SetupDockerNodes() error {
    // Set up Docker Compose environment with provided settings
    // Create test directory for test-specific data
    // Configure environment settings including TEST_ID
    // Set up shared storage client for local docker-compose
    // Initialize teranode and legacy node configurations
}

Initializing Node Clients

The InitializeTeranodeTestClients method sets up all the necessary client connections for the nodes:

func (t *TeranodeTestEnv) InitializeTeranodeTestClients() error {
    // Set up blob stores for block and subtree data
    // Retrieve IP addresses for containers
    // Set up RPC and Asset service URLs
    // Initialize blockchain, blockassembly and distributor clients
    // Configure UTXO stores and other required connections
    // Connect to necessary services for testing
}

Using the Framework in Tests

A typical test using this framework would follow this pattern:

func TestSomeFunctionality(t *testing.T) {
    // Create test configuration
    config := tconfig.NewTConfig("testID")

    // Create test environment
    env := utils.NewTeraNodeTestEnv(config)

    // Set up Docker nodes
    err := env.SetupDockerNodes()
    require.NoError(t, err)

    // Initialize node clients
    err = env.InitializeTeranodeTestClients()
    require.NoError(t, err)

    // Run tests using the environment
    // Access node clients via env.Nodes[i]

    // Clean up when done
    env.Cancel()
}

Test Categories and Tags

Core Test Categories

Category Tag Description
TNA tnatests Node responsibilities and network communication
TNB tnbtests Transaction validation and processing
TNC tnctests Block assembly and Merkle tree construction
TND tndtests Block propagation through network
TNE tnetests Block validation
TNF tnftests Longest chain management
TNJ tnjtests Consensus rules compliance
TEC tectests Error handling and recovery scenarios

Service Port Mappings

Service Internal Port External Port Pattern
Coinbase GRPC 8093/tcp 1009X
Blockchain GRPC 8087/tcp 1208X
Block Assembly GRPC 8085/tcp 1408X
Propagation GRPC 8084/tcp 1608X

Configuration Reference

Environment Variables

# Core Settings
SETTINGS_CONTEXT      # Configuration context for the test run
LOG_LEVEL            # Logging verbosity (DEBUG, INFO, WARN, ERROR)
GITHUB_ACTIONS       # CI environment indicator

# Node Settings
SETTINGS_CONTEXT_1   # Configuration for node 1
SETTINGS_CONTEXT_2   # Configuration for node 2
SETTINGS_CONTEXT_3   # Configuration for node 3

Docker Compose Configuration

# Base Configuration (docker-compose.e2etest.yml)
services:
teranode-1:
image: teranode
environment:

- SETTINGS_CONTEXT=${SETTINGS_CONTEXT_1}
ports:

- "10090:8090"  # Health check port
- "10093:8093"  # Coinbase service
- "10087:8087"  # Blockchain service
- "10085:8085"  # Block assembly

teranode-2:
# Similar configuration with different ports

teranode-3:
# Similar configuration with different ports

Test Suite Configuration

// Default Compose Files
func (suite *BitcoinTestSuite) DefaultComposeFiles() []string {
    return []string{"../../docker-compose.e2etest.yml"}
}

// Default Settings Map
func (suite *BitcoinTestSuite) DefaultSettingsMap() map[string]string {
    return map[string]string{
        "SETTINGS_CONTEXT_1": "docker.ci.teranode1.tc1",
        "SETTINGS_CONTEXT_2": "docker.ci.teranode2.tc1",
        "SETTINGS_CONTEXT_3": "docker.ci.teranode3.tc1",
    }
}

Utility Methods

Node Management Methods

// StartNode starts a specific TeraNode by name
func (t *TeranodeTestEnv) StartNode(nodeName string) error {
    // Start a specific node in the Docker Compose environment
    // Wait for the node to be healthy
}

// StopNode stops a specific TeraNode by name
func (t *TeranodeTestEnv) StopNode(nodeName string) error {
    // Stop a specific node in the Docker Compose environment
}

// RestartDockerNodes restarts the Docker Compose services
func (t *TeranodeTestEnv) RestartDockerNodes(envSettings map[string]string) error {
    // Stop the current Docker Compose environment
    // Re-initialize with potentially new settings
    // Restart the services with the updated configuration
}

// StopDockerNodes stops the Docker Compose services and removes volumes
func (t *TeranodeTestEnv) StopDockerNodes() error {
    // Stop all services and clean up resources
}

Client Setup Methods

// Sets up HTTP stores for blocks and subtrees
func (t *TeranodeTestEnv) setupBlobStores() error {
    // Create HTTP clients for blob stores
    // Configure block and subtree storage access
}

// Sets up blockchain client for a node
func (t *TeranodeTestEnv) setupBlockchainClient(node *TeranodeTestClient) error {
    // Initialize gRPC connection to blockchain service
    // Create and configure blockchain client
}

// Sets up block assembly client for a node
func (t *TeranodeTestEnv) setupBlockassemblyClient(node *TeranodeTestClient) error {
    // Initialize gRPC connection to block assembly service
    // Create and configure block assembly client
}

// Sets up distributor client for a node
func (t *TeranodeTestEnv) setupDistributorClient(node *TeranodeTestClient) error {
    // Initialize gRPC connection to distributor service
    // Create and configure distributor client
}

// GetMappedPort retrieves the mapped port for a service running in Docker Compose
func (t *TeranodeTestEnv) GetMappedPort(nodeName string, port nat.Port) (nat.Port, error) {
    // Find the exposed port mapping for a container service
}

Transaction Utilities

// CreateAndSendTx creates and sends a transaction
func (n *TeranodeTestClient) CreateAndSendTx(t *testing.T, ctx context.Context, parentTx *bt.Tx) (*bt.Tx, error) {
    // Create a new transaction spending outputs from the parent transaction
    // Sign the transaction with test keys
    // Submit the transaction to the node
    // Return the created transaction
}

// CreateAndSendTxs creates and sends a chain of transactions
func (n *TeranodeTestClient) CreateAndSendTxs(t *testing.T, ctx context.Context, parentTx *bt.Tx, count int) ([]*bt.Tx, []*chainhash.Hash, error) {
    // Create a series of chained transactions
    // Each transaction spends outputs from the previous one
    // Submit all transactions to the node
    // Return the created transactions and their hashes
}

// CreateAndSendTxsConcurrently creates and sends transactions concurrently
func (n *TeranodeTestClient) CreateAndSendTxsConcurrently(t *testing.T, ctx context.Context, parentTx *bt.Tx, count int) ([]*bt.Tx, []*chainhash.Hash, error) {
    // Create multiple transactions concurrently
    // Use goroutines to parallelize transaction creation and submission
    // Wait for all transactions to complete
    // Return the created transactions and their hashes
}

API Reference

Framework Methods

// Core Framework Methods
func NewBitcoinTestFramework(composeFilePaths []string) *BitcoinTestFramework
func (b *BitcoinTestFramework) SetupNodes(m map[string]string) error
func (b *BitcoinTestFramework) GetClientHandles() error
func (b *BitcoinTestFramework) StopNodes() error
func (b *BitcoinTestFramework) RestartNodes(m map[string]string) error
func (b *BitcoinTestFramework) StartNode(nodeName string) error
func (b *BitcoinTestFramework) StopNode(nodeName string) error
func (b *BitcoinTestFramework) GetMappedPort(nodeName string, port nat.Port) (nat.Port, error)

// Test Suite Methods
func (suite *BitcoinTestSuite) SetupTest()
func (suite *BitcoinTestSuite) SetupTestWithCustomSettings(settingsMap map[string]string)
func (suite *BitcoinTestSuite) SetupTestWithCustomComposeAndSettings(settingsMap map[string]string, composeFiles []string)
func (suite *BitcoinTestSuite) TearDownTest()

Client Interfaces

Blockchain Client

type ClientI interface {
    Health(ctx context.Context) (*HealthResponse, error)
    Run(ctx context.Context) error
    SubmitTransaction(ctx context.Context, tx *Transaction) error
    VerifyTransaction(ctx context.Context, txid string) (bool, error)
}

Block Assembly Client

type Client interface {
    BlockAssemblyAPIClient() blockassembly_api.BlockAssemblyAPIClient
    Health(ctx context.Context) (*HealthResponse, error)
}

Coinbase Client

type Client interface {
    Health(ctx context.Context) (*HealthResponse, error)
    GetCoinbaseTransaction(ctx context.Context) (*Transaction, error)
}

Test Data Structures

Health Response

type HealthResponse struct {
    Ok      bool   `json:"ok"`
    Message string `json:"message,omitempty"`
}

Transaction Structure

type Transaction struct {
    ID        string    `json:"id"`
    Data      []byte    `json:"data"`
    Timestamp time.Time `json:"timestamp"`
}

Error Types

// Common error categories
errors.NewConfigurationError(format string, args ...interface{}) error
errors.NewServiceError(format string, args ...interface{}) error
errors.NewValidationError(format string, args ...interface{}) error

Testing Constants

Node URLs

const (
    NodeURL1 = "http://localhost:10090" // Node 1 base URL
    NodeURL2 = "http://localhost:12090" // Node 2 base URL
    NodeURL3 = "http://localhost:14090" // Node 3 base URL
)

Timeouts and Delays

const (
    DefaultSetupTimeout    = 30 * time.Second
    NodeStartupDelay      = 10 * time.Second
    PropagationDelay      = 2 * time.Second
)

Directory Structure

test/
├── blockassembly/        # Block assembly test data
├── explorer/             # Blockchain explorer tests
├── fixtures/            # Test fixtures and data
├── fsm/                # Finite State Machine tests
├── seed/               # Seed data for tests
├── settings/           # Test settings
├── setup/             # Test setup utilities
├── smoke/             # Smoke tests
├── system/            # System integration tests
├── tec/               # Error case tests
├── test_framework/    # Core framework code
├── testenv/           # Test environment utilities
├── tna/              # Node responsibility tests
├── tnb/              # Transaction validation tests
└── utils/            # Utility functions

Other Resources