aboutsummaryrefslogtreecommitdiffstats
path: root/src/simtest/policy.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/simtest/policy.rs')
-rw-r--r--src/simtest/policy.rs66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/simtest/policy.rs b/src/simtest/policy.rs
index 0d590d7..7e881e7 100644
--- a/src/simtest/policy.rs
+++ b/src/simtest/policy.rs
@@ -1012,3 +1012,69 @@ async fn a_swarm_turning_strict_through_a_remake() {
assert!(crate::access::policy::of(&replica.doc).strict());
}
}
+
+/// A strict remake only one member's `--strict-keys` take: no majority, aborted, its
+/// reason naming the members that didn't vote, for the operator to tell why.
+#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
+async fn a_strict_remake_too_few_take() {
+ use crate::access::{sshsig, strict};
+ let key = ed25519_dalek::SigningKey::from_bytes(&[13; 32]);
+ let public = sshsig::PublicKey(key.verifying_key().to_bytes());
+ let sim = Sim::with_identity(93);
+ let a = sim.start_with("a", &[], Start::Genesis, move |config| {
+ config.first_users = [("alice".to_owned(), Default::default())].into();
+ config.strict_keys = vec![public];
+ });
+ let b = sim.start("b", &["a"], Start::Join);
+ let c = sim.start("c", &["a"], Start::Join);
+ sim.wait_ready(&[&a, &b, &c], SOON).await;
+ let nodes = [a.clone(), b.clone(), c.clone()];
+ sim.wait_until("every node is registered", SOON, || {
+ let nodes = nodes.clone();
+ async move {
+ for node in &nodes {
+ if crate::swarm::members::members(&node.doc.read().await.doc).len() < 3 {
+ return false;
+ }
+ }
+ true
+ }
+ })
+ .await;
+ let text = {
+ let replica = a.doc.read().await;
+ let swarm = store::read_path(&replica.doc, &path("_continuum/swarm"))
+ .unwrap()
+ .unwrap();
+ let policy = json!({"version": 1, "values": "signed"});
+ let line = strict::manifest_of(&replica.doc, swarm.as_str().unwrap(), policy, "alice", 1);
+ let signed = sshsig::sign(&key, strict::NAMESPACE, line.as_bytes());
+ format!("{line}\n{signed}")
+ };
+ let (status, report) = crate::remake::testing::start(
+ a.clone(),
+ json!({"kind": "strict", "spec": {"manifest": text}, "settle": "3s"}),
+ None,
+ )
+ .await;
+ assert!(status.is_success(), "proposal refused: {status} {report}");
+ let id = report["id"].as_str().expect("remake id").to_owned();
+ let (a_ref, id_ref) = (&a, id.as_str());
+ sim.wait_until("the strict remake is aborted", SOON, move || async move {
+ crate::remake::testing::report(a_ref, id_ref)
+ .await
+ .is_some_and(|report| report["phase"] == "aborted")
+ })
+ .await;
+ let report = crate::remake::testing::report(&a, &id).await.unwrap();
+ let reason = report.to_string();
+ assert!(
+ reason.contains("a strict remake, not voted for by"),
+ "{reason}"
+ );
+ assert!(
+ reason.contains(b.local_id()) && reason.contains(c.local_id()),
+ "{reason}"
+ );
+ assert_eq!(a.local_epoch().generation, 0);
+}