node: Set test peer's time on creation

Allow setting a test peer's local time to avoid slight race conditions in
tests.  The race condition's happen because peers created within a test may
unexpectedly have slightly different local times.

To support this, a struct is used as argument to peer::config(..).  The
linter 'cargo clippy' will complain if instead of using a struct, the local
time is passed as an additional parameter in config()'s function call.

Signed-off-by: Slack Coder <slackcoder@server.ky>
This commit is contained in:
Slack Coder 2022-12-09 12:35:20 -05:00
parent b7c1f091fa
commit c676d8b99a
2 changed files with 144 additions and 110 deletions

View File

@ -15,7 +15,6 @@ use crate::identity::Id;
use crate::node; use crate::node;
use crate::prelude::NodeId; use crate::prelude::NodeId;
use crate::service; use crate::service;
use crate::service::config::*;
use crate::service::message::*; use crate::service::message::*;
use crate::service::reactor::Io; use crate::service::reactor::Io;
use crate::service::*; use crate::service::*;
@ -23,6 +22,7 @@ use crate::storage::git::transport::remote;
use crate::storage::{RemoteId, WriteStorage}; use crate::storage::{RemoteId, WriteStorage};
use crate::test::arbitrary; use crate::test::arbitrary;
use crate::test::simulator; use crate::test::simulator;
use crate::test::storage::MockStorage;
use crate::{Link, LocalDuration, LocalTime}; use crate::{Link, LocalDuration, LocalTime};
/// Service instantiation used for testing. /// Service instantiation used for testing.
@ -67,16 +67,32 @@ impl<S, G> DerefMut for Peer<S, G> {
} }
} }
impl<S> Peer<S, MockSigner> impl Peer<MockStorage, MockSigner> {
where pub fn new(name: &'static str, ip: impl Into<net::IpAddr>) -> Self {
S: WriteStorage + 'static, Self::config(name, ip, MockStorage::empty(), Config::default())
{ }
pub fn new(name: &'static str, ip: impl Into<net::IpAddr>, storage: S) -> Self { }
pub struct Config<G: Signer + 'static> {
pub config: service::Config,
pub addrs: address::Book,
pub local_time: LocalTime,
pub signer: G,
pub rng: fastrand::Rng,
}
impl Default for Config<MockSigner> {
fn default() -> Self {
let mut rng = fastrand::Rng::new(); let mut rng = fastrand::Rng::new();
let signer = MockSigner::new(&mut rng); let signer = MockSigner::new(&mut rng);
let addrs = address::Book::memory().unwrap(); Config {
Self::config(name, Config::default(), ip, storage, addrs, signer, rng) config: service::Config::default(),
addrs: address::Book::memory().unwrap(),
local_time: LocalTime::now(),
signer,
rng,
}
} }
} }
@ -87,35 +103,31 @@ where
{ {
pub fn config( pub fn config(
name: &'static str, name: &'static str,
config: Config,
ip: impl Into<net::IpAddr>, ip: impl Into<net::IpAddr>,
storage: S, storage: S,
addrs: address::Book, config: Config<G>,
signer: G,
rng: fastrand::Rng,
) -> Self { ) -> Self {
let local_time = LocalTime::now();
let routing = routing::Table::memory().unwrap(); let routing = routing::Table::memory().unwrap();
let tracking = tracking::Config::memory().unwrap(); let tracking = tracking::Config::memory().unwrap();
let service = Service::new( let service = Service::new(
config, config.config,
local_time, config.local_time,
routing, routing,
storage, storage,
addrs, config.addrs,
tracking, tracking,
signer, config.signer,
rng.clone(), config.rng.clone(),
); );
let ip = ip.into(); let ip = ip.into();
let local_addr = net::SocketAddr::new(ip, rng.u16(..)); let local_addr = net::SocketAddr::new(ip, config.rng.u16(..));
Self { Self {
name, name,
service, service,
ip, ip,
local_addr, local_addr,
rng, rng: config.rng,
initialized: false, initialized: false,
} }
} }

View File

@ -1,10 +1,10 @@
use std::default::*;
use std::io; use std::io;
use std::sync::Arc; use std::sync::Arc;
use crossbeam_channel as chan; use crossbeam_channel as chan;
use nakamoto_net as nakamoto; use nakamoto_net as nakamoto;
use crate::address;
use crate::collections::{HashMap, HashSet}; use crate::collections::{HashMap, HashSet};
use crate::crypto::test::signer::MockSigner; use crate::crypto::test::signer::MockSigner;
use crate::identity::Id; use crate::identity::Id;
@ -24,6 +24,7 @@ use crate::test::assert_matches;
use crate::test::fixtures; use crate::test::fixtures;
#[allow(unused)] #[allow(unused)]
use crate::test::logger; use crate::test::logger;
use crate::test::peer;
use crate::test::peer::Peer; use crate::test::peer::Peer;
use crate::test::simulator; use crate::test::simulator;
use crate::test::simulator::{Peer as _, Simulation}; use crate::test::simulator::{Peer as _, Simulation};
@ -57,9 +58,9 @@ fn test_inventory_decode() {
#[test] #[test]
fn test_ping_response() { fn test_ping_response() {
let mut alice = Peer::new("alice", [8, 8, 8, 8], MockStorage::empty()); let mut alice = Peer::new("alice", [8, 8, 8, 8]);
let bob = Peer::new("bob", [9, 9, 9, 9], MockStorage::empty()); let bob = Peer::new("bob", [9, 9, 9, 9]);
let eve = Peer::new("eve", [7, 7, 7, 7], MockStorage::empty()); let eve = Peer::new("eve", [7, 7, 7, 7]);
alice.connect_to(&bob); alice.connect_to(&bob);
alice.receive( alice.receive(
@ -92,8 +93,8 @@ fn test_ping_response() {
#[test] #[test]
fn test_disconnecting_unresponsive_peer() { fn test_disconnecting_unresponsive_peer() {
let mut alice = Peer::new("alice", [8, 8, 8, 8], MockStorage::empty()); let mut alice = Peer::new("alice", [8, 8, 8, 8]);
let bob = Peer::new("bob", [9, 9, 9, 9], MockStorage::empty()); let bob = Peer::new("bob", [9, 9, 9, 9]);
alice.connect_to(&bob); alice.connect_to(&bob);
assert_eq!(1, alice.sessions().negotiated().count(), "bob connects"); assert_eq!(1, alice.sessions().negotiated().count(), "bob connects");
@ -106,8 +107,8 @@ fn test_disconnecting_unresponsive_peer() {
#[test] #[test]
fn test_connection_kept_alive() { fn test_connection_kept_alive() {
let mut alice = Peer::new("alice", [8, 8, 8, 8], MockStorage::empty()); let mut alice = Peer::new("alice", [8, 8, 8, 8]);
let mut bob = Peer::new("bob", [9, 9, 9, 9], MockStorage::empty()); let mut bob = Peer::new("bob", [9, 9, 9, 9]);
let mut sim = Simulation::new( let mut sim = Simulation::new(
LocalTime::now(), LocalTime::now(),
@ -136,9 +137,9 @@ fn test_connection_kept_alive() {
#[test] #[test]
fn test_outbound_connection() { fn test_outbound_connection() {
let mut alice = Peer::new("alice", [8, 8, 8, 8], MockStorage::empty()); let mut alice = Peer::new("alice", [8, 8, 8, 8]);
let bob = Peer::new("bob", [9, 9, 9, 9], MockStorage::empty()); let bob = Peer::new("bob", [9, 9, 9, 9]);
let eve = Peer::new("eve", [7, 7, 7, 7], MockStorage::empty()); let eve = Peer::new("eve", [7, 7, 7, 7]);
alice.connect_to(&bob); alice.connect_to(&bob);
alice.connect_to(&eve); alice.connect_to(&eve);
@ -156,9 +157,9 @@ fn test_outbound_connection() {
#[test] #[test]
fn test_inbound_connection() { fn test_inbound_connection() {
let mut alice = Peer::new("alice", [8, 8, 8, 8], MockStorage::empty()); let mut alice = Peer::new("alice", [8, 8, 8, 8]);
let bob = Peer::new("bob", [9, 9, 9, 9], MockStorage::empty()); let bob = Peer::new("bob", [9, 9, 9, 9]);
let eve = Peer::new("eve", [7, 7, 7, 7], MockStorage::empty()); let eve = Peer::new("eve", [7, 7, 7, 7]);
alice.connect_from(&bob); alice.connect_from(&bob);
alice.connect_from(&eve); alice.connect_from(&eve);
@ -176,21 +177,19 @@ fn test_inbound_connection() {
#[test] #[test]
fn test_persistent_peer_connect() { fn test_persistent_peer_connect() {
let mut rng = fastrand::Rng::new(); let bob = Peer::new("bob", [8, 8, 8, 8]);
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty()); let eve = Peer::new("eve", [9, 9, 9, 9]);
let eve = Peer::new("eve", [9, 9, 9, 9], MockStorage::empty());
let config = Config {
connect: vec![bob.address(), eve.address()],
..Config::default()
};
let mut alice = Peer::config( let mut alice = Peer::config(
"alice", "alice",
config,
[7, 7, 7, 7], [7, 7, 7, 7],
MockStorage::empty(), MockStorage::empty(),
address::Book::memory().unwrap(), peer::Config {
MockSigner::new(&mut rng), config: Config {
rng, connect: vec![bob.address(), eve.address()],
..Config::default()
},
..peer::Config::default()
},
); );
alice.initialize(); alice.initialize();
@ -216,14 +215,15 @@ fn test_wrong_peer_magic() {
#[test] #[test]
fn test_inventory_sync() { fn test_inventory_sync() {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let mut alice = Peer::new( let mut alice = Peer::config(
"alice", "alice",
[7, 7, 7, 7], [7, 7, 7, 7],
Storage::open(tmp.path().join("alice")).unwrap(), Storage::open(tmp.path().join("alice")).unwrap(),
peer::Config::default(),
); );
let bob_signer = MockSigner::default(); let bob_signer = MockSigner::default();
let bob_storage = fixtures::storage(tmp.path().join("bob"), &bob_signer).unwrap(); let bob_storage = fixtures::storage(tmp.path().join("bob"), &bob_signer).unwrap();
let bob = Peer::new("bob", [8, 8, 8, 8], bob_storage); let bob = Peer::config("bob", [8, 8, 8, 8], bob_storage, peer::Config::default());
let now = LocalTime::now().as_secs(); let now = LocalTime::now().as_secs();
let projs = bob.storage().inventory().unwrap(); let projs = bob.storage().inventory().unwrap();
@ -300,18 +300,26 @@ fn test_inventory_pruning() {
for test in tests { for test in tests {
let mut alice = Peer::config( let mut alice = Peer::config(
"alice", "alice",
Config {
limits: test.limits,
..Config::default()
},
[7, 7, 7, 7], [7, 7, 7, 7],
MockStorage::empty(), MockStorage::empty(),
address::Book::memory().unwrap(), peer::Config {
MockSigner::default(), config: Config {
fastrand::Rng::new(), limits: test.limits,
..Config::default()
},
..peer::Config::default()
},
); );
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty()); let bob = Peer::config(
"bob",
[8, 8, 8, 8],
MockStorage::empty(),
peer::Config {
local_time: alice.local_time(),
..peer::Config::default()
},
);
// Tell Alice about the amazing projects available // Tell Alice about the amazing projects available
alice.connect_to(&bob); alice.connect_to(&bob);
@ -341,15 +349,7 @@ fn test_inventory_pruning() {
#[test] #[test]
fn test_tracking() { fn test_tracking() {
let mut alice = Peer::config( let mut alice = Peer::new("alice", [7, 7, 7, 7]);
"alice",
Config::default(),
[7, 7, 7, 7],
MockStorage::empty(),
address::Book::memory().unwrap(),
MockSigner::default(),
fastrand::Rng::new(),
);
let proj_id: identity::Id = test::arbitrary::gen(1); let proj_id: identity::Id = test::arbitrary::gen(1);
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
@ -373,8 +373,8 @@ fn test_tracking() {
#[test] #[test]
fn test_inventory_relay_bad_timestamp() { fn test_inventory_relay_bad_timestamp() {
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty()); let mut alice = Peer::new("alice", [7, 7, 7, 7]);
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty()); let bob = Peer::new("bob", [8, 8, 8, 8]);
let two_hours = 3600 * 2; let two_hours = 3600 * 2;
let timestamp = alice.timestamp() + two_hours; let timestamp = alice.timestamp() + two_hours;
@ -398,9 +398,9 @@ fn test_inventory_relay_bad_timestamp() {
#[test] #[test]
fn test_announcement_rebroadcast() { fn test_announcement_rebroadcast() {
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty()); let mut alice = Peer::new("alice", [7, 7, 7, 7]);
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty()); let bob = Peer::new("bob", [8, 8, 8, 8]);
let eve = Peer::new("eve", [9, 9, 9, 9], MockStorage::empty()); let eve = Peer::new("eve", [9, 9, 9, 9]);
alice.connect_to(&bob); alice.connect_to(&bob);
@ -425,9 +425,9 @@ fn test_announcement_rebroadcast() {
#[test] #[test]
fn test_announcement_rebroadcast_timestamp_filtered() { fn test_announcement_rebroadcast_timestamp_filtered() {
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty()); let mut alice = Peer::new("alice", [7, 7, 7, 7]);
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty()); let bob = Peer::new("bob", [8, 8, 8, 8]);
let eve = Peer::new("eve", [9, 9, 9, 9], MockStorage::empty()); let eve = Peer::new("eve", [9, 9, 9, 9]);
alice.connect_to(&bob); alice.connect_to(&bob);
@ -464,9 +464,9 @@ fn test_announcement_rebroadcast_timestamp_filtered() {
#[test] #[test]
fn test_announcement_relay() { fn test_announcement_relay() {
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty()); let mut alice = Peer::new("alice", [7, 7, 7, 7]);
let mut bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty()); let mut bob = Peer::new("bob", [8, 8, 8, 8]);
let mut eve = Peer::new("eve", [9, 9, 9, 9], MockStorage::empty()); let mut eve = Peer::new("eve", [9, 9, 9, 9]);
alice.connect_to(&bob); alice.connect_to(&bob);
alice.connect_to(&eve); alice.connect_to(&eve);
@ -527,31 +527,33 @@ fn test_announcement_relay() {
#[test] #[test]
fn test_refs_announcement_relay() { fn test_refs_announcement_relay() {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let mut alice = Peer::new( let mut alice = Peer::config(
"alice", "alice",
[7, 7, 7, 7], [7, 7, 7, 7],
Storage::open(tmp.path().join("alice")).unwrap(), Storage::open(tmp.path().join("alice")).unwrap(),
peer::Config::default(),
); );
let eve = Peer::new( let eve = Peer::config(
"eve", "eve",
[8, 8, 8, 8], [8, 8, 8, 8],
Storage::open(tmp.path().join("eve")).unwrap(), Storage::open(tmp.path().join("eve")).unwrap(),
peer::Config::default(),
); );
let bob = { let bob = {
let mut rng = fastrand::Rng::new(); let mut rng = fastrand::Rng::new();
let addresses = address::Book::memory().unwrap();
let signer = MockSigner::new(&mut rng); let signer = MockSigner::new(&mut rng);
let storage = fixtures::storage(tmp.path().join("bob"), &signer).unwrap(); let storage = fixtures::storage(tmp.path().join("bob"), &signer).unwrap();
Peer::config( Peer::config(
"bob", "bob",
Config::default(),
[9, 9, 9, 9], [9, 9, 9, 9],
storage, storage,
addresses, peer::Config {
signer, signer,
rng, rng,
..peer::Config::default()
},
) )
}; };
let bob_inv = bob.inventory().unwrap(); let bob_inv = bob.inventory().unwrap();
@ -593,9 +595,9 @@ fn test_refs_announcement_relay() {
#[test] #[test]
fn test_refs_announcement_no_subscribe() { fn test_refs_announcement_no_subscribe() {
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty()); let mut alice = Peer::new("alice", [7, 7, 7, 7]);
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty()); let bob = Peer::new("bob", [8, 8, 8, 8]);
let eve = Peer::new("eve", [9, 9, 9, 9], MockStorage::empty()); let eve = Peer::new("eve", [9, 9, 9, 9]);
let id = arbitrary::gen(1); let id = arbitrary::gen(1);
alice.track_repo(&id, tracking::Scope::All).unwrap(); alice.track_repo(&id, tracking::Scope::All).unwrap();
@ -609,9 +611,9 @@ fn test_refs_announcement_no_subscribe() {
#[test] #[test]
fn test_inventory_relay() { fn test_inventory_relay() {
// Topology is eve <-> alice <-> bob // Topology is eve <-> alice <-> bob
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty()); let mut alice = Peer::new("alice", [7, 7, 7, 7]);
let bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty()); let bob = Peer::new("bob", [8, 8, 8, 8]);
let eve = Peer::new("eve", [9, 9, 9, 9], MockStorage::empty()); let eve = Peer::new("eve", [9, 9, 9, 9]);
let inv = BoundedVec::new(); let inv = BoundedVec::new();
let now = LocalTime::now().as_secs(); let now = LocalTime::now().as_secs();
@ -704,19 +706,19 @@ fn test_inventory_relay() {
#[test] #[test]
fn test_persistent_peer_reconnect() { fn test_persistent_peer_reconnect() {
let mut bob = Peer::new("bob", [8, 8, 8, 8], MockStorage::empty()); let mut bob = Peer::new("bob", [8, 8, 8, 8]);
let mut eve = Peer::new("eve", [9, 9, 9, 9], MockStorage::empty()); let mut eve = Peer::new("eve", [9, 9, 9, 9]);
let mut alice = Peer::config( let mut alice = Peer::config(
"alice", "alice",
Config {
connect: vec![bob.address(), eve.address()],
..Config::default()
},
[7, 7, 7, 7], [7, 7, 7, 7],
MockStorage::empty(), MockStorage::empty(),
address::Book::memory().unwrap(), peer::Config {
MockSigner::default(), config: Config {
fastrand::Rng::new(), connect: vec![bob.address(), eve.address()],
..Config::default()
},
..peer::Config::default()
},
); );
let mut sim = Simulation::new( let mut sim = Simulation::new(
@ -774,18 +776,18 @@ fn test_persistent_peer_reconnect() {
fn test_maintain_connections() { fn test_maintain_connections() {
// Peers alice starts out connected to. // Peers alice starts out connected to.
let connected = vec![ let connected = vec![
Peer::new("connected", [8, 8, 8, 1], MockStorage::empty()), Peer::new("connected", [8, 8, 8, 1]),
Peer::new("connected", [8, 8, 8, 2], MockStorage::empty()), Peer::new("connected", [8, 8, 8, 2]),
Peer::new("connected", [8, 8, 8, 3], MockStorage::empty()), Peer::new("connected", [8, 8, 8, 3]),
]; ];
// Peers alice will connect to once the others disconnect. // Peers alice will connect to once the others disconnect.
let mut unconnected = vec![ let mut unconnected = vec![
Peer::new("unconnected", [9, 9, 9, 1], MockStorage::empty()), Peer::new("unconnected", [9, 9, 9, 1]),
Peer::new("unconnected", [9, 9, 9, 2], MockStorage::empty()), Peer::new("unconnected", [9, 9, 9, 2]),
Peer::new("unconnected", [9, 9, 9, 3], MockStorage::empty()), Peer::new("unconnected", [9, 9, 9, 3]),
]; ];
let mut alice = Peer::new("alice", [7, 7, 7, 7], MockStorage::empty()); let mut alice = Peer::new("alice", [7, 7, 7, 7]);
alice.import_addresses(&unconnected); alice.import_addresses(&unconnected);
for peer in connected.iter() { for peer in connected.iter() {
@ -827,13 +829,18 @@ fn test_push_and_pull() {
let storage_alice = Storage::open(tempdir.path().join("alice").join("storage")).unwrap(); let storage_alice = Storage::open(tempdir.path().join("alice").join("storage")).unwrap();
let (repo, _) = fixtures::repository(tempdir.path().join("working")); let (repo, _) = fixtures::repository(tempdir.path().join("working"));
let mut alice = Peer::new("alice", [7, 7, 7, 7], storage_alice); let mut alice = Peer::config(
"alice",
[7, 7, 7, 7],
storage_alice,
peer::Config::default(),
);
let storage_bob = Storage::open(tempdir.path().join("bob").join("storage")).unwrap(); let storage_bob = Storage::open(tempdir.path().join("bob").join("storage")).unwrap();
let mut bob = Peer::new("bob", [8, 8, 8, 8], storage_bob); let mut bob = Peer::config("bob", [8, 8, 8, 8], storage_bob, peer::Config::default());
let storage_eve = Storage::open(tempdir.path().join("eve").join("storage")).unwrap(); let storage_eve = Storage::open(tempdir.path().join("eve").join("storage")).unwrap();
let mut eve = Peer::new("eve", [9, 9, 9, 9], storage_eve); let mut eve = Peer::config("eve", [9, 9, 9, 9], storage_eve, peer::Config::default());
remote::mock::register(&alice.node_id(), alice.storage().path()); remote::mock::register(&alice.node_id(), alice.storage().path());
remote::mock::register(&eve.node_id(), eve.storage().path()); remote::mock::register(&eve.node_id(), eve.storage().path());
@ -906,9 +913,24 @@ fn test_push_and_pull() {
fn prop_inventory_exchange_dense() { fn prop_inventory_exchange_dense() {
fn property(alice_inv: MockStorage, bob_inv: MockStorage, eve_inv: MockStorage) { fn property(alice_inv: MockStorage, bob_inv: MockStorage, eve_inv: MockStorage) {
let rng = fastrand::Rng::new(); let rng = fastrand::Rng::new();
let alice = Peer::new("alice", [7, 7, 7, 7], alice_inv.clone()); let alice = Peer::config(
let mut bob = Peer::new("bob", [8, 8, 8, 8], bob_inv.clone()); "alice",
let mut eve = Peer::new("eve", [9, 9, 9, 9], eve_inv.clone()); [7, 7, 7, 7],
alice_inv.clone(),
peer::Config::default(),
);
let mut bob = Peer::config(
"bob",
[8, 8, 8, 8],
bob_inv.clone(),
peer::Config::default(),
);
let mut eve = Peer::config(
"eve",
[9, 9, 9, 9],
eve_inv.clone(),
peer::Config::default(),
);
let mut routing = HashMap::with_hasher(rng.clone().into()); let mut routing = HashMap::with_hasher(rng.clone().into());
for (inv, peer) in &[ for (inv, peer) in &[