// 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;
use polkadot_node_subsystem::{
FromOverseer, SubsystemContext, SubsystemError, SubsystemResult, Subsystem,
SpawnedSubsystem, OverseerSignal,
};
use polkadot_node_subsystem_util::TimeoutExt;
use futures::channel::mpsc;
use futures::poll;
use futures::prelude::*;
use parking_lot::Mutex;
use sp_core::{testing::TaskExecutor, traits::SpawnNamed};
use std::convert::Infallible;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll, Waker};
use std::time::Duration;
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>>);
/// 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