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 })).unwrap();
68 let cid = make_cid(&empty_node);
69 let mut blocks = HashMap::new();
70 blocks.insert(cid, Bytes::from(empty_node));
71 let result = verifier.verify_mst_structure(&cid, &blocks);
72 assert!(result.is_ok());
73 }
74
75 #[test]
76 fn test_mst_validation_missing_left_pointer() {
77 use ipld_core::ipld::Ipld;
78
79 let verifier = CarVerifier::new();
80 let missing_left_cid = make_cid(b"missing left");
81 let node = Ipld::Map(std::collections::BTreeMap::from([
82 ("l".to_string(), Ipld::Link(missing_left_cid)),
83 ("e".to_string(), Ipld::List(vec![])),
84 ]));
85 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
86 let cid = make_cid(&node_bytes);
87 let mut blocks = HashMap::new();
88 blocks.insert(cid, Bytes::from(node_bytes));
89 let result = verifier.verify_mst_structure(&cid, &blocks);
90 assert!(result.is_err());
91 let err = result.unwrap_err();
92 assert!(matches!(err, VerifyError::BlockNotFound(_)));
93 assert!(err.to_string().contains("left pointer"));
94 }
95
96 #[test]
97 fn test_mst_validation_missing_subtree() {
98 use ipld_core::ipld::Ipld;
99
100 let verifier = CarVerifier::new();
101 let missing_subtree_cid = make_cid(b"missing subtree");
102 let record_cid = make_cid(b"record");
103 let entry = Ipld::Map(std::collections::BTreeMap::from([
104 ("k".to_string(), Ipld::Bytes(b"key1".to_vec())),
105 ("v".to_string(), Ipld::Link(record_cid)),
106 ("p".to_string(), Ipld::Integer(0)),
107 ("t".to_string(), Ipld::Link(missing_subtree_cid)),
108 ]));
109 let node = Ipld::Map(std::collections::BTreeMap::from([
110 ("e".to_string(), Ipld::List(vec![entry])),
111 ]));
112 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
113 let cid = make_cid(&node_bytes);
114 let mut blocks = HashMap::new();
115 blocks.insert(cid, Bytes::from(node_bytes));
116 let result = verifier.verify_mst_structure(&cid, &blocks);
117 assert!(result.is_err());
118 let err = result.unwrap_err();
119 assert!(matches!(err, VerifyError::BlockNotFound(_)));
120 assert!(err.to_string().contains("subtree"));
121 }
122
123 #[test]
124 fn test_mst_validation_unsorted_keys() {
125 use ipld_core::ipld::Ipld;
126
127 let verifier = CarVerifier::new();
128 let record_cid = make_cid(b"record");
129 let entry1 = Ipld::Map(std::collections::BTreeMap::from([
130 ("k".to_string(), Ipld::Bytes(b"zzz".to_vec())),
131 ("v".to_string(), Ipld::Link(record_cid)),
132 ("p".to_string(), Ipld::Integer(0)),
133 ]));
134 let entry2 = Ipld::Map(std::collections::BTreeMap::from([
135 ("k".to_string(), Ipld::Bytes(b"aaa".to_vec())),
136 ("v".to_string(), Ipld::Link(record_cid)),
137 ("p".to_string(), Ipld::Integer(0)),
138 ]));
139 let node = Ipld::Map(std::collections::BTreeMap::from([
140 ("e".to_string(), Ipld::List(vec![entry1, entry2])),
141 ]));
142 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
143 let cid = make_cid(&node_bytes);
144 let mut blocks = HashMap::new();
145 blocks.insert(cid, Bytes::from(node_bytes));
146 let result = verifier.verify_mst_structure(&cid, &blocks);
147 assert!(result.is_err());
148 let err = result.unwrap_err();
149 assert!(matches!(err, VerifyError::MstValidationFailed(_)));
150 assert!(err.to_string().contains("sorted"));
151 }
152
153 #[test]
154 fn test_mst_validation_sorted_keys_ok() {
155 use ipld_core::ipld::Ipld;
156
157 let verifier = CarVerifier::new();
158 let record_cid = make_cid(b"record");
159 let entry1 = 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 let entry2 = Ipld::Map(std::collections::BTreeMap::from([
165 ("k".to_string(), Ipld::Bytes(b"bbb".to_vec())),
166 ("v".to_string(), Ipld::Link(record_cid)),
167 ("p".to_string(), Ipld::Integer(0)),
168 ]));
169 let entry3 = Ipld::Map(std::collections::BTreeMap::from([
170 ("k".to_string(), Ipld::Bytes(b"zzz".to_vec())),
171 ("v".to_string(), Ipld::Link(record_cid)),
172 ("p".to_string(), Ipld::Integer(0)),
173 ]));
174 let node = Ipld::Map(std::collections::BTreeMap::from([
175 ("e".to_string(), Ipld::List(vec![entry1, entry2, entry3])),
176 ]));
177 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
178 let cid = make_cid(&node_bytes);
179 let mut blocks = HashMap::new();
180 blocks.insert(cid, Bytes::from(node_bytes));
181 let result = verifier.verify_mst_structure(&cid, &blocks);
182 assert!(result.is_ok());
183 }
184
185 #[test]
186 fn test_mst_validation_with_valid_left_pointer() {
187 use ipld_core::ipld::Ipld;
188
189 let verifier = CarVerifier::new();
190 let left_node = Ipld::Map(std::collections::BTreeMap::from([
191 ("e".to_string(), Ipld::List(vec![])),
192 ]));
193 let left_node_bytes = serde_ipld_dagcbor::to_vec(&left_node).unwrap();
194 let left_cid = make_cid(&left_node_bytes);
195 let root_node = Ipld::Map(std::collections::BTreeMap::from([
196 ("l".to_string(), Ipld::Link(left_cid)),
197 ("e".to_string(), Ipld::List(vec![])),
198 ]));
199 let root_node_bytes = serde_ipld_dagcbor::to_vec(&root_node).unwrap();
200 let root_cid = make_cid(&root_node_bytes);
201 let mut blocks = HashMap::new();
202 blocks.insert(root_cid, Bytes::from(root_node_bytes));
203 blocks.insert(left_cid, Bytes::from(left_node_bytes));
204 let result = verifier.verify_mst_structure(&root_cid, &blocks);
205 assert!(result.is_ok());
206 }
207
208 #[test]
209 fn test_mst_validation_cycle_detection() {
210 let verifier = CarVerifier::new();
211 let node = serde_ipld_dagcbor::to_vec(&serde_json::json!({
212 "e": []
213 })).unwrap();
214 let cid = make_cid(&node);
215 let mut blocks = HashMap::new();
216 blocks.insert(cid, Bytes::from(node));
217 let result = verifier.verify_mst_structure(&cid, &blocks);
218 assert!(result.is_ok());
219 }
220
221 #[tokio::test]
222 async fn test_unsupported_did_method() {
223 let verifier = CarVerifier::new();
224 let result = verifier.resolve_did_document("did:unknown:test").await;
225 assert!(result.is_err());
226 let err = result.unwrap_err();
227 assert!(matches!(err, VerifyError::DidResolutionFailed(_)));
228 assert!(err.to_string().contains("Unsupported"));
229 }
230
231 #[test]
232 fn test_mst_validation_with_prefix_compression() {
233 use ipld_core::ipld::Ipld;
234
235 let verifier = CarVerifier::new();
236 let record_cid = make_cid(b"record");
237 let entry1 = Ipld::Map(std::collections::BTreeMap::from([
238 ("k".to_string(), Ipld::Bytes(b"app.bsky.feed.post/abc".to_vec())),
239 ("v".to_string(), Ipld::Link(record_cid)),
240 ("p".to_string(), Ipld::Integer(0)),
241 ]));
242 let entry2 = Ipld::Map(std::collections::BTreeMap::from([
243 ("k".to_string(), Ipld::Bytes(b"def".to_vec())),
244 ("v".to_string(), Ipld::Link(record_cid)),
245 ("p".to_string(), Ipld::Integer(19)),
246 ]));
247 let entry3 = Ipld::Map(std::collections::BTreeMap::from([
248 ("k".to_string(), Ipld::Bytes(b"xyz".to_vec())),
249 ("v".to_string(), Ipld::Link(record_cid)),
250 ("p".to_string(), Ipld::Integer(19)),
251 ]));
252 let node = Ipld::Map(std::collections::BTreeMap::from([
253 ("e".to_string(), Ipld::List(vec![entry1, entry2, entry3])),
254 ]));
255 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
256 let cid = make_cid(&node_bytes);
257 let mut blocks = HashMap::new();
258 blocks.insert(cid, Bytes::from(node_bytes));
259 let result = verifier.verify_mst_structure(&cid, &blocks);
260 assert!(result.is_ok(), "Prefix-compressed keys should be validated correctly");
261 }
262
263 #[test]
264 fn test_mst_validation_prefix_compression_unsorted() {
265 use ipld_core::ipld::Ipld;
266
267 let verifier = CarVerifier::new();
268 let record_cid = make_cid(b"record");
269 let entry1 = Ipld::Map(std::collections::BTreeMap::from([
270 ("k".to_string(), Ipld::Bytes(b"app.bsky.feed.post/xyz".to_vec())),
271 ("v".to_string(), Ipld::Link(record_cid)),
272 ("p".to_string(), Ipld::Integer(0)),
273 ]));
274 let entry2 = Ipld::Map(std::collections::BTreeMap::from([
275 ("k".to_string(), Ipld::Bytes(b"abc".to_vec())),
276 ("v".to_string(), Ipld::Link(record_cid)),
277 ("p".to_string(), Ipld::Integer(19)),
278 ]));
279 let node = Ipld::Map(std::collections::BTreeMap::from([
280 ("e".to_string(), Ipld::List(vec![entry1, entry2])),
281 ]));
282 let node_bytes = serde_ipld_dagcbor::to_vec(&node).unwrap();
283 let cid = make_cid(&node_bytes);
284 let mut blocks = HashMap::new();
285 blocks.insert(cid, Bytes::from(node_bytes));
286 let result = verifier.verify_mst_structure(&cid, &blocks);
287 assert!(result.is_err(), "Unsorted prefix-compressed keys should fail validation");
288 let err = result.unwrap_err();
289 assert!(matches!(err, VerifyError::MstValidationFailed(_)));
290 }
291}