this repo has no description
1#[cfg(test)]
2mod tests {
3 use crate::sync::verify::{CarVerifier, VerifyError};
4 use bytes::Bytes;
5 use cid::Cid;
6 use sha2::{Digest, Sha256};
7 use std::collections::HashMap;
8
9 fn make_cid(data: &[u8]) -> Cid {
10 let mut hasher = Sha256::new();
11 hasher.update(data);
12 let hash = hasher.finalize();
13 let multihash = multihash::Multihash::wrap(0x12, &hash).unwrap();
14 Cid::new_v1(0x71, multihash)
15 }
16
17 #[test]
18 fn test_verifier_creation() {
19 let _verifier = CarVerifier::new();
20 }
21
22 #[test]
23 fn test_verify_error_display() {
24 let err = VerifyError::DidMismatch {
25 commit_did: "did:plc:abc".to_string(),
26 expected_did: "did:plc:xyz".to_string(),
27 };
28 assert!(err.to_string().contains("did:plc:abc"));
29 assert!(err.to_string().contains("did:plc:xyz"));
30 let err = VerifyError::InvalidSignature;
31 assert!(err.to_string().contains("signature"));
32 let err = VerifyError::NoSigningKey;
33 assert!(err.to_string().contains("signing key"));
34 let err = VerifyError::MstValidationFailed("test error".to_string());
35 assert!(err.to_string().contains("test error"));
36 }
37
38 #[test]
39 fn test_mst_validation_missing_root_block() {
40 let verifier = CarVerifier::new();
41 let blocks: HashMap<Cid, Bytes> = HashMap::new();
42 let fake_cid = make_cid(b"fake data");
43 let result = verifier.verify_mst_structure(&fake_cid, &blocks);
44 assert!(result.is_err());
45 let err = result.unwrap_err();
46 assert!(matches!(err, VerifyError::BlockNotFound(_)));
47 }
48
49 #[test]
50 fn test_mst_validation_invalid_cbor() {
51 let verifier = CarVerifier::new();
52 let bad_cbor = Bytes::from(vec![0xFF, 0xFF, 0xFF]);
53 let cid = make_cid(&bad_cbor);
54 let mut blocks = HashMap::new();
55 blocks.insert(cid, bad_cbor);
56 let result = verifier.verify_mst_structure(&cid, &blocks);
57 assert!(result.is_err());
58 let err = result.unwrap_err();
59 assert!(matches!(err, VerifyError::InvalidCbor(_)));
60 }
61
62 #[test]
63 fn test_mst_validation_empty_node() {
64 let verifier = CarVerifier::new();
65 let empty_node = serde_ipld_dagcbor::to_vec(&serde_json::json!({
66 "e": []
67 }))
68 .unwrap();
69 let cid = make_cid(&empty_node);
70 let mut blocks = HashMap::new();
71 blocks.insert(cid, Bytes::from(empty_node));
72 let result = verifier.verify_mst_structure(&cid, &blocks);
73 assert!(result.is_ok());
74 }
75
76 #[test]
77 fn test_mst_validation_missing_left_pointer() {
78 use ipld_core::ipld::Ipld;
79
80 let verifier = CarVerifier::new();
81 let missing_left_cid = make_cid(b"missing left");
82 let node = Ipld::Map(std::collections::BTreeMap::from([
83 ("l".to_string(), Ipld::Link(missing_left_cid)),
84 ("e".to_string(), Ipld::List(vec![])),
85 ]));
86 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
87 let cid = make_cid(&node_bytes);
88 let mut blocks = HashMap::new();
89 blocks.insert(cid, Bytes::from(node_bytes));
90 let result = verifier.verify_mst_structure(&cid, &blocks);
91 assert!(result.is_err());
92 let err = result.unwrap_err();
93 assert!(matches!(err, VerifyError::BlockNotFound(_)));
94 assert!(err.to_string().contains("left pointer"));
95 }
96
97 #[test]
98 fn test_mst_validation_missing_subtree() {
99 use ipld_core::ipld::Ipld;
100
101 let verifier = CarVerifier::new();
102 let missing_subtree_cid = make_cid(b"missing subtree");
103 let record_cid = make_cid(b"record");
104 let entry = Ipld::Map(std::collections::BTreeMap::from([
105 ("k".to_string(), Ipld::Bytes(b"key1".to_vec())),
106 ("v".to_string(), Ipld::Link(record_cid)),
107 ("p".to_string(), Ipld::Integer(0)),
108 ("t".to_string(), Ipld::Link(missing_subtree_cid)),
109 ]));
110 let node = Ipld::Map(std::collections::BTreeMap::from([(
111 "e".to_string(),
112 Ipld::List(vec![entry]),
113 )]));
114 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
115 let cid = make_cid(&node_bytes);
116 let mut blocks = HashMap::new();
117 blocks.insert(cid, Bytes::from(node_bytes));
118 let result = verifier.verify_mst_structure(&cid, &blocks);
119 assert!(result.is_err());
120 let err = result.unwrap_err();
121 assert!(matches!(err, VerifyError::BlockNotFound(_)));
122 assert!(err.to_string().contains("subtree"));
123 }
124
125 #[test]
126 fn test_mst_validation_unsorted_keys() {
127 use ipld_core::ipld::Ipld;
128
129 let verifier = CarVerifier::new();
130 let record_cid = make_cid(b"record");
131 let entry1 = Ipld::Map(std::collections::BTreeMap::from([
132 ("k".to_string(), Ipld::Bytes(b"zzz".to_vec())),
133 ("v".to_string(), Ipld::Link(record_cid)),
134 ("p".to_string(), Ipld::Integer(0)),
135 ]));
136 let entry2 = Ipld::Map(std::collections::BTreeMap::from([
137 ("k".to_string(), Ipld::Bytes(b"aaa".to_vec())),
138 ("v".to_string(), Ipld::Link(record_cid)),
139 ("p".to_string(), Ipld::Integer(0)),
140 ]));
141 let node = Ipld::Map(std::collections::BTreeMap::from([(
142 "e".to_string(),
143 Ipld::List(vec![entry1, entry2]),
144 )]));
145 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
146 let cid = make_cid(&node_bytes);
147 let mut blocks = HashMap::new();
148 blocks.insert(cid, Bytes::from(node_bytes));
149 let result = verifier.verify_mst_structure(&cid, &blocks);
150 assert!(result.is_err());
151 let err = result.unwrap_err();
152 assert!(matches!(err, VerifyError::MstValidationFailed(_)));
153 assert!(err.to_string().contains("sorted"));
154 }
155
156 #[test]
157 fn test_mst_validation_sorted_keys_ok() {
158 use ipld_core::ipld::Ipld;
159
160 let verifier = CarVerifier::new();
161 let record_cid = make_cid(b"record");
162 let entry1 = Ipld::Map(std::collections::BTreeMap::from([
163 ("k".to_string(), Ipld::Bytes(b"aaa".to_vec())),
164 ("v".to_string(), Ipld::Link(record_cid)),
165 ("p".to_string(), Ipld::Integer(0)),
166 ]));
167 let entry2 = Ipld::Map(std::collections::BTreeMap::from([
168 ("k".to_string(), Ipld::Bytes(b"bbb".to_vec())),
169 ("v".to_string(), Ipld::Link(record_cid)),
170 ("p".to_string(), Ipld::Integer(0)),
171 ]));
172 let entry3 = Ipld::Map(std::collections::BTreeMap::from([
173 ("k".to_string(), Ipld::Bytes(b"zzz".to_vec())),
174 ("v".to_string(), Ipld::Link(record_cid)),
175 ("p".to_string(), Ipld::Integer(0)),
176 ]));
177 let node = Ipld::Map(std::collections::BTreeMap::from([(
178 "e".to_string(),
179 Ipld::List(vec![entry1, entry2, entry3]),
180 )]));
181 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
182 let cid = make_cid(&node_bytes);
183 let mut blocks = HashMap::new();
184 blocks.insert(cid, Bytes::from(node_bytes));
185 let result = verifier.verify_mst_structure(&cid, &blocks);
186 assert!(result.is_ok());
187 }
188
189 #[test]
190 fn test_mst_validation_with_valid_left_pointer() {
191 use ipld_core::ipld::Ipld;
192
193 let verifier = CarVerifier::new();
194 let left_node = Ipld::Map(std::collections::BTreeMap::from([(
195 "e".to_string(),
196 Ipld::List(vec![]),
197 )]));
198 let left_node_bytes = serde_ipld_dagcbor::to_vec(&left_node).unwrap();
199 let left_cid = make_cid(&left_node_bytes);
200 let root_node = Ipld::Map(std::collections::BTreeMap::from([
201 ("l".to_string(), Ipld::Link(left_cid)),
202 ("e".to_string(), Ipld::List(vec![])),
203 ]));
204 let root_node_bytes = serde_ipld_dagcbor::to_vec(&root_node).unwrap();
205 let root_cid = make_cid(&root_node_bytes);
206 let mut blocks = HashMap::new();
207 blocks.insert(root_cid, Bytes::from(root_node_bytes));
208 blocks.insert(left_cid, Bytes::from(left_node_bytes));
209 let result = verifier.verify_mst_structure(&root_cid, &blocks);
210 assert!(result.is_ok());
211 }
212
213 #[test]
214 fn test_mst_validation_cycle_detection() {
215 let verifier = CarVerifier::new();
216 let node = serde_ipld_dagcbor::to_vec(&serde_json::json!({
217 "e": []
218 }))
219 .unwrap();
220 let cid = make_cid(&node);
221 let mut blocks = HashMap::new();
222 blocks.insert(cid, Bytes::from(node));
223 let result = verifier.verify_mst_structure(&cid, &blocks);
224 assert!(result.is_ok());
225 }
226
227 #[tokio::test]
228 async fn test_unsupported_did_method() {
229 let verifier = CarVerifier::new();
230 let result = verifier.resolve_did_document("did:unknown:test").await;
231 assert!(result.is_err());
232 let err = result.unwrap_err();
233 assert!(matches!(err, VerifyError::DidResolutionFailed(_)));
234 assert!(err.to_string().contains("Unsupported"));
235 }
236
237 #[test]
238 fn test_mst_validation_with_prefix_compression() {
239 use ipld_core::ipld::Ipld;
240
241 let verifier = CarVerifier::new();
242 let record_cid = make_cid(b"record");
243 let entry1 = Ipld::Map(std::collections::BTreeMap::from([
244 (
245 "k".to_string(),
246 Ipld::Bytes(b"app.bsky.feed.post/abc".to_vec()),
247 ),
248 ("v".to_string(), Ipld::Link(record_cid)),
249 ("p".to_string(), Ipld::Integer(0)),
250 ]));
251 let entry2 = Ipld::Map(std::collections::BTreeMap::from([
252 ("k".to_string(), Ipld::Bytes(b"def".to_vec())),
253 ("v".to_string(), Ipld::Link(record_cid)),
254 ("p".to_string(), Ipld::Integer(19)),
255 ]));
256 let entry3 = Ipld::Map(std::collections::BTreeMap::from([
257 ("k".to_string(), Ipld::Bytes(b"xyz".to_vec())),
258 ("v".to_string(), Ipld::Link(record_cid)),
259 ("p".to_string(), Ipld::Integer(19)),
260 ]));
261 let node = Ipld::Map(std::collections::BTreeMap::from([(
262 "e".to_string(),
263 Ipld::List(vec![entry1, entry2, entry3]),
264 )]));
265 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
266 let cid = make_cid(&node_bytes);
267 let mut blocks = HashMap::new();
268 blocks.insert(cid, Bytes::from(node_bytes));
269 let result = verifier.verify_mst_structure(&cid, &blocks);
270 assert!(
271 result.is_ok(),
272 "Prefix-compressed keys should be validated correctly"
273 );
274 }
275
276 #[test]
277 fn test_mst_validation_prefix_compression_unsorted() {
278 use ipld_core::ipld::Ipld;
279
280 let verifier = CarVerifier::new();
281 let record_cid = make_cid(b"record");
282 let entry1 = Ipld::Map(std::collections::BTreeMap::from([
283 (
284 "k".to_string(),
285 Ipld::Bytes(b"app.bsky.feed.post/xyz".to_vec()),
286 ),
287 ("v".to_string(), Ipld::Link(record_cid)),
288 ("p".to_string(), Ipld::Integer(0)),
289 ]));
290 let entry2 = Ipld::Map(std::collections::BTreeMap::from([
291 ("k".to_string(), Ipld::Bytes(b"abc".to_vec())),
292 ("v".to_string(), Ipld::Link(record_cid)),
293 ("p".to_string(), Ipld::Integer(19)),
294 ]));
295 let node = Ipld::Map(std::collections::BTreeMap::from([(
296 "e".to_string(),
297 Ipld::List(vec![entry1, entry2]),
298 )]));
299 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
300 let cid = make_cid(&node_bytes);
301 let mut blocks = HashMap::new();
302 blocks.insert(cid, Bytes::from(node_bytes));
303 let result = verifier.verify_mst_structure(&cid, &blocks);
304 assert!(
305 result.is_err(),
306 "Unsorted prefix-compressed keys should fail validation"
307 );
308 let err = result.unwrap_err();
309 assert!(matches!(err, VerifyError::MstValidationFailed(_)));
310 }
311}