switchgear-testing 0.1.7

CI Integration Testing Framework for Switchgear
Documentation
# LNURL Balancer Testing Environment

This directory contains the Docker-based regtest environment for testing Switchgear with Lightning Network nodes, plus the `switchgear-testing` Rust crate for accessing test credentials and port allocation.

## Architecture

The regtest environment provides:
- **Bitcoin Core** (regtest mode) - Local Bitcoin network for testing
- **Core Lightning (CLN)** - Lightning Network node implementation  
- **LND** - Lightning Network Daemon implementation
- **PostgreSQL** - Database for testing
- **MySQL** - Alternative database for testing
- **Setup Container** - Automated initialization and credential extraction
- **Testing Crate** - Rust library for reading Lightning node credentials and dynamic port allocation

## Quick Start

1. **Start the environment:**
   ```bash
   docker-compose up --build -d
   ```

2. **Run integration tests:**
   ```bash
   cargo test --release
   ```

## Components

### Docker Services

- **bitcoin** (port 18443) - Bitcoin Core in regtest mode
- **cln** (ports 9735, 9736) - Core Lightning node with gRPC
- **lnd** (ports 8080, 9734, 10009) - LND node with REST and gRPC APIs
- **postgres** (port 5432) - PostgreSQL database
- **mysql** (port 3306) - MySQL database
- **setup** - Initialization container that:
  - Generates initial Bitcoin blocks
  - Funds Lightning node wallets
  - Creates bidirectional payment channels
  - Extracts credentials and external addresses to shared volume

### Credential Management

The setup container automatically extracts Lightning node credentials and external addresses to a mounted directory (`./shared-credentials/credentials`) containing:

**CLN Credentials:**
- `cln*/node_id` - Node public key (hex-encoded)
- `cln*/address.txt` - External gRPC address (host:port format)
- `cln*/ca.pem` - CA certificate
- `cln*/client.pem` - Client certificate  
- `cln*/client-key.pem` - Client private key
- `cln*/access.rune` - Access rune for authentication

**LND Credentials:**
- `lnd*/node_id` - Node public key (hex-encoded)
- `lnd*/address.txt` - External gRPC address (host:port format)
- `lnd*/tls.cert` - TLS certificate
- `lnd*/admin.macaroon` - Admin authentication macaroon (binary)

Note: Multiple nodes of each type may be present with numbered suffixes (e.g., cln1, cln2, lnd1, lnd2)

## Testing Crate (`switchgear-testing`)

The testing crate provides a Rust library for accessing Lightning node credentials and dynamic port allocation for integration tests.

### API

The crate exposes functionality for credential management and port allocation:

#### Credentials API

```rust
use switchgear_testing::credentials::{get_backends, RegTestLnNode, RegTestLnNodeAddress};

// Get all backends
let backends = get_backends()?;

// Match on node types
for backend in backends {
    match backend {
        RegTestLnNode::Cln(cln) => {
            println!("CLN Node ID: {:?}", cln.public_key);
            println!("CLN Address: {:?}", cln.address);
            println!("CLN SNI: {}", cln.sni);
            // Access paths: cln.ca_cert_path, cln.client_cert_path, cln.client_key_path
        }
        RegTestLnNode::Lnd(lnd) => {
            println!("LND Node ID: {:?}", lnd.public_key);
            println!("LND Address: {:?}", lnd.address);
            // Access paths: lnd.tls_cert_path, lnd.macaroon_path
        }
    }
}
```

#### Port Allocation API

```rust
use switchgear_testing::ports::PortAllocator;
use std::path::PathBuf;

// Find an available port (with file-based locking to prevent conflicts)
let ports_path = PathBuf::from("/tmp/test_ports");
let port = PortAllocator::find_available_port(&ports_path)?;
```

### Credential Types

The crate uses strongly-typed credential structures:

```rust
pub enum RegTestLnNode {
    Cln(ClnRegTestLnNode),
    Lnd(LndRegTestLnNode),
}

pub struct ClnRegTestLnNode {
    pub public_key: PublicKey,
    pub address: RegTestLnNodeAddress,
    pub ca_cert_path: PathBuf,
    pub client_cert_path: PathBuf,
    pub client_key_path: PathBuf,
    pub sni: String,  // Server Name Indication (default: "localhost")
}

pub struct LndRegTestLnNode {
    pub public_key: PublicKey,
    pub address: RegTestLnNodeAddress,
    pub tls_cert_path: PathBuf,
    pub macaroon_path: PathBuf,
}
```

