lib

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

authored_draft_all_schemas.rs (7985B)


      1 use futures_executor::block_on;
      2 use radroots_storage::{
      3     authored_draft::{AuthoredDraft, AuthoredDraftId, AuthoredDraftStage, AuthoredDraftStore},
      4     authored_draft_query::{
      5         AuthoredDraftCursor, AuthoredDraftPage, AuthoredDraftQuery, AuthoredDraftQueryRecord,
      6         AuthoredDraftScope,
      7     },
      8     memory::MemoryStorage,
      9 };
     10 
     11 fn draft(id: u128, author: u8, schema: &str, payload: Vec<u8>) -> AuthoredDraft {
     12     let value = AuthoredDraft::initial(
     13         AuthoredDraftId::new(id.to_be_bytes()).unwrap(),
     14         [author; 32],
     15         schema,
     16         payload,
     17         AuthoredDraftStage::Draft,
     18         None,
     19         10,
     20     )
     21     .unwrap();
     22     if id.is_multiple_of(2) {
     23         value
     24             .with_scope(AuthoredDraftScope::new([3; 32]).unwrap())
     25             .unwrap()
     26     } else {
     27         value
     28     }
     29 }
     30 
     31 #[test]
     32 fn all_schema_cursor_has_explicit_independent_authority_and_no_wildcard_schema() {
     33     let q = AuthoredDraftQuery::for_author_all_schemas([7; 32], 37).unwrap();
     34     assert!(q.is_author_wide());
     35     assert_eq!(q.scope(), None);
     36     assert_eq!(q.payload_schema(), None);
     37     for (author, limit) in [([0; 32], 1), ([7; 32], 0), ([7; 32], 257)] {
     38         assert!(AuthoredDraftQuery::for_author_all_schemas(author, limit).is_err());
     39     }
     40     let cursor = q.cursor_after([0; 16]);
     41     let encoded = serde_json::to_string(&cursor).unwrap();
     42     let expected = format!(
     43         "{{\"schema_version\":3,\"author\":{},\"payload_schema\":null,\"scope\":null,\"after_id\":{},\"selection\":\"author_all_schemas\"}}",
     44         serde_json::to_string(&[7; 32]).unwrap(),
     45         serde_json::to_string(&[0; 16]).unwrap()
     46     );
     47     assert_eq!(encoded, expected);
     48     let decoded: AuthoredDraftCursor = serde_json::from_str(&encoded).unwrap();
     49     assert_eq!(decoded, cursor);
     50     assert_eq!(
     51         q.clone().with_cursor(&decoded).unwrap().after(),
     52         Some([0; 16])
     53     );
     54     assert_eq!(serde_json::to_string(&decoded).unwrap(), encoded);
     55     for other in [
     56         AuthoredDraftQuery::new([7; 32], "known.v1", None, 1).unwrap(),
     57         AuthoredDraftQuery::for_author([7; 32], "known.v1", 1).unwrap(),
     58         AuthoredDraftQuery::for_author_all_schemas([8; 32], 1).unwrap(),
     59     ] {
     60         assert!(q.clone().with_cursor(&other.cursor_after([0; 16])).is_err());
     61         assert!(other.with_cursor(&cursor).is_err());
     62     }
     63     let wire = serde_json::to_value(&cursor).unwrap();
     64     for (field, value) in [
     65         ("schema_version", serde_json::json!(1)),
     66         ("schema_version", serde_json::json!(2)),
     67         ("schema_version", serde_json::json!(4)),
     68         ("selection", serde_json::json!("author_schema")),
     69         ("selection", serde_json::Value::Null),
     70         ("selection", serde_json::json!("future")),
     71         ("payload_schema", serde_json::json!("known.v1")),
     72         ("payload_schema", serde_json::json!("")),
     73         ("scope", serde_json::json!([3; 32].to_vec())),
     74         ("author", serde_json::json!([0; 32].to_vec())),
     75         ("after_id", serde_json::json!([0; 15].to_vec())),
     76         ("unexpected", serde_json::json!(true)),
     77     ] {
     78         let mut changed = wire.clone();
     79         changed[field] = value;
     80         assert!(
     81             serde_json::from_value::<AuthoredDraftCursor>(changed).is_err(),
     82             "{field}"
     83         );
     84     }
     85     for field in [
     86         "schema_version",
     87         "author",
     88         "payload_schema",
     89         "scope",
     90         "after_id",
     91         "selection",
     92     ] {
     93         let mut changed = wire.clone();
     94         changed.as_object_mut().unwrap().remove(field);
     95         assert!(
     96             serde_json::from_value::<AuthoredDraftCursor>(changed).is_err(),
     97             "missing {field}"
     98         );
     99     }
    100     let duplicate = encoded.replace("\"scope\":null", "\"scope\":null,\"scope\":null");
    101     assert!(serde_json::from_str::<AuthoredDraftCursor>(&duplicate).is_err());
    102     let exact = AuthoredDraftQuery::for_author([7; 32], "known.v1", 1).unwrap();
    103     let mut wrong_marker = serde_json::to_value(exact.cursor_after([0; 16])).unwrap();
    104     wrong_marker["selection"] = serde_json::json!("author_all_schemas");
    105     assert!(serde_json::from_value::<AuthoredDraftCursor>(wrong_marker).is_err());
    106     assert_eq!(exact.payload_schema(), Some("known.v1"));
    107     assert!(AuthoredDraftQuery::new([7; 32], "", None, 1).is_err());
    108 }
    109 
    110 #[test]
    111 fn all_schema_memory_inventory_covers_unknown_schemas_and_scopes_beyond_one_thousand() {
    112     let store = MemoryStorage::default();
    113     for id in (1..=1001).rev() {
    114         let schema = if id % 3 == 0 {
    115             "future.unknown.v999"
    116         } else {
    117             "known.v1"
    118         };
    119         block_on(store.append_authored_draft(draft(id, 7, schema, vec![1]), None)).unwrap();
    120     }
    121     block_on(store.append_authored_draft(draft(1002, 8, "future.unknown.v999", vec![1]), None))
    122         .unwrap();
    123     let q = AuthoredDraftQuery::for_author_all_schemas([7; 32], 37).unwrap();
    124     let mut next = None;
    125     let mut found = Vec::new();
    126     loop {
    127         let query = next.as_ref().map_or_else(
    128             || q.clone(),
    129             |cursor| q.clone().with_cursor(cursor).unwrap(),
    130         );
    131         let page = block_on(store.query_authored_drafts(query)).unwrap();
    132         assert!(page.records().len() <= 37);
    133         for record in page.records() {
    134             let AuthoredDraftQueryRecord::Draft(value) = record else {
    135                 panic!("valid fixture")
    136             };
    137             let id = u128::from_be_bytes(record.draft_key());
    138             found.push(id);
    139             assert_eq!(
    140                 value.payload_schema(),
    141                 if id % 3 == 0 {
    142                     "future.unknown.v999"
    143                 } else {
    144                     "known.v1"
    145                 }
    146             );
    147             if id == 1001 {
    148                 assert_eq!(value.revision().get(), 2);
    149             }
    150         }
    151         next = page.next_cursor().cloned();
    152         if found.len() == 37 {
    153             for id in [1_u128, 1001] {
    154                 let value = block_on(
    155                     store.authored_draft_head(AuthoredDraftId::new(id.to_be_bytes()).unwrap()),
    156                 )
    157                 .unwrap()
    158                 .unwrap();
    159                 let revised = value
    160                     .successor(vec![2], AuthoredDraftStage::Draft, None, 11)
    161                     .unwrap();
    162                 block_on(store.append_authored_draft(revised, Some(value.revision()))).unwrap();
    163             }
    164         }
    165         if next.is_none() {
    166             break;
    167         }
    168     }
    169     assert_eq!(found, (1..=1001).collect::<Vec<_>>());
    170     let fresh = block_on(store.query_authored_drafts(q)).unwrap();
    171     assert_eq!(fresh.records()[0].revision().get(), 2);
    172 }
    173 
    174 #[test]
    175 fn all_schema_memory_pages_keep_payload_bounds_and_validate_authority() {
    176     let store = MemoryStorage::default();
    177     let first = draft(1, 7, "known.v1", vec![1; 3 * 1024 * 1024]);
    178     let second = draft(2, 7, "future.v999", vec![2; 3 * 1024 * 1024]);
    179     for value in [first.clone(), second.clone()] {
    180         block_on(store.append_authored_draft(value, None)).unwrap();
    181     }
    182     let q = AuthoredDraftQuery::for_author_all_schemas([7; 32], 256).unwrap();
    183     let page = block_on(store.query_authored_drafts(q.clone())).unwrap();
    184     assert_eq!(
    185         page.records(),
    186         [AuthoredDraftQueryRecord::Draft(first.clone())]
    187     );
    188     let next = block_on(
    189         store.query_authored_drafts(q.clone().with_cursor(page.next_cursor().unwrap()).unwrap()),
    190     )
    191     .unwrap();
    192     assert_eq!(
    193         next.records(),
    194         [AuthoredDraftQueryRecord::Draft(second.clone())]
    195     );
    196     assert!(next.next_cursor().is_none());
    197     assert!(
    198         AuthoredDraftPage::new(
    199             &q,
    200             vec![
    201                 AuthoredDraftQueryRecord::Draft(first),
    202                 AuthoredDraftQueryRecord::Draft(second)
    203             ],
    204             false
    205         )
    206         .is_err()
    207     );
    208     let foreign = AuthoredDraftQueryRecord::Draft(draft(3, 8, "known.v1", vec![1]));
    209     assert!(AuthoredDraftPage::new(&q, vec![foreign], false).is_err());
    210 }