You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
3.7 KiB
Markdown
77 lines
3.7 KiB
Markdown
---
|
|
# quotesdb-jpu5
|
|
title: '[TRIAGE] Integration test isolation strategy — per-test temp DB vs shared DB with transaction rollback?'
|
|
status: completed
|
|
type: task
|
|
priority: critical
|
|
created_at: 2026-03-10T23:32:11Z
|
|
updated_at: 2026-03-10T23:32:11Z
|
|
---
|
|
|
|
<context>
|
|
This is a triage decision ticket. It must be resolved before dependent implementation tickets can proceed.
|
|
</context>
|
|
|
|
<question>
|
|
Integration test isolation strategy: should each test get its own temporary database (per-test DB creation/deletion) or should tests share a database and use transaction rollback for cleanup?
|
|
</question>
|
|
|
|
<options>
|
|
1. **Per-test temp DB** — each test creates a fresh SQLite file (or in-memory DB) and drops it on cleanup. Maximum isolation, slower due to migration overhead per test.
|
|
2. **Shared DB with transaction rollback** — all tests share one DB, each test wraps its operations in a transaction that is rolled back at the end. Faster, but requires the test harness to manage transactions.
|
|
3. **Per-test in-memory SQLite** — SQLite `:memory:` database per test. Fast (no file I/O) and fully isolated. May require `--test-threads=1` if the server shares state.
|
|
</options>
|
|
|
|
<decision>
|
|
**Per-test temp SQLite file** (Option 1 variant), using the `tempfile` crate for RAII cleanup.
|
|
|
|
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). `TempDir` from the `tempfile` crate provides RAII cleanup — the file is deleted when the `TestContext` is dropped. Tests run in parallel safely (each has a unique path).
|
|
|
|
Implementation in test harness (`tests/helpers.rs`):
|
|
```rust
|
|
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).
|
|
</decision>
|
|
|
|
<resolution>
|
|
1. Research the options above and choose the best approach for this project.
|
|
2. Update ticket 9b581f (test harness) with the chosen isolation strategy.
|
|
3. Mark this ticket done with a note on the chosen approach in the body or a comment.
|
|
</resolution>
|
|
|
|
<commit>
|
|
`chore(quotesdb): resolve triage — integration-test-isolation-per-test-tempfile-sqlite`
|
|
</commit>
|