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}