Added broadcast stage test for leader rotation exit
This commit is contained in:
parent
98b47d2540
commit
d3cb161c36
|
@ -235,3 +235,159 @@ impl Service for BroadcastStage {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crdt::{Crdt, LEADER_ROTATION_INTERVAL, Node};
|
||||||
|
use entry::Entry;
|
||||||
|
use ledger::Block;
|
||||||
|
use hash::Hash;
|
||||||
|
use packet::BlobRecycler;
|
||||||
|
use recorder::Recorder;
|
||||||
|
use service::Service;
|
||||||
|
use signature::{Keypair, KeypairUtil, Pubkey};
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
use std::sync::mpsc::{channel, Receiver};
|
||||||
|
use broadcast_stage::BroadcastStage;
|
||||||
|
use mint::Mint;
|
||||||
|
use streamer::BlobSender;
|
||||||
|
use std::cmp;
|
||||||
|
use window::{new_window_from_entries, SharedWindow};
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
fn setup_dummy_broadcast_stage() ->
|
||||||
|
(Pubkey, Pubkey, BroadcastStage, SharedWindow, BlobSender, BlobRecycler, Arc<RwLock<Crdt>>, Vec<Entry>, Receiver<bool>)
|
||||||
|
{
|
||||||
|
// Setup dummy leader info
|
||||||
|
let leader_keypair = Keypair::new();
|
||||||
|
let id = leader_keypair.pubkey();
|
||||||
|
let leader_info = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
|
|
||||||
|
// Give the leader somebody to broadcast to so he isn't lonely
|
||||||
|
let buddy_keypair = Keypair::new();
|
||||||
|
let buddy_id = buddy_keypair.pubkey();
|
||||||
|
let broadcast_buddy = Node::new_localhost_with_pubkey(buddy_keypair.pubkey());
|
||||||
|
|
||||||
|
// Fill the crdt with the buddy's info
|
||||||
|
let mut crdt = Crdt::new(leader_info.info.clone()).expect("Crdt::new");
|
||||||
|
crdt.insert(&broadcast_buddy.info);
|
||||||
|
let crdt = Arc::new(RwLock::new(crdt));
|
||||||
|
let blob_recycler = BlobRecycler::default();
|
||||||
|
|
||||||
|
// Make dummy initial entries
|
||||||
|
let mint = Mint::new(10000);
|
||||||
|
let entries = mint.create_entries();
|
||||||
|
let entry_height = entries.len() as u64;
|
||||||
|
|
||||||
|
// Setup a window
|
||||||
|
let window =
|
||||||
|
new_window_from_entries(&entries, entry_height, &leader_info.info, &blob_recycler);
|
||||||
|
|
||||||
|
let shared_window = Arc::new(RwLock::new(window));
|
||||||
|
|
||||||
|
let (blob_sender, blob_receiver) = channel();
|
||||||
|
let (exit_sender, exit_receiver) = channel();
|
||||||
|
|
||||||
|
// Start up the broadcast stage
|
||||||
|
let broadcast_stage = BroadcastStage::new(
|
||||||
|
leader_info.sockets.broadcast,
|
||||||
|
crdt.clone(),
|
||||||
|
shared_window.clone(),
|
||||||
|
entry_height,
|
||||||
|
blob_recycler.clone(),
|
||||||
|
blob_receiver,
|
||||||
|
exit_sender,
|
||||||
|
);
|
||||||
|
|
||||||
|
(
|
||||||
|
id,
|
||||||
|
buddy_id,
|
||||||
|
broadcast_stage,
|
||||||
|
shared_window,
|
||||||
|
blob_sender,
|
||||||
|
blob_recycler,
|
||||||
|
crdt,
|
||||||
|
entries,
|
||||||
|
exit_receiver,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_highest_window_index(shared_window: &SharedWindow) -> u64 {
|
||||||
|
let window = shared_window.read().unwrap();
|
||||||
|
window.iter().fold(0, |m, w_slot| {
|
||||||
|
if let Some(ref blob) = w_slot.data {
|
||||||
|
cmp::max(m, blob.read().unwrap().get_index().unwrap())
|
||||||
|
} else {
|
||||||
|
m
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_broadcast_stage_leader_rotation_exit() {
|
||||||
|
let (
|
||||||
|
id,
|
||||||
|
buddy_id,
|
||||||
|
broadcast_stage,
|
||||||
|
shared_window,
|
||||||
|
blob_sender,
|
||||||
|
blob_recycler,
|
||||||
|
crdt,
|
||||||
|
entries,
|
||||||
|
exit_receiver,
|
||||||
|
) = setup_dummy_broadcast_stage();
|
||||||
|
{
|
||||||
|
let mut wcrdt = crdt.write().unwrap();
|
||||||
|
// Set leader to myself
|
||||||
|
wcrdt.set_leader(id);
|
||||||
|
// Set the leader for the next rotation to also be myself
|
||||||
|
wcrdt.set_scheduled_leader(LEADER_ROTATION_INTERVAL, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let genesis_len = entries.len() as u64;
|
||||||
|
let last_entry_hash =
|
||||||
|
entries.last().expect("Ledger should not be empty").id;
|
||||||
|
|
||||||
|
// Input enough entries to make exactly LEADER_ROTATION_INTERVAL entries, which will
|
||||||
|
// trigger a check for leader rotation. Because the next scheduled leader
|
||||||
|
// is ourselves, we won't exit
|
||||||
|
let mut recorder = Recorder::new(last_entry_hash);
|
||||||
|
|
||||||
|
for _ in genesis_len..LEADER_ROTATION_INTERVAL {
|
||||||
|
let new_entry = recorder.record(vec![]);
|
||||||
|
let blob = new_entry.to_blobs(&blob_recycler);
|
||||||
|
blob_sender.send(blob).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the scheduled next leader in the crdt to the other buddy on the network
|
||||||
|
crdt.write()
|
||||||
|
.unwrap()
|
||||||
|
.set_scheduled_leader(2 * LEADER_ROTATION_INTERVAL, buddy_id);
|
||||||
|
|
||||||
|
// Input another LEADER_ROTATION_INTERVAL dummy entries, which will take us
|
||||||
|
// past the point of the leader rotation. The write_stage will see that
|
||||||
|
// it's no longer the leader after checking the crdt, and exit
|
||||||
|
for _ in 0..LEADER_ROTATION_INTERVAL {
|
||||||
|
let new_entry = recorder.record(vec![]);
|
||||||
|
let blob = new_entry.to_blobs(&blob_recycler);
|
||||||
|
match blob_sender.send(blob) {
|
||||||
|
// We disconnected, break out of loop and check the results
|
||||||
|
Err(_) => break,
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
match exit_receiver.recv() {
|
||||||
|
Ok(x) if x == false =>
|
||||||
|
panic!("Unexpected value on exit channel for Broadcast stage"),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let highest_index = find_highest_window_index(&shared_window);
|
||||||
|
|
||||||
|
assert_eq!(highest_index, 2 * LEADER_ROTATION_INTERVAL - 1);
|
||||||
|
// Make sure the threads closed cleanly
|
||||||
|
broadcast_stage.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue