use super::*;
fn node(fill: u8, mood: Mood, items: Vec<Mutable>) -> FakeNode {
let mut n = FakeNode::bind(id(fill));
n.serve(vec![], mood, items);
n
}
#[test]
fn silent_nodes_leave_the_frontier_for_the_live_ones_past_them() {
let kp = keypair();
let item = kp.sign(b"s".to_vec(), 1, b"held".to_vec()).unwrap();
let t = item.target().0;
let near = |bit: usize| {
let mut x = t;
x[bit / 8] ^= 0x80 >> (bit % 8);
NodeId(x)
};
let mut ranked: Vec<FakeNode> = (0..5).map(|i| FakeNode::bind(near(40 - i * 8))).collect();
for (i, n) in ranked.iter_mut().enumerate() {
let (mood, items) = if i < 3 {
(Mood::Silent, vec![])
} else {
(Mood::Answer, vec![item.clone()])
};
n.serve(vec![], mood, items);
}
let door = router(ranked.iter().map(FakeNode::node).collect());
let mut dht = client(vec![door.addr], quick());
assert_eq!(
dht.get(kp.public(), b"s".to_vec()).unwrap(),
Some(item.clone())
);
let mut dht = client(vec![door.addr], quick());
assert_eq!(
lookup(&mut dht, item.target()).unwrap(),
vec![ranked[3].node(), ranked[4].node()]
);
}
#[test]
fn a_node_the_socket_cannot_reach_spends_no_query() {
let a = node(0x42, Mood::Answer, vec![]);
let unreachable = Node {
id: id(0xfe),
addr: "[::1]:9".parse().unwrap(),
};
let door = router(vec![unreachable, a.node()]);
let config = Config {
alpha: 1,
max_queries: 2,
..quick()
};
let mut dht = client(vec![unreachable.addr, door.addr], config);
assert_eq!(lookup(&mut dht, id(0xff)).unwrap(), vec![a.node()]);
}
#[test]
fn a_dry_frontier_asks_the_door_again_for_fresh_seeds() {
let silent = [
node(0x41, Mood::Silent, vec![]),
node(0x42, Mood::Silent, vec![]),
];
let live = node(0x43, Mood::Answer, vec![]);
let mut door = FakeNode::bind(id(0x00));
door.serve(
vec![silent[0].node(), silent[1].node(), live.node()],
Mood::Rotor,
vec![],
);
let mut dht = client(vec![door.addr], quick());
assert_eq!(lookup(&mut dht, id(0xff)).unwrap(), vec![live.node()]);
}
#[test]
fn a_door_naming_only_the_dead_is_asked_until_the_cap() {
let silent = node(0x41, Mood::Silent, vec![]);
let door = router(vec![silent.node()]);
let config = Config {
max_queries: 6,
deadline: Duration::from_millis(100),
..quick()
};
let mut dht = client(vec![door.addr], config);
let started = std::time::Instant::now();
assert!(lookup(&mut dht, id(0xff)).is_err());
assert!(started.elapsed() < Duration::from_secs(1));
}
#[test]
fn a_refusal_is_no_reply_and_the_door_is_asked_again() {
let refusing = node(0x41, Mood::Refuse, vec![]);
let live = node(0x43, Mood::Answer, vec![]);
let mut door = FakeNode::bind(id(0x00));
door.serve(vec![refusing.node(), live.node()], Mood::Rotor, vec![]);
let mut dht = client(vec![door.addr], quick());
assert_eq!(lookup(&mut dht, id(0xff)).unwrap(), vec![live.node()]);
}
#[test]
fn a_walk_short_of_k_replies_asks_the_door_again() {
let first = node(0x41, Mood::Answer, vec![]);
let second = node(0x42, Mood::Answer, vec![]);
let mut door = FakeNode::bind(id(0x00));
door.serve(vec![first.node(), second.node()], Mood::Rotor, vec![]);
let mut dht = client(vec![door.addr], quick());
assert_eq!(
lookup(&mut dht, id(0xff)).unwrap(),
vec![second.node(), first.node()]
);
}
#[test]
fn a_silent_router_leaves_the_door_after_its_first_deadline() {
let silent = [
node(0x41, Mood::Silent, vec![]),
node(0x42, Mood::Silent, vec![]),
node(0x43, Mood::Silent, vec![]),
];
let live = node(0x44, Mood::Answer, vec![]);
let dead_router = node(0x01, Mood::Silent, vec![]);
let mut rotor = FakeNode::bind(id(0x00));
let seeds = silent.iter().map(FakeNode::node).chain([live.node()]);
rotor.serve(seeds.collect(), Mood::Rotor, vec![]);
let config = Config {
max_queries: 9,
deadline: Duration::from_millis(100),
..quick()
};
let mut dht = client(vec![dead_router.addr, rotor.addr], config);
assert_eq!(lookup(&mut dht, id(0xff)).unwrap(), vec![live.node()]);
}