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