From 07076388151c725a3723dbef4742ac1e5a8f97c3 Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Wed, 16 Dec 2020 13:01:36 +0100 Subject: [PATCH 01/16] Use 2018 edition --- Cargo.toml | 1 + src/lib.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f9a7616..d357e80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "riker-testkit" version = "0.1.0" +edition = "2018" authors = ["Lee Smith "] description = "Tools to make testing Riker applications easier" homepage = "http://riker.rs/logging" diff --git a/src/lib.rs b/src/lib.rs index 6347748..059a637 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,2 @@ -extern crate chrono; pub mod probe; From 019f2185b0dafe8e9cd29ac64fa4a3eefa9b85e4 Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Thu, 17 Dec 2020 10:14:26 +0100 Subject: [PATCH 02/16] Add tokio_executor feature --- Cargo.toml | 5 + src/lib.rs | 15 +++ src/probe.rs | 260 +++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 241 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d357e80..58a8d04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,8 @@ readme = "README.md" [dependencies] chrono = "0.4" +tokio = { version="0.3.6", features = ["rt-multi-thread", "macros", "sync"], optional = true } +async-trait = { version="0.1.42", optional = true } + +[features] +tokio_executor = ["tokio", "async-trait"] diff --git a/src/lib.rs b/src/lib.rs index 059a637..41eff2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,17 @@ pub mod probe; + +#[cfg(feature = "tokio_executor")] +#[macro_export] +macro_rules! test_fn { + ($(#[$($meta:meta)*])* $vis:vis $ident:ident $($tokens:tt)*) => { + $(#[$($meta)*])* #[tokio::test] $vis async $ident $($tokens)* + }; +} +#[cfg(not(feature = "tokio_executor"))] +#[macro_export] +macro_rules! test_fn { + ($(#[$($meta:meta)*])* $vis:vis $ident:ident $($tokens:tt)*) => { + $(#[$($meta)*])* #[test] $vis $ident $($tokens)* + }; +} diff --git a/src/probe.rs b/src/probe.rs index d207d9e..14a3c67 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -1,16 +1,29 @@ +#[cfg(feature = "tokio_executor")] +use std::{ + future::Future, + pin::Pin, +}; +#[cfg_attr(feature = "tokio_executor", async_trait::async_trait)] pub trait Probe { type Msg: Send; type Pay: Clone + Send; + #[cfg(not(feature = "tokio_executor"))] fn event(&self, evt: Self::Msg); + #[cfg(feature = "tokio_executor")] + fn event(&self, evt: Self::Msg) -> Pin + Send>>; fn payload(&self) -> &Self::Pay; } +#[cfg_attr(feature = "tokio_executor", async_trait::async_trait)] pub trait ProbeReceive { type Msg: Send; + #[cfg(not(feature = "tokio_executor"))] fn recv(&self) -> Self::Msg; + #[cfg(feature = "tokio_executor")] + async fn recv(&mut self) -> Self::Msg; fn reset_timer(&mut self); fn last_event_milliseconds(&self) -> u64; fn last_event_seconds(&self) -> u64; @@ -23,14 +36,25 @@ pub mod channel { use super::{Probe, ProbeReceive}; use chrono::prelude::*; + #[cfg(not(feature = "tokio_executor"))] use std::sync::mpsc::{channel, Sender, Receiver}; + #[cfg(feature = "tokio_executor")] + use tokio::sync::mpsc::{channel, Sender, Receiver}; + #[cfg(feature = "tokio_executor")] + use std::{ + future::Future, + pin::Pin, + }; pub fn probe() -> (ChannelProbe<(), T>, ChannelProbeReceive) { probe_with_payload(()) } pub fn probe_with_payload(payload: P) -> (ChannelProbe, ChannelProbeReceive) { + #[cfg(not(feature = "tokio_executor"))] let (tx, rx) = channel::(); + #[cfg(feature = "tokio_executor")] + let (tx, rx) = channel::(100); let probe = ChannelProbe { payload: Some(payload), @@ -46,12 +70,20 @@ pub mod channel { (probe, receiver) } + #[cfg(not(feature = "tokio_executor"))] + #[derive(Clone, Debug)] + pub struct ChannelProbe { + payload: Option

, + tx: Sender, + } + #[cfg(feature = "tokio_executor")] #[derive(Clone, Debug)] pub struct ChannelProbe { payload: Option

