// Copyright 2017 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate 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. // Substrate 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 Substrate. If not, see . use super::*; use std::{fmt, sync::Arc, result::Result}; use codec::Encode; use extrinsic_pool::{api, txpool, watcher::{self, Watcher}}; use parking_lot::Mutex; use test_client; use tokio::runtime; type Extrinsic = u64; type Hash = u64; #[derive(Default)] struct DummyTxPool { submitted: Mutex>, sender: Mutex>>, } #[derive(Debug)] struct Error; impl api::Error for Error {} impl ::std::error::Error for Error { fn description(&self) -> &str { "Error" } } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, fmt) } } impl api::ExtrinsicPool for DummyTxPool { type Error = Error; type InPool = Vec; /// Submit extrinsic for inclusion in block. fn submit(&self, _block: BlockHash, xt: Vec) -> Result, Self::Error> { let mut submitted = self.submitted.lock(); if submitted.len() < 1 { let hashes = xt.iter().map(|_xt| 1).collect(); submitted.extend(xt); Ok(hashes) } else { Err(Error) } } fn submit_and_watch(&self, _block: BlockHash, xt: Extrinsic) -> Result, Self::Error> { let mut submitted = self.submitted.lock(); if submitted.len() < 1 { submitted.push(xt); let mut sender = watcher::Sender::default(); let watcher = sender.new_watcher(); *self.sender.lock() = Some(sender); Ok(watcher) } else { Err(Error) } } fn light_status(&self) -> txpool::LightStatus { unreachable!() } fn import_notification_stream(&self) -> api::EventStream { unreachable!() } fn all(&self) -> Self::InPool { vec![1, 2, 3, 4, 5] } } #[test] fn submit_transaction_should_not_cause_error() { let runtime = runtime::Runtime::new().unwrap(); let p = Author { client: Arc::new(test_client::new()), pool: Arc::new(DummyTxPool::default()), subscriptions: Subscriptions::new(runtime.executor()), }; assert_matches!( AuthorApi::submit_extrinsic(&p, u64::encode(&5).into()), Ok(1) ); assert!( AuthorApi::submit_extrinsic(&p, u64::encode(&5).into()).is_err() ); } #[test] fn submit_rich_transaction_should_not_cause_error() { let runtime = runtime::Runtime::new().unwrap(); let p = Author { client: Arc::new(test_client::new()), pool: Arc::new(DummyTxPool::default()), subscriptions: Subscriptions::new(runtime.executor()), }; assert_matches!( AuthorApi::submit_rich_extrinsic(&p, 5), Ok(1) ); assert!( AuthorApi::submit_rich_extrinsic(&p, 5).is_err() ); } #[test] fn should_watch_extrinsic() { //given let mut runtime = runtime::Runtime::new().unwrap(); let pool = Arc::new(DummyTxPool::default()); let p = Author { client: Arc::new(test_client::new()), pool: pool.clone(), subscriptions: Subscriptions::new(runtime.executor()), }; let (subscriber, id_rx, data) = ::jsonrpc_macros::pubsub::Subscriber::new_test("test"); // when p.watch_extrinsic(Default::default(), subscriber, u64::encode(&5).into()); // then assert_eq!(runtime.block_on(id_rx), Ok(Ok(0.into()))); // check notifications pool.sender.lock().as_mut().unwrap().usurped(5); assert_eq!( runtime.block_on(data.into_future()).unwrap().0, Some(r#"{"jsonrpc":"2.0","method":"test","params":{"result":{"usurped":5},"subscription":0}}"#.into()) ); } #[test] fn should_return_pending_extrinsics() { let runtime = runtime::Runtime::new().unwrap(); let p = Author { client: Arc::new(test_client::new()), pool: Arc::new(DummyTxPool::default()), subscriptions: Subscriptions::new(runtime.executor()), }; assert_matches!( p.pending_extrinsics(), Ok(ref expected) if expected == &[1u8, 2, 3, 4, 5] ); }