mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Further test improvements (#1166)
This commit is contained in:
parent
df4043cf10
commit
692c0a3978
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -1603,6 +1603,7 @@ impl Schema {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test))]
|
||||
pub(crate) fn write_blocking(&self) -> SchemaWriteTransaction<'_> {
|
||||
self.write()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue