What is Antithesis? How we're different Problems we solve Security approach Demo Fintech Blockchain Database Customer stories Working with Antithesis Contact us Backstory Leadership Careers Brand Trust center Distributed systems reliability glossary Cost of outages white paper Deterministic simulation testing

Getting started with Test Composer

In this guide, we’ll walk through how to evolve a traditional test into an autonomous one using Antithesis, with a real-world example from Turso, a rewrite of SQLite in Rust.

Turso have open sourced their tests on github – this guide explains what they did, and shows you how to do the same for your system.

If you haven’t already done so, you might want to read Test Composer Basics before tackling this.

The stress test

Turso started with a workload that stress-tests their database to ensure data integrity.

The test script:

  • Randomly generates a schema and table.
  • Generates a specified number of random SQL insert, update, and delete queries.
  • Executes the generated SQL queries.
  • Periodically checks the database for integrity violations.
Component Code lines
Schema and table creation gen_schema
Insert query generate_insert
Update query generate_update
Delete query generate_delete
Integrity check integritycheck

Instead of using some synthetic data and pre-written queries, this script uses randomness to lead the test. So this handwritten stress test is already stronger than a fixed example-based test, because it introduces randomized behavior, making it behave a little like real users who interact with the software in unexpected ways.

However, it still misses many potential execution paths – especially those that involve concurrency or failure scenarios.

The test also panics and exits execution when it encounters an error. While it’s good practice to exit when the system is in an unrecoverable state, it doesn’t allow you to see the consequences of encountering a bug.

Turso’s script uses our Rust SDK to provide randomness. While many programming languages and frameworks support built-in PRNGs, those initialize at runtime, which means you can’t regenerate a new random sequence without reseeding. This makes systematic exploration difficult, so Antithesis includes a few ways of providing randomness, either using our testing environment or our SDKs.

Running in Antithesis

Initially, Turso simply ran the stress test binary as an entrypoint in their first Antithesis testing setup, by including a single line of code in their dockerfile. That’s all you need to do to start testing with Antithesis!

An equivalent approach, demonstrated below, is to use Test Composer to execute the stress test binary. To do this, Turso made their stress test a singleton driver command by placing it in a simple shell script.

singleton_driver_stress.sh

#!/usr/bin/env bash

/bin/turso_stress --silent --nr-iterations 10000

Test Composer is an opinionated framework, so take note of the naming conventions and paths used. More details are here.

Containerization

Whichever approach you use, Turso’s containerization setup is a helpful example of how to set up your software in Antithesis.

Test quality

Now Turso’s test is running in Antithesis’ testing environment, which means it’s running many thousands of times while being subjected to faults.

Each test run now consists of:

  • Multiple test branches experiencing different faults.
  • The software undertaking the same fixed sequence of operations on every branch.

Strengthening with Test Composer

The next step in the evolution is to break down the monolithic stress test into one that allows Antithesis to control execution order, parallelism, and frequency, and guide the fuzzer to more interesting system states. You can read more about why this is helpful here.

Here’s how the core components of the stress test map to test composer commands:

Component Becomes a Test Command
Schema and table creation first_setup
Insert query parallel_driver_insert
Update query parallel_driver_update
Delete query parallel_driver_delete
Rollback ops parallel_driver_rollback
Integrity check parallel_driver_integritycheck

Apart from breaking down the monolithic stress test, some of the panics in the monolith are converted into always assertions. If the assertion fails or a panic is triggered, it’ll now show up as a property failure in the triage report. This allows Turso to see what the consequences of a given error are.

Containerization

This uses the same containerization and orchestration files as above, but look for the relevant lines that refer to this directory. Note that Turso’s current testing setup for Antithesis includes both the singleton_driver_stress, and the collection of test composer commands.

Test quality

Each test run now consists of:

  • Multiple test branches with different sequences of events.
  • Parallel insert/update/delete/rollback operations.

The evolved test template

Here’s the triage report that this test generates. More detail on the triage report – or if you’d like to see the search dashboard for this test, drop us a line at support@antithesis.com.

Summary

By following this progression, you move from writing fixed examples to defining properties and behaviors, letting Antithesis explore execution paths on its own.

Setup What you’re testing Will you find the bug?
Example-based testing, manual runs Fixed test path Only if it’s on the one path that you thought to test.
Example-based testing, partially randomized, manual runs Test a different path per test run, one path per click If randomization finds the buggy input sequence.
Example-based testing, partially randomized, automated runs Test a different path per test run, many paths per click If randomization finds the buggy input sequence.
Autonomous testing, singleton Many executions with randomness + fault injection If at least one combination of events and faults across the branches of execution leads to a bug.
Autonomous testing, composed Fully autonomous, parallel, property-based testing Very very likely!
  • Introduction
  • How Antithesis Works
  • Tutorial
  • Testing with Antithesis
  • Build and run an etcd cluster
  • Meet the Test Composer
  • User manual
  • Setup guide
  • Properties and Assertions
  • Properties in Antithesis
  • Assertions in Antithesis
  • Sometimes Assertions
  • Properties to Test For
  • Test Composer
  • Test Composer Basics
  • Test Composer Reference
  • Principles of Test Composition
  • Checking Test Templates Locally
  • Getting started with Test Composer
  • Webhooks
  • Launching a test
  • Retrieving logs
  • Launching a debugging session
  • Webhook API
  • Reports
  • The triage report
  • Findings
  • Environment
  • Utilization
  • Properties
  • The bug report
  • Context, Instance, & Logs
  • Bug likelihood over time
  • Statistical debug information
  • Search dashboard & multiverse map
  • Multiverse debugging
  • Overview
  • The Antithesis multiverse
  • Querying with event sets
  • The Environment and its utilities
  • Using the Antithesis Notebook
  • Cookbook
  • Antithesis' testing environment
  • The Antithesis Environment
  • Fault Injection
  • CPUID
  • Reference
  • Handling External Dependencies
  • SDK reference
  • Go
  • Tutorial
  • Instrumentor
  • Assert (reference)
  • Lifecycle (reference)
  • Random (reference)
  • Java
  • Tutorial
  • Instrumentation
  • Assert (reference)
  • Lifecycle (reference)
  • Random (reference)
  • C
  • C++
  • Tutorial
  • C/C++ Instrumentation
  • Assert (reference)
  • Lifecycle (reference)
  • Random (reference)
  • JavaScript
  • Python
  • Tutorial
  • Assert (reference)
  • Lifecycle (reference)
  • Random (reference)
  • Rust
  • Tutorial
  • Instrumentation
  • Assert (reference)
  • Lifecycle (reference)
  • Random (reference)
  • .NET
  • Languages not listed above
  • Assert (reference)
  • Lifecycle (reference)
  • Tooling integrations
  • CI integration
  • Discord and Slack integrations
  • Configuring Antithesis
  • Instrumentation
  • User management
  • Sizing your deployment
  • Best practices
  • Docker best practices
  • Is Antithesis working?
  • Optimizing for Antithesis
  • Finding more bugs
  • FAQ
  • About Antithesis POCs
  • Product FAQs
  • Release notes
  • Release notes