From a371dd652c2d8c20da6ecbe5adfc8f99feafb235 Mon Sep 17 00:00:00 2001 From: TimeEngineer Date: Tue, 17 Oct 2023 16:29:53 +0200 Subject: [PATCH] Add tests for poll_server_for_new_certificates --- .../client/src/certificates_ops/poll.rs | 9 +- .../client/tests/unit/certificates_ops/mod.rs | 1 + .../tests/unit/certificates_ops/poll.rs | 274 ++++++++++++++++++ 3 files changed, 280 insertions(+), 4 deletions(-) create mode 100644 libparsec/crates/client/tests/unit/certificates_ops/poll.rs diff --git a/libparsec/crates/client/src/certificates_ops/poll.rs b/libparsec/crates/client/src/certificates_ops/poll.rs index e7bed797b58..239718cd3f8 100644 --- a/libparsec/crates/client/src/certificates_ops/poll.rs +++ b/libparsec/crates/client/src/certificates_ops/poll.rs @@ -68,12 +68,12 @@ pub(super) async fn poll_server_for_new_certificates( // `latest_known_index` is useful to detect outdated `CertificatesUpdated` // events given the server has already been polled in the meantime. - let offset = match (&last_index, latest_known_index) { - (last_index, Some(latest_known_index)) if *last_index >= latest_known_index => { - return Ok(*last_index) + let offset = match (last_index, latest_known_index) { + (last_index, Some(latest_known_index)) if last_index >= latest_known_index => { + return Ok(last_index) } // Certificate index starts at 1, so can be used as-is as offset - (last_index, _) => *last_index, + (last_index, _) => last_index, }; // 2) We are missing some certificates, time to ask the server about them... @@ -120,6 +120,7 @@ pub(super) async fn poll_server_for_new_certificates( let outcome = ops .add_certificates_batch(&store, new_offset, certificates) .await?; + match outcome { MaybeRedactedSwitch::NoSwitch => (), // Unlike other profiles, Outsider is required to use the redacted diff --git a/libparsec/crates/client/tests/unit/certificates_ops/mod.rs b/libparsec/crates/client/tests/unit/certificates_ops/mod.rs index 981e8ecb769..970dcca252b 100644 --- a/libparsec/crates/client/tests/unit/certificates_ops/mod.rs +++ b/libparsec/crates/client/tests/unit/certificates_ops/mod.rs @@ -6,5 +6,6 @@ mod add_sequester_authority_certificate; mod add_user_certificate; mod add_user_revoked_certificate; mod add_user_update_certificate; +mod poll; mod store; mod utils; diff --git a/libparsec/crates/client/tests/unit/certificates_ops/poll.rs b/libparsec/crates/client/tests/unit/certificates_ops/poll.rs new file mode 100644 index 00000000000..5860ea25018 --- /dev/null +++ b/libparsec/crates/client/tests/unit/certificates_ops/poll.rs @@ -0,0 +1,274 @@ +// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS + +use libparsec_client_connection::{ + test_register_low_level_send_hook, test_register_send_hook, HeaderMap, ResponseMock, StatusCode, +}; +use libparsec_protocol::authenticated_cmds; +use libparsec_tests_fixtures::prelude::*; +use libparsec_types::prelude::*; + +use crate::certificates_ops::PollServerError; + +use super::utils::certificates_ops_factory; + +#[parsec_test(testbed = "minimal")] +async fn empty(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + + test_register_send_hook( + &env.discriminant_dir, + move |req: authenticated_cmds::latest::certificate_get::Req| { + p_assert_eq!(req.offset, 0); + + authenticated_cmds::latest::certificate_get::Rep::Ok { + certificates: vec![], + } + }, + ); + + let index = ops.poll_server_for_new_certificates(None).await.unwrap(); + + p_assert_eq!(index, 0); + + ops.stop().await; +} + +#[parsec_test(testbed = "minimal")] +async fn user_certificate(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + + let (_, alice_signed) = env.get_user_certificate("alice"); + + test_register_send_hook( + &env.discriminant_dir, + move |req: authenticated_cmds::latest::certificate_get::Req| { + p_assert_eq!(req.offset, 0); + + authenticated_cmds::latest::certificate_get::Rep::Ok { + certificates: vec![alice_signed], + } + }, + ); + + let index = ops.poll_server_for_new_certificates(None).await.unwrap(); + + p_assert_eq!(index, 1); + + ops.stop().await; +} + +#[parsec_test(testbed = "minimal")] +async fn certificates(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + + let (_, alice_signed) = env.get_user_certificate("alice"); + let (_, alice_dev1_signed) = env.get_device_certificate("alice@dev1"); + + test_register_send_hook( + &env.discriminant_dir, + move |req: authenticated_cmds::latest::certificate_get::Req| { + p_assert_eq!(req.offset, 0); + + authenticated_cmds::latest::certificate_get::Rep::Ok { + certificates: vec![alice_signed, alice_dev1_signed], + } + }, + ); + + let index = ops.poll_server_for_new_certificates(None).await.unwrap(); + + p_assert_eq!(index, 2); + + ops.stop().await; +} + +#[parsec_test(testbed = "minimal")] +async fn minimal(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + let certificates = env + .template + .certificates() + .map(|e| e.signed) + .collect::>(); + + test_register_send_hook( + &env.discriminant_dir, + move |req: authenticated_cmds::latest::certificate_get::Req| { + p_assert_eq!(req.offset, 0); + + authenticated_cmds::latest::certificate_get::Rep::Ok { certificates } + }, + ); + + let index = ops.poll_server_for_new_certificates(None).await.unwrap(); + + p_assert_eq!(index, env.template.certificates().count() as IndexInt); + + ops.stop().await; +} + +#[parsec_test(testbed = "coolorg")] +async fn coolorg(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + let certificates = env + .template + .certificates() + .map(|e| e.signed) + .collect::>(); + + test_register_send_hook( + &env.discriminant_dir, + move |req: authenticated_cmds::latest::certificate_get::Req| { + p_assert_eq!(req.offset, 0); + + authenticated_cmds::latest::certificate_get::Rep::Ok { certificates } + }, + ); + + let index = ops.poll_server_for_new_certificates(None).await.unwrap(); + + p_assert_eq!(index, env.template.certificates().count() as IndexInt); + + ops.stop().await; +} + +#[parsec_test(testbed = "minimal")] +async fn nothing_to_poll(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + let certificates = env + .template + .certificates() + .map(|e| e.signed) + .collect::>(); + let next_offset = certificates.len() as u64; + + test_register_send_hook( + &env.discriminant_dir, + move |req: authenticated_cmds::latest::certificate_get::Req| { + p_assert_eq!(req.offset, next_offset); + + authenticated_cmds::latest::certificate_get::Rep::Ok { + certificates: vec![], + } + }, + ); + + test_register_send_hook( + &env.discriminant_dir, + move |req: authenticated_cmds::latest::certificate_get::Req| { + p_assert_eq!(req.offset, 0); + + authenticated_cmds::latest::certificate_get::Rep::Ok { certificates } + }, + ); + + // Poll all + let last_index = ops.poll_server_for_new_certificates(None).await.unwrap(); + + // Nothing to poll + let index = ops + .poll_server_for_new_certificates(Some(last_index)) + .await + .unwrap(); + + p_assert_eq!(index, last_index); + + ops.stop().await; +} + +#[parsec_test(testbed = "minimal")] +async fn invalid_certif_received(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + + test_register_send_hook( + &env.discriminant_dir, + move |_: authenticated_cmds::latest::certificate_get::Req| { + authenticated_cmds::latest::certificate_get::Rep::Ok { + certificates: vec![Bytes::from_static(b"foo")], + } + }, + ); + + let err = ops + .poll_server_for_new_certificates(None) + .await + .unwrap_err(); + + p_assert_matches!(err, PollServerError::InvalidCertificate(..)); + + ops.stop().await; +} + +#[parsec_test(testbed = "minimal")] +async fn unknown_status(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + + test_register_send_hook( + &env.discriminant_dir, + move |_: authenticated_cmds::latest::certificate_get::Req| { + authenticated_cmds::latest::certificate_get::Rep::UnknownStatus { + unknown_status: "".into(), + reason: None, + } + }, + ); + + ops.poll_server_for_new_certificates(None) + .await + .unwrap_err(); + + ops.stop().await; +} + +#[parsec_test(testbed = "minimal")] +async fn offline(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + + let err = ops + .poll_server_for_new_certificates(None) + .await + .unwrap_err(); + + p_assert_matches!(err, PollServerError::Offline); + + ops.stop().await; +} + +#[parsec_test(testbed = "minimal")] +async fn invalid_response(env: &TestbedEnv) { + let alice = env.local_device("alice@dev1"); + + let ops = certificates_ops_factory(env, &alice).await; + + test_register_low_level_send_hook(&env.discriminant_dir, |_request_builder| async { + Ok(ResponseMock::Mocked(( + StatusCode::IM_A_TEAPOT, + HeaderMap::new(), + Bytes::new(), + ))) + }); + + ops.poll_server_for_new_certificates(None) + .await + .unwrap_err(); + + ops.stop().await; +}