SDK
Go Developer Testing SDK (chaostest)
Programmatic API in pkg/chaostest for embedding deterministic isolation fuzzing directly into standard go test suites.
Introduction to the SDK (pkg/chaostest)
The ChaosSQL Go Developer Testing SDK (pkg/chaostest) is built for software engineers who want to embed deterministic concurrency and invariant fuzzing directly into standard Go test suites (*testing.T). It allows developers to validate database repositories, persistence layers, and domain services natively via go test ./..., offering full compatibility with go test -race without requiring external binaries or CLI orchestration.
Fluent Builder API: chaostest.New(t) & NewHarness(t)
The package provides a fluent builder pattern (chaostest.New(t) or chaostest.NewHarness(t)) with method chaining to configure concurrency test harnesses intuitively:
| Method | Parameters | Technical Description |
|---|---|---|
New(t testing.TB)or NewHarness(t) |
testing.TB |
Initializes a new test harness bound to the lifecycle of the current testing context. |
WithDriver(driver) |
drivers.DatabaseDriver |
Sets the database driver instance. If omitted, automatically provisions an isolated in-memory SQLite database. |
WithSchema(sql) |
string |
Defines DDL SQL statements for table and index creation. |
WithSeed(sql) |
string |
Defines DML SQL statements for initial dataset seeding prior to fuzzing. |
WithInvariant(name, query, expr) |
string, string, string |
Registers a global consistency rule that must hold true upon completion. |
WithJitter(minMs, maxMs) |
int, int |
Sets the random millisecond jitter injected between transactional steps (default: 1ms to 5ms). |
AddOperation(name, steps...) |
string, ...string |
Registers a concurrent transaction. Supports variable capture (-> var) and expressions ({var - 100}). |
AddOperationWithParams(name, params, steps...) |
string, map[string]string, ...string |
Registers an operation with dynamically randomized per-transaction parameters. |
Test Assertions: AssertNoAnomalies vs AssertAnomalyDetected
1. AssertNoAnomalies(ctx, workers, iterations, seed)
Positive assertion: verifies that the service or repository implementation shows no invariant violation or anomaly under the configured seed and schedule. It is evidence for that schedule, not a proof for every schedule. If an invariant is violated or an anomaly is detected, the method invokes t.Fatalf, logging:
- Violated invariant name, expected condition, and actual query result.
- Formal Adya anomaly classification (e.g.,
P4_LOST_UPDATE). - Delta-Debugging (ddmin) compression statistics: shrinking N operations down to the minimal counterexample.
- Copy-pasteable Mermaid sequence diagram illustrating the conflicting schedule.
2. AssertAnomalyDetected(ctx, workers, iterations, seed, expectedAnomaly...)
Negative assertion: used in regression test suites to empirically prove that unmitigated code or insufficient transaction isolation levels trigger the expected anomaly. Use it to keep a regression test honest: if a refactor stops reproducing the bug, the test fails.
Complete Example: Testing and Mitigating Lost Update
The example below demonstrates how to write a native Go unit test proving the effectiveness of an atomic update mitigation against Lost Update (P4):
package bank_test
import (
"context"
"testing"
"github.com/bregaldahq/chaossql/internal/drivers"
"github.com/bregaldahq/chaossql/pkg/chaostest"
)
// TestAccountWithdrawal_AtomicMitigation verifies that concurrent withdrawals
// utilizing an atomic update prevent the Lost Update anomaly (P4).
func TestAccountWithdrawal_AtomicMitigation(t *testing.T) {
ctx := context.Background()
// 1. Instantiate database driver (pure-Go in-memory SQLite)
driver := drivers.NewSQLiteDriver("file:bank_test?mode=memory&cache=shared")
defer driver.Close()
// 2. Build concurrency fuzzer harness using the fluent SDK
tester := chaostest.NewHarness(t).
WithDriver(driver).
WithSchema(`
CREATE TABLE accounts (
id INT PRIMARY KEY,
balance INT NOT NULL
);
CREATE TABLE ledger (
id INTEGER PRIMARY KEY AUTOINCREMENT,
amount INT NOT NULL
);
`).
WithSeed("INSERT INTO accounts (id, balance) VALUES (1, 1000);").
WithInvariant(
"ledger_balance_consistency",
"SELECT (SELECT balance FROM accounts WHERE id = 1) AS actual, " +
"(1000 - COALESCE(SUM(amount), 0)) AS expected FROM ledger;",
"actual == expected",
).
WithJitter(1, 4).
// Mitigated transaction: atomic UPDATE with balance guard predicate
AddOperation("atomic_withdrawal",
"UPDATE accounts SET balance = balance - 100 WHERE id = 1 AND balance >= 100;",
"INSERT INTO ledger (amount) VALUES (100);",
)
// 3. Execute fuzzer across 8 concurrent workers and 40 transactions
// Must pass with 100% success and zero invariant violations
tester.AssertNoAnomalies(ctx, 8, 40, 42)
}
Automated Synthesis of repro_test.go via ddmin
When a test executed via the SDK fails under AssertNoAnomalies, the Delta-Debugging (ddmin) engine isolates the 2-operation minimal counterexample and synthesizes ready-to-run Go source code for an independent repro_test.go directly into the test logs.
Engineers can copy this generated test into a local file and attach Delve debugger breakpoints, reproducing the race condition without running the fuzzer.
seed: 42). The same seed produces the same schedule on every CI runner, so a failure reproduces instead of flaking.