Further test improvements (#1166)

This commit is contained in:
Firstyear 2022-11-02 19:46:09 +10:00 committed by GitHub
parent df4043cf10
commit 692c0a3978
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 733 additions and 649 deletions

View file

@ -97,3 +97,84 @@ pub(crate) fn qs_test(_args: &TokenStream, item: TokenStream, with_init: bool) -
result.into()
}
pub(crate) fn idm_test(_args: &TokenStream, item: TokenStream) -> TokenStream {
let input: syn::ItemFn = match syn::parse(item.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
if let Some(attr) = input.attrs.iter().find(|attr| attr.path.is_ident("test")) {
let msg = "second test attribute is supplied";
return token_stream_with_error(item, syn::Error::new_spanned(&attr, msg));
};
if input.sig.asyncness.is_none() {
let msg = "the `async` keyword is missing from the function declaration";
return token_stream_with_error(item, syn::Error::new_spanned(input.sig.fn_token, msg));
}
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, _last_stmt_end_span) = {
let mut last_stmt = input
.block
.stmts
.last()
.map(ToTokens::into_token_stream)
.unwrap_or_default()
.into_iter();
// `Span` on stable Rust has a limitation that only points to the first
// token, not the whole tokens. We can work around this limitation by
// using the first/last span of the tokens like
// `syn::Error::new_spanned` does.
let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
let end = last_stmt.last().map_or(start, |t| t.span());
(start, end)
};
let rt = quote_spanned! {last_stmt_start_span=>
tokio::runtime::Builder::new_current_thread()
};
let header = quote! {
#[::core::prelude::v1::test]
};
let test_fn = &input.sig.ident;
let test_driver = Ident::new(&format!("idm_{}", test_fn), input.sig.span());
// Effectively we are just injecting a real test function around this which we will
// call.
let result = quote! {
#input
#header
fn #test_driver() {
let body = async {
let (test_server, mut idms_delayed) = crate::testkit::setup_idm_test().await;
#test_fn(&test_server, &mut idms_delayed).await;
// Any needed teardown?
// Make sure there are no errors.
let mut idm_read_txn = test_server.proxy_read().await;
let verifications = idm_read_txn.qs_read.verify();
trace!("Verification result: {:?}", verifications);
assert!(verifications.len() == 0);
idms_delayed.check_is_empty_or_panic();
};
#[allow(clippy::expect_used, clippy::diverging_sub_expression)]
{
return #rt
.enable_all()
.build()
.expect("Failed building the Runtime")
.block_on(body);
}
}
};
result.into()
}

View file

