Make AllSubsystems usage easier in tests (#1794)

* Make `AllSubsystems` usage easier in tests

This makes the usage of `AllSubsystems` easier in tests by introducing
new methods.

- `dummy` initializes `AllSubsystems` with all systems set to dummy
- `replace_*` to replace any subsystem

Besides that this pr adds a `ForwardSubsystem` that is also useful for
tests. This subsystem will forward all incoming messages to the given channel.

* Update node/overseer/src/lib.rs

Co-authored-by: Andronik Ordian <write@reusable.software>

* Update node/subsystem/src/lib.rs

Co-authored-by: Andronik Ordian <write@reusable.software>

* Update node/subsystem/src/lib.rs

Co-authored-by: Andronik Ordian <write@reusable.software>

* Move ForwardSubsystem and add a test

* Break some lines

Co-authored-by: Andronik Ordian <write@reusable.software>
This commit is contained in:
Bastian Köcher
2020-10-08 11:27:19 +02:00
committed by GitHub
parent fc1153681e
commit f2d7b6f5ac
6 changed files with 505 additions and 135 deletions
@@ -17,7 +17,10 @@
//! Utilities for testing subsystems.
use polkadot_node_subsystem::messages::AllMessages;
use polkadot_node_subsystem::{FromOverseer, SubsystemContext, SubsystemError, SubsystemResult};
use polkadot_node_subsystem::{
FromOverseer, SubsystemContext, SubsystemError, SubsystemResult, Subsystem,
SpawnedSubsystem, OverseerSignal,
};
use polkadot_node_subsystem_util::TimeoutExt;
use futures::channel::mpsc;
@@ -283,3 +286,59 @@ pub fn subsystem_test_harness<M, OverseerFactory, Overseer, TestFactory, Test>(
.expect("test timed out instead of completing")
});
}
/// A forward subsystem that implements [`Subsystem`].
///
/// It forwards all communication from the overseer to the internal message
/// channel.
///
/// This subsystem is useful for testing functionality that interacts with the overseer.
pub struct ForwardSubsystem<Msg>(pub mpsc::Sender<Msg>);
impl<C: SubsystemContext<Message = Msg>, Msg: Send + 'static> Subsystem<C> for ForwardSubsystem<Msg> {
fn start(mut self, mut ctx: C) -> SpawnedSubsystem {
let future = Box::pin(async move {
loop {
match ctx.recv().await {
Ok(FromOverseer::Signal(OverseerSignal::Conclude)) => return,
Ok(FromOverseer::Communication { msg }) => {
let _ = self.0.send(msg).await;
},
Err(_) => return,
_ => (),
}
}
});
SpawnedSubsystem {
name: "forward-subsystem",
future,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use polkadot_overseer::{Overseer, AllSubsystems};
use futures::executor::block_on;
use polkadot_node_subsystem::messages::CandidateSelectionMessage;
#[test]
fn forward_subsystem_works() {
let spawner = sp_core::testing::TaskExecutor::new();
let (tx, rx) = mpsc::channel(2);
let all_subsystems = AllSubsystems::<()>::dummy().replace_candidate_selection(ForwardSubsystem(tx));
let (overseer, mut handler) = Overseer::new(
Vec::new(),
all_subsystems,
None,
spawner.clone(),
).unwrap();
spawner.spawn("overseer", overseer.run().then(|_| async { () }).boxed());
block_on(handler.send_msg(CandidateSelectionMessage::Invalid(Default::default(), Default::default()))).unwrap();
assert!(matches!(block_on(rx.into_future()).0.unwrap(), CandidateSelectionMessage::Invalid(_, _)));
}
}