commit ef6f025c3a70563d7fe0fb3a064a932ea33fe12d
parent 4f10489b13ff45e8eec38fd41c4cfd1a42f1337d
Author: Silas Brack <silas@teton.ai>
Date: Sat, 7 Mar 2026 10:39:19 +0100
Add node ring testing
Diffstat:
| M | src/hasher.rs | | | 63 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 63 insertions(+), 0 deletions(-)
diff --git a/src/hasher.rs b/src/hasher.rs
@@ -112,4 +112,67 @@ mod tests {
);
}
}
+
+ #[test]
+ fn test_ring_stability_on_add() {
+ // Adding a 4th volume to a 3-volume ring should only move ~25% of keys
+ let volumes: Vec<String> = (1..=3).map(|i| format!("http://vol{i}")).collect();
+ let ring_before = Ring::new(&volumes, 100);
+
+ let mut volumes4 = volumes.clone();
+ volumes4.push("http://vol4".into());
+ let ring_after = Ring::new(&volumes4, 100);
+
+ let total = 10000;
+ let mut moved = 0;
+ for i in 0..total {
+ let key = format!("key-{i}");
+ let before = &ring_before.get_volumes(&key, 1)[0];
+ let after = &ring_after.get_volumes(&key, 1)[0];
+ if before != after {
+ moved += 1;
+ }
+ }
+
+ // Ideal: 1/4 of keys move (25%). Allow 15%-40%.
+ let pct = moved as f64 / total as f64 * 100.0;
+ assert!(
+ pct > 15.0 && pct < 40.0,
+ "expected ~25% of keys to move, got {pct:.1}% ({moved}/{total})"
+ );
+ }
+
+ #[test]
+ fn test_ring_stability_on_remove() {
+ // Removing 1 volume from a 4-volume ring should only move ~25% of keys
+ let volumes: Vec<String> = (1..=4).map(|i| format!("http://vol{i}")).collect();
+ let ring_before = Ring::new(&volumes, 100);
+
+ let volumes3: Vec<String> = (1..=3).map(|i| format!("http://vol{i}")).collect();
+ let ring_after = Ring::new(&volumes3, 100);
+
+ let total = 10000;
+ let mut moved = 0;
+ for i in 0..total {
+ let key = format!("key-{i}");
+ let before = &ring_before.get_volumes(&key, 1)[0];
+ let after = &ring_after.get_volumes(&key, 1)[0];
+ if before != after {
+ moved += 1;
+ }
+ }
+
+ // Ideal: 1/4 of keys move (25%). Allow 15%-40%.
+ let pct = moved as f64 / total as f64 * 100.0;
+ assert!(
+ pct > 15.0 && pct < 40.0,
+ "expected ~25% of keys to move, got {pct:.1}% ({moved}/{total})"
+ );
+ }
+
+ #[test]
+ fn test_ring_empty() {
+ let ring = Ring::new(&[], 100);
+ assert_eq!(ring.get_volumes("key", 1), Vec::<String>::new());
+ }
}