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}