, tx: Sender, } + #[cfg(not(feature = "tokio_executor"))] impl Probe for ChannelProbe where P: Clone + Send, T: Send { type Msg = T; @@ -66,6 +98,7 @@ pub mod channel { } } + #[cfg(not(feature = "tokio_executor"))] impl Probe for Option> where P: Clone + Send, T: Send { type Msg = T; @@ -79,6 +112,43 @@ pub mod channel { &self.as_ref().unwrap().payload.as_ref().unwrap() } } + #[cfg(feature = "tokio_executor")] + #[async_trait::async_trait] + impl Probe for ChannelProbe + where P: Clone + Send, T: Send { + type Msg = T; + type Pay = P; + + fn event(&self, evt: T) -> Pin + Send>> { + let tx = self.clone().tx.clone(); + Box::pin(async move { + tx.send(evt).await.unwrap() + }) + } + + fn payload(&self) -> &P { + &self.payload.as_ref().unwrap() + } + } + + #[cfg(feature = "tokio_executor")] + #[async_trait::async_trait] + impl Probe for Option> + where P: Clone + Send, T: Send { + type Msg = T; + type Pay = P; + + fn event(&self, evt: T) -> Pin + Send>> { + let tx = self.clone().as_ref().unwrap().tx.clone(); + Box::pin(async move { + drop(tx.send(evt).await) + }) + } + + fn payload(&self) -> &P { + &self.as_ref().unwrap().payload.as_ref().unwrap() + } + } #[allow(dead_code)] pub struct ChannelProbeReceive { @@ -87,12 +157,18 @@ pub mod channel { timer_start: DateTime, } + #[cfg_attr(feature = "tokio_executor", async_trait::async_trait)] impl ProbeReceive for ChannelProbeReceive { type Msg = T; + #[cfg(not(feature = "tokio_executor"))] fn recv(&self) -> T { self.rx.recv().unwrap() } + #[cfg(feature = "tokio_executor")] + async fn recv(&mut self) -> T { + self.rx.recv().await.unwrap() + } fn reset_timer(&mut self) { self.timer_start = Utc::now(); @@ -110,65 +186,63 @@ pub mod channel { } } -#[cfg(test)] -mod tests { - use super::{Probe, ProbeReceive}; - use super::channel::{probe, probe_with_payload}; - use std::thread; - - #[test] - fn chan_probe() { - let (probe, listen) = probe(); - - thread::spawn(move || { - probe.event("some event"); - }); - - assert_eq!(listen.recv(), "some event"); - } - - #[test] - fn chan_probe_with_payload() { - let payload = "test data".to_string(); - let (probe, listen) = probe_with_payload(payload); - - thread::spawn(move || { - // only event the expected result if the payload is what we expect - if probe.payload() == "test data" { - probe.event("data received"); - } else { - probe.event(""); - } - - }); - - assert_eq!(listen.recv(), "data received"); - } -} - /// Macros that provide easy use of Probes +#[macro_use] pub mod macros { /// Mimicks assert_eq! /// Performs an assert_eq! on the first event sent by the probe. + #[cfg(not(feature = "tokio_executor"))] #[macro_export] macro_rules! p_assert_eq { ($listen:expr, $expected:expr) => { assert_eq!($listen.recv(), $expected); }; } + #[cfg(feature = "tokio_executor")] + #[macro_export] + macro_rules! p_assert_eq { + ($listen:expr, $expected:expr) => { + assert_eq!($listen.recv().await, $expected); + }; + } /// Evaluates events sent from the probe with a vector of expected events. /// If an unexpected event is received it will assert!(false). /// Each good event is removed from the expected vector. /// The assertion is complete when there are no more expected events. + #[cfg(feature = "tokio_executor")] #[macro_export] macro_rules! p_assert_events { ($listen:expr, $expected:expr) => { let mut expected = $expected.clone(); // so we don't need the original mutable loop { - match expected.iter().position(|x| x == &$listen.recv()) { + let val = $listen.recv().await; + match expected.iter().position(|x| x == &val) { + Some(pos) => { + expected.remove(pos); + if expected.len() == 0 { + break; + } + } + _ => { + // probe has received an unexpected event value + assert!(false); + } + } + } + }; + } + #[cfg(not(feature = "tokio_executor"))] + #[macro_export] + macro_rules! p_assert_events { + ($listen:expr, $expected:expr) => { + let mut expected = $expected.clone(); // so we don't need the original mutable + + loop { + let val = $listen.recv(); + match expected.iter().position(|x| x == &val) { Some(pos) => { expected.remove(pos); if expected.len() == 0 { @@ -191,10 +265,10 @@ pub mod macros { }; } + #[cfg(not(feature = "tokio_executor"))] #[cfg(test)] mod tests { - use probe::{Probe, ProbeReceive}; - use probe::channel::probe; + use crate::probe::{Probe, ProbeReceive, channel::probe}; #[test] fn p_assert_eq() { @@ -226,4 +300,112 @@ pub mod macros { } } + #[cfg(feature = "tokio_executor")] + #[cfg(test)] + mod tests { + use crate::probe::{Probe, ProbeReceive, channel::probe}; + + #[tokio::test] + async fn p_assert_eq() { + let (probe, mut listen) = probe(); + + probe.event("test".to_string()).await; + + p_assert_eq!(listen, "test".to_string()); + } + + #[tokio::test] + async fn p_assert_events() { + let (probe, mut listen) = probe(); + + let expected = vec!["event_1", "event_2", "event_3"]; + probe.event("event_1").await; + probe.event("event_2").await; + probe.event("event_3").await; + + p_assert_events!(listen, expected); + } + + #[tokio::test] + async fn p_timer() { + let (probe, listen) = probe(); + probe.event("event_3").await; + + println!("Milliseconds: {}", p_timer!(listen)); + } + + } +} + +#[cfg(not(feature = "tokio_executor"))] +#[cfg(test)] +mod tests { + use super::{Probe, ProbeReceive}; + use super::channel::{probe, probe_with_payload}; + use std::thread; + + #[test] + fn chan_probe() { + let (probe, listen) = probe(); + + thread::spawn(move || { + probe.event("some event"); + }); + + p_assert_eq!(listen, "some event"); + } + + #[test] + fn chan_probe_with_payload() { + let payload = "test data".to_string(); + let (probe, listen) = probe_with_payload(payload); + + thread::spawn(move || { + // only event the expected result if the payload is what we expect + if probe.payload() == "test data" { + probe.event("data received"); + } else { + probe.event(""); + } + + }); + + p_assert_eq!(listen, "data received"); + } +} + +#[cfg(feature = "tokio_executor")] +#[cfg(test)] +mod tests { + use super::{Probe, ProbeReceive}; + use super::channel::{probe, probe_with_payload}; + + #[tokio::test] + async fn chan_probe() { + let (probe, mut listen) = probe(); + + tokio::spawn(async move { + probe.event("some event").await; + }); + + p_assert_eq!(listen, "some event"); + } + + #[tokio::test] + async fn chan_probe_with_payload() { + let payload = "test data".to_string(); + let (probe, mut listen) = probe_with_payload(payload); + + tokio::spawn(async move { + // only event the expected result if the payload is what we expect + if probe.payload() == "test data" { + probe.event("data received").await; + } else { + probe.event("").await; + } + + }); + + p_assert_eq!(listen, "data received"); + } } From 06aa73e5914ccc5560c3ce74674fdc0ea42e0938 Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Thu, 17 Dec 2020 10:15:02 +0100 Subject: [PATCH 03/16] Ignore Cargo.lock --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c977131..a9339b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +Cargo.lock /target **/*.rs.bk .vscode From 5cfdee7f6269d8ae67d042d2497d11c99e6f70e6 Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Thu, 17 Dec 2020 10:26:09 +0100 Subject: [PATCH 04/16] Minor refactoring --- src/probe.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/probe.rs b/src/probe.rs index 14a3c67..10c775a 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -38,12 +38,14 @@ pub mod channel { use chrono::prelude::*; #[cfg(not(feature = "tokio_executor"))] use std::sync::mpsc::{channel, Sender, Receiver}; + #[cfg(feature = "tokio_executor")] - use tokio::sync::mpsc::{channel, Sender, Receiver}; - #[cfg(feature = "tokio_executor")] - use std::{ - future::Future, - pin::Pin, + use { + tokio::sync::mpsc::{channel, Sender, Receiver}, + std::{ + future::Future, + pin::Pin, + } }; pub fn probe() -> (ChannelProbe<(), T>, ChannelProbeReceive) { @@ -70,13 +72,6 @@ pub mod channel { (probe, receiver) } - #[cfg(not(feature = "tokio_executor"))] - #[derive(Clone, Debug)] - pub struct ChannelProbe { - payload: Option

