// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see .
//! Utilities for testing subsystems.
#![warn(missing_docs)]
use polkadot_node_subsystem::{
messages::AllMessages, overseer, FromOrchestra, OverseerSignal, SpawnGlue, SpawnedSubsystem,
SubsystemError, SubsystemResult,
};
use polkadot_node_subsystem_util::TimeoutExt;
use futures::{channel::mpsc, poll, prelude::*};
use parking_lot::Mutex;
use sp_core::testing::TaskExecutor;
use std::{
convert::Infallible,
pin::Pin,
sync::Arc,
task::{Context, Poll, Waker},
time::Duration,
};
/// Generally useful mock data providers for unit tests.
pub mod mock;
enum SinkState {
Empty { read_waker: Option },
Item { item: T, ready_waker: Option, flush_waker: Option },
}
/// The sink half of a single-item sink that does not resolve until the item has been read.
pub struct SingleItemSink(Arc>>);
// Derive clone not possible, as it puts `Clone` constraint on `T` which is not sensible here.
impl Clone for SingleItemSink {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
/// The stream half of a single-item sink.
pub struct SingleItemStream(Arc>>);
impl Sink for SingleItemSink {
type Error = Infallible;
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context) -> Poll> {
let mut state = self.0.lock();
match *state {
SinkState::Empty { .. } => Poll::Ready(Ok(())),
SinkState::Item { ref mut ready_waker, .. } => {
*ready_waker = Some(cx.waker().clone());
Poll::Pending
},
}
}
fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Infallible> {
let mut state = self.0.lock();
match *state {
SinkState::Empty { ref mut read_waker } =>
if let Some(waker) = read_waker.take() {
waker.wake();
},
_ => panic!("start_send called outside of empty sink state ensured by poll_ready"),
}
*state = SinkState::Item { item, ready_waker: None, flush_waker: None };
Ok(())
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> {
let mut state = self.0.lock();
match *state {
SinkState::Empty { .. } => Poll::Ready(Ok(())),
SinkState::Item { ref mut flush_waker, .. } => {
*flush_waker = Some(cx.waker().clone());
Poll::Pending
},
}
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll> {
self.poll_flush(cx)
}
}
impl Stream for SingleItemStream {
type Item = T;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll