lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

conformance.rs (5344B)


      1 #![cfg(feature = "serde")]
      2 
      3 use std::collections::BTreeSet;
      4 
      5 use radroots_protocol::{
      6     capability::v1::{ReticulumTarget, TransportKind},
      7     error::v1::ErrorReport,
      8     event::v1::{EventClass, TradeState},
      9     radrootsd::transport_publish::v5::{DeliveryPolicy, TargetPolicy},
     10     runtime::v1::{OperationId, Risk, TransportRoute},
     11     schema::{ModuleVersion, protocol_v1_registry},
     12 };
     13 use serde::{Serialize, de::DeserializeOwned};
     14 use serde_json::Value;
     15 
     16 const WIRE_VECTORS: &str = include_str!("fixtures/wire_values.v1.json");
     17 const GENERATED_INVENTORY: &str = include_str!("fixtures/protocol_v1.inventory.json");
     18 
     19 #[test]
     20 fn language_neutral_wire_vectors_are_unique_and_executable() {
     21     let document: Value = serde_json::from_str(WIRE_VECTORS).expect("protocol wire vectors");
     22     assert_eq!(document["suite"], "protocol_wire_values_v1");
     23     assert_eq!(document["contract_version"], "1.0.0");
     24     let vectors = document["vectors"].as_array().expect("vector array");
     25     let mut ids = BTreeSet::new();
     26     for vector in vectors {
     27         let id = vector["id"].as_str().expect("vector id");
     28         assert!(ids.insert(id), "duplicate protocol vector id `{id}`");
     29         let kind = vector["kind"].as_str().expect("vector kind");
     30         let input = vector["input"].clone();
     31         let result = match kind {
     32             "protocol.capability.transport_kind" => execute::<TransportKind>(input),
     33             "protocol.capability.reticulum_target" => execute::<ReticulumTarget>(input),
     34             "protocol.event.event_class" => execute::<EventClass>(input),
     35             "protocol.event.trade_state" => execute::<TradeState>(input),
     36             "protocol.runtime.operation_id" => execute::<OperationId>(input),
     37             "protocol.runtime.risk" => execute::<Risk>(input),
     38             "protocol.runtime.transport_route" => execute::<TransportRoute>(input),
     39             "protocol.radrootsd.target_policy" => execute::<TargetPolicy>(input),
     40             "protocol.radrootsd.delivery_policy" => execute::<DeliveryPolicy>(input),
     41             "protocol.error.report" => execute::<ErrorReport>(input),
     42             other => panic!("unimplemented protocol vector kind `{other}`"),
     43         };
     44         match (
     45             vector.get("expected"),
     46             vector.get("expected_error_contains"),
     47             result,
     48         ) {
     49             (Some(expected), None, Ok(actual)) => assert_eq!(&actual, expected, "vector `{id}`"),
     50             (None, Some(expected), Err(error)) => assert!(
     51                 error.contains(expected.as_str().expect("error fragment")),
     52                 "vector `{id}` expected `{expected}`, found `{error}`"
     53             ),
     54             (Some(_), None, Err(error)) => panic!("vector `{id}` unexpectedly failed: {error}"),
     55             (None, Some(_), Ok(actual)) => {
     56                 panic!("vector `{id}` unexpectedly succeeded: {actual}")
     57             }
     58             _ => panic!("vector `{id}` has an invalid expectation shape"),
     59         }
     60     }
     61     assert_eq!(ids.len(), 13);
     62 }
     63 
     64 #[test]
     65 fn generated_inventory_is_complete_unique_and_matches_the_schema_registry() {
     66     let inventory: Value =
     67         serde_json::from_str(GENERATED_INVENTORY).expect("generated protocol inventory");
     68     assert_eq!(inventory["schema_version"], 1);
     69     assert_eq!(inventory["package"], "radroots_protocol");
     70 
     71     let sources = inventory["sources"].as_array().expect("sources");
     72     let actual_modules = sources
     73         .iter()
     74         .map(|source| source["module"].as_str().expect("source module"))
     75         .collect::<BTreeSet<_>>();
     76     let expected_modules = ModuleVersion::ALL
     77         .iter()
     78         .map(|module| module.path())
     79         .collect::<BTreeSet<_>>();
     80     assert_eq!(actual_modules, expected_modules);
     81 
     82     let type_paths = sources
     83         .iter()
     84         .flat_map(|source| source["types"].as_array().expect("source types"))
     85         .map(|item| item["rust_path"].as_str().expect("Rust path"))
     86         .collect::<Vec<_>>();
     87     assert_eq!(type_paths.len(), 60);
     88     assert_eq!(
     89         type_paths.iter().copied().collect::<BTreeSet<_>>().len(),
     90         60
     91     );
     92     assert!(type_paths.contains(&"radroots_protocol::runtime::v1::OperationId"));
     93 
     94     let inventory_schemas = inventory["schemas"]
     95         .as_array()
     96         .expect("schemas")
     97         .iter()
     98         .map(|schema| {
     99             (
    100                 schema["schema_id"].as_str().expect("schema id").to_owned(),
    101                 schema["module"].as_str().expect("schema module").to_owned(),
    102                 schema["generation"].as_u64().expect("generation") as u16,
    103             )
    104         })
    105         .collect::<BTreeSet<_>>();
    106     let registry_schemas = protocol_v1_registry()
    107         .expect("protocol registry")
    108         .descriptors()
    109         .iter()
    110         .map(|descriptor| {
    111             (
    112                 descriptor.id().as_str().to_owned(),
    113                 descriptor.module().path().to_owned(),
    114                 descriptor.module().generation(),
    115             )
    116         })
    117         .collect::<BTreeSet<_>>();
    118     assert_eq!(inventory_schemas.len(), 121);
    119     assert_eq!(inventory_schemas, registry_schemas);
    120 }
    121 
    122 fn execute<T>(input: Value) -> Result<Value, String>
    123 where
    124     T: DeserializeOwned + Serialize,
    125 {
    126     let decoded: T = serde_json::from_value(input).map_err(|error| error.to_string())?;
    127     serde_json::to_value(decoded).map_err(|error| error.to_string())
    128 }