mothership 0.0.13

Process supervisor with HTTP exposure - wrap, monitor, and expose your fleet
Documentation
# Testing Guide

WarpDrive includes comprehensive unit and integration tests covering all major features.

## Quick Start

**Run all tests with Docker Compose** (recommended - includes PostgreSQL and Redis):
```bash
docker-compose up --build test
```

**Run tests locally** (requires PostgreSQL and Redis):
```bash
# Start services
docker-compose up -d postgres redis

# Set environment variables
export WARPDRIVE_DATABASE_URL=postgresql://warpdrive:warpdrive_test@localhost:5432/warpdrive_test
export WARPDRIVE_REDIS_URL=redis://localhost:6379

# Run tests
cargo test --workspace --all-features
```

## Test Structure

### Unit Tests
Located in `src/` alongside implementation code using `#[cfg(test)]` modules:

```bash
# Run all unit tests
cargo test --lib

# Run specific module tests
cargo test --lib cache
cargo test --lib middleware
cargo test --lib router
```

### Integration Tests
Located in `tests/`:

- `config_test.rs` — Configuration parsing and validation
- `memory_cache_test.rs` — In-memory LRU cache
- `redis_test.rs` — Redis distributed cache (requires Redis)
- `postgres_test.rs` — PostgreSQL connection and LISTEN/NOTIFY (requires PostgreSQL)
- `process_supervisor_test.rs` — Process supervision
- `mock-upstream.rs` — Test HTTP server

```bash
# Run integration tests
cargo test --test '*'

# Run specific integration test
cargo test --test redis_test
cargo test --test postgres_test
```

## Docker Compose Test Services

The `docker-compose.yml` includes services for testing:

### PostgreSQL (`postgres`)
- **Image**: `postgres:17-alpine`
- **Port**: `5432`
- **Database**: `warpdrive_test`
- **User/Password**: `warpdrive` / `warpdrive_test`
- **Schema**: Auto-loaded from `tests/fixtures/schema.sql`
- **Health Check**: `pg_isready`

### Redis (`redis`)
- **Image**: `redis:7-alpine`
- **Port**: `6379`
- **Persistence**: AOF enabled
- **Health Check**: `redis-cli ping`

### Test Runner (`test`)
- **Dockerfile**: `Dockerfile.test`
- **Dependencies**: Waits for PostgreSQL and Redis to be healthy
- **Volumes**: Mounts source code and caches cargo registry + target
- **Environment**:
  - `WARPDRIVE_DATABASE_URL=postgresql://warpdrive:warpdrive_test@postgres:5432/warpdrive_test`
  - `WARPDRIVE_REDIS_URL=redis://redis:6379`
  - `RUST_LOG=debug`
  - `RUST_BACKTRACE=1`

## Running Tests

### Full Test Suite
```bash
# Docker Compose (isolated environment)
docker-compose up --build test

# Local (faster if services already running)
docker-compose up -d postgres redis
cargo test --workspace --all-features
```

### Specific Test Categories

**Cache Tests:**
```bash
# Memory cache only (no services needed)
cargo test --lib cache::memory

# Redis cache (requires Redis)
cargo test --test redis_test

# PostgreSQL invalidation (requires PostgreSQL)
cargo test --test postgres_test
```

**Middleware Tests:**
```bash
cargo test --lib middleware::rate_limit
cargo test --lib middleware::circuit_breaker
cargo test --lib middleware::headers
```

**Router Tests:**
```bash
cargo test --lib router
```

**ACME Tests:**
```bash
cargo test --lib acme
```

### Test Output Options

```bash
# Show test output (useful for debugging)
cargo test -- --nocapture

# Run tests serially (helpful for database tests)
cargo test -- --test-threads=1

# Show ignored tests
cargo test -- --ignored

# Run with verbose output
cargo test -- --nocapture --test-threads=1
```

## Test Environment Variables

Tests use these environment variables (auto-configured in Docker Compose):