@ -26,3 +26,8 @@ pub fn qs_test(args: TokenStream, item: TokenStream) -> TokenStream {
pub fn qs_test_no_init(args: TokenStream, item: TokenStream) -> TokenStream {
entry::qs_test(&args, item, false)
}
#[proc_macro_attribute]
pub fn idm_test(args: TokenStream, item: TokenStream) -> TokenStream {
entry::idm_test(&args, item)
}

View file

@ -1,15 +1,11 @@
use std::time::{Duration, Instant};
use async_std::task;
use criterion::{
criterion_group, criterion_main, BenchmarkId, Criterion, SamplingMode, Throughput,
};
use kanidmd_lib;
use kanidmd_lib::entry::{Entry, EntryInit, EntryNew};
use kanidmd_lib::entry_init;
use kanidmd_lib::idm::server::{IdmServer, IdmServerDelayed};
use kanidmd_lib::macros::run_idm_test_no_logging;
use kanidmd_lib::server::QueryServer;
use kanidmd_lib::utils::duration_from_epoch_now;
use kanidmd_lib::value::Value;
@ -28,14 +24,19 @@ pub fn scaling_user_create_single(c: &mut Criterion) {
println!("iters, size -> {:?}, {:?}", iters, size);
for _i in 0..iters {
run_idm_test_no_logging(
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let ct = duration_from_epoch_now();
let mut rt = tokio::runtime::Builder::new_current_thread();
elapsed = rt
.enable_all()
.build()
.expect("Failed building the Runtime")
.block_on(async {
let (idms, _idms_delayed) =
kanidmd_lib::testkit::setup_idm_test().await;
let ct = duration_from_epoch_now();
let start = Instant::now();
for counter in 0..size {
let idms_prox_write = task::block_on(idms.proxy_write_async(ct));
let mut idms_prox_write = idms.proxy_write(ct).await;
let name = format!("testperson_{}", counter);
let e1 = entry_init!(
("class", Value::new_class("object")),
@ -51,9 +52,8 @@ pub fn scaling_user_create_single(c: &mut Criterion) {
idms_prox_write.commit().expect("Must not fail");
}
elapsed = elapsed.checked_add(start.elapsed()).unwrap();
},
);
elapsed.checked_add(start.elapsed()).unwrap()
});
}
elapsed
});
@ -92,20 +92,25 @@ pub fn scaling_user_create_batched(c: &mut Criterion) {
.collect();
for _i in 0..iters {
kanidmd_lib::macros::run_idm_test_no_logging(
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let ct = duration_from_epoch_now();
let mut rt = tokio::runtime::Builder::new_current_thread();
elapsed = rt
.enable_all()
.build()
.expect("Failed building the Runtime")
.block_on(async {
let (idms, _idms_delayed) =
kanidmd_lib::testkit::setup_idm_test().await;
let ct = duration_from_epoch_now();
let start = Instant::now();
let idms_prox_write = task::block_on(idms.proxy_write_async(ct));
let mut idms_prox_write = idms.proxy_write(ct).await;
let cr = idms_prox_write.qs_write.internal_create(data.clone());
assert!(cr.is_ok());
idms_prox_write.commit().expect("Must not fail");
elapsed = elapsed.checked_add(start.elapsed()).unwrap();
},
);
elapsed.checked_add(start.elapsed()).unwrap()
});
}
elapsed
});

View file

