test(backend): DB-backed tests for the risky SQL; test isolation; clippy cleanup

All 40 backend tests were pure-function tests — not one line of SQL ran under `cargo test`,
even though the riskiest code in the repo is SQL. Add 12 DB-backed `#[sqlx::test]` tests
(fresh throwaway DB per test, real migrations) pinning the invariants that code is
load-bearing for, each mutation-verified to fail on broken code:

  export_epoch.rs (8): epoch is post-increment on release (a worker born pre-increment is
    inert); epoch strictly monotonic across reopen; a retired-epoch worker's writes are
    no-ops; export_current is EXACTLY the invariant (8-case table); the ViewerOnly
    carry-forward carries a done ZIP forward AND matches nothing when the ZIP is unfinished
    (the af997a8 strand bug); boot recovery doesn't clobber a live ZIP.
  upload_concurrency.rs (4): the atomic quota UPDATE stops two stale-snapshot uploads from
    both committing (sequential AND concurrent-tx via EPQ); the FOR SHARE upload lock
    serializes against release, blocking a photo from committing after the export snapshot.

Deleting FOR SHARE, or the carry-forward's `status='done'`, each makes a test fail.

Test isolation: TRUNCATE now also resets disk_cache and sse_tickets. The stale disk
reading was harmless only while quotas were globally off in e2e (they no longer are — see
the new quota spec), i.e. two holes were masking each other.

clippy: `cargo clippy --all-targets -- -D warnings` now passes (it did not). Deleted the
dead jobs.rs (an unused BackgroundJob sketch) and unused model methods; `#[allow(dead_code)]`
+ comment on the sqlx FromRow field-sets that ARE populated by the DB. No SQL or logic
changed. `cargo test` requires DATABASE_URL by design.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
fabi
2026-07-15 07:26:08 +02:00
parent c229b560d8
commit e5201a9889
18 changed files with 1075 additions and 57 deletions

View File

@@ -34,6 +34,17 @@ impl DiskCache {
}
}
/// Drop the cached reading so the next `snapshot()` re-measures the filesystem.
///
/// Used by the e2e TRUNCATE endpoint. Truncating deletes every uploaded file, which materially
/// changes free space — but the cached reading survives for up to the TTL, so the next test can
/// compute a quota from the PREVIOUS test's disk. That matters now that the quota tests steer
/// the per-user limit off `free_disk_bytes`: a stale reading makes the limit wrong and the test
/// flaky, for reasons that have nothing to do with the code under test.
pub fn invalidate(&self) {
*self.inner.write().unwrap() = None;
}
/// Cached `(total, free)` bytes for the filesystem that holds `media_path`.
///
/// Returns `None` when the mount can't be resolved — callers MUST treat that as
@@ -47,10 +58,11 @@ impl DiskCache {
/// caller to ask about a different volume (e.g. the exports volume, which is a separate mount)
/// would have silently got the wrong filesystem's free space.
pub fn snapshot(&self, path: &Path) -> Option<DiskInfo> {
if let Some((cached_path, info, at)) = self.inner.read().unwrap().as_ref() {
if cached_path == path && at.elapsed() < TTL {
return Some(*info);
}
if let Some((cached_path, info, at)) = self.inner.read().unwrap().as_ref()
&& cached_path == path
&& at.elapsed() < TTL
{
return Some(*info);
}
let info = read_disk_for_path(path)?;
*self.inner.write().unwrap() = Some((path.to_path_buf(), info, Instant::now()));