3.7 KiB
| title | status | type | priority | created_at | updated_at |
|---|---|---|---|---|---|
| [TRIAGE] Integration test isolation strategy — per-test temp DB vs shared DB with transaction rollback? | completed | task | critical | 2026-03-10T23:32:11Z | 2026-03-10T23:32:11Z |
Rationale:
-
Transaction rollback (Option 2) is not viable for HTTP integration tests. The test harness spawns a real Axum server as a tokio task. That server manages its own SQLx connection pool and commits transactions independently. The test client cannot intercept or roll back those server-side transactions.
-
In-memory SQLite (Option 3) conflicts with SQLx connection pools. Each connection in a SQLx pool that opens
sqlite::memory:gets its own isolated empty database. The test server and the test client would be talking to different databases. Named shared-cache URIs (file:test_N?mode=memory&cache=shared) work around this but are less-known, have edge cases in SQLx, and offer no meaningful speed advantage over a temp file on a tmpfs. -
Per-test temp file (chosen) works correctly with SQLx pools because all pool connections share the same file path. Migration runs once per test (≈ milliseconds for 2 tables).
TempDirfrom thetempfilecrate provides RAII cleanup — the file is deleted when theTestContextis dropped. Tests run in parallel safely (each has a unique path).
Implementation in test harness (tests/helpers.rs):
pub struct TestContext {
_db_dir: TempDir, // keeps temp file alive; deleted on drop
pub base_url: String,
_shutdown: tokio::task::JoinHandle<()>,
}
pub async fn spawn_test_server() -> TestContext {
let db_dir = TempDir::new().unwrap();
let db_path = db_dir.path().join("test.sqlite");
let pool = SqlitePool::connect(&format!("sqlite:{}", db_path.display()))
.await
.unwrap();
sqlx::migrate!("./migrations").run(&pool).await.unwrap();
let app = build_router(Arc::new(NativeRepository::new(pool)));
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let port = listener.local_addr().unwrap().port();
let handle = tokio::spawn(axum::serve(listener, app).into_future());
TestContext {
_db_dir: db_dir,
base_url: format!("http://127.0.0.1:{port}"),
_shutdown: handle,
}
}
Dev-dependency added: tempfile = "3" (tracked in ticket 5f5ba0).