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}