A better Rust ATProto crate

fixing some tests

Orual df39d157 62fb1f0f

+269 -129
+9 -9
crates/jacquard-repo/src/mst/cursor.rs
··· 242 242 async fn test_cursor_single_leaf() { 243 243 let storage = Arc::new(MemoryBlockStore::new()); 244 244 let tree = Mst::new(storage); 245 - let tree = tree.add("key1", test_cid(1)).await.unwrap(); 245 + let tree = tree.add("com.example.test/key1", test_cid(1)).await.unwrap(); 246 246 247 247 let mut cursor = MstCursor::new(tree); 248 248 ··· 251 251 252 252 // Advance to first leaf 253 253 cursor.advance().await.unwrap(); 254 - assert_eq!(cursor.key(), Some("key1")); 254 + assert_eq!(cursor.key(), Some("com.example.test/key1")); 255 255 256 256 // Advance past last leaf 257 257 cursor.advance().await.unwrap(); ··· 262 262 async fn test_cursor_multiple_leaves() { 263 263 let storage = Arc::new(MemoryBlockStore::new()); 264 264 let tree = Mst::new(storage); 265 - let tree = tree.add("a", test_cid(1)).await.unwrap(); 266 - let tree = tree.add("b", test_cid(2)).await.unwrap(); 267 - let tree = tree.add("c", test_cid(3)).await.unwrap(); 265 + let tree = tree.add("com.example.test/a", test_cid(1)).await.unwrap(); 266 + let tree = tree.add("com.example.test/b", test_cid(2)).await.unwrap(); 267 + let tree = tree.add("com.example.test/c", test_cid(3)).await.unwrap(); 268 268 269 269 let mut cursor = MstCursor::new(tree); 270 270 ··· 280 280 cursor.advance().await.unwrap(); 281 281 } 282 282 283 - assert_eq!(keys, vec!["a", "b", "c"]); 283 + assert_eq!(keys, vec!["com.example.test/a", "com.example.test/b", "com.example.test/c"]); 284 284 } 285 285 286 286 #[tokio::test] ··· 289 289 let tree = Mst::new(storage); 290 290 291 291 // Add enough keys to create subtrees 292 - let tree = tree.add("a", test_cid(1)).await.unwrap(); 293 - let tree = tree.add("b", test_cid(2)).await.unwrap(); 294 - let tree = tree.add("c", test_cid(3)).await.unwrap(); 292 + let tree = tree.add("com.example.test/a", test_cid(1)).await.unwrap(); 293 + let tree = tree.add("com.example.test/b", test_cid(2)).await.unwrap(); 294 + let tree = tree.add("com.example.test/c", test_cid(3)).await.unwrap(); 295 295 296 296 let mut cursor = MstCursor::new(tree); 297 297
+26 -26
crates/jacquard-repo/src/mst/diff.rs
··· 548 548 549 549 let storage2 = Arc::new(MemoryBlockStore::new()); 550 550 let tree2 = Mst::new(storage2); 551 - let tree2 = tree2.add("a", test_cid(1)).await.unwrap(); 552 - let tree2 = tree2.add("b", test_cid(2)).await.unwrap(); 551 + let tree2 = tree2.add("com.example.test/a", test_cid(1)).await.unwrap(); 552 + let tree2 = tree2.add("com.example.test/b", test_cid(2)).await.unwrap(); 553 553 554 554 let diff = tree1.diff(&tree2).await.unwrap(); 555 555 ··· 562 562 assert!( 563 563 diff.creates 564 564 .iter() 565 - .any(|(k, c)| k == "a" && *c == test_cid(1)) 565 + .any(|(k, c)| k == "com.example.test/a" && *c == test_cid(1)) 566 566 ); 567 567 assert!( 568 568 diff.creates 569 569 .iter() 570 - .any(|(k, c)| k == "b" && *c == test_cid(2)) 570 + .any(|(k, c)| k == "com.example.test/b" && *c == test_cid(2)) 571 571 ); 572 572 } 573 573 ··· 575 575 async fn test_diff_deletes() { 576 576 let storage1 = Arc::new(MemoryBlockStore::new()); 577 577 let tree1 = Mst::new(storage1); 578 - let tree1 = tree1.add("a", test_cid(1)).await.unwrap(); 579 - let tree1 = tree1.add("b", test_cid(2)).await.unwrap(); 578 + let tree1 = tree1.add("com.example.test/a", test_cid(1)).await.unwrap(); 579 + let tree1 = tree1.add("com.example.test/b", test_cid(2)).await.unwrap(); 580 580 581 581 let storage2 = Arc::new(MemoryBlockStore::new()); 582 582 let tree2 = Mst::new(storage2); ··· 592 592 assert!( 593 593 diff.deletes 594 594 .iter() 595 - .any(|(k, c)| k == "a" && *c == test_cid(1)) 595 + .any(|(k, c)| k == "com.example.test/a" && *c == test_cid(1)) 596 596 ); 597 597 assert!( 598 598 diff.deletes 599 599 .iter() 600 - .any(|(k, c)| k == "b" && *c == test_cid(2)) 600 + .any(|(k, c)| k == "com.example.test/b" && *c == test_cid(2)) 601 601 ); 602 602 } 603 603 ··· 605 605 async fn test_diff_updates() { 606 606 let storage1 = Arc::new(MemoryBlockStore::new()); 607 607 let tree1 = Mst::new(storage1); 608 - let tree1 = tree1.add("a", test_cid(1)).await.unwrap(); 609 - let tree1 = tree1.add("b", test_cid(2)).await.unwrap(); 608 + let tree1 = tree1.add("com.example.test/a", test_cid(1)).await.unwrap(); 609 + let tree1 = tree1.add("com.example.test/b", test_cid(2)).await.unwrap(); 610 610 611 611 let storage2 = Arc::new(MemoryBlockStore::new()); 612 612 let tree2 = Mst::new(storage2); 613 - let tree2 = tree2.add("a", test_cid(10)).await.unwrap(); // Changed CID 614 - let tree2 = tree2.add("b", test_cid(2)).await.unwrap(); // Same CID 613 + let tree2 = tree2.add("com.example.test/a", test_cid(10)).await.unwrap(); // Changed CID 614 + let tree2 = tree2.add("com.example.test/b", test_cid(2)).await.unwrap(); // Same CID 615 615 616 616 let diff = tree1.diff(&tree2).await.unwrap(); 617 617 ··· 621 621 assert_eq!(diff.op_count(), 1); 622 622 623 623 // Check update content 624 - assert_eq!(diff.updates[0].0, "a"); 624 + assert_eq!(diff.updates[0].0, "com.example.test/a"); 625 625 assert_eq!(diff.updates[0].1, test_cid(10)); // new CID 626 626 assert_eq!(diff.updates[0].2, test_cid(1)); // old CID 627 627 } ··· 630 630 async fn test_diff_mixed_operations() { 631 631 let storage1 = Arc::new(MemoryBlockStore::new()); 632 632 let tree1 = Mst::new(storage1); 633 - let tree1 = tree1.add("a", test_cid(1)).await.unwrap(); 634 - let tree1 = tree1.add("b", test_cid(2)).await.unwrap(); 635 - let tree1 = tree1.add("c", test_cid(3)).await.unwrap(); 633 + let tree1 = tree1.add("com.example.test/a", test_cid(1)).await.unwrap(); 634 + let tree1 = tree1.add("com.example.test/b", test_cid(2)).await.unwrap(); 635 + let tree1 = tree1.add("com.example.test/c", test_cid(3)).await.unwrap(); 636 636 637 637 let storage2 = Arc::new(MemoryBlockStore::new()); 638 638 let tree2 = Mst::new(storage2); 639 - let tree2 = tree2.add("a", test_cid(10)).await.unwrap(); // Updated 640 - let tree2 = tree2.add("b", test_cid(2)).await.unwrap(); // Unchanged 639 + let tree2 = tree2.add("com.example.test/a", test_cid(10)).await.unwrap(); // Updated 640 + let tree2 = tree2.add("com.example.test/b", test_cid(2)).await.unwrap(); // Unchanged 641 641 // "c" deleted 642 - let tree2 = tree2.add("d", test_cid(4)).await.unwrap(); // Created 642 + let tree2 = tree2.add("com.example.test/d", test_cid(4)).await.unwrap(); // Created 643 643 644 644 let diff = tree1.diff(&tree2).await.unwrap(); 645 645 ··· 653 653 async fn test_diff_to_empty() { 654 654 let storage = Arc::new(MemoryBlockStore::new()); 655 655 let tree = Mst::new(storage); 656 - let tree = tree.add("a", test_cid(1)).await.unwrap(); 657 - let tree = tree.add("b", test_cid(2)).await.unwrap(); 658 - let tree = tree.add("c", test_cid(3)).await.unwrap(); 656 + let tree = tree.add("com.example.test/a", test_cid(1)).await.unwrap(); 657 + let tree = tree.add("com.example.test/b", test_cid(2)).await.unwrap(); 658 + let tree = tree.add("com.example.test/c", test_cid(3)).await.unwrap(); 659 659 660 660 let diff = tree.diff_to_empty().await.unwrap(); 661 661 ··· 688 688 // diff(A, B) should be inverse of diff(B, A) 689 689 let storage1 = Arc::new(MemoryBlockStore::new()); 690 690 let tree1 = Mst::new(storage1); 691 - let tree1 = tree1.add("a", test_cid(1)).await.unwrap(); 692 - let tree1 = tree1.add("b", test_cid(2)).await.unwrap(); 691 + let tree1 = tree1.add("com.example.test/a", test_cid(1)).await.unwrap(); 692 + let tree1 = tree1.add("com.example.test/b", test_cid(2)).await.unwrap(); 693 693 694 694 let storage2 = Arc::new(MemoryBlockStore::new()); 695 695 let tree2 = Mst::new(storage2); 696 - let tree2 = tree2.add("b", test_cid(2)).await.unwrap(); 697 - let tree2 = tree2.add("c", test_cid(3)).await.unwrap(); 696 + let tree2 = tree2.add("com.example.test/b", test_cid(2)).await.unwrap(); 697 + let tree2 = tree2.add("com.example.test/c", test_cid(3)).await.unwrap(); 698 698 699 699 let diff1 = tree1.diff(&tree2).await.unwrap(); 700 700 let diff2 = tree2.diff(&tree1).await.unwrap();
+222 -89
crates/jacquard-repo/src/mst/tree.rs
··· 3 3 use super::node::NodeEntry; 4 4 use super::util; 5 5 use crate::error::{RepoError, Result}; 6 + use crate::mst::util::validate_key; 6 7 use crate::storage::BlockStore; 7 8 use cid::Cid as IpldCid; 8 9 use core::fmt; ··· 412 413 ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Option<IpldCid>>> + Send + 'a>> 413 414 { 414 415 Box::pin(async move { 415 - util::validate_key(key)?; 416 + validate_key(key)?; 416 417 417 418 let entries = self.get_entries().await?; 418 419 let index = Self::find_gt_or_equal_leaf_index_in(&entries, key); ··· 448 449 cid: IpldCid, 449 450 ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Mst<S>>> + Send + 'a>> { 450 451 Box::pin(async move { 451 - util::validate_key(key)?; 452 + validate_key(key)?; 452 453 453 454 let key_layer = util::layer_for_key(key); 454 455 let node_layer = self.get_layer().await?; ··· 571 572 key: &'a str, 572 573 ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Mst<S>>> + Send + 'a>> { 573 574 Box::pin(async move { 574 - util::validate_key(key)?; 575 + validate_key(key)?; 575 576 576 577 let altered = self.delete_recurse(key).await?; 577 578 altered.trim_top().await ··· 645 646 646 647 /// Update an existing key (returns new tree) 647 648 pub async fn update(&self, key: &str, cid: IpldCid) -> Result<Mst<S>> { 648 - util::validate_key(key)?; 649 + validate_key(key)?; 649 650 650 651 // Check key exists 651 652 if self.get(key).await?.is_none() { ··· 1085 1086 ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Vec<IpldCid>>> + Send + 'a>> 1086 1087 { 1087 1088 Box::pin(async move { 1088 - util::validate_key(key)?; 1089 + validate_key(key)?; 1089 1090 1090 1091 let mut cids = vec![self.get_pointer().await?]; 1091 1092 let entries = self.get_entries().await?; ··· 1308 1309 let storage = Arc::new(MemoryBlockStore::new()); 1309 1310 let mst = Mst::new(storage); 1310 1311 1311 - let result = mst.get("test/key").await.unwrap(); 1312 + let result = mst.get("com.example.test/key").await.unwrap(); 1312 1313 assert!(result.is_none()); 1313 1314 } 1314 1315 ··· 1319 1320 1320 1321 let entries = vec![ 1321 1322 NodeEntry::Leaf { 1322 - key: SmolStr::new("a"), 1323 + key: SmolStr::new("com.example.test/a"), 1323 1324 value: test_cid(1), 1324 1325 }, 1325 1326 NodeEntry::Leaf { 1326 - key: SmolStr::new("b"), 1327 + key: SmolStr::new("com.example.test/b"), 1327 1328 value: test_cid(2), 1328 1329 }, 1329 1330 NodeEntry::Leaf { 1330 - key: SmolStr::new("c"), 1331 + key: SmolStr::new("com.example.test/c"), 1331 1332 value: test_cid(3), 1332 1333 }, 1333 1334 ]; 1334 1335 1335 1336 let mst = Mst::create(storage, entries, Some(0)).await.unwrap(); 1336 1337 1337 - assert_eq!(mst.get("a").await.unwrap(), Some(test_cid(1))); 1338 - assert_eq!(mst.get("b").await.unwrap(), Some(test_cid(2))); 1339 - assert_eq!(mst.get("c").await.unwrap(), Some(test_cid(3))); 1340 - assert_eq!(mst.get("d").await.unwrap(), None); 1338 + assert_eq!( 1339 + mst.get("com.example.test/a").await.unwrap(), 1340 + Some(test_cid(1)) 1341 + ); 1342 + assert_eq!( 1343 + mst.get("com.example.test/b").await.unwrap(), 1344 + Some(test_cid(2)) 1345 + ); 1346 + assert_eq!( 1347 + mst.get("com.example.test/c").await.unwrap(), 1348 + Some(test_cid(3)) 1349 + ); 1350 + assert_eq!(mst.get("com.example.test/d").await.unwrap(), None); 1351 + } 1352 + 1353 + #[tokio::test] 1354 + async fn test_allowed_keys() -> Result<()> { 1355 + let cid1str = "bafyreie5cvv4h45feadgeuwhbcutmh6t2ceseocckahdoe6uat64zmz454"; 1356 + let cid1 = IpldCid::try_from(cid1str).unwrap(); 1357 + 1358 + let storage = Arc::new(MemoryBlockStore::new()); 1359 + let mst = Mst::new(storage); 1360 + // Rejects empty key 1361 + let result = mst.add(&"".to_string(), cid1).await; 1362 + assert!(result.is_err()); 1363 + 1364 + // Rejects a key with no collection 1365 + let result = mst.add(&"asdf".to_string(), cid1).await; 1366 + assert!(result.is_err()); 1367 + 1368 + // Rejects a key with a nested collection 1369 + let result = mst.add(&"nested/collection/asdf".to_string(), cid1).await; 1370 + assert!(result.is_err()); 1371 + 1372 + // Rejects on empty coll or rkey 1373 + let result = mst.add(&"coll/".to_string(), cid1).await; 1374 + assert!(result.is_err()); 1375 + let result = mst.add(&"/rkey".to_string(), cid1).await; 1376 + assert!(result.is_err()); 1377 + 1378 + // Rejects non-ascii chars 1379 + let result = mst.add(&"coll/jalapeñoA".to_string(), cid1).await; 1380 + assert!(result.is_err()); 1381 + let result = mst.add(&"coll/coöperative".to_string(), cid1).await; 1382 + assert!(result.is_err()); 1383 + let result = mst.add(&"coll/abc💩".to_string(), cid1).await; 1384 + assert!(result.is_err()); 1385 + 1386 + // Rejects ascii that we don't support 1387 + let invalid_chars = vec!["$", "%", "(", ")", "+", "="]; 1388 + for ch in invalid_chars { 1389 + let key = format!("coll/key{}", ch); 1390 + let result = mst.add(&key, cid1).await; 1391 + assert!(result.is_err(), "Key '{}' should be invalid", key); 1392 + } 1393 + 1394 + // Rejects keys over 256 chars 1395 + let long_key: String = "a".repeat(253); 1396 + let key = format!("coll/{}", long_key); 1397 + let result = mst.add(&key, cid1).await; 1398 + assert!(result.is_err()); 1399 + 1400 + // Allows long key under 256 chars 1401 + let long_key: String = "a".repeat(250); 1402 + let key = format!("coll/{}", long_key); 1403 + let result = mst.add(&key, cid1).await; 1404 + assert!(result.is_ok()); 1405 + 1406 + // Allows URL-safe chars 1407 + let valid_keys = vec![ 1408 + "coll/key0", 1409 + "coll/key_", 1410 + "coll/key:", 1411 + "coll/key.", 1412 + "coll/key-", 1413 + ]; 1414 + for key in valid_keys { 1415 + let result = mst.add(&key.to_string(), cid1).await; 1416 + assert!(result.is_ok(), "Key '{}' should be valid", key); 1417 + } 1418 + 1419 + Ok(()) 1341 1420 } 1342 1421 1343 1422 #[tokio::test] ··· 1345 1424 let storage = Arc::new(MemoryBlockStore::new()); 1346 1425 let mst = Mst::new(storage); 1347 1426 1348 - let updated = mst.add("test/key", test_cid(1)).await.unwrap(); 1427 + let updated = mst.add("com.example.test/key", test_cid(1)).await.unwrap(); 1349 1428 1350 - assert_eq!(updated.get("test/key").await.unwrap(), Some(test_cid(1))); 1429 + assert_eq!( 1430 + updated.get("com.example.test/key").await.unwrap(), 1431 + Some(test_cid(1)) 1432 + ); 1351 1433 } 1352 1434 1353 1435 #[tokio::test] ··· 1355 1437 let storage = Arc::new(MemoryBlockStore::new()); 1356 1438 let mst = Mst::new(storage); 1357 1439 1358 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1359 - let mst = mst.add("b", test_cid(2)).await.unwrap(); 1360 - let mst = mst.add("c", test_cid(3)).await.unwrap(); 1440 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1441 + let mst = mst.add("com.example.test/b", test_cid(2)).await.unwrap(); 1442 + let mst = mst.add("com.example.test/c", test_cid(3)).await.unwrap(); 1361 1443 1362 - assert_eq!(mst.get("a").await.unwrap(), Some(test_cid(1))); 1363 - assert_eq!(mst.get("b").await.unwrap(), Some(test_cid(2))); 1364 - assert_eq!(mst.get("c").await.unwrap(), Some(test_cid(3))); 1444 + assert_eq!( 1445 + mst.get("com.example.test/a").await.unwrap(), 1446 + Some(test_cid(1)) 1447 + ); 1448 + assert_eq!( 1449 + mst.get("com.example.test/b").await.unwrap(), 1450 + Some(test_cid(2)) 1451 + ); 1452 + assert_eq!( 1453 + mst.get("com.example.test/c").await.unwrap(), 1454 + Some(test_cid(3)) 1455 + ); 1365 1456 } 1366 1457 1367 1458 #[tokio::test] ··· 1369 1460 let storage = Arc::new(MemoryBlockStore::new()); 1370 1461 let mst = Mst::new(storage); 1371 1462 1372 - let mst = mst.add("test", test_cid(1)).await.unwrap(); 1373 - let mst = mst.add("test", test_cid(2)).await.unwrap(); 1463 + let mst = mst.add("com.example.test/key1", test_cid(1)).await.unwrap(); 1464 + let mst = mst.add("com.example.test/key1", test_cid(2)).await.unwrap(); 1374 1465 1375 - assert_eq!(mst.get("test").await.unwrap(), Some(test_cid(2))); 1466 + assert_eq!( 1467 + mst.get("com.example.test/key1").await.unwrap(), 1468 + Some(test_cid(2)) 1469 + ); 1376 1470 } 1377 1471 1378 1472 #[tokio::test] ··· 1380 1474 let storage = Arc::new(MemoryBlockStore::new()); 1381 1475 let mst = Mst::new(storage); 1382 1476 1383 - let mst = mst.add("test", test_cid(1)).await.unwrap(); 1384 - let mst = mst.delete("test").await.unwrap(); 1477 + let mst = mst.add("com.example.test/key1", test_cid(1)).await.unwrap(); 1478 + let mst = mst.delete("com.example.test/key1").await.unwrap(); 1385 1479 1386 - assert_eq!(mst.get("test").await.unwrap(), None); 1480 + assert_eq!(mst.get("com.example.test/key1").await.unwrap(), None); 1387 1481 assert_eq!(mst.get_entries().await.unwrap().len(), 0); 1388 1482 } 1389 1483 ··· 1392 1486 let storage = Arc::new(MemoryBlockStore::new()); 1393 1487 let mst = Mst::new(storage); 1394 1488 1395 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1396 - let mst = mst.add("b", test_cid(2)).await.unwrap(); 1397 - let mst = mst.add("c", test_cid(3)).await.unwrap(); 1489 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1490 + let mst = mst.add("com.example.test/b", test_cid(2)).await.unwrap(); 1491 + let mst = mst.add("com.example.test/c", test_cid(3)).await.unwrap(); 1398 1492 1399 - let mst = mst.delete("b").await.unwrap(); 1493 + let mst = mst.delete("com.example.test/b").await.unwrap(); 1400 1494 1401 - assert_eq!(mst.get("a").await.unwrap(), Some(test_cid(1))); 1402 - assert_eq!(mst.get("b").await.unwrap(), None); 1403 - assert_eq!(mst.get("c").await.unwrap(), Some(test_cid(3))); 1495 + assert_eq!( 1496 + mst.get("com.example.test/a").await.unwrap(), 1497 + Some(test_cid(1)) 1498 + ); 1499 + assert_eq!(mst.get("com.example.test/b").await.unwrap(), None); 1500 + assert_eq!( 1501 + mst.get("com.example.test/c").await.unwrap(), 1502 + Some(test_cid(3)) 1503 + ); 1404 1504 } 1405 1505 1406 1506 #[tokio::test] ··· 1408 1508 let storage = Arc::new(MemoryBlockStore::new()); 1409 1509 let mst = Mst::new(storage); 1410 1510 1411 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1511 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1412 1512 1413 - let result = mst.delete("b").await; 1513 + let result = mst.delete("com.example.test/b").await; 1414 1514 assert!(result.is_err()); 1415 1515 } 1416 1516 ··· 1419 1519 let storage = Arc::new(MemoryBlockStore::new()); 1420 1520 let mst = Mst::new(storage.clone()); 1421 1521 1422 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1423 - let mst = mst.add("b", test_cid(2)).await.unwrap(); 1424 - let mst = mst.add("c", test_cid(3)).await.unwrap(); 1522 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1523 + let mst = mst.add("com.example.test/b", test_cid(2)).await.unwrap(); 1524 + let mst = mst.add("com.example.test/c", test_cid(3)).await.unwrap(); 1425 1525 1426 1526 // Persist to storage 1427 1527 let cid = mst.persist().await.unwrap(); ··· 1430 1530 let reloaded = Mst::load(storage, cid, Some(0)); 1431 1531 1432 1532 // Verify all keys are present 1433 - assert_eq!(reloaded.get("a").await.unwrap(), Some(test_cid(1))); 1434 - assert_eq!(reloaded.get("b").await.unwrap(), Some(test_cid(2))); 1435 - assert_eq!(reloaded.get("c").await.unwrap(), Some(test_cid(3))); 1533 + assert_eq!( 1534 + reloaded.get("com.example.test/a").await.unwrap(), 1535 + Some(test_cid(1)) 1536 + ); 1537 + assert_eq!( 1538 + reloaded.get("com.example.test/b").await.unwrap(), 1539 + Some(test_cid(2)) 1540 + ); 1541 + assert_eq!( 1542 + reloaded.get("com.example.test/c").await.unwrap(), 1543 + Some(test_cid(3)) 1544 + ); 1436 1545 } 1437 1546 1438 1547 #[tokio::test] ··· 1440 1549 // Same keys inserted in same order should produce same CID 1441 1550 let storage1 = Arc::new(MemoryBlockStore::new()); 1442 1551 let mst1 = Mst::new(storage1); 1443 - let mst1 = mst1.add("a", test_cid(1)).await.unwrap(); 1444 - let mst1 = mst1.add("b", test_cid(2)).await.unwrap(); 1445 - let mst1 = mst1.add("c", test_cid(3)).await.unwrap(); 1552 + let mst1 = mst1.add("com.example.test/a", test_cid(1)).await.unwrap(); 1553 + let mst1 = mst1.add("com.example.test/b", test_cid(2)).await.unwrap(); 1554 + let mst1 = mst1.add("com.example.test/c", test_cid(3)).await.unwrap(); 1446 1555 let cid1 = mst1.get_pointer().await.unwrap(); 1447 1556 1448 1557 let storage2 = Arc::new(MemoryBlockStore::new()); 1449 1558 let mst2 = Mst::new(storage2); 1450 - let mst2 = mst2.add("a", test_cid(1)).await.unwrap(); 1451 - let mst2 = mst2.add("b", test_cid(2)).await.unwrap(); 1452 - let mst2 = mst2.add("c", test_cid(3)).await.unwrap(); 1559 + let mst2 = mst2.add("com.example.test/a", test_cid(1)).await.unwrap(); 1560 + let mst2 = mst2.add("com.example.test/b", test_cid(2)).await.unwrap(); 1561 + let mst2 = mst2.add("com.example.test/c", test_cid(3)).await.unwrap(); 1453 1562 let cid2 = mst2.get_pointer().await.unwrap(); 1454 1563 1455 1564 assert_eq!(cid1, cid2); ··· 1460 1569 // Different insertion orders should produce same CID 1461 1570 let storage1 = Arc::new(MemoryBlockStore::new()); 1462 1571 let mst1 = Mst::new(storage1); 1463 - let mst1 = mst1.add("a", test_cid(1)).await.unwrap(); 1464 - let mst1 = mst1.add("b", test_cid(2)).await.unwrap(); 1465 - let mst1 = mst1.add("c", test_cid(3)).await.unwrap(); 1572 + let mst1 = mst1.add("com.example.test/a", test_cid(1)).await.unwrap(); 1573 + let mst1 = mst1.add("com.example.test/b", test_cid(2)).await.unwrap(); 1574 + let mst1 = mst1.add("com.example.test/c", test_cid(3)).await.unwrap(); 1466 1575 let cid1 = mst1.get_pointer().await.unwrap(); 1467 1576 1468 1577 let storage2 = Arc::new(MemoryBlockStore::new()); 1469 1578 let mst2 = Mst::new(storage2); 1470 - let mst2 = mst2.add("c", test_cid(3)).await.unwrap(); 1471 - let mst2 = mst2.add("a", test_cid(1)).await.unwrap(); 1472 - let mst2 = mst2.add("b", test_cid(2)).await.unwrap(); 1579 + let mst2 = mst2.add("com.example.test/c", test_cid(3)).await.unwrap(); 1580 + let mst2 = mst2.add("com.example.test/a", test_cid(1)).await.unwrap(); 1581 + let mst2 = mst2.add("com.example.test/b", test_cid(2)).await.unwrap(); 1473 1582 let cid2 = mst2.get_pointer().await.unwrap(); 1474 1583 1475 1584 assert_eq!(cid1, cid2); ··· 1482 1591 1483 1592 let ops = vec![ 1484 1593 VerifiedWriteOp::Create { 1485 - key: SmolStr::new("a"), 1594 + key: SmolStr::new("com.example.test/a"), 1486 1595 cid: test_cid(1), 1487 1596 }, 1488 1597 VerifiedWriteOp::Create { 1489 - key: SmolStr::new("b"), 1598 + key: SmolStr::new("com.example.test/b"), 1490 1599 cid: test_cid(2), 1491 1600 }, 1492 1601 VerifiedWriteOp::Create { 1493 - key: SmolStr::new("c"), 1602 + key: SmolStr::new("com.example.test/c"), 1494 1603 cid: test_cid(3), 1495 1604 }, 1496 1605 ]; 1497 1606 1498 1607 let mst = mst.batch(&ops).await.unwrap(); 1499 1608 1500 - assert_eq!(mst.get("a").await.unwrap(), Some(test_cid(1))); 1501 - assert_eq!(mst.get("b").await.unwrap(), Some(test_cid(2))); 1502 - assert_eq!(mst.get("c").await.unwrap(), Some(test_cid(3))); 1609 + assert_eq!( 1610 + mst.get("com.example.test/a").await.unwrap(), 1611 + Some(test_cid(1)) 1612 + ); 1613 + assert_eq!( 1614 + mst.get("com.example.test/b").await.unwrap(), 1615 + Some(test_cid(2)) 1616 + ); 1617 + assert_eq!( 1618 + mst.get("com.example.test/c").await.unwrap(), 1619 + Some(test_cid(3)) 1620 + ); 1503 1621 } 1504 1622 1505 1623 #[tokio::test] ··· 1508 1626 let mst = Mst::new(storage); 1509 1627 1510 1628 // Start with some keys 1511 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1512 - let mst = mst.add("b", test_cid(2)).await.unwrap(); 1513 - let mst = mst.add("c", test_cid(3)).await.unwrap(); 1629 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1630 + let mst = mst.add("com.example.test/b", test_cid(2)).await.unwrap(); 1631 + let mst = mst.add("com.example.test/c", test_cid(3)).await.unwrap(); 1514 1632 1515 1633 let ops = vec![ 1516 1634 VerifiedWriteOp::Create { 1517 - key: SmolStr::new("d"), 1635 + key: SmolStr::new("com.example.test/d"), 1518 1636 cid: test_cid(4), 1519 1637 }, 1520 1638 VerifiedWriteOp::Update { 1521 - key: SmolStr::new("a"), 1639 + key: SmolStr::new("com.example.test/a"), 1522 1640 cid: test_cid(10), 1523 1641 prev: test_cid(1), 1524 1642 }, 1525 1643 VerifiedWriteOp::Delete { 1526 - key: SmolStr::new("b"), 1644 + key: SmolStr::new("com.example.test/b"), 1527 1645 prev: test_cid(2), 1528 1646 }, 1529 1647 ]; 1530 1648 1531 1649 let mst = mst.batch(&ops).await.unwrap(); 1532 1650 1533 - assert_eq!(mst.get("a").await.unwrap(), Some(test_cid(10))); // Updated 1534 - assert_eq!(mst.get("b").await.unwrap(), None); // Deleted 1535 - assert_eq!(mst.get("c").await.unwrap(), Some(test_cid(3))); // Unchanged 1536 - assert_eq!(mst.get("d").await.unwrap(), Some(test_cid(4))); // Created 1651 + assert_eq!( 1652 + mst.get("com.example.test/a").await.unwrap(), 1653 + Some(test_cid(10)) 1654 + ); // Updated 1655 + assert_eq!(mst.get("com.example.test/b").await.unwrap(), None); // Deleted 1656 + assert_eq!( 1657 + mst.get("com.example.test/c").await.unwrap(), 1658 + Some(test_cid(3)) 1659 + ); // Unchanged 1660 + assert_eq!( 1661 + mst.get("com.example.test/d").await.unwrap(), 1662 + Some(test_cid(4)) 1663 + ); // Created 1537 1664 } 1538 1665 1539 1666 #[tokio::test] 1540 1667 async fn test_batch_with_prev_validation() { 1541 1668 let storage = Arc::new(MemoryBlockStore::new()); 1542 1669 let mst = Mst::new(storage); 1543 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1670 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1544 1671 1545 1672 // Update with correct prev - should succeed 1546 1673 let ops = vec![VerifiedWriteOp::Update { 1547 - key: SmolStr::new("a"), 1674 + key: SmolStr::new("com.example.test/a"), 1548 1675 cid: test_cid(2), 1549 1676 prev: test_cid(1), 1550 1677 }]; 1551 1678 let mst = mst.batch(&ops).await.unwrap(); 1552 - assert_eq!(mst.get("a").await.unwrap(), Some(test_cid(2))); 1679 + assert_eq!( 1680 + mst.get("com.example.test/a").await.unwrap(), 1681 + Some(test_cid(2)) 1682 + ); 1553 1683 1554 1684 // Update with wrong prev - should fail 1555 1685 let ops = vec![VerifiedWriteOp::Update { 1556 - key: SmolStr::new("a"), 1686 + key: SmolStr::new("com.example.test/a"), 1557 1687 cid: test_cid(3), 1558 1688 prev: test_cid(99), // Wrong CID 1559 1689 }]; ··· 1561 1691 1562 1692 // Delete with correct prev - should succeed 1563 1693 let ops = vec![VerifiedWriteOp::Delete { 1564 - key: SmolStr::new("a"), 1694 + key: SmolStr::new("com.example.test/a"), 1565 1695 prev: test_cid(2), 1566 1696 }]; 1567 1697 let mst = mst.batch(&ops).await.unwrap(); 1568 - assert_eq!(mst.get("a").await.unwrap(), None); 1698 + assert_eq!(mst.get("com.example.test/a").await.unwrap(), None); 1569 1699 } 1570 1700 1571 1701 #[tokio::test] 1572 1702 async fn test_batch_create_duplicate_error() { 1573 1703 let storage = Arc::new(MemoryBlockStore::new()); 1574 1704 let mst = Mst::new(storage); 1575 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1705 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1576 1706 1577 1707 let ops = vec![VerifiedWriteOp::Create { 1578 - key: SmolStr::new("a"), 1708 + key: SmolStr::new("com.example.test/a"), 1579 1709 cid: test_cid(2), 1580 1710 }]; 1581 1711 ··· 1589 1719 let mst = Mst::new(storage); 1590 1720 1591 1721 let ops = vec![VerifiedWriteOp::Update { 1592 - key: SmolStr::new("a"), 1722 + key: SmolStr::new("com.example.test/a"), 1593 1723 cid: test_cid(1), 1594 1724 prev: test_cid(99), // Doesn't matter since key doesn't exist 1595 1725 }]; ··· 1604 1734 let mst = Mst::new(storage); 1605 1735 1606 1736 let ops = vec![VerifiedWriteOp::Delete { 1607 - key: SmolStr::new("a"), 1737 + key: SmolStr::new("com.example.test/a"), 1608 1738 prev: test_cid(99), // Doesn't matter since key doesn't exist 1609 1739 }]; 1610 1740 ··· 1616 1746 async fn test_batch_empty() { 1617 1747 let storage = Arc::new(MemoryBlockStore::new()); 1618 1748 let mst = Mst::new(storage); 1619 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1749 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1620 1750 1621 1751 let ops = vec![]; 1622 1752 let mst = mst.batch(&ops).await.unwrap(); 1623 1753 1624 1754 // Should be unchanged 1625 - assert_eq!(mst.get("a").await.unwrap(), Some(test_cid(1))); 1755 + assert_eq!( 1756 + mst.get("com.example.test/a").await.unwrap(), 1757 + Some(test_cid(1)) 1758 + ); 1626 1759 } 1627 1760 1628 1761 #[tokio::test] ··· 1631 1764 let storage = Arc::new(MemoryBlockStore::new()); 1632 1765 let mst = Mst::new(storage); 1633 1766 1634 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1635 - let mst = mst.add("b", test_cid(2)).await.unwrap(); 1636 - let mst = mst.add("c", test_cid(3)).await.unwrap(); 1767 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1768 + let mst = mst.add("com.example.test/b", test_cid(2)).await.unwrap(); 1769 + let mst = mst.add("com.example.test/c", test_cid(3)).await.unwrap(); 1637 1770 1638 1771 // Get proof path for key "b" 1639 - let cids = mst.cids_for_path("b").await.unwrap(); 1772 + let cids = mst.cids_for_path("com.example.test/b").await.unwrap(); 1640 1773 1641 1774 // Should contain: root CID, record CID 1642 1775 assert_eq!(cids.len(), 2); ··· 1650 1783 let storage = Arc::new(MemoryBlockStore::new()); 1651 1784 let mst = Mst::new(storage); 1652 1785 1653 - let mst = mst.add("a", test_cid(1)).await.unwrap(); 1654 - let mst = mst.add("c", test_cid(3)).await.unwrap(); 1786 + let mst = mst.add("com.example.test/a", test_cid(1)).await.unwrap(); 1787 + let mst = mst.add("com.example.test/c", test_cid(3)).await.unwrap(); 1655 1788 1656 1789 // Get proof path for nonexistent key "b" 1657 - let cids = mst.cids_for_path("b").await.unwrap(); 1790 + let cids = mst.cids_for_path("com.example.test/b").await.unwrap(); 1658 1791 1659 1792 // Should contain root CID first, and NOT contain the record CID (proves absence) 1660 1793 assert!(cids.len() >= 1, "Should have at least the root CID");
+12 -5
crates/jacquard-repo/src/mst/util.rs
··· 60 60 61 61 /// Validate MST key format 62 62 /// 63 - /// Keys must match: [a-zA-Z0-9._:~-]+ 64 - /// Max length: 256 bytes (atproto limit) 65 63 pub fn validate_key(key: &str) -> Result<()> { 66 64 if key.is_empty() { 67 65 return Err(MstError::EmptyKey.into()); ··· 85 83 .into()); 86 84 } 87 85 88 - Ok(()) 86 + let split: Vec<&str> = key.split("/").collect(); 87 + 88 + return if split.len() == 2 && split[0].len() > 0 && split[1].len() > 0 { 89 + Ok(()) 90 + } else { 91 + Err(MstError::InvalidKeyChars { 92 + key: key.to_string(), 93 + } 94 + .into()) 95 + }; 89 96 } 90 97 91 98 /// Count shared prefix length between two strings ··· 223 230 #[test] 224 231 fn test_validate_key_valid() { 225 232 assert!(validate_key("app.bsky.feed.post/abc123").is_ok()); 226 - assert!(validate_key("foo.bar/test-key_2024").is_ok()); 227 - assert!(validate_key("a").is_ok()); 233 + assert!(validate_key("foo.bar.baz/test-key_2024").is_ok()); 234 + assert!(validate_key("com.example.test/a").is_ok()); 228 235 } 229 236 230 237 #[test]