From 1f7c9efcc119ba1888f645566ce0f4142f4adbb2 Mon Sep 17 00:00:00 2001 From: ennucore Date: Sat, 20 Nov 2021 23:34:20 +0300 Subject: [PATCH] Improved `IFError`, wrote `TestInterface` and some tests for `Transport` --- Cargo.lock | 10 +++++++++ Cargo.toml | 1 + src/crypto.rs | 3 +++ src/interface.rs | 37 +++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/res.rs | 3 ++- src/transport.rs | 54 +++++++++++++++++++++++++++++++++++++++++------- 7 files changed, 100 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2482002..3ed9fe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,6 +65,15 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" +[[package]] +name = "core-error" +version = "0.0.1-rc4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7851bcb61e74ebcf5f2f1f1ee119f647c03fec697768bbcc86c26654fd21f977" +dependencies = [ + "version_check", +] + [[package]] name = "crossbeam-channel" version = "0.5.1" @@ -214,6 +223,7 @@ dependencies = [ name = "ironforce" version = "0.1.0" dependencies = [ + "core-error", "rand", "rand_os", "rayon", diff --git a/Cargo.toml b/Cargo.toml index 85e2385..00994e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ rand = "*" rsa = { version = "0.5", features = ["serde"] } serde = { version = "1.0", features = ["derive", "alloc"], default-features = false } rayon = { version = "1.5.1", optional = true } +core-error = "0.0.1-rc4" [profile.dev.package.num-bigint-dig] opt-level = 3 diff --git a/src/crypto.rs b/src/crypto.rs index c6bda43..91456ff 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -74,6 +74,9 @@ fn test_encrypt() { ); } +#[cfg(test)] +use alloc::vec; + #[test] fn test_invalid_encrypt() { let data = vec![0, 5, 8, 135, 67]; diff --git a/src/interface.rs b/src/interface.rs index 939d5d1..b4b4c16 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -12,6 +12,7 @@ pub(crate) type TargetingData = String; /// In an std environment we require that the interface can be send safely between threads #[cfg(not(std))] pub trait InterfaceRequirements {} + #[cfg(std)] pub trait InterfaceRequirements = Send + Sync; @@ -39,3 +40,39 @@ pub trait Interface: InterfaceRequirements { /// The implementations of this function shouldn't wait for new messages, but fn receive(&mut self) -> IFResult>; } + +#[cfg(test)] +pub mod test_interface { + use crate::interface::{Interface, InterfaceRequirements, TargetingData}; + use crate::message::MessageBytes; + use crate::res::IFResult; + use alloc::vec::Vec; + + #[derive(Default)] + pub struct TestInterface { + messages: Vec<(Vec, TargetingData)>, + } + + impl InterfaceRequirements for TestInterface {} + + impl Interface for TestInterface { + fn main_loop_iteration(&mut self) -> IFResult<()> { + Ok(()) + } + + fn id(&self) -> &str { + "test_interface" + } + + fn send(&mut self, message: &[u8], interface_data: Option) -> IFResult<()> { + self.messages.push((Vec::from(message), interface_data.unwrap_or_default())); + Ok(()) + } + + fn receive(&mut self) -> IFResult> { + Ok( + self.messages.pop() + ) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index e9be0d2..2cafc3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ extern crate alloc; extern crate rand; extern crate rsa; +extern crate core_error; mod crypto; mod ironforce; diff --git a/src/res.rs b/src/res.rs index 60c591e..0b282c6 100644 --- a/src/res.rs +++ b/src/res.rs @@ -3,13 +3,14 @@ use alloc::string::String; use core::fmt::Debug; /// An enum for all errors that may occur +#[derive(Clone, PartialEq, Debug)] pub enum IFError { /// An error that was created in some dependency and then converted to `IFError` General(String), } -impl From for IFError { +impl From for IFError { /// Convert from other error fn from(e: T) -> Self { Self::General(format!("{:?}", e)) diff --git a/src/transport.rs b/src/transport.rs index 3ca46cd..6fe63fa 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -1,6 +1,7 @@ use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; +use alloc::vec; use crate::interface::{Interface, TargetingData}; use crate::message::MessageBytes; use crate::res::IFResult; @@ -10,7 +11,7 @@ use rayon::prelude::*; /// An identification of a peer - something that we can use to send a message to id -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct PeerInfo { /// Something to locally identify this peer pub peer_id: u64, @@ -38,6 +39,11 @@ pub struct Transport { } impl Transport { + /// Create new transport with given interfaces + pub fn new(interfaces: Vec>) -> Self { + Self { interfaces, peers: vec![] } + } + /// Find a peer in `self.peers` by its id fn get_peer_by_id(&self, peer_id: u64) -> Option { self.peers.iter().find(|peer| peer.peer_id == peer_id).cloned() @@ -73,16 +79,16 @@ impl Transport { // Broadcast None => { #[cfg(not(std))] - { - for interface in &mut self.interfaces { - interface.send(&message, None)?; + { + for interface in &mut self.interfaces { + interface.send(&message, None)?; + } } - } // If we have concurrency, we will do it concurrently #[cfg(std)] - { - self.interfaces.par_iter_mut().map(|interface| interface.send(&message, None)).for_each(drop); - } + { + self.interfaces.par_iter_mut().map(|interface| interface.send(&message, None)).for_each(drop); + } Ok(()) } // Singlecast @@ -93,3 +99,35 @@ impl Transport { } } } + +#[cfg(test)] +use crate::interface::test_interface::TestInterface; +#[cfg(test)] +use alloc::string::ToString; + +#[test] +fn test_adding_peer_to_transport() { + let mut transport = Transport::new(vec![Box::new(TestInterface::default())]); + let (interface_id, interface_targeting_data) = ("test_interface".to_string(), "hi".to_string()); + assert!(transport.get_peer_by_parameters(interface_id.as_str(), interface_targeting_data.as_str()).is_none()); + let peer_id = transport.find_or_add_peer(interface_id.clone(), interface_targeting_data.clone()); + let peer = PeerInfo { + peer_id, + interface_id: interface_id.clone(), + interface_targeting_data: interface_targeting_data.clone(), + }; + assert_eq!(transport.get_peer_by_parameters(interface_id.as_str(), interface_targeting_data.as_str()), Some(&peer)); + assert_eq!(transport.get_peer_by_id(peer_id), Some(peer)); +} + +#[test] +fn test_transport_sending() { + let mut transport = Transport::new(vec![Box::new(TestInterface::default())]); + let (interface_id, interface_targeting_data) = ("test_interface".to_string(), "hi".to_string()); + let peer_id = transport.find_or_add_peer(interface_id.clone(), interface_targeting_data.clone()); + transport.send_message(vec![239, 123], None).unwrap(); + assert_eq!(transport.interfaces[0].receive().unwrap(), Some((vec![239u8, 123], "".to_string()))); + assert!(transport.interfaces[0].receive() == IFResult::Ok(None)); + transport.send_message(vec![239, 123], Some(peer_id)).unwrap(); + assert_eq!(transport.interfaces[0].receive(), IFResult::Ok(Some((vec![239, 123], interface_targeting_data)))); +}