stemedb/sdk/go/steme/INTEGRATION_TESTS.md
jordan b3e8a9a058 feat: Multi-application expansion with chaos testing and community UI
Major additions:
- Community Next.js app (port 18187) for browsing claims with API docs
- stemedb-chaos crate: Fault injection, chaos testing, CRDT properties
- Latent ingestion system: Reddit/FDA ingesters with ADK-Go agents
- Disputed claims handling: Manual review workflows and validation
- Aphoria security scanner: New extractors (SQL injection, command
  injection, weak crypto, TLS version), policy-based ignores, UAT reports
- Docker infrastructure: Dockerfile, docker-compose.yml for full stack
- VulnBank demo: Intentionally vulnerable multi-language test corpus

SDK & API enhancements:
- Source registry handlers for tracking data provenance
- Metrics endpoint
- Skeptic filtering improvements

Code quality:
- Split 14 large files (>500 lines) into focused modules
- All files now under 500-line limit per project guidelines

Documentation:
- Chaos testing guide, circuit breakers, observability docs
- Phase 7 UAT documentation updates
- Martin Kleppmann technical writer agent

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 01:24:14 -07:00

5.4 KiB

StemeDB Go SDK Integration Tests

Integration tests that run the Go SDK against a live StemeDB server.

Quick Start

  1. Start the StemeDB API server:
cd /path/to/stemedb
cargo run --bin stemedb-api

The server will start on http://localhost:18180 by default.

  1. Run the integration tests:
cd sdk/go/steme
STEMEDB_URL=http://localhost:18180 go test -tags=integration -v

Test Coverage

The integration test suite is split across multiple files for maintainability:

integration_helpers_test.go - Test Helpers & Health

  • getTestClient() - Creates test client with auto-generated signer
  • uniqueSubject() - Generates unique subjects for test isolation
  • TestIntegration_Health - Verify health endpoint works

integration_assert_test.go - Assert Operations

  • TestIntegration_Assert_Query_Roundtrip - Create assertion, query it back
  • TestIntegration_Assert_AllObjectTypes - Test all supported value types (Text, Number, Boolean, Reference)
  • TestIntegration_Assert_InvalidAssertion - Verify invalid assertions are rejected (missing source_hash, invalid/negative confidence)
  • TestIntegration_Lifecycle - Filter by lifecycle stage (Proposed, Approved, Deprecated)

integration_query_test.go - Query Operations

  • TestIntegration_Query_WithLens - Query with different lenses (Recency, Consensus, Authority)
  • TestIntegration_Query_NotFound - Query for non-existent data returns empty
  • TestIntegration_Query_Limit - Verify limit parameter works

integration_trace_test.go - Audit Trail

  • TestIntegration_Trace - Verify trace endpoint for audit trail querying
  • TestIntegration_Trace_WithPattern - Trace with subject pattern filtering using wildcards

Running Individual Tests

# Run a specific test
STEMEDB_URL=http://localhost:18180 go test -tags=integration -v -run TestIntegration_Health

# Run tests matching a pattern
STEMEDB_URL=http://localhost:18180 go test -tags=integration -v -run Query

Test Isolation

Each test uses uniqueSubject() to generate unique subject IDs based on timestamps:

subject := uniqueSubject("IntegrationTest_Entity")
// => "IntegrationTest_Entity_1738425600000000000"

This ensures tests don't interfere with each other, even when running in parallel.

CI/CD Integration

Integration tests are skipped by default (build tag integration) so they don't break CI when no server is running.

To run integration tests in CI:

# GitHub Actions example
- name: Start StemeDB server
  run: cargo run --bin stemedb-api &
  working-directory: /path/to/stemedb

- name: Wait for server
  run: |
    for i in {1..30}; do
      curl -f http://localhost:18180/v1/health && break
      sleep 1
    done    

- name: Run integration tests
  run: STEMEDB_URL=http://localhost:18180 go test -tags=integration -v ./...
  working-directory: sdk/go/steme

Troubleshooting

Tests skip with "STEMEDB_URL not set"

Set the environment variable:

export STEMEDB_URL=http://localhost:18180
go test -tags=integration -v

Tests fail with connection errors

Verify the server is running:

curl http://localhost:18180/v1/health

Should return:

{
  "status": "healthy",
  "version": "0.1.0",
  "assertions_count": 0
}

Tests fail after server restart

The server uses persistent storage. If tests fail due to stale data, clear the data directory:

# Check server logs for data directory location
rm -rf /path/to/data/stemedb_*

Test File Organization

Each test file is under 400 lines for maintainability:

  • integration_helpers_test.go (73 lines) - Shared helpers
  • integration_assert_test.go (302 lines) - Assert/lifecycle tests
  • integration_query_test.go (170 lines) - Query/lens tests
  • integration_trace_test.go (203 lines) - Audit trail tests

Adding New Tests

  1. Choose the appropriate file:

    • Assert operations → integration_assert_test.go
    • Query operations → integration_query_test.go
    • Trace/audit → integration_trace_test.go
    • New category → Create new integration_*_test.go
  2. Use the build tag:

//go:build integration

package steme
  1. Get a test client:
client := getTestClient(t) // Auto-skips if STEMEDB_URL not set
  1. Use unique subjects:
subject := uniqueSubject("YourTest_Name")
  1. Add indexing delay after writes:
_, err := client.Assert(ctx, assertion)
time.Sleep(100 * time.Millisecond) // Allow indexing to complete
  1. Check for errors:
if err != nil {
    t.Fatalf("Assert() failed: %v", err)
}

Example Test

func TestIntegration_MyFeature(t *testing.T) {
    client := getTestClient(t)
    ctx := context.Background()

    subject := uniqueSubject("MyFeature_Test")

    // Create assertion
    assertion := NewAssertion(subject, "has_value").
        WithText("test").
        WithSourceHash("0000000000000000000000000000000000000000000000000000000000000000").
        Build()

    hash, err := client.Assert(ctx, assertion)
    if err != nil {
        t.Fatalf("Assert() failed: %v", err)
    }

    t.Logf("Created assertion: %s", hash)

    // Small delay for indexing
    time.Sleep(100 * time.Millisecond)

    // Query it back
    result, err := client.Query(ctx, NewQuery().WithSubject(subject).Build())
    if err != nil {
        t.Fatalf("Query() failed: %v", err)
    }

    if result.TotalCount == 0 {
        t.Fatal("Expected results, got none")
    }
}