```bash
# PostgreSQL connection
WARPDRIVE_DATABASE_URL=postgresql://warpdrive:warpdrive_test@localhost:5432/warpdrive_test

# Redis connection
WARPDRIVE_REDIS_URL=redis://localhost:6379

# Logging (optional)
RUST_LOG=debug
RUST_BACKTRACE=1
```

## Continuous Integration

For CI environments (GitHub Actions, GitLab CI, etc.):

```yaml
# Example GitHub Actions workflow
name: Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      postgres:
        image: postgres:17-alpine
        env:
          POSTGRES_USER: warpdrive
          POSTGRES_PASSWORD: warpdrive_test
          POSTGRES_DB: warpdrive_test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      redis:
        image: redis:7-alpine
        ports:
          - 6379:6379
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry
        uses: actions/cache@v3
        with:
          path: ~/.cargo/registry
          key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache cargo target
        uses: actions/cache@v3
        with:
          path: target
          key: ${{ runner.os }}-cargo-target-${{ hashFiles('**/Cargo.lock') }}

      - name: Initialize database
        run: |
          PGPASSWORD=warpdrive_test psql -h localhost -U warpdrive -d warpdrive_test -f tests/fixtures/schema.sql

      - name: Run tests
        env:
          WARPDRIVE_DATABASE_URL: postgresql://warpdrive:warpdrive_test@localhost:5432/warpdrive_test
          WARPDRIVE_REDIS_URL: redis://localhost:6379
        run: cargo test --workspace --all-features
```

## Test Coverage

Generate code coverage report:

```bash
# Install tarpaulin
cargo install cargo-tarpaulin

# Generate coverage
cargo tarpaulin --workspace --all-features --out Html --output-dir coverage

# Open report
open coverage/index.html
```

## Troubleshooting

### Tests Hang

**Symptom**: Tests appear to hang indefinitely

**Cause**: Usually waiting for PostgreSQL or Redis connection

**Solution**:
```bash
# Check services are running
docker-compose ps

# Check service health
docker-compose logs postgres
docker-compose logs redis

# Restart services
docker-compose restart postgres redis
```

### Connection Refused

**Symptom**: `Connection refused` errors

**Cause**: PostgreSQL or Redis not running or wrong port

**Solution**:
```bash
# Verify services are listening
docker-compose ps
netstat -an | grep 5432  # PostgreSQL
netstat -an | grep 6379  # Redis

# Check environment variables
echo $WARPDRIVE_DATABASE_URL
echo $WARPDRIVE_REDIS_URL
```

### Permission Denied

**Symptom**: `permission denied` or `could not connect` to PostgreSQL

**Cause**: Database user/password mismatch

**Solution**:
```bash
# Recreate PostgreSQL service
docker-compose down -v postgres
docker-compose up -d postgres

# Verify connection manually
docker-compose exec postgres psql -U warpdrive -d warpdrive_test
```

### Tests Fail Sporadically

**Symptom**: Tests pass sometimes, fail other times

**Cause**: Race conditions or shared state

**Solution**:
```bash
# Run tests serially
cargo test -- --test-threads=1

# Check for test isolation issues
cargo test --lib -- --test-threads=1 --nocapture
```

## Writing New Tests

### Unit Test Template

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_feature_name() {
        // Arrange
        let input = setup_test_data();

        // Act
        let result = function_under_test(input);

        // Assert
        assert_eq!(result, expected_value);
    }

    #[tokio::test]
    async fn test_async_feature() {
        // Async test using tokio runtime
        let result = async_function().await;
        assert!(result.is_ok());
    }
}
```

### Integration Test Template

```rust
// tests/my_feature_test.rs
use wrap_drive::*;

#[tokio::test]
async fn test_feature_integration() {
    // Setup
    let config = Config::default();

    // Test
    let result = integration_function(config).await;

    // Verify
    assert!(result.is_ok());
}
```

## Test Data

Test fixtures are in `tests/fixtures/`:
- `schema.sql` — PostgreSQL database schema
- Add other test data files as needed

## Performance Tests

```bash
# Run benchmarks (if added)
cargo bench

# Profile tests
cargo test --release -- --nocapture
```