, - tx: Sender, - } - #[cfg(feature = "tokio_executor")] #[derive(Clone, Debug)] pub struct ChannelProbe { payload: Option

, @@ -141,7 +136,7 @@ pub mod channel { fn event(&self, evt: T) -> Pin + Send>> { let tx = self.clone().as_ref().unwrap().tx.clone(); Box::pin(async move { - drop(tx.send(evt).await) + tx.send(evt).await.unwrap() }) } From 5289097afe0d9348cf1585cc7f49079dc0edf09f Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Sun, 10 Jan 2021 04:59:42 +0100 Subject: [PATCH 05/16] Downgrade tokio to v0.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 58a8d04..d739ca1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" [dependencies] chrono = "0.4" -tokio = { version="0.3.6", features = ["rt-multi-thread", "macros", "sync"], optional = true } +tokio = { version = "^0.2", features = ["rt-threaded", "macros"], optional = true } async-trait = { version="0.1.42", optional = true } [features] From d928ab1be905fa55c5be80d4457a550270f848ba Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Sun, 10 Jan 2021 05:00:27 +0100 Subject: [PATCH 06/16] Unwrap results instead of dropping them --- src/probe.rs | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/src/probe.rs b/src/probe.rs index 10c775a..d313524 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -85,7 +85,7 @@ pub mod channel { type Pay = P; fn event(&self, evt: T) { - drop(self.tx.send(evt)); + self.tx.send(evt).unwrap() } fn payload(&self) -> &P { @@ -100,7 +100,7 @@ pub mod channel { type Pay = P; fn event(&self, evt: T) { - drop(self.as_ref().unwrap().tx.send(evt)); + self.as_ref().unwrap().tx.send(evt).unwrap() } fn payload(&self) -> &P { @@ -206,37 +206,16 @@ pub mod macros { /// If an unexpected event is received it will assert!(false). /// Each good event is removed from the expected vector. /// The assertion is complete when there are no more expected events. - #[cfg(feature = "tokio_executor")] - #[macro_export] - macro_rules! p_assert_events { - ($listen:expr, $expected:expr) => { - let mut expected = $expected.clone(); // so we don't need the original mutable - - loop { - let val = $listen.recv().await; - match expected.iter().position(|x| x == &val) { - Some(pos) => { - expected.remove(pos); - if expected.len() == 0 { - break; - } - } - _ => { - // probe has received an unexpected event value - assert!(false); - } - } - } - }; - } - #[cfg(not(feature = "tokio_executor"))] #[macro_export] macro_rules! p_assert_events { ($listen:expr, $expected:expr) => { let mut expected = $expected.clone(); // so we don't need the original mutable loop { + #[cfg(not(feature = "tokio_executor"))] let val = $listen.recv(); + #[cfg(feature = "tokio_executor")] + let val = $listen.recv().await; match expected.iter().position(|x| x == &val) { Some(pos) => { expected.remove(pos); From 04e9fd59ca5f5e6bebb3eb24e12d3dbe79f10b58 Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Sun, 10 Jan 2021 05:47:55 +0100 Subject: [PATCH 07/16] Fix missing mut --- src/probe.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/probe.rs b/src/probe.rs index d313524..61a0759 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -115,7 +115,7 @@ pub mod channel { type Pay = P; fn event(&self, evt: T) -> Pin + Send>> { - let tx = self.clone().tx.clone(); + let mut tx = self.clone().tx.clone(); Box::pin(async move { tx.send(evt).await.unwrap() }) @@ -134,7 +134,7 @@ pub mod channel { type Pay = P; fn event(&self, evt: T) -> Pin + Send>> { - let tx = self.clone().as_ref().unwrap().tx.clone(); + let mut tx = self.clone().as_ref().unwrap().tx.clone(); Box::pin(async move { tx.send(evt).await.unwrap() }) From eb265dbfc3b1d7fcbefd839013121677ba881a59 Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Sun, 10 Jan 2021 05:57:11 +0100 Subject: [PATCH 08/16] Fix missing tokio feature --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d739ca1..08a7bcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" [dependencies] chrono = "0.4" -tokio = { version = "^0.2", features = ["rt-threaded", "macros"], optional = true } +tokio = { version = "^0.2", features = ["rt-threaded", "macros", "sync"], optional = true } async-trait = { version="0.1.42", optional = true } [features] From 3c274438a23ed038ce151fde23739d79ba7f0f6e Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Mon, 11 Jan 2021 00:45:43 +0100 Subject: [PATCH 09/16] Upgrade to tokio 1.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 08a7bcb..b7bc8b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" [dependencies] chrono = "0.4" -tokio = { version = "^0.2", features = ["rt-threaded", "macros", "sync"], optional = true } +tokio = { version = "^1", features = ["rt-multi-thread", "macros", "sync"], optional = true } async-trait = { version="0.1.42", optional = true } [features] From 9c16c35386015eb22ba2ccf2bfe06e6abb27531a Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Mon, 11 Jan 2021 04:06:57 +0100 Subject: [PATCH 10/16] Remove tokio_executor feature, use tokio by default --- Cargo.toml | 7 +-- src/lib.rs | 8 --- src/probe.rs | 144 ++------------------------------------------------- 3 files changed, 7 insertions(+), 152 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b7bc8b9..d31cc10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,5 @@ readme = "README.md" [dependencies] chrono = "0.4" -tokio = { version = "^1", features = ["rt-multi-thread", "macros", "sync"], optional = true } -async-trait = { version="0.1.42", optional = true } - -[features] -tokio_executor = ["tokio", "async-trait"] +tokio = { version = "^1", features = ["rt-multi-thread", "macros", "sync"] } +async-trait = { version="0.1.42" } diff --git a/src/lib.rs b/src/lib.rs index 41eff2d..c61a3db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,17 +1,9 @@ pub mod probe; -#[cfg(feature = "tokio_executor")] #[macro_export] macro_rules! test_fn { ($(#[$($meta:meta)*])* $vis:vis $ident:ident $($tokens:tt)*) => { $(#[$($meta)*])* #[tokio::test] $vis async $ident $($tokens)* }; } -#[cfg(not(feature = "tokio_executor"))] -#[macro_export] -macro_rules! test_fn { - ($(#[$($meta:meta)*])* $vis:vis $ident:ident $($tokens:tt)*) => { - $(#[$($meta)*])* #[test] $vis $ident $($tokens)* - }; -} diff --git a/src/probe.rs b/src/probe.rs index 61a0759..95f48cc 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -1,28 +1,21 @@ -#[cfg(feature = "tokio_executor")] use std::{ future::Future, pin::Pin, }; -#[cfg_attr(feature = "tokio_executor", async_trait::async_trait)] +#[async_trait::async_trait] pub trait Probe { type Msg: Send; type Pay: Clone + Send; - #[cfg(not(feature = "tokio_executor"))] - fn event(&self, evt: Self::Msg); - #[cfg(feature = "tokio_executor")] fn event(&self, evt: Self::Msg) -> Pin + Send>>; fn payload(&self) -> &Self::Pay; } -#[cfg_attr(feature = "tokio_executor", async_trait::async_trait)] +#[async_trait::async_trait] pub trait ProbeReceive { type Msg: Send; - #[cfg(not(feature = "tokio_executor"))] - fn recv(&self) -> Self::Msg; - #[cfg(feature = "tokio_executor")] async fn recv(&mut self) -> Self::Msg; fn reset_timer(&mut self); fn last_event_milliseconds(&self) -> u64; @@ -36,10 +29,7 @@ pub mod channel { use super::{Probe, ProbeReceive}; use chrono::prelude::*; - #[cfg(not(feature = "tokio_executor"))] - use std::sync::mpsc::{channel, Sender, Receiver}; - #[cfg(feature = "tokio_executor")] use { tokio::sync::mpsc::{channel, Sender, Receiver}, std::{ @@ -53,9 +43,6 @@ pub mod channel { } pub fn probe_with_payload(payload: P) -> (ChannelProbe, ChannelProbeReceive) { - #[cfg(not(feature = "tokio_executor"))] - let (tx, rx) = channel::(); - #[cfg(feature = "tokio_executor")] let (tx, rx) = channel::(100); let probe = ChannelProbe { @@ -78,36 +65,6 @@ pub mod channel { tx: Sender, } - #[cfg(not(feature = "tokio_executor"))] - impl Probe for ChannelProbe - where P: Clone + Send, T: Send { - type Msg = T; - type Pay = P; - - fn event(&self, evt: T) { - self.tx.send(evt).unwrap() - } - - fn payload(&self) -> &P { - &self.payload.as_ref().unwrap() - } - } - - #[cfg(not(feature = "tokio_executor"))] - impl Probe for Option> - where P: Clone + Send, T: Send { - type Msg = T; - type Pay = P; - - fn event(&self, evt: T) { - self.as_ref().unwrap().tx.send(evt).unwrap() - } - - fn payload(&self) -> &P { - &self.as_ref().unwrap().payload.as_ref().unwrap() - } - } - #[cfg(feature = "tokio_executor")] #[async_trait::async_trait] impl Probe for ChannelProbe where P: Clone + Send, T: Send { @@ -115,7 +72,7 @@ pub mod channel { type Pay = P; fn event(&self, evt: T) -> Pin + Send>> { - let mut tx = self.clone().tx.clone(); + let tx = self.clone().tx.clone(); Box::pin(async move { tx.send(evt).await.unwrap() }) @@ -126,7 +83,6 @@ pub mod channel { } } - #[cfg(feature = "tokio_executor")] #[async_trait::async_trait] impl Probe for Option> where P: Clone + Send, T: Send { @@ -134,7 +90,7 @@ pub mod channel { type Pay = P; fn event(&self, evt: T) -> Pin + Send>> { - let mut tx = self.clone().as_ref().unwrap().tx.clone(); + let tx = self.clone().as_ref().unwrap().tx.clone(); Box::pin(async move { tx.send(evt).await.unwrap() }) @@ -152,15 +108,10 @@ pub mod channel { timer_start: DateTime, } - #[cfg_attr(feature = "tokio_executor", async_trait::async_trait)] + #[async_trait::async_trait] impl ProbeReceive for ChannelProbeReceive { type Msg = T; - #[cfg(not(feature = "tokio_executor"))] - fn recv(&self) -> T { - self.rx.recv().unwrap() - } - #[cfg(feature = "tokio_executor")] async fn recv(&mut self) -> T { self.rx.recv().await.unwrap() } @@ -187,14 +138,6 @@ pub mod channel { pub mod macros { /// Mimicks assert_eq! /// Performs an assert_eq! on the first event sent by the probe. - #[cfg(not(feature = "tokio_executor"))] - #[macro_export] - macro_rules! p_assert_eq { - ($listen:expr, $expected:expr) => { - assert_eq!($listen.recv(), $expected); - }; - } - #[cfg(feature = "tokio_executor")] #[macro_export] macro_rules! p_assert_eq { ($listen:expr, $expected:expr) => { @@ -212,9 +155,6 @@ pub mod macros { let mut expected = $expected.clone(); // so we don't need the original mutable loop { - #[cfg(not(feature = "tokio_executor"))] - let val = $listen.recv(); - #[cfg(feature = "tokio_executor")] let val = $listen.recv().await; match expected.iter().position(|x| x == &val) { Some(pos) => { @@ -239,42 +179,6 @@ pub mod macros { }; } - #[cfg(not(feature = "tokio_executor"))] - #[cfg(test)] - mod tests { - use crate::probe::{Probe, ProbeReceive, channel::probe}; - - #[test] - fn p_assert_eq() { - let (probe, listen) = probe(); - - probe.event("test".to_string()); - - p_assert_eq!(listen, "test".to_string()); - } - - #[test] - fn p_assert_events() { - let (probe, listen) = probe(); - - let expected = vec!["event_1", "event_2", "event_3"]; - probe.event("event_1"); - probe.event("event_2"); - probe.event("event_3"); - - p_assert_events!(listen, expected); - } - - #[test] - fn p_timer() { - let (probe, listen) = probe(); - probe.event("event_3"); - - println!("Milliseconds: {}", p_timer!(listen)); - } - - } - #[cfg(feature = "tokio_executor")] #[cfg(test)] mod tests { use crate::probe::{Probe, ProbeReceive, channel::probe}; @@ -311,44 +215,6 @@ pub mod macros { } } -#[cfg(not(feature = "tokio_executor"))] -#[cfg(test)] -mod tests { - use super::{Probe, ProbeReceive}; - use super::channel::{probe, probe_with_payload}; - use std::thread; - - #[test] - fn chan_probe() { - let (probe, listen) = probe(); - - thread::spawn(move || { - probe.event("some event"); - }); - - p_assert_eq!(listen, "some event"); - } - - #[test] - fn chan_probe_with_payload() { - let payload = "test data".to_string(); - let (probe, listen) = probe_with_payload(payload); - - thread::spawn(move || { - // only event the expected result if the payload is what we expect - if probe.payload() == "test data" { - probe.event("data received"); - } else { - probe.event(""); - } - - }); - - p_assert_eq!(listen, "data received"); - } -} - -#[cfg(feature = "tokio_executor")] #[cfg(test)] mod tests { use super::{Probe, ProbeReceive}; From edf0eed64bb3924b7a36f51685ba015d55521795 Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Mon, 11 Jan 2021 07:00:29 +0100 Subject: [PATCH 11/16] Fix Probe on tokio --- src/probe.rs | 68 ++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/src/probe.rs b/src/probe.rs index 95f48cc..d2ca069 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -1,14 +1,9 @@ -use std::{ - future::Future, - pin::Pin, -}; - #[async_trait::async_trait] pub trait Probe { type Msg: Send; - type Pay: Clone + Send; + type Pay: Clone + Send + Sync; - fn event(&self, evt: Self::Msg) -> Pin + Send>>; + fn event(&self, evt: Self::Msg); fn payload(&self) -> &Self::Pay; } @@ -30,12 +25,10 @@ pub mod channel { use chrono::prelude::*; - use { - tokio::sync::mpsc::{channel, Sender, Receiver}, - std::{ - future::Future, - pin::Pin, - } + use tokio::sync::mpsc::{ + channel, + Sender, + Receiver, }; pub fn probe() -> (ChannelProbe<(), T>, ChannelProbeReceive) { @@ -67,15 +60,15 @@ pub mod channel { #[async_trait::async_trait] impl Probe for ChannelProbe - where P: Clone + Send, T: Send { + where P: Clone + Send + Sync, T: Send { type Msg = T; type Pay = P; - fn event(&self, evt: T) -> Pin + Send>> { + fn event(&self, evt: T) { let tx = self.clone().tx.clone(); - Box::pin(async move { - tx.send(evt).await.unwrap() - }) + tokio::spawn(async move { + tx.send(evt).await.unwrap(); + }); } fn payload(&self) -> &P { @@ -85,15 +78,15 @@ pub mod channel { #[async_trait::async_trait] impl Probe for Option> - where P: Clone + Send, T: Send { + where P: Clone + Send + Sync, T: Send { type Msg = T; type Pay = P; - fn event(&self, evt: T) -> Pin + Send>> { + fn event(&self, evt: T) { let tx = self.clone().as_ref().unwrap().tx.clone(); - Box::pin(async move { - tx.send(evt).await.unwrap() - }) + tokio::spawn(async move { + tx.send(evt).await.unwrap(); + }); } fn payload(&self) -> &P { @@ -187,7 +180,7 @@ pub mod macros { async fn p_assert_eq() { let (probe, mut listen) = probe(); - probe.event("test".to_string()).await; + probe.event("test".to_string()); p_assert_eq!(listen, "test".to_string()); } @@ -197,9 +190,9 @@ pub mod macros { let (probe, mut listen) = probe(); let expected = vec!["event_1", "event_2", "event_3"]; - probe.event("event_1").await; - probe.event("event_2").await; - probe.event("event_3").await; + probe.event("event_1"); + probe.event("event_2"); + probe.event("event_3"); p_assert_events!(listen, expected); } @@ -207,7 +200,7 @@ pub mod macros { #[tokio::test] async fn p_timer() { let (probe, listen) = probe(); - probe.event("event_3").await; + probe.event("event_3"); println!("Milliseconds: {}", p_timer!(listen)); } @@ -224,9 +217,7 @@ mod tests { async fn chan_probe() { let (probe, mut listen) = probe(); - tokio::spawn(async move { - probe.event("some event").await; - }); + probe.event("some event"); p_assert_eq!(listen, "some event"); } @@ -236,15 +227,12 @@ mod tests { let payload = "test data".to_string(); let (probe, mut listen) = probe_with_payload(payload); - tokio::spawn(async move { - // only event the expected result if the payload is what we expect - if probe.payload() == "test data" { - probe.event("data received").await; - } else { - probe.event("").await; - } - - }); + // only event the expected result if the payload is what we expect + if probe.payload() == "test data" { + probe.event("data received"); + } else { + probe.event(""); + } p_assert_eq!(listen, "data received"); } From 849e28815433042ac9c5be2bddd1ef4e5956d2a3 Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Sat, 6 Feb 2021 10:45:03 +0100 Subject: [PATCH 12/16] Ignore **/target (target in any subdirectory) --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a9339b5..ebde65a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ Cargo.lock -/target +**/target **/*.rs.bk .vscode From 7e3b55573cae21084ebc2000c048f2a3d7eee61c Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Sat, 6 Feb 2021 10:43:55 +0100 Subject: [PATCH 13/16] Add test_fn_macro proc-macro crate --- src/lib.rs | 2 +- test_fn_macro/Cargo.toml | 17 +++++++++++++++++ test_fn_macro/src/lib.rs | 24 ++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 test_fn_macro/Cargo.toml create mode 100644 test_fn_macro/src/lib.rs diff --git a/src/lib.rs b/src/lib.rs index c61a3db..4ee3d92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ - +pub use test_fn_macro::test; pub mod probe; #[macro_export] diff --git a/test_fn_macro/Cargo.toml b/test_fn_macro/Cargo.toml new file mode 100644 index 0000000..30a685f --- /dev/null +++ b/test_fn_macro/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "test_fn_macro" +version = "0.1.0" +authors = ["Linus Behrbohm "] +edition = "2018" + +[lib] +proc-macro = true + +[features] +default = [] +tokio_executor = [] + +[dependencies] +quote = "^1" +proc-macro2 = "^1" +syn = "^1" diff --git a/test_fn_macro/src/lib.rs b/test_fn_macro/src/lib.rs new file mode 100644 index 0000000..64b3e0a --- /dev/null +++ b/test_fn_macro/src/lib.rs @@ -0,0 +1,24 @@ +use proc_macro::{ + TokenStream, +}; +use proc_macro2::{ + TokenStream as TokenStream2, +}; +use quote::quote; + +#[proc_macro_attribute] +pub fn test(_args: TokenStream, input: TokenStream) -> TokenStream { + let input = TokenStream2::from(input); + #[cfg(feature = "tokio_executor")] + let attr = quote!{#[tokio::test]}; + #[cfg(not(feature = "tokio_executor"))] + let attr = quote!{#[::core::prelude::v1::test]}; + #[cfg(feature = "tokio_executor")] + let qual = quote!{async}; + #[cfg(not(feature = "tokio_executor"))] + let qual = quote!{}; + TokenStream::from(quote! { + #attr + #qual #input + }) +} From 9c4dac706776b4f51806791acfa14238329f6b3b Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Sat, 6 Feb 2021 11:22:24 +0100 Subject: [PATCH 14/16] Support tokio and non-tokio executors --- Cargo.toml | 8 ++++++-- src/lib.rs | 7 ------- src/probe.rs | 57 ++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 48 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d31cc10..e554892 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,11 @@ homepage = "http://riker.rs/logging" license = "MIT" readme = "README.md" +[features] +default = [] +tokio_executor = ["tokio", "async-trait", "test_fn_macro/tokio_executor"] [dependencies] chrono = "0.4" -tokio = { version = "^1", features = ["rt-multi-thread", "macros", "sync"] } -async-trait = { version="0.1.42" } +tokio = { version = "^1", features = ["rt-multi-thread", "macros", "sync"], optional = true} +async-trait = { version="0.1.42", optional = true} +test_fn_macro = { path = "./test_fn_macro" } diff --git a/src/lib.rs b/src/lib.rs index 4ee3d92..d9e13ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,2 @@ pub use test_fn_macro::test; pub mod probe; - -#[macro_export] -macro_rules! test_fn { - ($(#[$($meta:meta)*])* $vis:vis $ident:ident $($tokens:tt)*) => { - $(#[$($meta)*])* #[tokio::test] $vis async $ident $($tokens)* - }; -} diff --git a/src/probe.rs b/src/probe.rs index d2ca069..bf829f3 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -1,4 +1,3 @@ -#[async_trait::async_trait] pub trait Probe { type Msg: Send; type Pay: Clone + Send + Sync; @@ -7,11 +6,14 @@ pub trait Probe { fn payload(&self) -> &Self::Pay; } -#[async_trait::async_trait] +#[cfg_attr(feature = "tokio_executor", async_trait::async_trait)] pub trait ProbeReceive { type Msg: Send; + #[cfg(feature = "tokio_executor")] async fn recv(&mut self) -> Self::Msg; + #[cfg(not(feature = "tokio_executor"))] + fn recv(&mut self) -> Self::Msg; fn reset_timer(&mut self); fn last_event_milliseconds(&self) -> u64; fn last_event_seconds(&self) -> u64; @@ -25,18 +27,28 @@ pub mod channel { use chrono::prelude::*; + #[cfg(feature = "tokio_executor")] use tokio::sync::mpsc::{ channel, Sender, Receiver, }; + #[cfg(not(feature = "tokio_executor"))] + use std::sync::mpsc::{ + channel, + Sender, + Receiver, + }; pub fn probe() -> (ChannelProbe<(), T>, ChannelProbeReceive) { probe_with_payload(()) } pub fn probe_with_payload(payload: P) -> (ChannelProbe, ChannelProbeReceive) { + #[cfg(feature = "tokio_executor")] let (tx, rx) = channel::(100); + #[cfg(not(feature = "tokio_executor"))] + let (tx, rx) = channel::(); let probe = ChannelProbe { payload: Some(payload), @@ -58,7 +70,6 @@ pub mod channel { tx: Sender, } - #[async_trait::async_trait] impl Probe for ChannelProbe where P: Clone + Send + Sync, T: Send { type Msg = T; @@ -66,9 +77,12 @@ pub mod channel { fn event(&self, evt: T) { let tx = self.clone().tx.clone(); + #[cfg(feature = "tokio_executor")] tokio::spawn(async move { tx.send(evt).await.unwrap(); }); + #[cfg(not(feature = "tokio_executor"))] + drop(tx.send(evt)); } fn payload(&self) -> &P { @@ -76,7 +90,6 @@ pub mod channel { } } - #[async_trait::async_trait] impl Probe for Option> where P: Clone + Send + Sync, T: Send { type Msg = T; @@ -84,9 +97,12 @@ pub mod channel { fn event(&self, evt: T) { let tx = self.clone().as_ref().unwrap().tx.clone(); + #[cfg(feature = "tokio_executor")] tokio::spawn(async move { tx.send(evt).await.unwrap(); }); + #[cfg(not(feature = "tokio_executor"))] + drop(tx.send(evt)); } fn payload(&self) -> &P { @@ -101,13 +117,18 @@ pub mod channel { timer_start: DateTime, } - #[async_trait::async_trait] + #[cfg_attr(feature = "tokio_executor", async_trait::async_trait)] impl ProbeReceive for ChannelProbeReceive { type Msg = T; + #[cfg(feature = "tokio_executor")] async fn recv(&mut self) -> T { self.rx.recv().await.unwrap() } + #[cfg(not(feature = "tokio_executor"))] + fn recv(&mut self) -> T { + self.rx.recv().unwrap() + } fn reset_timer(&mut self) { self.timer_start = Utc::now(); @@ -134,7 +155,10 @@ pub mod macros { #[macro_export] macro_rules! p_assert_eq { ($listen:expr, $expected:expr) => { + #[cfg(feature = "tokio_executor")] assert_eq!($listen.recv().await, $expected); + #[cfg(not(feature = "tokio_executor"))] + assert_eq!($listen.recv(), $expected); }; } @@ -148,7 +172,10 @@ pub mod macros { let mut expected = $expected.clone(); // so we don't need the original mutable loop { + #[cfg(feature = "tokio_executor")] let val = $listen.recv().await; + #[cfg(not(feature = "tokio_executor"))] + let val = $listen.recv(); match expected.iter().position(|x| x == &val) { Some(pos) => { expected.remove(pos); @@ -176,8 +203,8 @@ pub mod macros { mod tests { use crate::probe::{Probe, ProbeReceive, channel::probe}; - #[tokio::test] - async fn p_assert_eq() { + #[test_fn_macro::test] + fn p_assert_eq() { let (probe, mut listen) = probe(); probe.event("test".to_string()); @@ -185,8 +212,8 @@ pub mod macros { p_assert_eq!(listen, "test".to_string()); } - #[tokio::test] - async fn p_assert_events() { + #[test_fn_macro::test] + fn p_assert_events() { let (probe, mut listen) = probe(); let expected = vec!["event_1", "event_2", "event_3"]; @@ -197,8 +224,8 @@ pub mod macros { p_assert_events!(listen, expected); } - #[tokio::test] - async fn p_timer() { + #[test_fn_macro::test] + fn p_timer() { let (probe, listen) = probe(); probe.event("event_3"); @@ -213,8 +240,8 @@ mod tests { use super::{Probe, ProbeReceive}; use super::channel::{probe, probe_with_payload}; - #[tokio::test] - async fn chan_probe() { + #[test_fn_macro::test] + fn chan_probe() { let (probe, mut listen) = probe(); probe.event("some event"); @@ -222,8 +249,8 @@ mod tests { p_assert_eq!(listen, "some event"); } - #[tokio::test] - async fn chan_probe_with_payload() { + #[test_fn_macro::test] + fn chan_probe_with_payload() { let payload = "test data".to_string(); let (probe, mut listen) = probe_with_payload(payload); From de9b2ff0457c695b4f0b41e9482663c65e6d793b Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Sat, 6 Feb 2021 13:52:20 +0100 Subject: [PATCH 15/16] Spawn tx.send on std::thread --- src/probe.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/probe.rs b/src/probe.rs index bf829f3..1969207 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -82,7 +82,9 @@ pub mod channel { tx.send(evt).await.unwrap(); }); #[cfg(not(feature = "tokio_executor"))] - drop(tx.send(evt)); + std::thread::spawn(move || { + drop(tx.send(evt)); + }); } fn payload(&self) -> &P { @@ -96,17 +98,11 @@ pub mod channel { type Pay = P; fn event(&self, evt: T) { - let tx = self.clone().as_ref().unwrap().tx.clone(); - #[cfg(feature = "tokio_executor")] - tokio::spawn(async move { - tx.send(evt).await.unwrap(); - }); - #[cfg(not(feature = "tokio_executor"))] - drop(tx.send(evt)); + self.as_ref().unwrap().event(evt); } fn payload(&self) -> &P { - &self.as_ref().unwrap().payload.as_ref().unwrap() + self.as_ref().unwrap().payload() } } From 4ad850b3837dc031076b5b85380877172523d073 Mon Sep 17 00:00:00 2001 From: Linus Behrbohm Date: Sat, 6 Feb 2021 23:54:22 +0100 Subject: [PATCH 16/16] Refactor --- src/probe.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/probe.rs b/src/probe.rs index 1969207..436e8be 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -82,9 +82,7 @@ pub mod channel { tx.send(evt).await.unwrap(); }); #[cfg(not(feature = "tokio_executor"))] - std::thread::spawn(move || { - drop(tx.send(evt)); - }); + drop(tx.send(evt)); } fn payload(&self) -> &P {