From f2d7b6f5ac7d611f7c807fca72f287321311c058 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bastian=20K=C3=B6cher?= <bkchr@users.noreply.github.com>
Date: Thu, 8 Oct 2020 11:27:19 +0200
Subject: [PATCH] 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>
---
 polkadot/Cargo.lock                           |   1 +
 .../node/overseer/examples/minimal-example.rs |  25 +-
 polkadot/node/overseer/src/lib.rs             | 548 ++++++++++++++----
 .../node/subsystem-test-helpers/Cargo.toml    |   3 +
 .../node/subsystem-test-helpers/src/lib.rs    |  61 +-
 polkadot/node/subsystem/src/lib.rs            |   2 +-
 6 files changed, 505 insertions(+), 135 deletions(-)

diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock
index 976d77b7315..f4de76c2e2c 100644
--- a/polkadot/Cargo.lock
+++ b/polkadot/Cargo.lock
@@ -5060,6 +5060,7 @@ dependencies = [
  "polkadot-node-primitives",
  "polkadot-node-subsystem",
  "polkadot-node-subsystem-util",
+ "polkadot-overseer",
  "polkadot-primitives",
  "polkadot-statement-table",
  "sc-network",
diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs
index 2b55fa2634c..9c0864a9b79 100644
--- a/polkadot/node/overseer/examples/minimal-example.rs
+++ b/polkadot/node/overseer/examples/minimal-example.rs
@@ -30,10 +30,7 @@ use kv_log_macro as log;
 use polkadot_primitives::v1::{BlockData, PoV};
 use polkadot_overseer::{Overseer, AllSubsystems};
 
-use polkadot_subsystem::{
-	Subsystem, SubsystemContext, DummySubsystem,
-	SpawnedSubsystem, FromOverseer,
-};
+use polkadot_subsystem::{Subsystem, SubsystemContext, SpawnedSubsystem, FromOverseer};
 use polkadot_subsystem::messages::{
 	CandidateValidationMessage, CandidateBackingMessage, AllMessages,
 };
@@ -141,23 +138,9 @@ fn main() {
 			Delay::new(Duration::from_secs(1)).await;
 		});
 
-		let all_subsystems = AllSubsystems {
-			candidate_validation: Subsystem2,
-			candidate_backing: Subsystem1,
-			candidate_selection: DummySubsystem,
-			statement_distribution: DummySubsystem,
-			availability_distribution: DummySubsystem,
-			bitfield_signing: DummySubsystem,
-			bitfield_distribution: DummySubsystem,
-			provisioner: DummySubsystem,
-			pov_distribution: DummySubsystem,
-			runtime_api: DummySubsystem,
-			availability_store: DummySubsystem,
-			network_bridge: DummySubsystem,
-			chain_api: DummySubsystem,
-			collation_generation: DummySubsystem,
-			collator_protocol: DummySubsystem,
-		};
+		let all_subsystems = AllSubsystems::<()>::dummy()
+			.replace_candidate_validation(Subsystem2)
+			.replace_candidate_backing(Subsystem1);
 		let (overseer, _handler) = Overseer::new(
 			vec![],
 			all_subsystems,
diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs
index 0318cad34b4..e33a5756c80 100644
--- a/polkadot/node/overseer/src/lib.rs
+++ b/polkadot/node/overseer/src/lib.rs
@@ -83,7 +83,7 @@ use polkadot_subsystem::messages::{
 };
 pub use polkadot_subsystem::{
 	Subsystem, SubsystemContext, OverseerSignal, FromOverseer, SubsystemError, SubsystemResult,
-	SpawnedSubsystem, ActiveLeavesUpdate,
+	SpawnedSubsystem, ActiveLeavesUpdate, DummySubsystem,
 };
 use polkadot_node_subsystem_util::metrics::{self, prometheus};
 use polkadot_node_primitives::SpawnNamed;
@@ -348,7 +348,7 @@ struct OverseenSubsystem<M> {
 }
 
 /// The `Overseer` itself.
-pub struct Overseer<S: SpawnNamed> {
+pub struct Overseer<S> {
 	/// A candidate validation subsystem.
 	candidate_validation_subsystem: OverseenSubsystem<CandidateValidationMessage>,
 
@@ -429,10 +429,10 @@ pub struct Overseer<S: SpawnNamed> {
 /// Each [`Subsystem`] is supposed to implement some interface that is generic over
 /// message type that is specific to this [`Subsystem`]. At the moment not all
 /// subsystems are implemented and the rest can be mocked with the [`DummySubsystem`].
-///
-/// [`Subsystem`]: trait.Subsystem.html
-/// [`DummySubsystem`]: struct.DummySubsystem.html
-pub struct AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA, CG, CP> {
+pub struct AllSubsystems<
+	CV = (), CB = (), CS = (), SD = (), AD = (), BS = (), BD = (), P = (),
+	PoVD = (), RA = (), AS = (), NB = (), CA = (), CG = (), CP = ()
+> {
 	/// A candidate validation subsystem.
 	pub candidate_validation: CV,
 	/// A candidate backing subsystem.
@@ -465,6 +465,418 @@ pub struct AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA, CG
 	pub collator_protocol: CP,
 }
 
+impl<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA, CG, CP>
+	AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA, CG, CP>
+{
+	/// Create a new instance of [`AllSubsystems`].
+	///
+	/// Each subsystem is set to [`DummySystem`].
+	///
+	///# Note
+	///
+	/// Because of a bug in rustc it is required that when calling this function,
+	/// you provide a "random" type for the first generic parameter:
+	///
+	/// ```
+	/// polkadot_overseer::AllSubsystems::<()>::dummy();
+	/// ```
+	pub fn dummy() -> AllSubsystems<
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem,
+		DummySubsystem
+	> {
+		AllSubsystems {
+			candidate_validation: DummySubsystem,
+			candidate_backing: DummySubsystem,
+			candidate_selection: DummySubsystem,
+			statement_distribution: DummySubsystem,
+			availability_distribution: DummySubsystem,
+			bitfield_signing: DummySubsystem,
+			bitfield_distribution: DummySubsystem,
+			provisioner: DummySubsystem,
+			pov_distribution: DummySubsystem,
+			runtime_api: DummySubsystem,
+			availability_store: DummySubsystem,
+			network_bridge: DummySubsystem,
+			chain_api: DummySubsystem,
+			collation_generation: DummySubsystem,
+			collator_protocol: DummySubsystem,
+		}
+	}
+
+	/// Replace the `candidate_validation` instance in `self`.
+	pub fn replace_candidate_validation<NEW>(
+		self,
+		candidate_validation: NEW,
+	) -> AllSubsystems<NEW, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `candidate_backing` instance in `self`.
+	pub fn replace_candidate_backing<NEW>(
+		self,
+		candidate_backing: NEW,
+	) -> AllSubsystems<CV, NEW, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `candidate_selection` instance in `self`.
+	pub fn replace_candidate_selection<NEW>(
+		self,
+		candidate_selection: NEW,
+	) -> AllSubsystems<CV, CB, NEW, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `statement_distribution` instance in `self`.
+	pub fn replace_statement_distribution<NEW>(
+		self,
+		statement_distribution: NEW,
+	) -> AllSubsystems<CV, CB, CS, NEW, AD, BS, BD, P, PoVD, RA, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `availability_distribution` instance in `self`.
+	pub fn replace_availability_distribution<NEW>(
+		self,
+		availability_distribution: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, NEW, BS, BD, P, PoVD, RA, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `bitfield_signing` instance in `self`.
+	pub fn replace_bitfield_signing<NEW>(
+		self,
+		bitfield_signing: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, NEW, BD, P, PoVD, RA, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `bitfield_distribution` instance in `self`.
+	pub fn replace_bitfield_distribution<NEW>(
+		self,
+		bitfield_distribution: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, BS, NEW, P, PoVD, RA, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `provisioner` instance in `self`.
+	pub fn replace_provisioner<NEW>(
+		self,
+		provisioner: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, BS, BD, NEW, PoVD, RA, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `pov_distribution` instance in `self`.
+	pub fn replace_pov_distribution<NEW>(
+		self,
+		pov_distribution: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, NEW, RA, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `runtime_api` instance in `self`.
+	pub fn replace_runtime_api<NEW>(
+		self,
+		runtime_api: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, NEW, AS, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `availability_store` instance in `self`.
+	pub fn replace_availability_store<NEW>(
+		self,
+		availability_store: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, NEW, NB, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `network_bridge` instance in `self`.
+	pub fn replace_network_bridge<NEW>(
+		self,
+		network_bridge: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NEW, CA, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `chain_api` instance in `self`.
+	pub fn replace_chain_api<NEW>(
+		self,
+		chain_api: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, NEW, CG, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `collation_generation` instance in `self`.
+	pub fn replace_collation_generation<NEW>(
+		self,
+		collation_generation: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA, NEW, CP> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation,
+			collator_protocol: self.collator_protocol,
+		}
+	}
+
+	/// Replace the `collator_protocol` instance in `self`.
+	pub fn replace_collator_protocol<NEW>(
+		self,
+		collator_protocol: NEW,
+	) -> AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA, CG, NEW> {
+		AllSubsystems {
+			candidate_validation: self.candidate_validation,
+			candidate_backing: self.candidate_backing,
+			candidate_selection: self.candidate_selection,
+			statement_distribution: self.statement_distribution,
+			availability_distribution: self.availability_distribution,
+			bitfield_signing: self.bitfield_signing,
+			bitfield_distribution: self.bitfield_distribution,
+			provisioner: self.provisioner,
+			pov_distribution: self.pov_distribution,
+			runtime_api: self.runtime_api,
+			availability_store: self.availability_store,
+			network_bridge: self.network_bridge,
+			chain_api: self.chain_api,
+			collation_generation: self.collation_generation,
+			collator_protocol,
+		}
+	}
+}
+
 /// Overseer Prometheus metrics.
 #[derive(Clone)]
 struct MetricsInner {
@@ -591,23 +1003,7 @@ where
 	///
 	/// # fn main() { executor::block_on(async move {
 	/// let spawner = sp_core::testing::TaskExecutor::new();
-	/// let all_subsystems = AllSubsystems {
-	///     candidate_validation: ValidationSubsystem,
-	///     candidate_backing: DummySubsystem,
-	///     candidate_selection: DummySubsystem,
-	///     statement_distribution: DummySubsystem,
-	///     availability_distribution: DummySubsystem,
-	///     bitfield_signing: DummySubsystem,
-	///     bitfield_distribution: DummySubsystem,
-	///     provisioner: DummySubsystem,
-	///     pov_distribution: DummySubsystem,
-	///     runtime_api: DummySubsystem,
-	///     availability_store: DummySubsystem,
-	///     network_bridge: DummySubsystem,
-	///     chain_api: DummySubsystem,
-	///     collation_generation: DummySubsystem,
-	///     collator_protocol: DummySubsystem,
-	/// };
+	/// let all_subsystems = AllSubsystems::<()>::dummy().replace_candidate_validation(ValidationSubsystem);
 	/// let (overseer, _handler) = Overseer::new(
 	///     vec![],
 	///     all_subsystems,
@@ -1228,7 +1624,6 @@ mod tests {
 	use futures::{executor, pin_mut, select, channel::mpsc, FutureExt};
 
 	use polkadot_primitives::v1::{BlockData, CollatorPair, PoV};
-	use polkadot_subsystem::DummySubsystem;
 	use polkadot_subsystem::messages::RuntimeApiRequest;
 	use polkadot_node_primitives::{Collation, CollationGenerationConfig};
 	use polkadot_node_network_protocol::{PeerId, ReputationChange, NetworkBridgeEvent};
@@ -1237,7 +1632,6 @@ mod tests {
 
 	use super::*;
 
-
 	struct TestSubsystem1(mpsc::Sender<usize>);
 
 	impl<C> Subsystem<C> for TestSubsystem1
@@ -1334,26 +1728,13 @@ mod tests {
 		let spawner = sp_core::testing::TaskExecutor::new();
 
 		executor::block_on(async move {
-			let (s1_tx, mut s1_rx) = mpsc::channel(64);
-			let (s2_tx, mut s2_rx) = mpsc::channel(64);
+			let (s1_tx, mut s1_rx) = mpsc::channel::<usize>(64);
+			let (s2_tx, mut s2_rx) = mpsc::channel::<usize>(64);
+
+			let all_subsystems = AllSubsystems::<()>::dummy()
+				.replace_candidate_validation(TestSubsystem1(s1_tx))
+				.replace_candidate_backing(TestSubsystem2(s2_tx));
 
-			let all_subsystems = AllSubsystems {
-				candidate_validation: TestSubsystem1(s1_tx),
-				candidate_backing: TestSubsystem2(s2_tx),
-				candidate_selection: DummySubsystem,
-				statement_distribution: DummySubsystem,
-				availability_distribution: DummySubsystem,
-				bitfield_signing: DummySubsystem,
-				bitfield_distribution: DummySubsystem,
-				provisioner: DummySubsystem,
-				pov_distribution: DummySubsystem,
-				runtime_api: DummySubsystem,
-				availability_store: DummySubsystem,
-				network_bridge: DummySubsystem,
-				chain_api: DummySubsystem,
-				collation_generation: DummySubsystem,
-				collator_protocol: DummySubsystem,
-			};
 			let (overseer, mut handler) = Overseer::new(
 				vec![],
 				all_subsystems,
@@ -1421,23 +1802,7 @@ mod tests {
 				number: 3,
 			};
 
-			let all_subsystems = AllSubsystems {
-				collation_generation: DummySubsystem,
-				candidate_validation: DummySubsystem,
-				candidate_backing: DummySubsystem,
-				candidate_selection: DummySubsystem,
-				collator_protocol: DummySubsystem,
-				statement_distribution: DummySubsystem,
-				availability_distribution: DummySubsystem,
-				bitfield_signing: DummySubsystem,
-				bitfield_distribution: DummySubsystem,
-				provisioner: DummySubsystem,
-				pov_distribution: DummySubsystem,
-				runtime_api: DummySubsystem,
-				availability_store: DummySubsystem,
-				network_bridge: DummySubsystem,
-				chain_api: DummySubsystem,
-			};
+			let all_subsystems = AllSubsystems::<()>::dummy();
 			let registry = prometheus::Registry::new();
 			let (overseer, mut handler) = Overseer::new(
 				vec![first_block],
@@ -1491,23 +1856,9 @@ mod tests {
 
 		executor::block_on(async move {
 			let (s1_tx, _) = mpsc::channel(64);
-			let all_subsystems = AllSubsystems {
-				candidate_validation: TestSubsystem1(s1_tx),
-				candidate_backing: TestSubsystem4,
-				candidate_selection: DummySubsystem,
-				statement_distribution: DummySubsystem,
-				availability_distribution: DummySubsystem,
-				bitfield_signing: DummySubsystem,
-				bitfield_distribution: DummySubsystem,
-				provisioner: DummySubsystem,
-				pov_distribution: DummySubsystem,
-				runtime_api: DummySubsystem,
-				availability_store: DummySubsystem,
-				network_bridge: DummySubsystem,
-				chain_api: DummySubsystem,
-				collation_generation: DummySubsystem,
-				collator_protocol: DummySubsystem,
-			};
+			let all_subsystems = AllSubsystems::<()>::dummy()
+				.replace_candidate_validation(TestSubsystem1(s1_tx))
+				.replace_candidate_backing(TestSubsystem4);
 			let (overseer, _handle) = Overseer::new(
 				vec![],
 				all_subsystems,
@@ -1611,23 +1962,9 @@ mod tests {
 
 			let (tx_5, mut rx_5) = mpsc::channel(64);
 			let (tx_6, mut rx_6) = mpsc::channel(64);
-			let all_subsystems = AllSubsystems {
-				candidate_validation: TestSubsystem5(tx_5),
-				candidate_backing: TestSubsystem6(tx_6),
-				candidate_selection: DummySubsystem,
-				statement_distribution: DummySubsystem,
-				availability_distribution: DummySubsystem,
-				bitfield_signing: DummySubsystem,
-				bitfield_distribution: DummySubsystem,
-				provisioner: DummySubsystem,
-				pov_distribution: DummySubsystem,
-				runtime_api: DummySubsystem,
-				availability_store: DummySubsystem,
-				network_bridge: DummySubsystem,
-				chain_api: DummySubsystem,
-				collation_generation: DummySubsystem,
-				collator_protocol: DummySubsystem,
-			};
+			let all_subsystems = AllSubsystems::<()>::dummy()
+				.replace_candidate_validation(TestSubsystem5(tx_5))
+				.replace_candidate_backing(TestSubsystem6(tx_6));
 			let (overseer, mut handler) = Overseer::new(
 				vec![first_block],
 				all_subsystems,
@@ -1716,23 +2053,10 @@ mod tests {
 			let (tx_5, mut rx_5) = mpsc::channel(64);
 			let (tx_6, mut rx_6) = mpsc::channel(64);
 
-			let all_subsystems = AllSubsystems {
-				candidate_validation: TestSubsystem5(tx_5),
-				candidate_backing: TestSubsystem6(tx_6),
-				candidate_selection: DummySubsystem,
-				statement_distribution: DummySubsystem,
-				availability_distribution: DummySubsystem,
-				bitfield_signing: DummySubsystem,
-				bitfield_distribution: DummySubsystem,
-				provisioner: DummySubsystem,
-				pov_distribution: DummySubsystem,
-				runtime_api: DummySubsystem,
-				availability_store: DummySubsystem,
-				network_bridge: DummySubsystem,
-				chain_api: DummySubsystem,
-				collation_generation: DummySubsystem,
-				collator_protocol: DummySubsystem,
-			};
+			let all_subsystems = AllSubsystems::<()>::dummy()
+				.replace_candidate_validation(TestSubsystem5(tx_5))
+				.replace_candidate_backing(TestSubsystem6(tx_6));
+
 			// start with two forks of different height.
 			let (overseer, mut handler) = Overseer::new(
 				vec![first_block, second_block],
diff --git a/polkadot/node/subsystem-test-helpers/Cargo.toml b/polkadot/node/subsystem-test-helpers/Cargo.toml
index 220af40deb9..5f1388136a3 100644
--- a/polkadot/node/subsystem-test-helpers/Cargo.toml
+++ b/polkadot/node/subsystem-test-helpers/Cargo.toml
@@ -22,3 +22,6 @@ polkadot-statement-table = { path = "../../statement-table" }
 sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
 smallvec = "1.4.1"
 sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
+
+[dev-dependencies]
+polkadot-overseer = { path = "../overseer" }
diff --git a/polkadot/node/subsystem-test-helpers/src/lib.rs b/polkadot/node/subsystem-test-helpers/src/lib.rs
index 817cad37f0d..ae1dd91ad1c 100644
--- a/polkadot/node/subsystem-test-helpers/src/lib.rs
+++ b/polkadot/node/subsystem-test-helpers/src/lib.rs
@@ -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(_, _)));
+	}
+}
diff --git a/polkadot/node/subsystem/src/lib.rs b/polkadot/node/subsystem/src/lib.rs
index 843791b7206..dea391c5b2c 100644
--- a/polkadot/node/subsystem/src/lib.rs
+++ b/polkadot/node/subsystem/src/lib.rs
@@ -223,7 +223,7 @@ impl<C: SubsystemContext> Subsystem<C> for DummySubsystem {
 		});
 
 		SpawnedSubsystem {
-			name: "DummySubsystem",
+			name: "dummy-subsystem",
 			future,
 		}
 	}
-- 
GitLab