@ -1472,7 +1472,6 @@ impl<'a> IdmServerCredUpdateTransaction<'a> {
mod tests {
use std::time::Duration;
use async_std::task;
use kanidm_proto::v1::{AuthAllowed, AuthIssueSession, AuthMech, CredentialDetailType};
use uuid::uuid;
use webauthn_authenticator_rs::softpasskey::SoftPasskey;
@ -1494,13 +1493,13 @@ mod tests {
const TEST_CURRENT_TIME: u64 = 6000;
const TESTPERSON_UUID: Uuid = uuid!("cf231fea-1a8f-4410-a520-fd9b1a379c86");
#[test]
fn test_idm_credential_update_session_init() {
run_idm_test!(|_qs: &QueryServer,
#[idm_test]
async fn test_idm_credential_update_session_init(
idms: &IdmServer,
_idms_delayed: &mut IdmServerDelayed| {
_idms_delayed: &mut IdmServerDelayed,
) {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let mut idms_prox_write = idms.proxy_write(ct).await;
let testaccount_uuid = Uuid::new_v4();
@ -1600,14 +1599,13 @@ mod tests {
trace!(?cur);
assert!(cur.is_err());
})
}
fn setup_test_session(
async fn setup_test_session(
idms: &IdmServer,
ct: Duration,
) -> (CredentialUpdateSessionToken, CredentialUpdateSessionStatus) {
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let mut idms_prox_write = idms.proxy_write(ct).await;
let e2 = entry_init!(
("class", Value::new_class("object")),
@ -1638,11 +1636,11 @@ mod tests {
cur.expect("Failed to start update")
}
fn renew_test_session(
async fn renew_test_session(
idms: &IdmServer,
ct: Duration,
) -> (CredentialUpdateSessionToken, CredentialUpdateSessionStatus) {
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let mut idms_prox_write = idms.proxy_write(ct).await;
let testperson = idms_prox_write
.qs_write
@ -1659,8 +1657,8 @@ mod tests {
cur.expect("Failed to start update")
}
fn commit_session(idms: &IdmServer, ct: Duration, cust: CredentialUpdateSessionToken) {
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
async fn commit_session(idms: &IdmServer, ct: Duration, cust: CredentialUpdateSessionToken) {
let mut idms_prox_write = idms.proxy_write(ct).await;
idms_prox_write
.commit_credential_update(&cust, ct)
@ -1669,7 +1667,7 @@ mod tests {
idms_prox_write.commit().expect("Failed to commit txn");
}
fn check_testperson_password(
async fn check_testperson_password(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
pw: &str,
@ -1679,7 +1677,7 @@ mod tests {
let auth_init = AuthEvent::named_init("testperson");
let r1 = task::block_on(idms_auth.auth(&auth_init, ct));
let r1 = idms_auth.auth(&auth_init, ct).await;
let ar = r1.unwrap();
let AuthResult {
sessionid,
@ -1694,7 +1692,7 @@ mod tests {
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::Password);
let r2 = task::block_on(idms_auth.auth(&auth_begin, ct));
let r2 = idms_auth.auth(&auth_begin, ct).await;
let ar = r2.unwrap();
let AuthResult {
sessionid,
@ -1707,7 +1705,7 @@ mod tests {
let pw_step = AuthEvent::cred_step_password(sessionid, pw);
// Expect success
let r2 = task::block_on(idms_auth.auth(&pw_step, ct));
let r2 = idms_auth.auth(&pw_step, ct).await;
debug!("r2 ==> {:?}", r2);
idms_auth.commit().expect("Must not fail");
@ -1727,7 +1725,7 @@ mod tests {
}
}
fn check_testperson_password_totp(
async fn check_testperson_password_totp(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
pw: &str,
@ -1738,7 +1736,7 @@ mod tests {
let auth_init = AuthEvent::named_init("testperson");
let r1 = task::block_on(idms_auth.auth(&auth_init, ct));
let r1 = idms_auth.auth(&auth_init, ct).await;
let ar = r1.unwrap();
let AuthResult {
sessionid,
@ -1753,7 +1751,7 @@ mod tests {
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::PasswordMfa);
let r2 = task::block_on(idms_auth.auth(&auth_begin, ct));
let r2 = idms_auth.auth(&auth_begin, ct).await;
let ar = r2.unwrap();
let AuthResult {
sessionid,
@ -1768,7 +1766,7 @@ mod tests {
.expect("Failed to perform totp step");
let totp_step = AuthEvent::cred_step_totp(sessionid, totp);
let r2 = task::block_on(idms_auth.auth(&totp_step, ct));
let r2 = idms_auth.auth(&totp_step, ct).await;
let ar = r2.unwrap();
let AuthResult {
sessionid,
@ -1781,7 +1779,7 @@ mod tests {
let pw_step = AuthEvent::cred_step_password(sessionid, pw);
// Expect success
let r3 = task::block_on(idms_auth.auth(&pw_step, ct));
let r3 = idms_auth.auth(&pw_step, ct).await;
debug!("r3 ==> {:?}", r3);
idms_auth.commit().expect("Must not fail");
@ -1800,7 +1798,7 @@ mod tests {
}
}
fn check_testperson_password_backup_code(
async fn check_testperson_password_backup_code(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
pw: &str,
@ -1811,7 +1809,7 @@ mod tests {
let auth_init = AuthEvent::named_init("testperson");
let r1 = task::block_on(idms_auth.auth(&auth_init, ct));
let r1 = idms_auth.auth(&auth_init, ct).await;
let ar = r1.unwrap();
let AuthResult {
sessionid,
@ -1826,7 +1824,7 @@ mod tests {
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::PasswordMfa);
let r2 = task::block_on(idms_auth.auth(&auth_begin, ct));
let r2 = idms_auth.auth(&auth_begin, ct).await;
let ar = r2.unwrap();
let AuthResult {
sessionid,
@ -1837,7 +1835,7 @@ mod tests {
assert!(matches!(state, AuthState::Continue(_)));
let code_step = AuthEvent::cred_step_backup_code(sessionid, code);
let r2 = task::block_on(idms_auth.auth(&code_step, ct));
let r2 = idms_auth.auth(&code_step, ct).await;
let ar = r2.unwrap();
let AuthResult {
sessionid,
@ -1850,7 +1848,7 @@ mod tests {
let pw_step = AuthEvent::cred_step_password(sessionid, pw);
// Expect success
let r3 = task::block_on(idms_auth.auth(&pw_step, ct));
let r3 = idms_auth.auth(&pw_step, ct).await;
debug!("r3 ==> {:?}", r3);
idms_auth.commit().expect("Must not fail");
@ -1863,7 +1861,7 @@ mod tests {
// There now should be a backup code invalidation present
let da = idms_delayed.try_recv().expect("invalid");
assert!(matches!(da, DelayedAction::BackupCodeRemoval(_)));
let r = task::block_on(idms.delayed_action(ct, da));
let r = idms.delayed_action(ct, da).await;
assert!(r.is_ok());
// Process the auth session
@ -1875,7 +1873,7 @@ mod tests {
}
}
fn check_testperson_passkey(
async fn check_testperson_passkey(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
wa: &mut WebauthnAuthenticator<SoftPasskey>,
@ -1886,7 +1884,7 @@ mod tests {
let auth_init = AuthEvent::named_init("testperson");
let r1 = task::block_on(idms_auth.auth(&auth_init, ct));
let r1 = idms_auth.auth(&auth_init, ct).await;
let ar = r1.unwrap();
let AuthResult {
sessionid,
@ -1901,7 +1899,7 @@ mod tests {
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::Passkey);
let r2 = task::block_on(idms_auth.auth(&auth_begin, ct));
let r2 = idms_auth.auth(&auth_begin, ct).await;
let ar = r2.unwrap();
let AuthResult {
sessionid,
@ -1927,7 +1925,7 @@ mod tests {
let passkey_step = AuthEvent::cred_step_passkey(sessionid, resp);
let r3 = task::block_on(idms_auth.auth(&passkey_step, ct));
let r3 = idms_auth.auth(&passkey_step, ct).await;
debug!("r3 ==> {:?}", r3);
idms_auth.commit().expect("Must not fail");
@ -1940,7 +1938,7 @@ mod tests {
// Process the webauthn update
let da = idms_delayed.try_recv().expect("invalid");
assert!(matches!(da, DelayedAction::WebauthnCounterIncrement(_)));
let r = task::block_on(idms.delayed_action(ct, da));
let r = idms.delayed_action(ct, da).await;
assert!(r.is_ok());
// Process the auth session
@ -1953,13 +1951,13 @@ mod tests {
}
}
#[test]
fn test_idm_credential_update_session_cleanup() {
run_idm_test!(|_qs: &QueryServer,
#[idm_test]
async fn test_idm_credential_update_session_cleanup(
idms: &IdmServer,
_idms_delayed: &mut IdmServerDelayed| {
_idms_delayed: &mut IdmServerDelayed,
) {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (cust, _) = setup_test_session(idms, ct);
let (cust, _) = setup_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
// The session exists
@ -1968,7 +1966,8 @@ mod tests {
drop(cutxn);
// Making a new session is what triggers the clean of old sessions.
let _ = renew_test_session(idms, ct + MAXIMUM_CRED_UPDATE_TTL + Duration::from_secs(1));
let (_cust, _) =
renew_test_session(idms, ct + MAXIMUM_CRED_UPDATE_TTL + Duration::from_secs(1)).await;
let cutxn = idms.cred_update_transaction();
@ -1978,18 +1977,17 @@ mod tests {
.credential_update_status(&cust, ct)
.expect_err("Session is still valid!");
assert!(matches!(c_status, OperationError::InvalidState));
})
}
#[test]
fn test_idm_credential_update_onboarding_create_new_pw() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
let test_pw =
"fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
#[idm_test]
async fn test_idm_credential_update_onboarding_create_new_pw(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
) {
let test_pw = "fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (cust, _) = setup_test_session(idms, ct);
let (cust, _) = setup_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
@ -2013,13 +2011,15 @@ mod tests {
assert!(c_status.can_commit);
drop(cutxn);
commit_session(idms, ct, cust);
commit_session(idms, ct, cust).await;
// Check it works!
assert!(check_testperson_password(idms, idms_delayed, test_pw, ct).is_some());
assert!(check_testperson_password(idms, idms_delayed, test_pw, ct)
.await
.is_some());
// Test deleting the pw
let (cust, _) = renew_test_session(idms, ct);
let (cust, _) = renew_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
let c_status = cutxn
@ -2035,12 +2035,12 @@ mod tests {
assert!(c_status.primary.is_none());
drop(cutxn);
commit_session(idms, ct, cust);
commit_session(idms, ct, cust).await;
// Must fail now!
assert!(check_testperson_password(idms, idms_delayed, test_pw, ct).is_none());
}
)
assert!(check_testperson_password(idms, idms_delayed, test_pw, ct)
.await
.is_none());
}
// Test set of primary account password
@ -2048,15 +2048,15 @@ mod tests {
// - set correctly.
// - setup TOTP
#[test]
fn test_idm_credential_update_onboarding_create_new_mfa_totp_basic() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
let test_pw =
"fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
#[idm_test]
async fn test_idm_credential_update_onboarding_create_new_mfa_totp_basic(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
) {
let test_pw = "fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (cust, _) = setup_test_session(idms, ct);
let (cust, _) = setup_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
// Setup the PW
@ -2108,21 +2108,18 @@ mod tests {
// Should be okay now!
drop(cutxn);
commit_session(idms, ct, cust);
commit_session(idms, ct, cust).await;
// Check it works!
assert!(check_testperson_password_totp(
idms,
idms_delayed,
test_pw,
&totp_token,
ct
)
.is_some());
assert!(
check_testperson_password_totp(idms, idms_delayed, test_pw, &totp_token, ct)
.await
.is_some()
);
// No need to test delete of the whole cred, we already did with pw above.
// If we remove TOTP, show it reverts back.
let (cust, _) = renew_test_session(idms, ct);
let (cust, _) = renew_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
let c_status = cutxn
@ -2136,24 +2133,24 @@ mod tests {
));
drop(cutxn);
commit_session(idms, ct, cust);
commit_session(idms, ct, cust).await;
// Check it works with totp removed.
assert!(check_testperson_password(idms, idms_delayed, test_pw, ct).is_some());
}
)
assert!(check_testperson_password(idms, idms_delayed, test_pw, ct)
.await
.is_some());
}
// Check sha1 totp.
#[test]
fn test_idm_credential_update_onboarding_create_new_mfa_totp_sha1() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
let test_pw =
"fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
#[idm_test]
async fn test_idm_credential_update_onboarding_create_new_mfa_totp_sha1(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
) {
let test_pw = "fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (cust, _) = setup_test_session(idms, ct);
let (cust, _) = setup_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
// Setup the PW
@ -2208,31 +2205,26 @@ mod tests {
// Should be okay now!
drop(cutxn);
commit_session(idms, ct, cust);
commit_session(idms, ct, cust).await;
// Check it works!
assert!(check_testperson_password_totp(
idms,
idms_delayed,
test_pw,
&totp_token,
ct
)
.is_some());
assert!(
check_testperson_password_totp(idms, idms_delayed, test_pw, &totp_token, ct)
.await
.is_some()
);
// No need to test delete, we already did with pw above.
}
)
}
#[test]
fn test_idm_credential_update_onboarding_create_new_mfa_totp_backup_codes() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
let test_pw =
"fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
#[idm_test]
async fn test_idm_credential_update_onboarding_create_new_mfa_totp_backup_codes(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
) {
let test_pw = "fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (cust, _) = setup_test_session(idms, ct);
let (cust, _) = setup_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
// Setup the PW
@ -2293,7 +2285,7 @@ mod tests {
// Should be okay now!
drop(cutxn);
commit_session(idms, ct, cust);
commit_session(idms, ct, cust).await;
let backup_code = codes.iter().next().expect("No codes available");
@ -2305,10 +2297,11 @@ mod tests {
backup_code,
ct
)
.await
.is_some());
// Renew to start the next steps
let (cust, _) = renew_test_session(idms, ct);
let (cust, _) = renew_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
// Only 7 codes left.
@ -2358,20 +2351,18 @@ mod tests {
));
drop(cutxn);
commit_session(idms, ct, cust);
}
)
commit_session(idms, ct, cust).await;
}
#[test]
fn test_idm_credential_update_onboarding_cancel_inprogress_totp() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
let test_pw =
"fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
#[idm_test]
async fn test_idm_credential_update_onboarding_cancel_inprogress_totp(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
) {
let test_pw = "fo3EitierohF9AelaNgiem0Ei6vup4equo1Oogeevaetehah8Tobeengae3Ci0ooh0uki";
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (cust, _) = setup_test_session(idms, ct);
let (cust, _) = setup_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
// Setup the PW
@ -2402,12 +2393,12 @@ mod tests {
assert!(c_status.can_commit);
drop(cutxn);
commit_session(idms, ct, cust);
commit_session(idms, ct, cust).await;
// It's pw only, since we canceled TOTP
assert!(check_testperson_password(idms, idms_delayed, test_pw, ct).is_some());
}
)
assert!(check_testperson_password(idms, idms_delayed, test_pw, ct)
.await
.is_some());
}
// Primary cred must be pw or pwmfa
@ -2416,13 +2407,14 @@ mod tests {
// - remove webauthn
// - test mulitple webauthn token.
#[test]
fn test_idm_credential_update_onboarding_create_new_passkey() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
#[idm_test]
async fn test_idm_credential_update_onboarding_create_new_passkey(
idms: &IdmServer,
idms_delayed: &mut IdmServerDelayed,
) {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (cust, _) = setup_test_session(idms, ct);
let (cust, _) = setup_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
let origin = cutxn.get_origin().clone();
@ -2468,16 +2460,17 @@ mod tests {
// Commit
drop(cutxn);
commit_session(idms, ct, cust);
commit_session(idms, ct, cust).await;
// Do an auth test
assert!(
check_testperson_passkey(idms, idms_delayed, &mut wa, origin.clone(), ct)
.await
.is_some()
);
// Now test removing the token
let (cust, _) = renew_test_session(idms, ct);
let (cust, _) = renew_test_session(idms, ct).await;
let cutxn = idms.cred_update_transaction();
trace!(?c_status);
@ -2493,15 +2486,15 @@ mod tests {
assert!(c_status.passkeys.is_empty());
drop(cutxn);
commit_session(idms, ct, cust);
commit_session(idms, ct, cust).await;
// Must fail now!
assert!(
check_testperson_passkey(idms, idms_delayed, &mut wa, origin, ct).is_none()
check_testperson_passkey(idms, idms_delayed, &mut wa, origin, ct)
.await
.is_none()
);
}
)
}
// W_ policy, assert can't remove MFA if it's enforced.

View file

@ -1,4 +1,3 @@
use core::task::{Context, Poll};
use std::convert::TryFrom;
use std::str::FromStr;
use std::sync::Arc;
@ -11,8 +10,6 @@ use concread::cowcell::{CowCellReadTxn, CowCellWriteTxn};
use concread::hashmap::HashMap;
use concread::CowCell;
use fernet::Fernet;
// #[cfg(any(test,bench))]
use futures::task as futures_task;
use hashbrown::HashSet;
use kanidm_proto::v1::{
ApiToken, BackupCodesView, CredentialStatus, PasswordFeedback, RadiusAuthToken, UatPurpose,
@ -343,8 +340,12 @@ impl IdmServer {
}
impl IdmServerDelayed {
// #[cfg(any(test,bench))]
// I think we can just make this async in the future?
#[cfg(test)]
pub(crate) fn check_is_empty_or_panic(&mut self) {
use core::task::{Context, Poll};
use futures::task as futures_task;
let waker = futures_task::noop_waker();
let mut cx = Context::from_waker(&waker);
match self.async_rx.poll_recv(&mut cx) {
@ -365,6 +366,9 @@ impl IdmServerDelayed {
#[cfg(test)]
pub(crate) fn try_recv(&mut self) -> Result<DelayedAction, OperationError> {
use core::task::{Context, Poll};
use futures::task as futures_task;
let waker = futures_task::noop_waker();
let mut cx = Context::from_waker(&waker);
match self.async_rx.poll_recv(&mut cx) {

View file

@ -375,24 +375,22 @@ mod tests {
use kanidm_proto::v1::ApiToken;
use super::{DestroyApiTokenEvent, GenerateApiTokenEvent};
// use crate::prelude::*;
use crate::event::CreateEvent;
use crate::idm::server::IdmServerTransaction;
use async_std::task;
use crate::prelude::*;
const TEST_CURRENT_TIME: u64 = 6000;
#[test]
fn test_idm_service_account_api_token() {
run_idm_test!(|_qs: &QueryServer,
#[idm_test]
async fn test_idm_service_account_api_token(
idms: &IdmServer,
_idms_delayed: &mut IdmServerDelayed| {
_idms_delayed: &mut IdmServerDelayed,
) {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let past_grc = Duration::from_secs(TEST_CURRENT_TIME + 1) + GRACE_WINDOW;
let exp = Duration::from_secs(TEST_CURRENT_TIME + 6000);
let post_exp = Duration::from_secs(TEST_CURRENT_TIME + 6010);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let mut idms_prox_write = idms.proxy_write(ct).await;
let testaccount_uuid = Uuid::new_v4();
@ -443,10 +441,8 @@ mod tests {
);
// Delete session
let dte = DestroyApiTokenEvent::new_internal(
apitoken_inner.account_id,
apitoken_inner.token_id,
);
let dte =
DestroyApiTokenEvent::new_internal(apitoken_inner.account_id, apitoken_inner.token_id);
assert!(idms_prox_write
.service_account_destroy_api_token(&dte)
.is_ok());
@ -467,6 +463,5 @@ mod tests {
);
assert!(idms_prox_write.commit().is_ok());
});
}
}

View file

@ -52,8 +52,7 @@ mod repl;
pub mod schema;
pub mod server;
pub mod status;
#[cfg(test)]
mod testkit;
pub mod testkit;
/// A prelude of imports that should be imported by all other Kanidm modules to
/// help make imports cleaner.
@ -79,6 +78,7 @@ pub mod prelude {
FilterInvalid, FC,
};
pub use crate::identity::{AccessScope, IdentType, Identity, IdentityId};
pub use crate::idm::server::{IdmServer, IdmServerDelayed};
pub use crate::modify::{m_pres, m_purge, m_remove, Modify, ModifyInvalid, ModifyList};
pub use crate::server::{
QueryServer, QueryServerReadTransaction, QueryServerTransaction,

View file

@ -1,3 +1,4 @@
#[cfg(test)]
macro_rules! setup_test {
() => {{
let _ = sketching::test_init();
@ -71,6 +72,7 @@ macro_rules! entry_str_to_account {
}};
}
#[cfg(test)]
macro_rules! run_idm_test_inner {
($test_fn:expr) => {{
#[allow(unused_imports)]
@ -112,18 +114,6 @@ macro_rules! run_idm_test {
}};
}
pub fn run_idm_test_no_logging<F>(mut test_fn: F)
where
F: FnMut(
&crate::server::QueryServer,
&crate::idm::server::IdmServer,
&crate::idm::server::IdmServerDelayed,
),
{
sketching::test_init();
run_idm_test_inner!(test_fn);
}
// Test helpers for all plugins.
// #[macro_export]
#[cfg(test)]

View file

@ -1603,6 +1603,7 @@ impl Schema {
}
}
#[cfg(any(test))]
pub(crate) fn write_blocking(&self) -> SchemaWriteTransaction<'_> {
self.write()
}

View file

@ -820,7 +820,7 @@ impl<'a> QueryServerReadTransaction<'a> {
// Verify the data content of the server is as expected. This will probably
// call various functions for validation, including possibly plugin
// verifications.
fn verify(&mut self) -> Vec<Result<(), ConsistencyError>> {
pub(crate) fn verify(&mut self) -> Vec<Result<(), ConsistencyError>> {
// If we fail after backend, we need to return NOW because we can't
// assert any other faith in the DB states.
// * backend

View file

@ -19,3 +19,13 @@ pub async fn setup_test() -> QueryServer {
// Init is called via the proc macro
qs
}
pub async fn setup_idm_test() -> (IdmServer, IdmServerDelayed) {
let qs = setup_test().await;
qs.initialise_helper(duration_from_epoch_now())
.await
.expect("init failed!");
IdmServer::new(qs, "https://idm.example.com").expect("Failed to setup idms")
}