use std::time::{Duration, Instant};
#[tokio::test]
async fn async_hash_then_verify_round_trips() {
let hash = umbral_auth::hash_password_async("correct horse battery staple")
.await
.expect("hashing succeeds");
assert!(
umbral_auth::verify_password_async("correct horse battery staple", &hash)
.await
.expect("verify of correct password does not error"),
"the right password verifies"
);
assert!(
!umbral_auth::verify_password_async("wrong password", &hash)
.await
.expect("verify of wrong password is Ok(false), not an error"),
"the wrong password does not verify"
);
}
#[tokio::test]
async fn async_helpers_match_the_sync_helpers() {
let async_hash = umbral_auth::hash_password_async("shared-secret")
.await
.unwrap();
assert!(umbral_auth::verify_password("shared-secret", &async_hash).unwrap());
let sync_hash = umbral_auth::hash_password("shared-secret").unwrap();
assert!(
umbral_auth::verify_password_async("shared-secret", &sync_hash)
.await
.unwrap()
);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn argon2_burst_does_not_starve_the_single_worker() {
let hashes = (0..8)
.map(|i| {
tokio::spawn(async move {
umbral_auth::hash_password_async(&format!("pw-{i}"))
.await
.unwrap()
})
})
.collect::<Vec<_>>();
let t0 = Instant::now();
tokio::task::yield_now().await;
tokio::time::sleep(Duration::from_millis(5)).await;
assert!(
t0.elapsed() < Duration::from_millis(300),
"the single worker stayed responsive during the hash burst (elapsed {:?}); \
if this failed, argon2 ran on the worker thread, not spawn_blocking",
t0.elapsed()
);
for h in hashes {
let hash = h.await.unwrap();
assert!(hash.starts_with("$argon2"), "produced a PHC argon2 hash");
}
}