Skip to main content

Testing Infrastructure

AxonFlow maintains a comprehensive testing infrastructure that ensures reliability, performance, and security across all components. This guide covers our testing philosophy and how to run tests locally.

Testing Pyramid

Our testing strategy follows the industry-standard testing pyramid:

                    ┌─────────────┐
│ E2E / │ ← Fewest tests
│ Load Tests │ (expensive, slow)
┌┴─────────────┴┐
│ Integration │ ← Medium coverage
│ Tests │ (API contracts)
┌┴───────────────┴┐
│ Unit Tests │ ← Most tests
└─────────────────┘ (fast, isolated)

Unit Tests

Unit tests validate individual functions and business logic in isolation. Each Go package contains comprehensive unit tests.

Characteristics:

  • Fast execution (milliseconds)
  • No external dependencies (databases, APIs mocked)
  • High coverage of business logic paths
  • Run on every commit via CI

Integration Tests

Integration tests validate interactions between components and external systems.

Characteristics:

  • Test database operations with real PostgreSQL
  • Verify API contracts between services
  • Test connector integrations
  • Run before deployments

Load Tests

Load tests validate system performance under sustained traffic.

Characteristics:

  • Realistic client behavior (connection pooling, HTTP/2)
  • Multiple concurrent users
  • Percentile latency tracking (P50, P95, P99)
  • Run on-demand or scheduled

Performance Tests

Performance tests track system benchmarks over time.

Characteristics:

  • Scheduled execution (hourly, daily, weekly)
  • Historical trend tracking
  • Regression detection
  • Cost-optimized (no LLM calls by default)

Running Tests Locally

Prerequisites

  • Go 1.25+ installed
  • Docker and Docker Compose (for integration tests)
  • Make (optional, for convenience)

Unit Tests

Run all unit tests:

# Run all tests
go test ./...

# Run tests with coverage
go test -cover ./...

# Run tests for a specific package
go test ./platform/agent/...

# Run tests with verbose output
go test -v ./platform/orchestrator/...

Integration Tests

Integration tests require a running PostgreSQL instance:

# Start local infrastructure
docker compose up -d postgres redis

# Run integration tests
go test -tags=integration ./...

# Clean up
docker compose down

Benchmarks

Run performance benchmarks:

# Run all benchmarks
go test -bench=. ./...

# Run specific benchmark
go test -bench=BenchmarkPolicyEvaluation ./platform/agent/...

# Compare benchmark results
go test -bench=. ./... > new.txt
benchstat old.txt new.txt

Test Structure

File Naming Conventions

PatternPurposeExample
*_test.goUnit testspolicy_test.go
*_integration_test.goIntegration testsdb_integration_test.go
*_bench_test.goBenchmarksagent_bench_test.go

Test Organization

Tests are co-located with the code they test:

platform/
├── agent/
│ ├── main.go
│ ├── main_test.go # Unit tests
│ ├── agent_bench_test.go # Benchmarks
│ └── db_auth.go
│ └── db_auth_test.go # Unit tests
├── orchestrator/
│ ├── main.go
│ └── main_test.go
└── connectors/
└── amadeus/
├── connector.go
└── connector_test.go

CI/CD Integration

Tests run automatically in our GitHub Actions CI pipeline. The workflow files live in .github/workflows/.

Pipeline Overview

  1. On Pull Request (test.yml, test-community.yml, lint.yml):

    • All unit tests across Go 1.25
    • Coverage enforcement against per-module thresholds
    • Linting via golangci-lint
    • Security scanning via CodeQL (v4)
    • Community-mode tests run in parallel via test-community.yml
  2. On Merge to Main:

    • All unit tests
    • Integration tests (PostgreSQL via testcontainers)
    • Docker image builds (Alpine 3.23 base)
    • Coverage report published as artifact
  3. Scheduled (Nightly):

    • Full test suite
    • Performance benchmarks
    • Load tests against staging

Running the Full CI Suite Locally

You can approximate the CI pipeline locally:

# Lint (matches lint.yml)
golangci-lint run ./platform/...

# Unit tests with coverage (matches test.yml)
go test -cover -coverprofile=coverage.out ./platform/...

# Integration tests (requires Docker)
docker compose up -d postgres redis
go test -tags=integration ./platform/...
docker compose down

Coverage Requirements

We enforce minimum coverage thresholds in CI. Pull requests that drop coverage below these targets will fail the test workflow.

Coverage Targets

ModuleThresholdLatest CINotes
Orchestrator76%76.8%Core policy routing and LLM orchestration
Agent76%76.6%Policy enforcement and request handling
Connectors76%77.1%MCP connector implementations
Shared Policy80%82.4%Shared policy engine (higher bar)
EE Orchestrator80%80.9%Enterprise orchestrator extensions
EE Agent50%78.3%Enterprise agent extensions

Checking Coverage Locally

# Generate a coverage report for a specific module
go test -coverprofile=coverage.out ./platform/orchestrator/...
go tool cover -func=coverage.out | tail -1

# Open an HTML coverage report in the browser
go tool cover -html=coverage.out

Coverage reports are also generated during CI and visible in pull request checks.

Mock Usage

We use standard Go mocking patterns:

Database Mocking (go-sqlmock)

import "github.com/DATA-DOG/go-sqlmock"

func TestDatabaseQuery(t *testing.T) {
db, mock, err := sqlmock.New()
require.NoError(t, err)
defer db.Close()

mock.ExpectQuery("SELECT").WillReturnRows(
sqlmock.NewRows([]string{"id", "name"}).
AddRow(1, "test"),
)

// Test your function
}

HTTP Mocking (httptest)

import "net/http/httptest"

func TestExternalAPI(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "ok"}`))
}))
defer server.Close()

// Use server.URL in your tests
}

Next Steps