util fake-fetch
(#8363)
* start * hash-fetch * rpc * revert price-info * remove used file * adapt to changes in fetch * make fake-fetch generic over * fix tests to comply with the new `fake-fetch`
This commit is contained in:
parent
6cf441fc9e
commit
9fe991db1c
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -1025,6 +1025,15 @@ dependencies = [
|
||||
"vm 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-fetch"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"fetch 0.1.0",
|
||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdlimit"
|
||||
version = "0.1.1"
|
||||
@ -1940,6 +1949,7 @@ dependencies = [
|
||||
"ethcore-transaction 0.1.0",
|
||||
"ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethkey 0.3.0",
|
||||
"fake-fetch 0.0.1",
|
||||
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2063,6 +2073,7 @@ dependencies = [
|
||||
"ethabi-derive 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-bytes 0.1.0",
|
||||
"ethereum-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fake-fetch 0.0.1",
|
||||
"fetch 0.1.0",
|
||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2148,6 +2159,7 @@ dependencies = [
|
||||
"ethjson 0.1.0",
|
||||
"ethkey 0.3.0",
|
||||
"ethstore 0.2.0",
|
||||
"fake-fetch 0.0.1",
|
||||
"fetch 0.1.0",
|
||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2465,6 +2477,7 @@ dependencies = [
|
||||
name = "price-info"
|
||||
version = "1.11.0"
|
||||
dependencies = [
|
||||
"fake-fetch 0.0.1",
|
||||
"fetch 0.1.0",
|
||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -82,6 +82,7 @@ rustc_version = "0.2"
|
||||
pretty_assertions = "0.1"
|
||||
ipnetwork = "0.12.6"
|
||||
tempdir = "0.3"
|
||||
fake-fetch = { path = "util/fake-fetch" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = "0.2"
|
||||
|
@ -28,3 +28,4 @@ ethabi-contract = "5.0"
|
||||
[dev-dependencies]
|
||||
hyper = "0.11"
|
||||
parking_lot = "0.5"
|
||||
fake-fetch = { path = "../util/fake-fetch" }
|
||||
|
@ -193,53 +193,14 @@ fn random_temp_path() -> PathBuf {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate hyper;
|
||||
use fake_fetch::FakeFetch;
|
||||
use rustc_hex::FromHex;
|
||||
use std::sync::{Arc, mpsc};
|
||||
use parking_lot::Mutex;
|
||||
use futures::future;
|
||||
use futures_cpupool::CpuPool;
|
||||
use fetch::{self, Fetch, Url, Request};
|
||||
use parity_reactor::Remote;
|
||||
use urlhint::tests::{FakeRegistrar, URLHINT};
|
||||
use super::{Error, Client, HashFetch, random_temp_path};
|
||||
use self::hyper::StatusCode;
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FakeFetch {
|
||||
return_success: bool
|
||||
}
|
||||
|
||||
impl Fetch for FakeFetch {
|
||||
type Result = future::Ok<fetch::Response, fetch::Error>;
|
||||
|
||||
fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result {
|
||||
assert_eq!(request.url().as_str(), "https://parity.io/assets/images/ethcore-black-horizontal.png");
|
||||
let u = request.url().clone();
|
||||
future::ok(if self.return_success {
|
||||
fetch::client::Response::new(u, hyper::Response::new().with_body(&b"result"[..]), abort)
|
||||
} else {
|
||||
fetch::client::Response::new(u, hyper::Response::new().with_status(StatusCode::NotFound), abort)
|
||||
})
|
||||
}
|
||||
|
||||
fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::get(url), abort)
|
||||
}
|
||||
|
||||
fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::post(url), abort)
|
||||
}
|
||||
}
|
||||
|
||||
fn registrar() -> FakeRegistrar {
|
||||
let mut registrar = FakeRegistrar::new();
|
||||
@ -254,7 +215,7 @@ mod tests {
|
||||
fn should_return_error_if_hash_not_found() {
|
||||
// given
|
||||
let contract = Arc::new(FakeRegistrar::new());
|
||||
let fetch = FakeFetch { return_success: false };
|
||||
let fetch = FakeFetch::new(None::<usize>);
|
||||
let client = Client::with_fetch(contract.clone(), CpuPool::new(1), fetch, Remote::new_sync());
|
||||
|
||||
// when
|
||||
@ -272,7 +233,7 @@ mod tests {
|
||||
fn should_return_error_if_response_is_not_successful() {
|
||||
// given
|
||||
let registrar = Arc::new(registrar());
|
||||
let fetch = FakeFetch { return_success: false };
|
||||
let fetch = FakeFetch::new(None::<usize>);
|
||||
let client = Client::with_fetch(registrar.clone(), CpuPool::new(1), fetch, Remote::new_sync());
|
||||
|
||||
// when
|
||||
@ -290,7 +251,7 @@ mod tests {
|
||||
fn should_return_hash_mismatch() {
|
||||
// given
|
||||
let registrar = Arc::new(registrar());
|
||||
let fetch = FakeFetch { return_success: true };
|
||||
let fetch = FakeFetch::new(Some(1));
|
||||
let mut client = Client::with_fetch(registrar.clone(), CpuPool::new(1), fetch, Remote::new_sync());
|
||||
let path = random_temp_path();
|
||||
let path2 = path.clone();
|
||||
@ -304,7 +265,7 @@ mod tests {
|
||||
|
||||
// then
|
||||
let result = rx.recv().unwrap();
|
||||
let hash = "0x06b0a4f426f6713234b2d4b2468640bc4e0bb72657a920ad24c5087153c593c8".into();
|
||||
let hash = "0x2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".into();
|
||||
assert_eq!(result.unwrap_err(), Error::HashMismatch { expected: 2.into(), got: hash });
|
||||
assert!(!path.exists(), "Temporary file should be removed.");
|
||||
}
|
||||
@ -313,12 +274,12 @@ mod tests {
|
||||
fn should_return_path_if_hash_matches() {
|
||||
// given
|
||||
let registrar = Arc::new(registrar());
|
||||
let fetch = FakeFetch { return_success: true };
|
||||
let fetch = FakeFetch::new(Some(1));
|
||||
let client = Client::with_fetch(registrar.clone(), CpuPool::new(1), fetch, Remote::new_sync());
|
||||
|
||||
// when
|
||||
let (tx, rx) = mpsc::channel();
|
||||
client.fetch("0x06b0a4f426f6713234b2d4b2468640bc4e0bb72657a920ad24c5087153c593c8".into(),
|
||||
client.fetch("0x2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".into(),
|
||||
Default::default(),
|
||||
Box::new(move |result| { tx.send(result).unwrap(); }));
|
||||
|
||||
|
@ -42,6 +42,10 @@ extern crate ethabi_derive;
|
||||
extern crate ethabi_contract;
|
||||
#[cfg(test)]
|
||||
extern crate parking_lot;
|
||||
#[cfg(test)]
|
||||
extern crate hyper;
|
||||
#[cfg(test)]
|
||||
extern crate fake_fetch;
|
||||
|
||||
mod client;
|
||||
|
||||
|
@ -16,3 +16,4 @@ serde_json = "1.0"
|
||||
[dev-dependencies]
|
||||
hyper = "0.11"
|
||||
parking_lot = "0.5"
|
||||
fake-fetch = { path = "../util/fake-fetch" }
|
||||
|
@ -25,6 +25,9 @@ extern crate serde_json;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate fake_fetch;
|
||||
|
||||
pub extern crate fetch;
|
||||
|
||||
use std::cmp;
|
||||
@ -133,68 +136,18 @@ impl<F: Fetch> Client<F> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
extern crate hyper;
|
||||
extern crate parking_lot;
|
||||
|
||||
use self::parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use fetch;
|
||||
use fetch::{Fetch, Url, Request};
|
||||
use futures_cpupool::CpuPool;
|
||||
use futures::future::{self, FutureResult};
|
||||
use Client;
|
||||
use self::hyper::StatusCode;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use fake_fetch::FakeFetch;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FakeFetch(Option<String>, Arc<Mutex<u64>>);
|
||||
|
||||
impl FakeFetch {
|
||||
fn new() -> Result<Self, fetch::Error> {
|
||||
Ok(FakeFetch(None, Default::default()))
|
||||
}
|
||||
fn price_info_ok(response: &str) -> Client<FakeFetch<String>> {
|
||||
Client::new(FakeFetch::new(Some(response.to_owned())), CpuPool::new(1))
|
||||
}
|
||||
|
||||
impl Fetch for FakeFetch {
|
||||
type Result = FutureResult<fetch::Response, fetch::Error>;
|
||||
|
||||
fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result {
|
||||
assert_eq!(request.url().as_str(), "https://api.etherscan.io/api?module=stats&action=ethprice");
|
||||
let u = request.url().clone();
|
||||
let mut val = self.1.lock();
|
||||
*val = *val + 1;
|
||||
if let Some(ref response) = self.0 {
|
||||
let r = hyper::Response::new().with_body(response.clone());
|
||||
future::ok(fetch::client::Response::new(u, r, abort))
|
||||
} else {
|
||||
let r = hyper::Response::new().with_status(StatusCode::NotFound);
|
||||
future::ok(fetch::client::Response::new(u, r, abort))
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::get(url), abort)
|
||||
}
|
||||
|
||||
fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::post(url), abort)
|
||||
}
|
||||
}
|
||||
|
||||
fn price_info_ok(response: &str) -> Client<FakeFetch> {
|
||||
Client::new(FakeFetch(Some(response.to_owned()), Default::default()), CpuPool::new(1))
|
||||
}
|
||||
|
||||
fn price_info_not_found() -> Client<FakeFetch> {
|
||||
Client::new(FakeFetch::new().unwrap(), CpuPool::new(1))
|
||||
fn price_info_not_found() -> Client<FakeFetch<String>> {
|
||||
Client::new(FakeFetch::new(None::<String>), CpuPool::new(1))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -70,3 +70,4 @@ pretty_assertions = "0.1"
|
||||
macros = { path = "../util/macros" }
|
||||
ethcore-network = { path = "../util/network" }
|
||||
kvdb-memorydb = { path = "../util/kvdb-memorydb" }
|
||||
fake-fetch = { path = "../util/fake-fetch" }
|
||||
|
@ -91,6 +91,9 @@ extern crate macros;
|
||||
#[cfg(test)]
|
||||
extern crate kvdb_memorydb;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate fake_fetch;
|
||||
|
||||
extern crate tempdir;
|
||||
|
||||
pub extern crate jsonrpc_ws_server as ws;
|
||||
|
@ -17,14 +17,12 @@
|
||||
//! Test rpc services.
|
||||
|
||||
mod dapps;
|
||||
mod fetch;
|
||||
mod miner_service;
|
||||
mod snapshot_service;
|
||||
mod sync_provider;
|
||||
mod update_service;
|
||||
|
||||
pub use self::dapps::TestDappsService;
|
||||
pub use self::fetch::TestFetch;
|
||||
pub use self::miner_service::TestMinerService;
|
||||
pub use self::snapshot_service::TestSnapshotService;
|
||||
pub use self::sync_provider::{Config, TestSyncProvider};
|
||||
|
@ -26,9 +26,11 @@ use futures_cpupool::CpuPool;
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
use v1::{ParitySet, ParitySetClient};
|
||||
use v1::tests::helpers::{TestMinerService, TestFetch, TestUpdater, TestDappsService};
|
||||
use v1::tests::helpers::{TestMinerService, TestUpdater, TestDappsService};
|
||||
use super::manage_network::TestManageNetwork;
|
||||
|
||||
use fake_fetch::FakeFetch;
|
||||
|
||||
fn miner_service() -> Arc<TestMinerService> {
|
||||
Arc::new(TestMinerService::default())
|
||||
}
|
||||
@ -45,7 +47,7 @@ fn updater_service() -> Arc<TestUpdater> {
|
||||
Arc::new(TestUpdater::default())
|
||||
}
|
||||
|
||||
pub type TestParitySetClient = ParitySetClient<TestBlockChainClient, TestMinerService, TestUpdater, TestFetch>;
|
||||
pub type TestParitySetClient = ParitySetClient<TestBlockChainClient, TestMinerService, TestUpdater, FakeFetch<usize>>;
|
||||
|
||||
fn parity_set_client(
|
||||
client: &Arc<TestBlockChainClient>,
|
||||
@ -55,7 +57,7 @@ fn parity_set_client(
|
||||
) -> TestParitySetClient {
|
||||
let dapps_service = Arc::new(TestDappsService);
|
||||
let pool = CpuPool::new(1);
|
||||
ParitySetClient::new(client, miner, updater, &(net.clone() as Arc<ManageNetwork>), Some(dapps_service), TestFetch::default(), pool)
|
||||
ParitySetClient::new(client, miner, updater, &(net.clone() as Arc<ManageNetwork>), Some(dapps_service), FakeFetch::new(Some(1)), pool)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
11
util/fake-fetch/Cargo.toml
Normal file
11
util/fake-fetch/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
description = "Mock fetcher for testing"
|
||||
name = "fake-fetch"
|
||||
version = "0.0.1"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
fetch = { path = "../fetch" }
|
||||
futures = "0.1"
|
||||
hyper = "0.11"
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
@ -14,37 +14,42 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Test implementation of fetch client.
|
||||
extern crate fetch;
|
||||
extern crate hyper;
|
||||
extern crate futures;
|
||||
|
||||
use std::thread;
|
||||
use std::boxed::Box;
|
||||
use jsonrpc_core::futures::{self, Future};
|
||||
use fetch::{self, Fetch, Url, Request};
|
||||
use futures::future;
|
||||
use hyper;
|
||||
use hyper::StatusCode;
|
||||
use futures::{future, future::FutureResult};
|
||||
use fetch::{Fetch, Url, Request};
|
||||
|
||||
/// Test implementation of fetcher. Will always return the same file.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct TestFetch;
|
||||
#[derive(Clone, Default)]
|
||||
pub struct FakeFetch<T> where T: Clone + Send + Sync {
|
||||
val: Option<T>,
|
||||
}
|
||||
|
||||
impl Fetch for TestFetch {
|
||||
type Result = Box<Future<Item = fetch::Response, Error = fetch::Error> + Send + 'static>;
|
||||
impl<T> FakeFetch<T> where T: Clone + Send + Sync {
|
||||
pub fn new(t: Option<T>) -> Self {
|
||||
FakeFetch { val : t }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Fetch for FakeFetch<T> where T: Clone + Send+ Sync {
|
||||
type Result = FutureResult<fetch::Response, fetch::Error>;
|
||||
|
||||
fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result {
|
||||
let u = request.url().clone();
|
||||
let (tx, rx) = futures::oneshot();
|
||||
thread::spawn(move || {
|
||||
future::ok(if self.val.is_some() {
|
||||
let r = hyper::Response::new().with_body(&b"Some content"[..]);
|
||||
tx.send(fetch::Response::new(u, r, abort)).unwrap();
|
||||
});
|
||||
|
||||
Box::new(rx.map_err(|_| fetch::Error::Aborted))
|
||||
fetch::client::Response::new(u, r, abort)
|
||||
} else {
|
||||
fetch::client::Response::new(u, hyper::Response::new().with_status(StatusCode::NotFound), abort)
|
||||
})
|
||||
}
|
||||
|
||||
fn get(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::get(url), abort)
|
||||
}
|
||||
@ -52,7 +57,7 @@ impl Fetch for TestFetch {
|
||||
fn post(&self, url: &str, abort: fetch::Abort) -> Self::Result {
|
||||
let url: Url = match url.parse() {
|
||||
Ok(u) => u,
|
||||
Err(e) => return Box::new(future::err(e.into()))
|
||||
Err(e) => return future::err(e.into())
|
||||
};
|
||||
self.fetch(Request::post(url), abort)
|
||||
}
|
Loading…
Reference in New Issue
Block a user