style(backend): rustfmt the whole tree; gate cargo fmt --check in CI

The backend had never been run through rustfmt. Doing it in one mechanical pass (134 files)
so no future functional diff is buried under formatting churn, then gating `cargo fmt
--check` in checks.yml so it stays clean.

Formatting only — no logic, SQL, or behaviour changed. Verified after the reformat:
cargo test 56 passed, clippy --all-targets -D warnings clean, cargo fmt --check clean.

This is the deferred cleanup noted when CI's Format step was first left out.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
fabi
2026-07-15 19:52:17 +02:00
parent 0fa40ddf80
commit ee554e7f38
29 changed files with 589 additions and 306 deletions

View File

@@ -33,18 +33,34 @@ use sqlx::PgPool;
#[sqlx::test]
async fn release_returns_post_increment_epoch(pool: PgPool) {
let event_id = seed_event(&pool, "wedding").await;
assert_eq!(event_epoch(&pool, event_id).await, 0, "a fresh event starts at epoch 0");
assert_eq!(
event_epoch(&pool, event_id).await,
0,
"a fresh event starts at epoch 0"
);
let released = release_gallery(&pool, "wedding").await.expect("release claims the event");
assert_eq!(released, 1, "RETURNING must give the epoch AFTER the +1, not before");
assert_eq!(event_epoch(&pool, event_id).await, released, "worker's epoch == event's epoch");
let released = release_gallery(&pool, "wedding")
.await
.expect("release claims the event");
assert_eq!(
released, 1,
"RETURNING must give the epoch AFTER the +1, not before"
);
assert_eq!(
event_epoch(&pool, event_id).await,
released,
"worker's epoch == event's epoch"
);
// The jobs armed by the release carry exactly that epoch — this is what makes the worker's
// guarded writes match.
for t in ["zip", "html"] {
let (status, epoch, _) = job_row(&pool, event_id, t).await.expect("job armed");
assert_eq!(status, "pending");
assert_eq!(epoch, released, "{t} job must be armed at the epoch the worker was born with");
assert_eq!(
epoch, released,
"{t} job must be armed at the epoch the worker was born with"
);
}
}
@@ -61,15 +77,27 @@ async fn epoch_is_strictly_monotonic_across_reopen(pool: PgPool) {
assert_eq!(release_gallery(&pool, "wedding").await, Some(1));
// A duplicate release is a no-op (`WHERE export_released_at IS NULL`) and must NOT bump.
assert_eq!(release_gallery(&pool, "wedding").await, None, "already released");
assert_eq!(event_epoch(&pool, event_id).await, 1, "a rejected release must not move the epoch");
assert_eq!(
release_gallery(&pool, "wedding").await,
None,
"already released"
);
assert_eq!(
event_epoch(&pool, event_id).await,
1,
"a rejected release must not move the epoch"
);
// Reopen retires the generation with ONE write.
assert_eq!(open_event(&pool, "wedding").await, 1);
assert_eq!(event_epoch(&pool, event_id).await, 2, "reopen bumps");
// And re-releasing bumps again — never back to 1.
assert_eq!(release_gallery(&pool, "wedding").await, Some(3), "re-release bumps again");
assert_eq!(
release_gallery(&pool, "wedding").await,
Some(3),
"re-release bumps again"
);
assert_eq!(event_epoch(&pool, event_id).await, 3);
}
@@ -91,11 +119,19 @@ async fn retired_epoch_worker_writes_are_no_ops(pool: PgPool) {
let old_epoch = release_gallery(&pool, "wedding").await.unwrap();
// Worker A is born at epoch 1 and claims the ZIP.
assert!(claim_job(&pool, event_id, "zip", old_epoch).await, "worker A wins its claim");
assert!(update_progress(&pool, event_id, "zip", old_epoch, 40).await, "still live at 40%");
assert!(
claim_job(&pool, event_id, "zip", old_epoch).await,
"worker A wins its claim"
);
assert!(
update_progress(&pool, event_id, "zip", old_epoch, 40).await,
"still live at 40%"
);
// ── A takedown lands mid-export: `invalidate_and_arm(Affects::Both)` bumps and re-arms. ──
let (_, _, new_epoch) = bump_epoch(&pool, "wedding").await.expect("bump on a released event");
let (_, _, new_epoch) = bump_epoch(&pool, "wedding")
.await
.expect("bump on a released event");
assert_eq!(new_epoch, old_epoch + 1);
let mut conn = pool.acquire().await.unwrap();
enqueue_types_at_epoch(&mut conn, event_id, new_epoch, &["zip", "html"]).await;
@@ -116,7 +152,10 @@ async fn retired_epoch_worker_writes_are_no_ops(pool: PgPool) {
// fresh worker. (If worker A had won, this row would read `done` at epoch 1.)
let (status, epoch, file_path) = job_row(&pool, event_id, "zip").await.unwrap();
assert_eq!((status.as_str(), epoch), ("pending", new_epoch));
assert_eq!(file_path, None, "the loser's file_path must never be recorded");
assert_eq!(
file_path, None,
"the loser's file_path must never be recorded"
);
// And nothing is downloadable — not the stale archive, not anything.
assert_eq!(downloadable(&pool, event_id, "zip").await, None);
@@ -177,13 +216,25 @@ async fn export_current_is_exactly_the_invariant(pool: PgPool) {
// (name, released?, status, job epoch offset from the event epoch, expected visible)
let cases: &[(&str, bool, &str, i64, bool)] = &[
("released + done + current epoch", true, "done", 0, true),
("NOT released (done, epoch matches)", false, "done", 0, false),
(
"NOT released (done, epoch matches)",
false,
"done",
0,
false,
),
("NOT done: pending", true, "pending", 0, false),
("NOT done: running", true, "running", 0, false),
("NOT done: failed", true, "failed", 0, false),
("stale epoch (done, released)", true, "done", -1, false),
("future epoch (done, released)", true, "done", 1, false),
("migration-014 retired sentinel epoch -1", true, "done", -2, false),
(
"migration-014 retired sentinel epoch -1",
true,
"done",
-2,
false,
),
];
for (i, (name, released, status, offset, expect_visible)) in cases.iter().enumerate() {
@@ -209,7 +260,11 @@ async fn export_current_is_exactly_the_invariant(pool: PgPool) {
.await
.expect("clear armed jobs");
let job_epoch = if *offset == -2 { -1 } else { event_epoch_now + offset };
let job_epoch = if *offset == -2 {
-1
} else {
event_epoch_now + offset
};
sqlx::query(
"INSERT INTO export_job (event_id, type, status, progress_pct, epoch, file_path)
VALUES ($1, 'zip', $2::export_status, 100, $3, 'exports/Gallery.zip')",
@@ -251,12 +306,17 @@ async fn viewer_only_carries_a_done_zip_forward(pool: PgPool) {
assert!(claim_job(&pool, event_id, t, e1).await);
assert!(finalize_job(&pool, event_id, t, e1, &format!("exports/{t}.{e1}.zip")).await);
}
let zip_file = downloadable(&pool, event_id, "zip").await.expect("zip is live");
let zip_file = downloadable(&pool, event_id, "zip")
.await
.expect("zip is live");
// ── A comment is moderated: invalidate_and_arm(Affects::ViewerOnly). ──
let (_, _, e2) = bump_epoch(&pool, "wedding").await.unwrap();
let carried = carry_zip_forward(&pool, event_id, e2).await;
assert!(carried, "a `done` ZIP at epoch-1 MUST be carried forward (rows_affected == 1)");
assert!(
carried,
"a `done` ZIP at epoch-1 MUST be carried forward (rows_affected == 1)"
);
// Only the viewer is re-armed…
let mut conn = pool.acquire().await.unwrap();
@@ -265,7 +325,11 @@ async fn viewer_only_carries_a_done_zip_forward(pool: PgPool) {
// …and the ZIP is STILL DOWNLOADABLE, at the new epoch, pointing at the same, unrenamed file.
let (status, epoch, _) = job_row(&pool, event_id, "zip").await.unwrap();
assert_eq!((status.as_str(), epoch), ("done", e2), "the ZIP row rode the epoch bump");
assert_eq!(
(status.as_str(), epoch),
("done", e2),
"the ZIP row rode the epoch bump"
);
assert_eq!(
downloadable(&pool, event_id, "zip").await,
Some(zip_file),
@@ -354,8 +418,16 @@ async fn enqueue_preserves_a_done_half_at_the_current_epoch(pool: PgPool) {
// The good half survives untouched…
let (status, epoch, file_path) = job_row(&pool, event_id, "zip").await.unwrap();
assert_eq!((status.as_str(), epoch), ("done", e1), "a done half at the live epoch is preserved");
assert_eq!(file_path.as_deref(), Some("exports/Gallery.1.zip"), "file_path not nulled");
assert_eq!(
(status.as_str(), epoch),
("done", e1),
"a done half at the live epoch is preserved"
);
assert_eq!(
file_path.as_deref(),
Some("exports/Gallery.1.zip"),
"file_path not nulled"
);
assert!(downloadable(&pool, event_id, "zip").await.is_some());
// …and only the missing half is re-armed.

View File

@@ -17,12 +17,7 @@ use uuid::Uuid;
/// SRC: `handlers/upload.rs:313-322` — the guarded quota increment, verbatim.
/// Returns `rows_affected()`; the handler aborts the whole upload tx when this is 0.
async fn quota_inc(
exec: impl sqlx::PgExecutor<'_>,
user_id: Uuid,
size: i64,
limit: i64,
) -> u64 {
async fn quota_inc(exec: impl sqlx::PgExecutor<'_>, user_id: Uuid, size: i64, limit: i64) -> u64 {
sqlx::query(
"UPDATE \"user\" SET total_upload_bytes = total_upload_bytes + $2
WHERE id = $1 AND total_upload_bytes + $2 <= $3",
@@ -69,7 +64,11 @@ async fn quota_two_attempts_from_one_stale_snapshot_cannot_both_commit(pool: PgP
// Each upload, judged against that snapshot alone, fits: 0 + 60 <= 100. Twice.
assert!(snapshot + SIZE <= LIMIT);
assert_eq!(quota_inc(&pool, user_id, SIZE, LIMIT).await, 1, "the first upload commits");
assert_eq!(
quota_inc(&pool, user_id, SIZE, LIMIT).await,
1,
"the first upload commits"
);
assert_eq!(
quota_inc(&pool, user_id, SIZE, LIMIT).await,
0,
@@ -77,7 +76,11 @@ async fn quota_two_attempts_from_one_stale_snapshot_cannot_both_commit(pool: PgP
(60 + 60 = 120 > 100). rows_affected() == 0 is what makes the handler abort."
);
assert_eq!(total_bytes(&pool, user_id).await, SIZE, "never 120 — the quota held");
assert_eq!(
total_bytes(&pool, user_id).await,
SIZE,
"never 120 — the quota held"
);
}
/// The same, but genuinely CONCURRENT: two transactions that both read `total = 0`, then both try to
@@ -126,9 +129,17 @@ async fn quota_guard_is_atomic_under_concurrent_transactions(pool: PgPool) {
// And an upload that legitimately fits in what's left still succeeds — the guard rejects
// overruns, not everything.
assert_eq!(quota_inc(&pool, user_id, 40, LIMIT).await, 1, "0 + 60 + 40 == 100, exactly at the limit");
assert_eq!(
quota_inc(&pool, user_id, 40, LIMIT).await,
1,
"0 + 60 + 40 == 100, exactly at the limit"
);
assert_eq!(total_bytes(&pool, user_id).await, LIMIT);
assert_eq!(quota_inc(&pool, user_id, 1, LIMIT).await, 0, "and one byte more is refused");
assert_eq!(
quota_inc(&pool, user_id, 1, LIMIT).await,
0,
"and one byte more is refused"
);
}
// ─────────────────────────────────────────────────────────────────────────────
@@ -140,11 +151,13 @@ async fn lock_and_read_event(
tx: &mut sqlx::PgConnection,
event_id: Uuid,
) -> (Option<DateTime<Utc>>, Option<DateTime<Utc>>) {
sqlx::query_as("SELECT uploads_locked_at, export_released_at FROM event WHERE id = $1 FOR SHARE")
.bind(event_id)
.fetch_one(tx)
.await
.expect("FOR SHARE re-check")
sqlx::query_as(
"SELECT uploads_locked_at, export_released_at FROM event WHERE id = $1 FOR SHARE",
)
.bind(event_id)
.fetch_one(tx)
.await
.expect("FOR SHARE re-check")
}
/// THE GUARD AGAINST SILENT, PERMANENT PHOTO LOSS.
@@ -167,7 +180,10 @@ async fn for_share_upload_lock_serializes_against_release(pool: PgPool) {
// ── The guest's upload transaction takes the share lock. ──
let mut upload_tx = pool.begin().await.unwrap();
let (locked, released) = lock_and_read_event(&mut upload_tx, event_id).await;
assert!(locked.is_none() && released.is_none(), "uploads are open, so we proceed to commit");
assert!(
locked.is_none() && released.is_none(),
"uploads are open, so we proceed to commit"
);
// ── Concurrently, the host hits "Galerie freigeben". ──
let release_done = Arc::new(AtomicBool::new(false));
@@ -230,7 +246,11 @@ async fn for_share_upload_lock_serializes_against_release(pool: PgPool) {
.fetch_all(&pool)
.await
.unwrap();
assert_eq!(snapshot, vec![upload_id], "the released keepsake CONTAINS the in-flight photo");
assert_eq!(
snapshot,
vec![upload_id],
"the released keepsake CONTAINS the in-flight photo"
);
}
/// The other side of the same lock: once the release has COMMITTED, the next upload's `FOR SHARE`
@@ -255,14 +275,23 @@ async fn upload_after_release_commits_sees_the_lock_and_is_rejected(pool: PgPool
// After it, the identical re-check sees the release and the handler bails out.
let mut tx = pool.begin().await.unwrap();
let (locked, released) = lock_and_read_event(&mut tx, event_id).await;
assert!(released.is_some(), "the FOR SHARE re-read MUST observe the committed release");
assert!(locked.is_some(), "release locks uploads in the same statement (release ⇒ lock)");
assert!(
released.is_some(),
"the FOR SHARE re-read MUST observe the committed release"
);
assert!(
locked.is_some(),
"release locks uploads in the same statement (release ⇒ lock)"
);
tx.rollback().await.unwrap();
// And a reopen makes it uploadable again — the rejection was reversible, not terminal.
assert_eq!(open_event(&pool, "wedding").await, 1);
let mut tx = pool.begin().await.unwrap();
let (locked, released) = lock_and_read_event(&mut tx, event_id).await;
assert!(locked.is_none() && released.is_none(), "the guest can resume their upload");
assert!(
locked.is_none() && released.is_none(),
"the guest can resume their upload"
);
tx.rollback().await.unwrap();
}