persistant_relational/
contract.rs1use crate::RelationalBackend;
10use crate::conformance::{Certified, Leaf, certify_leaves};
11use persistant_core::choose::{Eligibility, LeafFailure};
12use persistant_core::{Config, Reason};
13
14pub fn evaluate(rows: &[Certified], required: &[Leaf]) -> Eligibility {
16 let mut out: Vec<LeafFailure> = Vec::new();
17 for leaf in required.iter().copied() {
18 if out.iter().any(|e| e.leaf == leaf.id()) {
19 continue;
20 }
21 match rows.iter().find(|c| c.leaf == leaf) {
22 Some(c) if c.row.enabled => {}
23 Some(c) => out.push(LeafFailure {
24 leaf: leaf.id().to_string(),
25 reason: c.row.reason.unwrap_or(Reason::Untested),
26 note: c.row.note.clone(),
27 }),
28 None => out.push(LeafFailure {
29 leaf: leaf.id().to_string(),
30 reason: Reason::Untested,
31 note: "no test ran for this leaf".to_string(),
32 }),
33 }
34 }
35 if out.is_empty() {
36 Eligibility::Eligible
37 } else {
38 Eligibility::Excluded(out)
39 }
40}
41
42pub async fn check<R: RelationalBackend>(target: &R, required: &[Leaf]) -> Eligibility {
44 let rows = certify_leaves(target, &Config::new(), &Config::new(), required).await;
45 evaluate(&rows, required)
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use crate::conformance::Certified;
52 use persistant_core::Row;
53 use std::collections::BTreeMap;
54
55 fn row(leaf: Leaf, enabled: bool, reason: Option<Reason>) -> Certified {
56 Certified {
57 leaf,
58 row: Row {
59 subject_kind: "capability".to_string(),
60 subject: persistant_core::CapabilityId::new(leaf.id()).unwrap(),
61 backend: "test".to_string(),
62 version: "0".to_string(),
63 config: Config::new(),
64 enabled,
65 reason,
66 metadata: Config::new(),
67 note: "n".to_string(),
68 extra: BTreeMap::new(),
69 },
70 }
71 }
72
73 #[test]
74 fn a_leaf_that_is_on_is_eligible_and_one_that_is_off_is_excluded_with_its_reason() {
75 let rows = [
76 row(Leaf::Values, true, None),
77 row(Leaf::Transaction, false, Some(Reason::Wrong)),
78 ];
79 assert_eq!(
80 evaluate(&rows, &[Leaf::Values]),
81 Eligibility::Eligible,
82 "control: the passing leaf alone is eligible"
83 );
84 let r = evaluate(&rows, &[Leaf::Values, Leaf::Transaction]);
85 assert!(
86 matches!(&r, Eligibility::Excluded(ex) if ex.len() == 1 && ex[0].reason == Reason::Wrong && ex[0].leaf == "rel.transaction"),
87 "{r:?}"
88 );
89 }
90
91 #[test]
92 fn a_required_leaf_with_no_row_is_untested_not_a_pass() {
93 let r = evaluate(&[], &[Leaf::Values]);
94 assert!(matches!(&r, Eligibility::Excluded(ex) if ex[0].reason == Reason::Untested));
95 assert_eq!(evaluate(&[], &[]), Eligibility::Eligible);
96 }
97}