poa-bridge/tests/src/lib.rs

242 lines
7.2 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extern crate serde_json;
extern crate futures;
extern crate jsonrpc_core as rpc;
extern crate web3;
extern crate bridge;
#[macro_use]
extern crate pretty_assertions;
extern crate ethcore;
use std::cell::Cell;
use web3::Transport;
#[derive(Debug, Clone)]
pub struct MockedRequest {
pub method: String,
pub params: Vec<rpc::Value>,
}
impl From<(&'static str, serde_json::Value)> for MockedRequest {
fn from(a: (&'static str, serde_json::Value)) -> Self {
MockedRequest {
method: a.0.to_owned(),
params: a.1.as_array().unwrap().clone()
}
}
}
#[derive(Debug, Clone)]
pub struct MockedTransport {
pub requests: Cell<usize>,
pub expected_requests: Vec<MockedRequest>,
pub mocked_responses: Vec<serde_json::Value>,
}
impl Transport for MockedTransport {
type Out = web3::Result<rpc::Value>;
fn prepare(&self, method: &str, params: Vec<rpc::Value>) -> (usize, rpc::Call) {
let n = self.requests.get();
assert_eq!(&self.expected_requests[n].method as &str, method, "invalid method called");
for (expected_params, params) in self.expected_requests[n].params.iter().zip(params.iter()) {
assert_eq!(expected_params.get("address"), params.get("address"), "invalid method params, addresses do not match");
assert_eq!(expected_params.get("fromBlock"), params.get("fromBlock"), "invalid method params, from-blocks do not match");
assert_eq!(expected_params.get("limit"), params.get("limit"), "invalid method params, limits do not match");
assert_eq!(expected_params.get("toBlock"), params.get("toBlock"), "invalid method params, to-blocks do not match");
let expected_topics: Vec<rpc::Value> = if let Some(ref topics) = expected_params.get("topics") {
topics.as_array().unwrap().clone()
.iter()
.filter_map(|topic|
if topic != &rpc::Value::Null {
Some(topic.clone())
} else {
None
}
)
.collect()
} else {
vec![]
};
let topics: Vec<rpc::Value> = if let Some(ref topics) = params.get("topics") {
topics.as_array().unwrap().clone()
.iter()
.filter_map(|topic|
if topic != &rpc::Value::Null {
Some(topic.clone())
} else {
None
}
)
.collect()
} else {
vec![]
};
assert_eq!(expected_topics, topics, "invalid method params, topics do not match");
}
self.requests.set(n + 1);
let request = web3::helpers::build_request(1, method, params);
(n + 1, request)
}
fn send(&self, _id: usize, _request: rpc::Call) -> web3::Result<rpc::Value> {
let response = self.mocked_responses.iter().nth(self.requests.get() - 1).expect("missing response");
let f = futures::finished(response.clone());
Box::new(f)
}
}
#[macro_export]
macro_rules! test_transport_stream {
(
name => $name: ident,
init => $init_stream: expr,
expected => $expected: expr,
$($method: expr => req => $req: expr, res => $res: expr ;)*
) => {
#[test]
fn $name() {
use self::futures::{Future, Stream};
let transport = $crate::MockedTransport {
requests: Default::default(),
expected_requests: vec![$($method),*].into_iter().zip(vec![$($req),*].into_iter()).map(Into::into).collect(),
mocked_responses: vec![$($res),*],
};
let stream = $init_stream(&transport);
let res = stream.collect().wait();
assert_eq!($expected, res.unwrap());
}
}
}
#[macro_export]
macro_rules! test_app_stream {
(
name => $name: ident,
database => $db: expr,
home => account => $home_acc: expr, confirmations => $home_conf: expr;
foreign => account => $foreign_acc: expr, confirmations => $foreign_conf: expr;
authorities => accounts => $authorities_accs: expr, signatures => $signatures: expr;
txs => $txs: expr,
init => $init_stream: expr,
expected => $expected: expr,
home_transport => [$($home_method: expr => req => $home_req: expr, res => $home_res: expr ;)*],
foreign_transport => [$($foreign_method: expr => req => $foreign_req: expr, res => $foreign_res: expr ;)*]
) => {
#[test]
#[allow(unused_imports)]
fn $name() {
use self::std::sync::Arc;
use self::std::sync::atomic::AtomicBool;
use self::std::time::Duration;
use self::futures::{Future, Stream};
use self::bridge::app::{App, Connections};
use self::bridge::contracts::{foreign, home};
use self::bridge::config::{Config, Authorities, Node, NodeInfo, ContractConfig, Transactions, TransactionConfig, GasPriceSpeed};
use self::bridge::database::Database;
use ethcore::account_provider::AccountProvider;
let home = $crate::MockedTransport {
requests: Default::default(),
expected_requests: vec![$($home_method),*].into_iter().zip(vec![$($home_req),*].into_iter()).map(Into::into).collect(),
mocked_responses: vec![$($home_res),*],
};
let foreign = $crate::MockedTransport {
requests: Default::default(),
expected_requests: vec![$($foreign_method),*].into_iter().zip(vec![$($foreign_req),*].into_iter()).map(Into::into).collect(),
mocked_responses: vec![$($foreign_res),*],
};
let config = Config {
txs: $txs,
home: Node {
account: $home_acc.parse().unwrap(),
contract: ContractConfig {
bin: Default::default(),
},
poll_interval: Duration::from_secs(0),
request_timeout: Duration::from_secs(5),
required_confirmations: $home_conf,
rpc_host: "".into(),
rpc_port: 8545,
password: "password.txt".into(),
info: NodeInfo::default(),
gas_price_oracle_url: None,
gas_price_speed: GasPriceSpeed::Fast,
gas_price_timeout: Duration::from_secs(5),
default_gas_price: 0,
},
foreign: Node {
account: $foreign_acc.parse().unwrap(),
contract: ContractConfig {
bin: Default::default(),
},
poll_interval: Duration::from_secs(0),
request_timeout: Duration::from_secs(5),
required_confirmations: $foreign_conf,
rpc_host: "".into(),
rpc_port: 8545,
password: "password.txt".into(),
info: NodeInfo::default(),
gas_price_oracle_url: None,
gas_price_speed: GasPriceSpeed::Fast,
gas_price_timeout: Duration::from_secs(5),
default_gas_price: 0,
},
authorities: Authorities {
accounts: $authorities_accs.iter().map(|a: &&str| a.parse().unwrap()).collect(),
required_signatures: $signatures,
},
estimated_gas_cost_of_withdraw: 100_000,
keystore: "/keys/".into(),
};
let app = App {
config,
database_path: "".into(),
connections: Connections {
home: &home,
foreign: &foreign,
},
home_bridge: home::HomeBridge::default(),
foreign_bridge: foreign::ForeignBridge::default(),
timer: Default::default(),
running: Arc::new(AtomicBool::new(true)),
keystore: AccountProvider::transient_provider(),
};
let app = Arc::new(app);
let stream = $init_stream(app, &$db);
let res = stream.collect().wait();
assert_eq!($expected, res.unwrap());
assert_eq!(
home.expected_requests.len(),
home.requests.get(),
"home: expected {} requests but received only {}",
home.expected_requests.len(),
home.requests.get()
);
assert_eq!(
foreign.expected_requests.len(),
foreign.requests.get(),
"foreign: expected {} requests but received only {}",
foreign.expected_requests.len(),
foreign.requests.get()
);
}
}
}
#[cfg(test)]
mod tests {
}