Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for poll_server_for_new_certificates #5538

Merged
merged 1 commit into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions libparsec/crates/client/src/certificates_ops/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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...
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,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;
254 changes: 254 additions & 0 deletions libparsec/crates/client/tests/unit/certificates_ops/poll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
// 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(
TimeEngineer marked this conversation as resolved.
Show resolved Hide resolved
&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::<Vec<_>>();
let expected_index = certificates.len() as IndexInt;

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, expected_index);

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::<Vec<_>>();
let next_offset = env.get_last_certificate_index();

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,
}
},
);

let err = ops
.poll_server_for_new_certificates(None)
.await
.unwrap_err();
TimeEngineer marked this conversation as resolved.
Show resolved Hide resolved

p_assert_matches!(err, PollServerError::Internal(..));

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(),
)))
});

let err = ops
.poll_server_for_new_certificates(None)
.await
.unwrap_err();
TimeEngineer marked this conversation as resolved.
Show resolved Hide resolved

p_assert_matches!(err, PollServerError::Internal(..));

ops.stop().await;
}