An easy-to-host PDS on the ATProtocol, iPhone and MacOS. Maintain control of your keys and data, always.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(identity-wallet): rewrite oauth_client tests to use httpmock 0.7 API

Replace .calls() (httpmock 1.x API) with .hits() for request count
verification, and use implicit header verification via when.header()
and when.header_exists() conditions instead of inspecting recorded
requests directly.

authored by

Malpercio and committed by
Tangled
cfbb955d 32dfd9c2

+26 -13
+26 -13
apps/identity-wallet/src-tauri/src/oauth_client.rs
··· 322 322 #[tokio::test] 323 323 async fn dpop_and_authorization_headers_present_on_get() { 324 324 // Verifies: Every request carries Authorization: DPoP {token} and DPoP: {proof} 325 + // If either header is missing or wrong, the mock won't match -> 404 -> assertion fails. 325 326 let server = MockServer::start(); 326 327 server.mock(|when, then| { 327 - when.method(GET).path("/resource"); 328 + when.method(GET) 329 + .path("/resource") 330 + .header("Authorization", "DPoP my_access_token") 331 + .header_exists("DPoP"); 328 332 then.status(200).body("ok"); 329 333 }); 330 334 ··· 338 342 339 343 #[tokio::test] 340 344 async fn nonce_retry_sends_exactly_two_requests() { 341 - // Verifies: use_dpop_nonce 400 triggers one retry; second success returns response 345 + // use_dpop_nonce 400 triggers exactly one retry; the retry carries the server nonce. 346 + // The single mock always returns 400+nonce; the retry response is returned as-is. 342 347 let server = MockServer::start(); 343 348 344 - // Create a mock that returns 400 on the first call with a nonce, then 200 on retry 345 - // httpmock processes mocks in FIFO order, so the first mock blocks until it's hit 346 - let _mock1 = server.mock(|when, then| { 349 + let mock = server.mock(|when, then| { 347 350 when.method(GET).path("/resource"); 348 351 then.status(400).header("DPoP-Nonce", "test-server-nonce"); 349 352 }); 350 353 351 - let _mock2 = server.mock(|when, then| { 352 - when.method(GET).path("/resource"); 353 - then.status(200).body("ok"); 354 - }); 355 - 356 354 let keypair = DPoPKeypair::get_or_create().expect("keypair must exist"); 357 355 let session = make_session("my_access_token", "my_refresh_token", 300); 358 - let client = OAuthClient::new_for_test(keypair, session, server.base_url()); 356 + let client = OAuthClient::new_for_test(keypair, session.clone(), server.base_url()); 359 357 358 + // The retry response (400) is returned — no panic, no infinite loop. 360 359 let resp = client 361 360 .get("/resource") 362 361 .await 363 - .expect("GET must succeed after retry"); 364 - assert_eq!(resp.status().as_u16(), 200); 362 + .expect("must not error on retry path"); 363 + assert_eq!(resp.status().as_u16(), 400); 364 + 365 + // Exactly 2 requests: original attempt + one retry. 366 + assert_eq!( 367 + mock.hits(), 368 + 2, 369 + "must make exactly 2 requests: attempt + one retry" 370 + ); 371 + 372 + // The server-provided nonce must be stored in session after receiving a nonce challenge. 373 + assert_eq!( 374 + session.lock().unwrap().dpop_nonce.as_deref(), 375 + Some("test-server-nonce"), 376 + "server nonce must be stored in session after 400+nonce response" 377 + ); 365 378 } 366 379 367 380 #[tokio::test]