lib

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

relay_delivery.rs (11879B)


      1 use radroots_local_events::{
      2     RelayDeliveryEvidence, RelayDeliveryFailure, RelayDeliveryState,
      3     canonical_relay_set_fingerprint,
      4 };
      5 use serde_json::json;
      6 
      7 #[test]
      8 fn pending_delivery_evidence_uses_canonical_json_shape() {
      9     let evidence = RelayDeliveryEvidence::pending([
     10         " wss://relay-b.example ",
     11         "wss://relay-a.example",
     12         "wss://relay-b.example",
     13     ])
     14     .expect("pending evidence");
     15 
     16     assert_eq!(evidence.state, RelayDeliveryState::Pending);
     17     assert_eq!(evidence.state.as_str(), "pending");
     18     assert_eq!(
     19         evidence.target_relays,
     20         vec![
     21             "wss://relay-b.example".to_owned(),
     22             "wss://relay-a.example".to_owned()
     23         ]
     24     );
     25     assert_eq!(
     26         evidence.to_json_value().expect("json"),
     27         json!({
     28             "state": "pending",
     29             "target_relays": ["wss://relay-b.example", "wss://relay-a.example"],
     30             "connected_relays": [],
     31             "acknowledged_relays": [],
     32             "failed_relays": []
     33         })
     34     );
     35 }
     36 
     37 #[test]
     38 fn acknowledged_delivery_evidence_uses_canonical_failure_fields() {
     39     let evidence = RelayDeliveryEvidence::acknowledged(
     40         ["wss://relay-a.example", "wss://relay-b.example"],
     41         [" wss://relay-a.example "],
     42         ["wss://relay-a.example"],
     43         vec![RelayDeliveryFailure::new(" wss://relay-b.example ", " timeout ").expect("failure")],
     44     )
     45     .expect("acknowledged evidence");
     46 
     47     assert_eq!(evidence.state.as_str(), "acknowledged");
     48     assert_eq!(
     49         evidence.to_json_value().expect("json"),
     50         json!({
     51             "state": "acknowledged",
     52             "target_relays": ["wss://relay-a.example", "wss://relay-b.example"],
     53             "connected_relays": ["wss://relay-a.example"],
     54             "acknowledged_relays": ["wss://relay-a.example"],
     55             "failed_relays": [
     56                 {"relay_url": "wss://relay-b.example", "error": "timeout"}
     57             ]
     58         })
     59     );
     60 }
     61 
     62 #[test]
     63 fn observed_delivery_evidence_tracks_observed_relays_without_acknowledgement() {
     64     let evidence = RelayDeliveryEvidence::observed(
     65         ["wss://relay-a.example", "wss://relay-b.example"],
     66         [" wss://relay-a.example ", "wss://relay-b.example"],
     67         ["wss://relay-b.example"],
     68         Vec::new(),
     69     )
     70     .expect("observed evidence");
     71 
     72     assert_eq!(evidence.state, RelayDeliveryState::Observed);
     73     assert_eq!(evidence.state.as_str(), "observed");
     74     assert!(evidence.acknowledged_relays.is_empty());
     75     assert_eq!(
     76         evidence.to_json_value().expect("json"),
     77         json!({
     78             "state": "observed",
     79             "target_relays": ["wss://relay-a.example", "wss://relay-b.example"],
     80             "connected_relays": ["wss://relay-a.example", "wss://relay-b.example"],
     81             "acknowledged_relays": [],
     82             "observed_relays": ["wss://relay-b.example"],
     83             "failed_relays": []
     84         })
     85     );
     86 }
     87 
     88 #[test]
     89 fn observed_delivery_evidence_allows_unknown_exact_relay_when_connected() {
     90     let evidence = RelayDeliveryEvidence::observed(
     91         ["wss://relay-a.example", "wss://relay-b.example"],
     92         ["wss://relay-a.example", "wss://relay-b.example"],
     93         Vec::<String>::new(),
     94         Vec::new(),
     95     )
     96     .expect("observed evidence");
     97 
     98     assert_eq!(evidence.state, RelayDeliveryState::Observed);
     99     assert!(evidence.observed_relays.is_empty());
    100     assert_eq!(
    101         evidence.to_json_value().expect("json"),
    102         json!({
    103             "state": "observed",
    104             "target_relays": ["wss://relay-a.example", "wss://relay-b.example"],
    105             "connected_relays": ["wss://relay-a.example", "wss://relay-b.example"],
    106             "acknowledged_relays": [],
    107             "failed_relays": []
    108         })
    109     );
    110 }
    111 
    112 #[test]
    113 fn failed_delivery_evidence_requires_failures_without_acknowledgements() {
    114     let evidence = RelayDeliveryEvidence::failed(
    115         ["wss://relay-a.example"],
    116         ["wss://relay-a.example"],
    117         vec![RelayDeliveryFailure::new("wss://relay-a.example", "closed").expect("failure")],
    118     )
    119     .expect("failed evidence");
    120 
    121     assert_eq!(evidence.state, RelayDeliveryState::Failed);
    122     assert_eq!(evidence.state.as_str(), "failed");
    123     assert!(evidence.acknowledged_relays.is_empty());
    124     assert_eq!(evidence.failed_relays.len(), 1);
    125 }
    126 
    127 #[test]
    128 fn acknowledged_delivery_evidence_rejects_observed_relays() {
    129     let err = RelayDeliveryEvidence::from_json_value(&json!({
    130         "state": "acknowledged",
    131         "target_relays": ["wss://relay-a.example"],
    132         "connected_relays": ["wss://relay-a.example"],
    133         "acknowledged_relays": ["wss://relay-a.example"],
    134         "observed_relays": ["wss://relay-a.example"],
    135         "failed_relays": []
    136     }))
    137     .expect_err("invalid evidence");
    138 
    139     assert!(err.to_string().contains("observed_relays"));
    140 }
    141 
    142 #[test]
    143 fn delivery_evidence_fingerprint_uses_target_relays() {
    144     let evidence = RelayDeliveryEvidence::acknowledged(
    145         ["wss://relay-b.example", "wss://relay-a.example"],
    146         ["wss://relay-a.example"],
    147         ["wss://relay-a.example"],
    148         Vec::new(),
    149     )
    150     .expect("evidence");
    151 
    152     assert_eq!(
    153         evidence.relay_set_fingerprint(),
    154         canonical_relay_set_fingerprint(["wss://relay-a.example", "wss://relay-b.example"])
    155     );
    156 }
    157 
    158 #[test]
    159 fn delivery_evidence_rejects_invalid_json_shape() {
    160     let err = RelayDeliveryEvidence::from_json_value(&json!({
    161         "state": "acknowledged",
    162         "target_relays": ["wss://relay-a.example"],
    163         "connected_relays": [],
    164         "acknowledged_relays": [],
    165         "failed_relays": []
    166     }))
    167     .expect_err("invalid evidence");
    168 
    169     assert!(err.to_string().contains("acknowledged_relays"));
    170 }
    171 
    172 #[test]
    173 fn delivery_evidence_rejects_pending_and_failed_cross_state_fields() {
    174     let pending_err = RelayDeliveryEvidence::from_json_value(&json!({
    175         "state": "pending",
    176         "target_relays": ["wss://relay-a.example"],
    177         "connected_relays": [],
    178         "acknowledged_relays": [],
    179         "observed_relays": ["wss://relay-a.example"],
    180         "failed_relays": [
    181             {"relay_url": "wss://relay-a.example", "error": "timeout"}
    182         ]
    183     }))
    184     .expect_err("pending evidence with terminal fields");
    185 
    186     assert!(
    187         pending_err
    188             .to_string()
    189             .contains("pending delivery evidence")
    190     );
    191 
    192     let failed_err = RelayDeliveryEvidence::from_json_value(&json!({
    193         "state": "failed",
    194         "target_relays": ["wss://relay-a.example"],
    195         "connected_relays": [],
    196         "acknowledged_relays": ["wss://relay-a.example"],
    197         "observed_relays": ["wss://relay-a.example"],
    198         "failed_relays": [
    199             {"relay_url": "wss://relay-a.example", "error": "timeout"}
    200         ]
    201     }))
    202     .expect_err("failed evidence with success fields");
    203 
    204     assert!(failed_err.to_string().contains("failed delivery evidence"));
    205 }
    206 
    207 #[test]
    208 fn delivery_evidence_rejects_invalid_failure_and_relay_values() {
    209     let normalized_failure_err = RelayDeliveryEvidence::from_json_value(&json!({
    210         "state": "failed",
    211         "target_relays": ["wss://relay-a.example"],
    212         "connected_relays": [],
    213         "acknowledged_relays": [],
    214         "failed_relays": [
    215             {"relay_url": " wss://relay-a.example ", "error": "timeout"}
    216         ]
    217     }))
    218     .expect_err("non-normalized failure relay");
    219 
    220     assert!(
    221         normalized_failure_err
    222             .to_string()
    223             .contains("failed_relays.relay_url")
    224     );
    225 
    226     let trimmed_error_err = RelayDeliveryEvidence::from_json_value(&json!({
    227         "state": "failed",
    228         "target_relays": ["wss://relay-a.example"],
    229         "connected_relays": [],
    230         "acknowledged_relays": [],
    231         "failed_relays": [
    232             {"relay_url": "wss://relay-a.example", "error": " timeout "}
    233         ]
    234     }))
    235     .expect_err("non-normalized failure text");
    236 
    237     assert!(trimmed_error_err.to_string().contains("must be trimmed"));
    238 
    239     let constructor_err =
    240         RelayDeliveryEvidence::pending(["http://relay-a.example"]).expect_err("invalid relay");
    241 
    242     assert!(constructor_err.to_string().contains("target_relays"));
    243 }
    244 
    245 #[test]
    246 fn delivery_evidence_rejects_invalid_relay_sets_in_each_field() {
    247     for (field, evidence) in [
    248         (
    249             "connected_relays",
    250             RelayDeliveryEvidence {
    251                 state: RelayDeliveryState::Pending,
    252                 target_relays: vec!["wss://relay-a.example".to_owned()],
    253                 connected_relays: vec!["http://relay-a.example".to_owned()],
    254                 acknowledged_relays: Vec::new(),
    255                 observed_relays: Vec::new(),
    256                 failed_relays: Vec::new(),
    257             },
    258         ),
    259         (
    260             "acknowledged_relays",
    261             RelayDeliveryEvidence {
    262                 state: RelayDeliveryState::Acknowledged,
    263                 target_relays: vec!["wss://relay-a.example".to_owned()],
    264                 connected_relays: Vec::new(),
    265                 acknowledged_relays: vec!["http://relay-a.example".to_owned()],
    266                 observed_relays: Vec::new(),
    267                 failed_relays: Vec::new(),
    268             },
    269         ),
    270         (
    271             "observed_relays",
    272             RelayDeliveryEvidence {
    273                 state: RelayDeliveryState::Observed,
    274                 target_relays: vec!["wss://relay-a.example".to_owned()],
    275                 connected_relays: Vec::new(),
    276                 acknowledged_relays: Vec::new(),
    277                 observed_relays: vec!["http://relay-a.example".to_owned()],
    278                 failed_relays: Vec::new(),
    279             },
    280         ),
    281     ] {
    282         let error = evidence.validate().expect_err("invalid relay set");
    283 
    284         assert!(
    285             error.to_string().contains(field),
    286             "expected error to contain {field}, got {error}"
    287         );
    288     }
    289 }
    290 
    291 #[test]
    292 fn delivery_evidence_rejects_constructor_and_json_error_paths() {
    293     let empty_failure_error = RelayDeliveryEvidence::failed(
    294         ["wss://relay-a.example"],
    295         Vec::<String>::new(),
    296         vec![RelayDeliveryFailure {
    297             relay_url: "wss://relay-a.example".to_owned(),
    298             error: " ".to_owned(),
    299         }],
    300     )
    301     .expect_err("empty failure error");
    302 
    303     assert!(
    304         empty_failure_error
    305             .to_string()
    306             .contains("failed_relays.error")
    307     );
    308 
    309     let invalid_json_error = RelayDeliveryEvidence::from_json_value(&json!({
    310         "state": 1,
    311         "target_relays": [],
    312         "connected_relays": [],
    313         "acknowledged_relays": [],
    314         "failed_relays": []
    315     }))
    316     .expect_err("invalid json");
    317 
    318     assert!(!invalid_json_error.to_string().is_empty());
    319 
    320     let to_json_error = RelayDeliveryEvidence {
    321         state: RelayDeliveryState::Pending,
    322         target_relays: Vec::new(),
    323         connected_relays: Vec::new(),
    324         acknowledged_relays: Vec::new(),
    325         observed_relays: Vec::new(),
    326         failed_relays: Vec::new(),
    327     }
    328     .to_json_value()
    329     .expect_err("invalid to json evidence");
    330 
    331     assert!(to_json_error.to_string().contains("target_relays"));
    332 
    333     for result in [
    334         RelayDeliveryEvidence::acknowledged(
    335             ["wss://relay-a.example"],
    336             ["http://relay-a.example"],
    337             ["wss://relay-a.example"],
    338             Vec::new(),
    339         ),
    340         RelayDeliveryEvidence::acknowledged(
    341             ["wss://relay-a.example"],
    342             Vec::<String>::new(),
    343             ["http://relay-a.example"],
    344             Vec::new(),
    345         ),
    346         RelayDeliveryEvidence::observed(
    347             ["wss://relay-a.example"],
    348             Vec::<String>::new(),
    349             ["http://relay-a.example"],
    350             Vec::new(),
    351         ),
    352         RelayDeliveryEvidence::acknowledged(
    353             ["wss://relay-a.example"],
    354             Vec::<String>::new(),
    355             Vec::<String>::new(),
    356             Vec::new(),
    357         ),
    358     ] {
    359         assert!(result.is_err());
    360     }
    361 }