lib

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

authored_draft.rs (4476B)


      1 use futures_executor::block_on;
      2 use radroots_storage::{
      3     Error,
      4     authored_draft::{
      5         AUTHORED_DRAFT_QUERY_LIMIT_MAX, AuthoredDraft, AuthoredDraftId, AuthoredDraftRevision,
      6         AuthoredDraftStage, AuthoredDraftStore, DraftAppendDisposition,
      7     },
      8     memory::MemoryStorage,
      9 };
     10 
     11 fn draft(id: u8, author: u8, created_at_unix_ms: u64) -> AuthoredDraft {
     12     AuthoredDraft::initial(
     13         AuthoredDraftId::new([id; 16]).expect("draft ID"),
     14         [author; 32],
     15         "radroots.phase1-draft.v1",
     16         vec![id],
     17         AuthoredDraftStage::Draft,
     18         None,
     19         created_at_unix_ms,
     20     )
     21     .expect("draft")
     22 }
     23 
     24 #[test]
     25 fn memory_draft_store_replays_conflicts_and_queries_exact_heads() {
     26     fn accepts_dyn(_: &dyn AuthoredDraftStore) {}
     27 
     28     let store = MemoryStorage::default();
     29     accepts_dyn(&store);
     30     let first = draft(1, 9, 10);
     31     assert_eq!(
     32         block_on(store.append_authored_draft(first.clone(), None))
     33             .expect("insert")
     34             .disposition(),
     35         DraftAppendDisposition::Inserted
     36     );
     37     let replay = block_on(store.append_authored_draft(first.clone(), None)).expect("replay");
     38     assert_eq!(replay.disposition(), DraftAppendDisposition::Replay);
     39     assert_eq!(replay.draft(), &first);
     40 
     41     let conflicting = AuthoredDraft::initial(
     42         first.draft_id(),
     43         *first.author(),
     44         first.payload_schema(),
     45         b"conflict".to_vec(),
     46         AuthoredDraftStage::Draft,
     47         None,
     48         first.created_at_unix_ms(),
     49     )
     50     .expect("conflicting revision");
     51     assert_eq!(
     52         block_on(store.append_authored_draft(conflicting, None)),
     53         Err(Error::DraftRevisionConflict)
     54     );
     55 
     56     let second = first
     57         .successor(
     58             b"second".to_vec(),
     59             AuthoredDraftStage::MediaPreparing,
     60             None,
     61             11,
     62         )
     63         .expect("successor");
     64     assert_eq!(
     65         block_on(store.append_authored_draft(second.clone(), None)),
     66         Err(Error::DraftRevisionConflict)
     67     );
     68     assert_eq!(
     69         block_on(store.append_authored_draft(
     70             second.clone(),
     71             Some(AuthoredDraftRevision::new(2).expect("revision")),
     72         )),
     73         Err(Error::DraftRevisionConflict)
     74     );
     75     block_on(store.append_authored_draft(second.clone(), Some(AuthoredDraftRevision::INITIAL)))
     76         .expect("successor insert");
     77 
     78     assert_eq!(
     79         block_on(store.authored_draft_head(first.draft_id()))
     80             .expect("head")
     81             .expect("stored head"),
     82         second
     83     );
     84     assert_eq!(
     85         block_on(store.authored_draft_revision(first.draft_id(), first.revision()))
     86             .expect("revision")
     87             .expect("stored revision"),
     88         first
     89     );
     90     assert!(
     91         block_on(store.authored_draft_revision(
     92             AuthoredDraftId::new([8; 16]).expect("missing ID"),
     93             AuthoredDraftRevision::INITIAL,
     94         ))
     95         .expect("missing revision query")
     96         .is_none()
     97     );
     98 }
     99 
    100 #[test]
    101 fn memory_draft_head_query_is_bounded_filtered_sorted_and_truncated() {
    102     let store = MemoryStorage::default();
    103     let first = draft(1, 9, 10);
    104     let second = draft(2, 9, 20);
    105     let other_author = draft(3, 8, 30);
    106     for value in [&first, &second, &other_author] {
    107         block_on(store.append_authored_draft(value.clone(), None)).expect("insert");
    108     }
    109     let first_head = first
    110         .successor(
    111             b"new head".to_vec(),
    112             AuthoredDraftStage::MediaPreparing,
    113             None,
    114             40,
    115         )
    116         .expect("new head");
    117     block_on(store.append_authored_draft(first_head.clone(), Some(first.revision())))
    118         .expect("head insert");
    119 
    120     let heads = block_on(store.authored_draft_heads([9; 32], 2)).expect("heads");
    121     assert_eq!(heads, vec![first_head.clone(), second]);
    122     assert_eq!(
    123         block_on(store.authored_draft_heads([9; 32], 1)).expect("truncated heads"),
    124         vec![first_head]
    125     );
    126     assert!(
    127         block_on(store.authored_draft_heads([7; 32], 2))
    128             .expect("unmatched author")
    129             .is_empty()
    130     );
    131     assert_eq!(
    132         block_on(store.authored_draft_heads([0; 32], 1)),
    133         Err(Error::InvalidAuthoredDraft)
    134     );
    135     assert_eq!(
    136         block_on(store.authored_draft_heads([9; 32], 0)),
    137         Err(Error::InvalidAuthoredDraft)
    138     );
    139     assert_eq!(
    140         block_on(store.authored_draft_heads([9; 32], AUTHORED_DRAFT_QUERY_LIMIT_MAX + 1,)),
    141         Err(Error::InvalidAuthoredDraft)
    142     );
    143 }