All credentials are provided as file paths for maximum flexibility and security.

### Data Structures

```rust
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum RegTestLnNodeAddress {
    Inet(SocketAddr),    // TCP address (standard)
    Path(Vec<u8>),       // Unix socket path (not currently used)
}
```

The `RegTestLnNode` enum provides convenience methods:
- `public_key()` - Get the node's public key
- `address()` - Get the node's address
- `kind()` - Get the node type ("cln" or "lnd")

### Environment Configuration

Set `LNURL_BALANCER_CREDENTIALS_PATH` to specify the credentials directory:

```bash
export LNURL_BALANCER_CREDENTIALS_PATH=/path/to/credentials
cargo test
```

To skip integration tests:

```bash
export LNURL_SKIP_INTEGRATION_TESTS=true
cargo test
```

### Integration Testing

Integration tests use the testing crate to access credentials:

```rust
use switchgear_testing::credentials::get_backends;

// Get all available backends
let backends = get_backends()?;

// Filter by type if needed
let cln_nodes: Vec<_> = backends.iter()
    .filter(|node| node.kind() == "cln")
    .collect();
```

**Test Environment Requirements:**
- Set `LNURL_BALANCER_CREDENTIALS_PATH` environment variable
- Or set `LNURL_SKIP_INTEGRATION_TESTS=true` to skip integration tests

## Configuration

### Environment Variables

- `LNURL_BALANCER_CREDENTIALS_PATH` - Path to credentials directory (required for tests)
  - Example: `/Users/user/dev/lnurl-balancer/testing/shared-credentials/credentials`
  - Used by `get_backends()` to locate credential files
  - Must be set when running integration tests
- `LNURL_SKIP_INTEGRATION_TESTS` - Set to `true` to skip integration tests
  - Useful for CI/CD environments without Docker
  - Returns empty backend list when set

### Ports

- `18443` - Bitcoin Core RPC
- `18444` - Bitcoin P2P
- `8080` - LND REST API  
- `9734` - LND P2P
- `9735` - CLN P2P
- `9736` - CLN gRPC (external address used in tests)
- `10009` - LND gRPC (external address used in tests)
- `28332-28333` - Bitcoin Core ZMQ
- `5432` - PostgreSQL
- `3306` - MySQL

External addresses for Lightning nodes are automatically configured:
- CLN: `127.0.0.1:9736`
- LND: `127.0.0.1:10009`

## Troubleshooting

### Setup Issues

Check the setup container logs:
```bash
docker-compose logs setup
```

Common issues:
- **Wallet creation failures** - Usually resolved by restarting: `docker-compose down && docker-compose up -d`
- **Channel creation timeouts** - Lightning nodes may need more time to sync
- **Block generation errors** - Bitcoin Core may need time to start

### Integration Test Issues

1. **Credentials not found** - Ensure setup completed successfully and check `./shared-credentials/credentials/`
2. **Connection failures** - Verify Docker containers are running: `docker-compose ps`
3. **Permission errors** - Check file permissions in credentials directory
4. **Address parsing errors** - Verify `address.txt` files contain valid `host:port` format
5. **Missing testing crate** - Ensure `switchgear-testing` is added as a dev-dependency
6. **Port conflicts** - The PortAllocator uses file-based locking to prevent conflicts
7. **Environment not set** - Remember to set `LNURL_BALANCER_CREDENTIALS_PATH` or `LNURL_SKIP_INTEGRATION_TESTS`

### Clean Restart

To completely reset the environment:
```bash
docker-compose down -v  # Remove volumes
docker-compose up --build -d
```

## Development Workflow

1. **Start environment:** `docker-compose up -d`
2. **Wait for setup:** `docker-compose logs -f setup`
3. **Set credentials path:** `export LNURL_BALANCER_CREDENTIALS_PATH=$(pwd)/shared-credentials/credentials`
4. **Run tests:** `cargo test --release`
5. **Iterate:** Make changes and re-run tests
6. **Clean up:** `docker-compose down` (or `down -v` for full reset)