test.rs

  1use clock::ReplicaId;
  2use std::path::{Path, PathBuf};
  3use tempdir::TempDir;
  4
  5#[derive(Clone)]
  6struct Envelope<T: Clone> {
  7    message: T,
  8}
  9
 10pub struct Network<T: Clone, R: rand::Rng> {
 11    inboxes: std::collections::BTreeMap<ReplicaId, Vec<Envelope<T>>>,
 12    all_messages: Vec<T>,
 13    rng: R,
 14}
 15
 16impl<T: Clone, R: rand::Rng> Network<T, R> {
 17    pub fn new(rng: R) -> Self {
 18        Network {
 19            inboxes: Default::default(),
 20            all_messages: Vec::new(),
 21            rng,
 22        }
 23    }
 24
 25    pub fn add_peer(&mut self, id: ReplicaId) {
 26        self.inboxes.insert(id, Vec::new());
 27    }
 28
 29    pub fn replicate(&mut self, old_replica_id: ReplicaId, new_replica_id: ReplicaId) {
 30        self.inboxes
 31            .insert(new_replica_id, self.inboxes[&old_replica_id].clone());
 32    }
 33
 34    pub fn is_idle(&self) -> bool {
 35        self.inboxes.values().all(|i| i.is_empty())
 36    }
 37
 38    pub fn broadcast(&mut self, sender: ReplicaId, messages: Vec<T>) {
 39        for (replica, inbox) in self.inboxes.iter_mut() {
 40            if *replica != sender {
 41                for message in &messages {
 42                    // Insert one or more duplicates of this message, potentially *before* the previous
 43                    // message sent by this peer to simulate out-of-order delivery.
 44                    for _ in 0..self.rng.gen_range(1..4) {
 45                        let insertion_index = self.rng.gen_range(0..inbox.len() + 1);
 46                        inbox.insert(
 47                            insertion_index,
 48                            Envelope {
 49                                message: message.clone(),
 50                            },
 51                        );
 52                    }
 53                }
 54            }
 55        }
 56        self.all_messages.extend(messages);
 57    }
 58
 59    pub fn has_unreceived(&self, receiver: ReplicaId) -> bool {
 60        !self.inboxes[&receiver].is_empty()
 61    }
 62
 63    pub fn receive(&mut self, receiver: ReplicaId) -> Vec<T> {
 64        let inbox = self.inboxes.get_mut(&receiver).unwrap();
 65        let count = self.rng.gen_range(0..inbox.len() + 1);
 66        inbox
 67            .drain(0..count)
 68            .map(|envelope| envelope.message)
 69            .collect()
 70    }
 71}
 72
 73pub fn temp_tree(tree: serde_json::Value) -> TempDir {
 74    let dir = TempDir::new("").unwrap();
 75    write_tree(dir.path(), tree);
 76    dir
 77}
 78
 79fn write_tree(path: &Path, tree: serde_json::Value) {
 80    use serde_json::Value;
 81    use std::fs;
 82
 83    if let Value::Object(map) = tree {
 84        for (name, contents) in map {
 85            let mut path = PathBuf::from(path);
 86            path.push(name);
 87            match contents {
 88                Value::Object(_) => {
 89                    fs::create_dir(&path).unwrap();
 90                    write_tree(&path, contents);
 91                }
 92                Value::Null => {
 93                    fs::create_dir(&path).unwrap();
 94                }
 95                Value::String(contents) => {
 96                    fs::write(&path, contents).unwrap();
 97                }
 98                _ => {
 99                    panic!("JSON object must contain only objects, strings, or null");
100                }
101            }
102        }
103    } else {
104        panic!("You must pass a JSON object to this helper")
105    }
106}
107
108pub fn sample_text(rows: usize, cols: usize, start_char: char) -> String {
109    let mut text = String::new();
110    for row in 0..rows {
111        let c: char = (start_char as u32 + row as u32) as u8 as char;
112        let mut line = c.to_string().repeat(cols);
113        if row < rows - 1 {
114            line.push('\n');
115        }
116        text += &line;
117    }
118    text
119}