Skip to main content

max / makenotwork

test: mint SyncKit JWT directly in per-key tests The HTTP /api/sync/auth path is rate-limited at 1/sec + burst 5. The per-key isolation test re-auths three times in quick succession, which fits inside the local-Debug-build timing but blows the burst on release-mode astra. Switch to create_sync_token directly — the auth handler still gets full coverage from the existing synckit.rs workflow tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-22 00:36 UTC
Commit: 6e4f24cbc425cfe0375ac27126cfd78906d55126
Parent: 6586d77
1 file changed, +22 insertions, -42 deletions
@@ -7,7 +7,6 @@
7 7
8 8 use crate::harness::{BuildOptions, TestHarness, stripe, storage::InMemoryStorage, client::TestResponse};
9 9 use makenotwork::db::{SyncAppId, UserId};
10 - use serde::Deserialize;
11 10 use serde_json::json;
12 11 use sqlx::PgPool;
13 12 use std::sync::Arc;
@@ -109,38 +108,19 @@ async fn claim_key(h: &mut TestHarness, api_key: &str, key: &str) {
109 108 assert_eq!(resp.status, 200, "claim_key {} failed: {}", key, resp.text);
110 109 }
111 110
112 - /// Run `/api/sync/auth` with the given key, set the bearer token on the
113 - /// client, and return the resolved (user_id, app_id) pair.
114 - async fn auth_as(
115 - h: &mut TestHarness,
116 - email: &str,
117 - password: &str,
118 - api_key: &str,
119 - key: &str,
120 - ) -> (UserId, SyncAppId) {
121 - #[derive(Deserialize)]
122 - struct AuthResp {
123 - token: String,
124 - user_id: UserId,
125 - app_id: SyncAppId,
126 - }
127 - let resp = h
128 - .client
129 - .post_json(
130 - "/api/sync/auth",
131 - &json!({
132 - "email": email,
133 - "password": password,
134 - "api_key": api_key,
135 - "key": key,
136 - })
137 - .to_string(),
138 - )
139 - .await;
140 - assert_eq!(resp.status, 200, "/api/sync/auth (key={}) failed: {}", key, resp.text);
141 - let body: AuthResp = resp.json();
142 - h.client.set_bearer_token(&body.token);
143 - (body.user_id, body.app_id)
111 + /// Mint a SyncKit JWT directly via `create_sync_token` and set it as the
112 + /// bearer token. Bypasses `/api/sync/auth` so the test doesn't blow the
113 + /// `SYNCKIT_AUTH_RATE_LIMIT_PER_SEC` budget when switching keys repeatedly —
114 + /// the rate limiter is real-environment-correct but punishes burst-y tests.
115 + fn auth_as(h: &mut TestHarness, user_id: UserId, app_id: SyncAppId, key: &str) {
116 + let token = makenotwork::synckit_auth::create_sync_token(
117 + "test-synckit-jwt-secret",
118 + user_id,
119 + app_id,
120 + key,
121 + )
122 + .expect("mint test JWT");
123 + h.client.set_bearer_token(&token);
144 124 }
145 125
146 126 /// 64-lowercase-hex hash for a given seed byte.
@@ -217,8 +197,8 @@ async fn per_key_full_blocks_only_that_key_other_keys_keep_uploading() {
217 197 .unwrap();
218 198
219 199 // Key A: any additional byte must trip the per-key cap.
220 - let (uid_a, _) = auth_as(&mut h, "perkey1@example.com", "Password1!", &api_key, "A").await;
221 - let resp = upload_and_confirm(&mut h, &blobs, app_id, uid_a, &fake_hash(0xaa), 1).await;
200 + auth_as(&mut h, user_id, app_id, "A");
201 + let resp = upload_and_confirm(&mut h, &blobs, app_id, user_id, &fake_hash(0xaa), 1).await;
222 202 assert_eq!(resp.status, 402, "expected 402 on key A: {}", resp.text);
223 203 let body: serde_json::Value = serde_json::from_str(&resp.text).expect("json body");
224 204 assert_eq!(body["reason"], "storage_limit_reached");
@@ -227,13 +207,13 @@ async fn per_key_full_blocks_only_that_key_other_keys_keep_uploading() {
227 207 assert_eq!(body["limit"], GIB);
228 208
229 209 // Key B: same app, sibling key — must succeed.
230 - let (uid_b, _) = auth_as(&mut h, "perkey1@example.com", "Password1!", &api_key, "B").await;
231 - let resp = upload_and_confirm(&mut h, &blobs, app_id, uid_b, &fake_hash(0xbb), 1_000).await;
210 + auth_as(&mut h, user_id, app_id, "B");
211 + let resp = upload_and_confirm(&mut h, &blobs, app_id, user_id, &fake_hash(0xbb), 1_000).await;
232 212 assert_eq!(resp.status, 204, "key B confirm should succeed: {}", resp.text);
233 213
234 214 // Key C: also fine.
235 - let (uid_c, _) = auth_as(&mut h, "perkey1@example.com", "Password1!", &api_key, "C").await;
236 - let resp = upload_and_confirm(&mut h, &blobs, app_id, uid_c, &fake_hash(0xcc), 2_000).await;
215 + auth_as(&mut h, user_id, app_id, "C");
216 + let resp = upload_and_confirm(&mut h, &blobs, app_id, user_id, &fake_hash(0xcc), 2_000).await;
237 217 assert_eq!(resp.status, 204, "key C confirm should succeed: {}", resp.text);
238 218
239 219 // Per-key counters should reflect B's and C's adds; A's is unchanged.
@@ -269,13 +249,13 @@ async fn per_key_full_blocks_only_that_key_other_keys_keep_uploading() {
269 249 async fn bulk_mode_returns_storage_dimension_without_key() {
270 250 let (mut h, blobs) = harness_with_billing_and_blobs().await;
271 251 let user_id = h.signup("bulk1", "bulk1@example.com", "Password1!").await;
272 - let (app_id, api_key) = create_draft_app(&h.db, user_id).await;
252 + let (app_id, _api_key) = create_draft_app(&h.db, user_id).await;
273 253
274 254 activate_bulk(&mut h, app_id, 1).await; // 1 GiB app-wide
275 255
276 256 // Bulk mode never calls claim_key but the JWT still requires *some* key
277 257 // string; pick any opaque value (developer's choice).
278 - let (uid, _) = auth_as(&mut h, "bulk1@example.com", "Password1!", &api_key, "single").await;
258 + auth_as(&mut h, user_id, app_id, "single");
279 259
280 260 // Pre-fill the app counter to cap.
281 261 sqlx::query("UPDATE sync_app_usage_current SET bytes_stored = $2 WHERE app_id = $1")
@@ -285,7 +265,7 @@ async fn bulk_mode_returns_storage_dimension_without_key() {
285 265 .await
286 266 .unwrap();
287 267
288 - let resp = upload_and_confirm(&mut h, &blobs, app_id, uid, &fake_hash(0x11), 1).await;
268 + let resp = upload_and_confirm(&mut h, &blobs, app_id, user_id, &fake_hash(0x11), 1).await;
289 269 assert_eq!(resp.status, 402, "expected 402 on bulk cap: {}", resp.text);
290 270 let body: serde_json::Value = serde_json::from_str(&resp.text).expect("json");
291 271 assert_eq!(body["reason"], "storage_limit_reached");