sqlmodel 0.5.0

SQL databases in Rust, designed to be intuitive and type-safe
# Chapter 11: Testing Strategies

Testing database code is often fraught with flakiness, slow execution times, and complex environment setups. **SQLModel Rust** provides first-class testing utilities for lightning-fast in-memory unit tests, transactional isolation, deterministic concurrency testing, and exhaustive cancellation sweeps.

---

## In-Memory SQLite Unit Tests

For fast, self-contained unit tests that require no external database servers, use in-memory SQLite:

```rust,no_run
use sqlmodel::prelude::*;
use sqlmodel::create_table;

#[derive(Model, Debug, Clone, PartialEq)]
#[sqlmodel(table = "users")]
pub struct User {
    #[sqlmodel(primary_key, auto_increment)]
    pub id: Option<i64>,
    pub name: String,
}

async fn test_user_creation(cx: &Cx, conn: &impl Connection) -> Outcome<(), Error> {
    // Create table schema
    let sql = create_table::<User>().dialect(conn.dialect()).build();
    match conn.execute(cx, &sql, &[]).await {
        Outcome::Ok(_) => {}
        Outcome::Err(e) => return Outcome::Err(e),
        Outcome::Cancelled(r) => return Outcome::Cancelled(r),
        Outcome::Panicked(p) => return Outcome::Panicked(p),
    }

    // Insert user
    let user = User { id: None, name: "Alice".into() };
    let id = match insert!(&user).execute(cx, conn).await {
        Outcome::Ok(i) => i,
        Outcome::Err(e) => return Outcome::Err(e),
        Outcome::Cancelled(r) => return Outcome::Cancelled(r),
        Outcome::Panicked(p) => return Outcome::Panicked(p),
    };
    assert_eq!(id, 1);

    // Query user
    let found: Option<User> = match select!(User)
        .filter(Expr::col("id").eq(id))
        .first(cx, conn)
        .await
    {
        Outcome::Ok(u) => u,
        Outcome::Err(e) => return Outcome::Err(e),
        Outcome::Cancelled(r) => return Outcome::Cancelled(r),
        Outcome::Panicked(p) => return Outcome::Panicked(p),
    };

    assert_eq!(found.map(|u| u.name), Some("Alice".into()));
    Outcome::Ok(())
}
```

---

## Transactional Test Isolation

When running integration tests against a shared staging PostgreSQL or MySQL database, you can isolate tests by wrapping each test body in a transaction and rolling it back upon completion:

```rust,no_run
use sqlmodel::prelude::*;

async fn run_isolated_test<'c, C, F, Fut>(cx: &Cx, conn: &'c C, test_fn: F) -> Outcome<(), Error>
where
    C: Connection,
    F: FnOnce(&C::Tx<'c>) -> Fut,
    Fut: std::future::Future<Output = Outcome<(), Error>>,
{
    let tx = match conn.begin(cx).await {
        Outcome::Ok(t) => t,
        Outcome::Err(e) => return Outcome::Err(e),
        Outcome::Cancelled(r) => return Outcome::Cancelled(r),
        Outcome::Panicked(p) => return Outcome::Panicked(p),
    };
    let result = test_fn(&tx).await;
    // Discard all writes by rolling back the transaction
    let _ = tx.rollback(cx).await;
    result
}
```

---

## Deterministic Concurrency Testing (`LabRuntime`)

Testing timing, race conditions, and connection pool timeouts with `thread::sleep` creates slow, flaky CI suites.

SQLModel Rust is tested using `asupersync::lab::LabRuntime`:
- **Virtual Time**: Time only advances when tasks are waiting for timers; multi-hour timeouts can be tested in microseconds.
- **Deterministic Scheduling**: Seeded task schedulers reproduce race conditions reliably.
- **Oracles & Invariants**: Concurrency properties can be formally verified on every run without flakiness.

---

## Fault Injection: Cancellation Sweeps (`CancelAt`)

To prove that multi-step database workflows are cancel-safe, SQLModel provides the `CancelAt` test wrapper (available under the `test-support` feature on `sqlmodel-core`):

```rust,ignore
use sqlmodel::prelude::*;
use sqlmodel_core::test_support::CancelAt;

async fn run_sweep<C: Connection>(cx: &Cx, base_conn: C) {
    // 1. First pass: count total database checkpoints in the operation
    let probe = CancelAt::new(base_conn, 0);
    // run operation to discover k_max ...

    // 2. Iterate through every checkpoint k = 1..=k_max
    // proving that cancelling at the k-th step leaves zero corrupted state
    // and returns Outcome::Cancelled.
}
```

This guarantees that an abrupt cancellation mid-workflow never leaves half-written rows, uncommitted locks, or broken state invariants.

---

## Differences from Python SQLModel

- **Virtual-Time Concurrency**: Python testing relies on `unittest.mock` or real sleeps, which either miss concurrency bugs or slow down CI. `asupersync::lab` enables instantaneous virtual-time tests.
- **Exhaustive Cancellation Proofs**: Python offers no native mechanism to prove cancel-safety across every checkpoint; SQLModel Rust's `CancelAt` sweep provides mathematical verification.
- **Zero-Setup In-Memory Speed**: Both pure-Rust FrankenSQLite and C-SQLite run thousands of in-memory ORM test cases per second with zero external dependencies.