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
| Pattern | Purpose | Example |
|---|---|---|
*_test.go | Unit tests | policy_test.go |
*_integration_test.go | Integration tests | db_integration_test.go |
*_bench_test.go | Benchmarks | agent_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
-
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
-
On Merge to Main:
- All unit tests
- Integration tests (PostgreSQL via testcontainers)
- Docker image builds (Alpine 3.23 base)
- Coverage report published as artifact
-
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
| Module | Threshold | Latest CI | Notes |
|---|---|---|---|
| Orchestrator | 76% | 76.8% | Core policy routing and LLM orchestration |
| Agent | 76% | 76.6% | Policy enforcement and request handling |
| Connectors | 76% | 77.1% | MCP connector implementations |
| Shared Policy | 80% | 82.4% | Shared policy engine (higher bar) |
| EE Orchestrator | 80% | 80.9% | Enterprise orchestrator extensions |
| EE Agent | 50% | 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
- Load Testing Methodology - Deep dive into load testing
- Performance Testing Architecture - Scheduled testing infrastructure
- Writing Tests Guide - How to contribute tests
