Skip to main content

max / makenotwork

Pin the storage-cap CAS contract at the DB layer /audit Run 13 Testing cold spot (money-DB illusory coverage): the storage cap's atomic conditional-UPDATE was exercised only indirectly through upload flows. Add DB-layer contract tests in db_payments_layer.rs: - an increment within the cap succeeds and updates the count - an increment past the cap is rejected and leaves the count unchanged - two concurrent over-cap increments: exactly one succeeds and the cap holds (the CAS never lets the total exceed the limit under a race) Made db::creator_tiers `pub` to match its already-`pub` DB-contract-tested siblings (license_keys, tips, pending_refunds); the lib has no external consumer, so this is test visibility only. 3 new tests green; clippy --tests clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-01 22:03 UTC
Commit: 21e12d070a4f5c52fd0a237a40fd36b754c80c2b
Parent: 4462fab
2 files changed, +73 insertions, -1 deletion
@@ -54,7 +54,7 @@ pub(crate) mod fan_plus;
54 54 pub(crate) mod collections;
55 55 pub(crate) mod ota;
56 56 pub(crate) mod builds;
57 - pub(crate) mod creator_tiers;
57 + pub mod creator_tiers;
58 58 pub(crate) mod mailing_lists;
59 59 pub mod custom_domains;
60 60 pub mod patches;
@@ -319,3 +319,75 @@ async fn try_create_activation_enforces_max_activations() {
319 319 "a revoked key must not activate"
320 320 );
321 321 }
322 +
323 + // ── db::creator_tiers — storage-cap compare-and-set (Run 13 Test) ──
324 + // The storage-cap enforcement was "illusory coverage": the atomic
325 + // conditional-UPDATE was exercised only indirectly through upload flows. Pin the
326 + // CAS contract at the DB layer: it must never let the cap be exceeded, including
327 + // under a concurrent race.
328 +
329 + #[tokio::test]
330 + async fn storage_increment_succeeds_under_cap() {
331 + let mut h = TestHarness::new().await;
332 + let user = h.create_creator("storagecap_under").await;
333 +
334 + db::creator_tiers::try_increment_storage(&h.db, user, 400, 1000)
335 + .await
336 + .expect("an increment within the cap must succeed");
337 +
338 + let used: i64 = sqlx::query_scalar("SELECT storage_used_bytes FROM users WHERE id = $1")
339 + .bind(user)
340 + .fetch_one(&h.db)
341 + .await
342 + .unwrap();
343 + assert_eq!(used, 400);
344 + }
345 +
346 + #[tokio::test]
347 + async fn storage_increment_past_cap_is_rejected_and_leaves_count_unchanged() {
348 + let mut h = TestHarness::new().await;
349 + let user = h.create_creator("storagecap_reject").await;
350 +
351 + db::creator_tiers::try_increment_storage(&h.db, user, 800, 1000)
352 + .await
353 + .unwrap();
354 + // 800 + 300 = 1100 > 1000 → rejected.
355 + assert!(
356 + db::creator_tiers::try_increment_storage(&h.db, user, 300, 1000).await.is_err(),
357 + "an increment past the cap must fail"
358 + );
359 +
360 + let used: i64 = sqlx::query_scalar("SELECT storage_used_bytes FROM users WHERE id = $1")
361 + .bind(user)
362 + .fetch_one(&h.db)
363 + .await
364 + .unwrap();
365 + assert_eq!(used, 800, "a rejected increment must not change the stored count");
366 + }
367 +
368 + #[tokio::test]
369 + async fn storage_increment_concurrent_never_exceeds_cap() {
370 + let mut h = TestHarness::new().await;
371 + let user = h.create_creator("storagecap_race").await;
372 +
373 + // Cap 900, starting at 0. Two concurrent +500 increments: only one fits
374 + // (0+500 ok → 500; the other then sees 500, 500+500=1000 > 900 → rejected).
375 + let (p1, p2) = (h.db.clone(), h.db.clone());
376 + let a = tokio::spawn(async move {
377 + db::creator_tiers::try_increment_storage(&p1, user, 500, 900).await
378 + });
379 + let b = tokio::spawn(async move {
380 + db::creator_tiers::try_increment_storage(&p2, user, 500, 900).await
381 + });
382 + let (ra, rb) = (a.await.unwrap(), b.await.unwrap());
383 +
384 + let succeeded = [ra.is_ok(), rb.is_ok()].iter().filter(|x| **x).count();
385 + assert_eq!(succeeded, 1, "exactly one of two racing over-cap increments may succeed");
386 +
387 + let used: i64 = sqlx::query_scalar("SELECT storage_used_bytes FROM users WHERE id = $1")
388 + .bind(user)
389 + .fetch_one(&h.db)
390 + .await
391 + .unwrap();
392 + assert_eq!(used, 500, "the cap holds under a race: total is 500, never 1000");
393 + }