structfs_handles/
conformance.rs1use structfs_core_store::{DetachedStore, Error, Path, Record, Value};
9
10fn root() -> Path {
11 Path::parse("").unwrap()
12}
13
14pub async fn check_handle_conventions<S: DetachedStore>(store: &mut S, request: Value) {
18 check_mint_returns_handle_path(store, request.clone()).await;
19 check_overwrite_conflicts(store, request.clone()).await;
20 check_release_and_absence(store, request.clone()).await;
21 check_release_idempotent(store, request).await;
22}
23
24pub async fn check_mint_returns_handle_path<S: DetachedStore>(store: &mut S, request: Value) {
26 let path = store
27 .write_detached(&root(), Record::parsed(request))
28 .await
29 .expect("mint write failed");
30 assert!(
31 path.len() == 2 && &path[0] == "outstanding" && path[1].parse::<u64>().is_ok(),
32 "mint must return outstanding/{{id}}, got: {}",
33 path
34 );
35 let record = store
36 .read_detached(&path)
37 .await
38 .expect("handle read failed");
39 assert!(record.is_some(), "a live handle must be readable");
40}
41
42pub async fn check_overwrite_conflicts<S: DetachedStore>(store: &mut S, request: Value) {
44 let path = store
45 .write_detached(&root(), Record::parsed(request))
46 .await
47 .expect("mint write failed");
48 let err = store
49 .write_detached(&path, Record::parsed(Value::from("clobber")))
50 .await
51 .expect_err("overwriting a live handle must fail");
52 assert!(
53 matches!(err, Error::Conflict { .. }),
54 "handle overwrite must be Error::Conflict, got: {}",
55 err
56 );
57}
58
59pub async fn check_release_and_absence<S: DetachedStore>(store: &mut S, request: Value) {
61 let path = store
62 .write_detached(&root(), Record::parsed(request))
63 .await
64 .expect("mint write failed");
65 store
66 .write_detached(&path, Record::parsed(Value::Null))
67 .await
68 .expect("Null write must release the handle");
69 let record = store
70 .read_detached(&path)
71 .await
72 .expect("post-release read failed");
73 assert!(record.is_none(), "a released handle must read as absent");
74}
75
76pub async fn check_release_idempotent<S: DetachedStore>(store: &mut S, request: Value) {
78 let path = store
79 .write_detached(&root(), Record::parsed(request))
80 .await
81 .expect("mint write failed");
82 store
83 .write_detached(&path, Record::parsed(Value::Null))
84 .await
85 .expect("first release failed");
86 store
87 .write_detached(&path, Record::parsed(Value::Null))
88 .await
89 .expect("double release must be a no-op");
90 store
91 .write_detached(
92 &Path::parse("outstanding/18446744073709551614").unwrap(),
93 Record::parsed(Value::Null),
94 )
95 .await
96 .expect("releasing an unknown handle must be a no-op");
97}