From a6f2180b1b590f362c231488ad618f3840bfc40e Mon Sep 17 00:00:00 2001 From: Lorenzo Tucci Date: Fri, 1 Sep 2023 17:15:24 +0300 Subject: [PATCH 1/3] fix rpc tests, only check for RPC errors and not returned values --- swap/src/cli/command.rs | 3 - swap/tests/rpc.rs | 348 ++++++++++++---------------------------- 2 files changed, 102 insertions(+), 249 deletions(-) diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index 86e48f16..70596bbe 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -507,7 +507,6 @@ mod tests { const ARGS_DATA_DIR: &str = "/tmp/dir/"; #[tokio::test] - #[serial] async fn given_buy_xmr_on_mainnet_then_defaults_to_mainnet() { let raw_ars = vec![ BINARY_NAME, @@ -538,7 +537,6 @@ mod tests { } #[tokio::test] - #[serial] async fn given_buy_xmr_on_testnet_then_defaults_to_testnet() { let raw_ars = vec![ BINARY_NAME, @@ -1016,7 +1014,6 @@ mod tests { let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (false, false, true); - let data_dir = data_dir_path_cli(is_testnet); let (expected_config, expected_request) = ( Config::default(is_testnet, None, debug, json), diff --git a/swap/tests/rpc.rs b/swap/tests/rpc.rs index f034e7b1..b27e69e4 100644 --- a/swap/tests/rpc.rs +++ b/swap/tests/rpc.rs @@ -1,11 +1,8 @@ -use anyhow::Result; -use jsonrpsee::rpc_params; use jsonrpsee::ws_client::WsClientBuilder; use jsonrpsee_core::client::ClientT; use jsonrpsee_core::params::ObjectParams; -use serial_test::serial; use std::collections::HashMap; use std::sync::Arc; @@ -13,24 +10,20 @@ use std::time::Duration; use swap::api::request::{Method, Request }; use swap::api::Context; use swap::cli::command::{Bitcoin, Monero}; +use tokio::sync::OnceCell; use uuid::Uuid; #[cfg(test)] -// to be replaced with actual "real" testing values -// need to create some kind of swap database and bitcoin environment with some -// funds const SERVER_ADDRESS: &str = "127.0.0.1:1234"; const BITCOIN_ADDR: &str = "tb1qr3em6k3gfnyl8r7q0v7t4tlnyxzgxma3lressv"; const MONERO_ADDR: &str = "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a"; const SELLER: &str = "/ip4/127.0.0.1/tcp/9939/p2p/12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi"; -const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b"; -pub async fn initialize_context() -> (Arc, Request) { +pub async fn initialize_context() -> Arc { let (is_testnet, debug, json) = (true, false, false); - // let data_dir = data::data_dir_from(None, is_testnet).unwrap(); let server_address = None; let bitcoin = Bitcoin { @@ -42,7 +35,6 @@ pub async fn initialize_context() -> (Arc, Request) { monero_daemon_address: None, }; - let request = Request::new(Method::StartDaemon { server_address: None }); let context = Context::build( Some(bitcoin), @@ -57,388 +49,252 @@ pub async fn initialize_context() -> (Arc, Request) { .await .unwrap(); - (Arc::new(context), request) + Arc::new(context) } -#[tokio::test] -#[serial] -pub async fn can_start_server() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); +pub async fn start_server() { + ONCE.get_or_init(|| async { + let ctx = initialize_context().await; + ctx + }).await; + let request = Request::new(Method::StartDaemon { server_address: None }); tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; + request.call(Arc::clone(ONCE.get().unwrap())).await }); - tokio::time::sleep(Duration::from_secs(3)).await; - assert!(true); } + +static ONCE: OnceCell> = OnceCell::const_new(); + + #[tokio::test] -#[serial] pub async fn get_bitcoin_balance() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); + start_server().await; - let url = format!("ws://{}", SERVER_ADDRESS); tokio::time::sleep(Duration::from_secs(3)).await; + let url = format!("ws://{}", SERVER_ADDRESS); + let mut params = ObjectParams::new(); + + params.insert("", "").unwrap(); let client = WsClientBuilder::default().build(&url).await.unwrap(); - let response: HashMap = client - .request("get_bitcoin_balance", rpc_params!["id"]) - .await - .unwrap(); + let response: Result, jsonrpsee_core::Error> = client + .request("get_bitcoin_balance", params) + .await; - assert_eq!(response, HashMap::from([("balance".to_string(), 0)])); + match response { + Ok(_) => (), + Err(e) => panic!("Expected a HashMap, got an error: {}", e), + } } #[tokio::test] -#[serial] pub async fn get_history() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); + start_server().await; + let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; + tokio::time::sleep(Duration::from_secs(3)).await; let client = WsClientBuilder::default().build(&url).await.unwrap(); let mut params = ObjectParams::new(); + params.insert("", "").unwrap(); - let response: HashMap> = - client.request("get_history", params).await.unwrap(); - let swaps: Vec<(Uuid, String)> = Vec::new(); + let response: Result>, jsonrpsee_core::Error> = + client.request("get_history", params).await; - assert_eq!(response, HashMap::from([("swaps".to_string(), swaps)])); + match response { + Ok(_) => (), + Err(e) => panic!("Expected a HashMap, got an error: {}", e), + } } #[tokio::test] -#[serial] pub async fn get_raw_history() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); + start_server().await; let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; + tokio::time::sleep(Duration::from_secs(3)).await; let client = WsClientBuilder::default().build(&url).await.unwrap(); let mut params = ObjectParams::new(); - let raw_history: HashMap = HashMap::new(); + params.insert("", "").unwrap(); - let response: HashMap> = - client.request("get_raw_history", params).await.unwrap(); - - assert_eq!( - response, - HashMap::from([("raw_history".to_string(), raw_history)]) - ); -} - -#[tokio::test] -#[serial] -pub async fn get_seller() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); - - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; - - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); - - let response: Result, _> = client.request("get_seller", params).await; - - // We should ideally match the expected error and panic if it's different one, - // but the request returns a custom error (to investigate) - // Err(jsonrpsee_core::Error::Call(CallError::InvalidParams(e))) => (), - // Err(e) => panic!("ErrorType was not ParseError but {e:?}"), + let response: Result>, jsonrpsee_core::Error> = + client.request("get_raw_history", params).await; match response { - Err(e) => (), - _ => panic!("Expected an error when swap_id is missing"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", "invalid_swap"); - - let response: Result, _> = client.request("get_seller", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error swap_id is malformed"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", SWAP_ID); - - let response: Result, _> = client.request("get_seller", params).await; - - match response { - Ok(hash) => (), - Err(e) => panic!( - "Expected a HashMap with correct params, got an error: {}", - e - ), - } -} - -#[tokio::test] -#[serial] -pub async fn get_swap_start_date() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); - - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; - - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when swap_id is missing"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", "invalid_swap"); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when swap_id is malformed"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", SWAP_ID); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Ok(hash) => (), + Ok(_) => (), Err(e) => panic!("Expected a HashMap, got an error: {}", e), } } #[tokio::test] -#[serial] -pub async fn resume_swap() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); +pub async fn get_swap_info() { + start_server().await; let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; + tokio::time::sleep(Duration::from_secs(3)).await; let client = WsClientBuilder::default().build(&url).await.unwrap(); let mut params = ObjectParams::new(); + params.insert("", "").unwrap(); - let response: Result, _> = - client.request("get_swap_start_date", params).await; + let response: Result, jsonrpsee_core::Error> = + client.request("get_swap_info", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when swap_id is missing"), } let mut params = ObjectParams::new(); - params.insert("swap_id", "invalid_swap"); + params.insert("swap_id", "invalid_swap").unwrap(); - let response: Result, _> = - client.request("get_swap_start_date", params).await; + let response: Result, jsonrpsee_core::Error> = + client.request("get_swap_info", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when swap_id is malformed"), } - - let mut params = ObjectParams::new(); - params.insert("swap_id", SWAP_ID); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Ok(hash) => (), - Err(e) => panic!("Expected a HashMap, got an error: {}", e), - } } #[tokio::test] -#[serial] pub async fn withdraw_btc() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); + start_server().await; let url = format!("ws://{}", SERVER_ADDRESS); + tokio::time::sleep(Duration::from_secs(3)).await; - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); + let params = ObjectParams::new(); - let response: Result, _> = client.request("withdraw_btc", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("withdraw_btc", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when withdraw_address is missing"), } let mut params = ObjectParams::new(); - params.insert("address", "invalid_address"); + params.insert("address", "invalid_address").unwrap(); - let response: Result, _> = client.request("withdraw_btc", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("withdraw_btc", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when withdraw_address is malformed"), } let mut params = ObjectParams::new(); - params.insert("address", BITCOIN_ADDR); - params.insert("amount", "0"); + params.insert("address", BITCOIN_ADDR).unwrap(); + params.insert("amount", "0").unwrap(); - let response: Result, _> = client.request("withdraw_btc", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("withdraw_btc", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when amount is 0"), } - let mut params = ObjectParams::new(); - params.insert("address", BITCOIN_ADDR); - params.insert("amount", "0.1"); - - let response: Result, _> = client.request("withdraw_btc", params).await; - - match response { - Ok(hash) => (), - Err(e) => panic!("Expected a HashMap, got an error: {}", e), - } - } #[tokio::test] -#[serial] pub async fn buy_xmr() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); + start_server().await; let url = format!("ws://{}", SERVER_ADDRESS); + tokio::time::sleep(Duration::from_secs(3)).await; - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); + let params = ObjectParams::new(); - let response: Result, _> = client.request("buy_xmr", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("buy_xmr", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when no params are given"), } let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("monero_receive_address", MONERO_ADDR); + params.insert("bitcoin_change_address", BITCOIN_ADDR).unwrap(); + params.insert("monero_receive_address", MONERO_ADDR).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("buy_xmr", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when seller is missing"), } let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("seller", SELLER); + params.insert("bitcoin_change_address", BITCOIN_ADDR).unwrap(); + params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("buy_xmr", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when monero_receive_address is missing"), } let mut params = ObjectParams::new(); - params.insert("monero_receive_address", MONERO_ADDR); - params.insert("seller", SELLER); + params.insert("monero_receive_address", MONERO_ADDR).unwrap(); + params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("buy_xmr", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when bitcoin_change_address is missing"), } let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", "invalid_address"); - params.insert("monero_receive_address", MONERO_ADDR); - params.insert("seller", SELLER); + params.insert("bitcoin_change_address", "invalid_address").unwrap(); + params.insert("monero_receive_address", MONERO_ADDR).unwrap(); + params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("buy_xmr", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when bitcoin_change_address is malformed"), } let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("monero_receive_address", "invalid_address"); - params.insert("seller", SELLER); + params.insert("bitcoin_change_address", BITCOIN_ADDR).unwrap(); + params.insert("monero_receive_address", "invalid_address").unwrap(); + params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("buy_xmr", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when monero_receive_address is malformed"), } let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("monero_receive_address", MONERO_ADDR); - params.insert("seller", "invalid_seller"); + params.insert("bitcoin_change_address", BITCOIN_ADDR).unwrap(); + params.insert("monero_receive_address", MONERO_ADDR).unwrap(); + params.insert("seller", "invalid_seller").unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("buy_xmr", params).await; match response { - Err(e) => (), + Err(_) => (), _ => panic!("Expected an error when seller is malformed"), } let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("monero_receive_address", MONERO_ADDR); - params.insert("seller", SELLER); + params.insert("bitcoin_change_address", BITCOIN_ADDR).unwrap(); + params.insert("monero_receive_address", MONERO_ADDR).unwrap(); + params.insert("seller", SELLER).unwrap(); - let response: Result, _> = client.request("buy_xmr", params).await; + let response: Result, jsonrpsee_core::Error> = client.request("buy_xmr", params).await; match response { - Ok(hash) => (), + Ok(_) => (), Err(e) => panic!("Expected a HashMap, got an error: {}", e), } From ec0bc8cd394978ecf719332e0902573cb2eab35c Mon Sep 17 00:00:00 2001 From: Lorenzo Tucci Date: Fri, 22 Sep 2023 23:28:49 +0300 Subject: [PATCH 2/3] fixing test_cli_arguments and other tests --- swap/Cargo.toml | 2 +- swap/src/bin/swap.rs | 58 +++++----- swap/src/cli/command.rs | 239 ++++++++++++++++++++-------------------- 3 files changed, 149 insertions(+), 150 deletions(-) diff --git a/swap/Cargo.toml b/swap/Cargo.toml index f2075aff..12886cdd 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -55,7 +55,7 @@ structopt = "0.3" strum = { version = "0.24", features = [ "derive" ] } thiserror = "1" time = "0.3" -tokio = { version = "1", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs", "net" ] } +tokio = { version = "1", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs", "net", "parking_lot" ] } tokio-socks = "0.5" tokio-tungstenite = { version = "0.15", features = [ "rustls-tls" ] } tokio-util = { version = "0.7", features = [ "io", "codec" ] } diff --git a/swap/src/bin/swap.rs b/swap/src/bin/swap.rs index 8cea4033..9e8ebbc5 100644 --- a/swap/src/bin/swap.rs +++ b/swap/src/bin/swap.rs @@ -75,10 +75,10 @@ mod tests { assert_eq!((amount, fees), (expected_amount, expected_fees)); assert_eq!( writer.captured(), - r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC - INFO swap: Deposit at least 0.00001000 BTC to cover the min quantity with fee! - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC - INFO swap: Received Bitcoin new_balance=0.00100000 BTC max_giveable=0.00090000 BTC + r" INFO swap::api::request: Received quote price=0.001 BTC minimum_amount=0 BTC maximum_amount=0.01 BTC + INFO swap::api::request: Deposit at least 0.00001 BTC to cover the min quantity with fee! + INFO swap::api::request: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00001 BTC max_giveable=0 BTC minimum_amount=0 BTC maximum_amount=0.01 BTC + INFO swap::api::request: Received Bitcoin new_balance=0.001 BTC max_giveable=0.0009 BTC " ); } @@ -112,10 +112,10 @@ mod tests { assert_eq!((amount, fees), (expected_amount, expected_fees)); assert_eq!( writer.captured(), - r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC - INFO swap: Deposit at least 0.00001000 BTC to cover the min quantity with fee! - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC - INFO swap: Received Bitcoin new_balance=0.10010000 BTC max_giveable=0.10000000 BTC + r" INFO swap::api::request: Received quote price=0.001 BTC minimum_amount=0 BTC maximum_amount=0.01 BTC + INFO swap::api::request: Deposit at least 0.00001 BTC to cover the min quantity with fee! + INFO swap::api::request: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00001 BTC max_giveable=0 BTC minimum_amount=0 BTC maximum_amount=0.01 BTC + INFO swap::api::request: Received Bitcoin new_balance=0.1001 BTC max_giveable=0.1 BTC " ); } @@ -149,7 +149,7 @@ mod tests { assert_eq!((amount, fees), (expected_amount, expected_fees)); assert_eq!( writer.captured(), - " INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC\n" + " INFO swap::api::request: Received quote price=0.001 BTC minimum_amount=0 BTC maximum_amount=0.01 BTC\n" ); } @@ -182,7 +182,7 @@ mod tests { assert_eq!((amount, fees), (expected_amount, expected_fees)); assert_eq!( writer.captured(), - " INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC\n" + " INFO swap::api::request: Received quote price=0.001 BTC minimum_amount=0 BTC maximum_amount=0.01 BTC\n" ); } @@ -215,10 +215,10 @@ mod tests { assert_eq!((amount, fees), (expected_amount, expected_fees)); assert_eq!( writer.captured(), - r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Deposit at least 0.01001000 BTC to cover the min quantity with fee! - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.01001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Received Bitcoin new_balance=0.01010000 BTC max_giveable=0.01000000 BTC + r" INFO swap::api::request: Received quote price=0.001 BTC minimum_amount=0.01 BTC maximum_amount=184467440737.09551615 BTC + INFO swap::api::request: Deposit at least 0.01001 BTC to cover the min quantity with fee! + INFO swap::api::request: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.01001 BTC max_giveable=0 BTC minimum_amount=0.01 BTC maximum_amount=184467440737.09551615 BTC + INFO swap::api::request: Received Bitcoin new_balance=0.0101 BTC max_giveable=0.01 BTC " ); } @@ -252,10 +252,10 @@ mod tests { assert_eq!((amount, fees), (expected_amount, expected_fees)); assert_eq!( writer.captured(), - r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Deposit at least 0.00991000 BTC to cover the min quantity with fee! - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00991000 BTC max_giveable=0.00010000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Received Bitcoin new_balance=0.01010000 BTC max_giveable=0.01000000 BTC + r" INFO swap::api::request: Received quote price=0.001 BTC minimum_amount=0.01 BTC maximum_amount=184467440737.09551615 BTC + INFO swap::api::request: Deposit at least 0.00991 BTC to cover the min quantity with fee! + INFO swap::api::request: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00991 BTC max_giveable=0.0001 BTC minimum_amount=0.01 BTC maximum_amount=184467440737.09551615 BTC + INFO swap::api::request: Received Bitcoin new_balance=0.0101 BTC max_giveable=0.01 BTC " ); } @@ -292,13 +292,13 @@ mod tests { assert!(matches!(error, tokio::time::error::Elapsed { .. })); assert_eq!( writer.captured(), - r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Deposit at least 0.10001000 BTC to cover the min quantity with fee! - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.10001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Received Bitcoin new_balance=0.01010000 BTC max_giveable=0.01000000 BTC - INFO swap: Deposited amount is less than `min_quantity` - INFO swap: Deposit at least 0.09001000 BTC to cover the min quantity with fee! - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.09001000 BTC max_giveable=0.01000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC + r" INFO swap::api::request: Received quote price=0.001 BTC minimum_amount=0.1 BTC maximum_amount=184467440737.09551615 BTC + INFO swap::api::request: Deposit at least 0.10001 BTC to cover the min quantity with fee! + INFO swap::api::request: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.10001 BTC max_giveable=0 BTC minimum_amount=0.1 BTC maximum_amount=184467440737.09551615 BTC + INFO swap::api::request: Received Bitcoin new_balance=0.0101 BTC max_giveable=0.01 BTC + INFO swap::api::request: Deposited amount is less than `min_quantity` + INFO swap::api::request: Deposit at least 0.09001 BTC to cover the min quantity with fee! + INFO swap::api::request: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.09001 BTC max_giveable=0.01 BTC minimum_amount=0.1 BTC maximum_amount=184467440737.09551615 BTC " ); } @@ -341,10 +341,10 @@ mod tests { assert_eq!( writer.captured(), - r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Deposit at least 0.10001000 BTC to cover the min quantity with fee! - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.10001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Received Bitcoin new_balance=0.21000000 BTC max_giveable=0.20000000 BTC + r" INFO swap::api::request: Received quote price=0.001 BTC minimum_amount=0.1 BTC maximum_amount=184467440737.09551615 BTC + INFO swap::api::request: Deposit at least 0.10001 BTC to cover the min quantity with fee! + INFO swap::api::request: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.10001 BTC max_giveable=0 BTC minimum_amount=0.1 BTC maximum_amount=184467440737.09551615 BTC + INFO swap::api::request: Received Bitcoin new_balance=0.21 BTC max_giveable=0.2 BTC " ); } diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index 70596bbe..242b48ce 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -499,15 +499,20 @@ mod tests { use crate::api::api_test::*; use crate::api::Config; - use crate::fs::system_data_dir; use crate::monero::monero_address::MoneroAddressNetworkMismatch; - use serial_test::serial; const BINARY_NAME: &str = "swap"; const ARGS_DATA_DIR: &str = "/tmp/dir/"; #[tokio::test] - async fn given_buy_xmr_on_mainnet_then_defaults_to_mainnet() { + + // this test is very long, however it just checks that various CLI arguments sets the + // internal Context and Request properly. It is unlikely to fail and splitting it in various + // tests would require to run the tests sequantially which is very slow (due to the context + // need to access files like the Bitcoin wallet). + async fn test_cli_arguments() { + // given_buy_xmr_on_mainnet_then_defaults_to_mainnet + let raw_ars = vec![ BINARY_NAME, "buy-xmr", @@ -522,22 +527,28 @@ mod tests { let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (false, false, false); - let (expected_config, expected_request) = ( - Config::default(is_testnet, None, debug, json), - Request::buy_xmr(is_testnet), - ); - let (actual_config, actual_request) = match args { ParseResult::Context(context, request) => (context.config.clone(), request), _ => panic!("Couldn't parse result"), }; + let (expected_config, mut expected_request) = ( + Config::default(is_testnet, None, debug, json), + Request::buy_xmr(is_testnet), + ); + + // since Uuid is random, copy before comparing requests + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - async fn given_buy_xmr_on_testnet_then_defaults_to_testnet() { + // given_buy_xmr_on_testnet_then_defaults_to_testnet let raw_ars = vec![ BINARY_NAME, "--testnet", @@ -553,7 +564,7 @@ mod tests { let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (true, false, false); - let (expected_config, expected_request) = ( + let (expected_config, mut expected_request) = ( Config::default(is_testnet, None, debug, json), Request::buy_xmr(is_testnet), ); @@ -563,13 +574,17 @@ mod tests { _ => panic!("Couldn't parse result"), }; + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_buy_xmr_on_mainnet_with_testnet_address_then_fails() { + // given_buy_xmr_on_mainnet_with_testnet_address_then_fails let raw_ars = vec![ BINARY_NAME, "buy-xmr", @@ -590,11 +605,8 @@ mod tests { actual: monero::Network::Stagenet } ); - } - #[tokio::test] - #[serial] - async fn given_buy_xmr_on_testnet_with_mainnet_address_then_fails() { + // given_buy_xmr_on_testnet_with_mainnet_address_then_fails let raw_ars = vec![ BINARY_NAME, "--testnet", @@ -616,11 +628,8 @@ mod tests { actual: monero::Network::Mainnet } ); - } - #[tokio::test] - #[serial] - async fn given_resume_on_mainnet_then_defaults_to_mainnet() { + // given_resume_on_mainnet_then_defaults_to_mainnet let raw_ars = vec![BINARY_NAME, "resume", "--swap-id", SWAP_ID]; let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); @@ -638,11 +647,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_resume_on_testnet_then_defaults_to_testnet() { + // given_resume_on_testnet_then_defaults_to_testnet let raw_ars = vec![BINARY_NAME, "--testnet", "resume", "--swap-id", SWAP_ID]; let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); @@ -660,11 +666,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_cancel_on_mainnet_then_defaults_to_mainnet() { + // given_cancel_on_mainnet_then_defaults_to_mainnet let raw_ars = vec![BINARY_NAME, "cancel", "--swap-id", SWAP_ID]; let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); @@ -683,11 +686,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_cancel_on_testnet_then_defaults_to_testnet() { + // given_cancel_on_testnet_then_defaults_to_testnet let raw_ars = vec![BINARY_NAME, "--testnet", "cancel", "--swap-id", SWAP_ID]; let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); @@ -705,11 +705,7 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_refund_on_mainnet_then_defaults_to_mainnet() { let raw_ars = vec![BINARY_NAME, "refund", "--swap-id", SWAP_ID]; let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); @@ -727,11 +723,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_refund_on_testnet_then_defaults_to_testnet() { + // given_refund_on_testnet_then_defaults_to_testnet let raw_ars = vec![BINARY_NAME, "--testnet", "refund", "--swap-id", SWAP_ID]; let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); @@ -749,11 +742,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_buy_xmr_on_mainnet_with_data_dir_then_data_dir_set() { + // given_buy_xmr_on_mainnet_with_data_dir_then_data_dir_set let raw_ars = vec![ BINARY_NAME, "--data-base-dir", @@ -771,7 +761,7 @@ mod tests { let (is_testnet, debug, json) = (false, false, false); let data_dir = PathBuf::from_str(ARGS_DATA_DIR).unwrap(); - let (expected_config, expected_request) = ( + let (expected_config, mut expected_request) = ( Config::default(is_testnet, Some(data_dir.clone()), debug, json), Request::buy_xmr(is_testnet), ); @@ -781,13 +771,17 @@ mod tests { _ => panic!("Couldn't parse result"), }; + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_buy_xmr_on_testnet_with_data_dir_then_data_dir_set() { + // given_buy_xmr_on_testnet_with_data_dir_then_data_dir_set let raw_ars = vec![ BINARY_NAME, "--testnet", @@ -806,7 +800,7 @@ mod tests { let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (true, false, false); - let (expected_config, expected_request) = ( + let (expected_config, mut expected_request) = ( Config::default(is_testnet, Some(data_dir.clone()), debug, json), Request::buy_xmr(is_testnet), ); @@ -816,13 +810,17 @@ mod tests { _ => panic!("Couldn't parse result"), }; + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_resume_on_mainnet_with_data_dir_then_data_dir_set() { + // given_resume_on_mainnet_with_data_dir_then_data_dir_set let raw_ars = vec![ BINARY_NAME, "--data-base-dir", @@ -836,11 +834,18 @@ mod tests { let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (false, false, false); - let (expected_config, expected_request) = ( + let (expected_config, mut expected_request) = ( Config::default(is_testnet, Some(data_dir.clone()), debug, json), Request::resume(), ); + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + let (actual_config, actual_request) = match args { ParseResult::Context(context, request) => (context.config.clone(), request), _ => panic!("Couldn't parse result"), @@ -848,11 +853,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_resume_on_testnet_with_data_dir_then_data_dir_set() { + // given_resume_on_testnet_with_data_dir_then_data_dir_set let raw_ars = vec![ BINARY_NAME, "--testnet", @@ -879,11 +881,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_buy_xmr_on_mainnet_with_debug_then_debug_set() { + // given_buy_xmr_on_mainnet_with_debug_then_debug_set let raw_ars = vec![ BINARY_NAME, "--debug", @@ -899,7 +898,7 @@ mod tests { let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (false, true, false); - let (expected_config, expected_request) = ( + let (expected_config, mut expected_request) = ( Config::default(is_testnet, None, debug, json), Request::buy_xmr(is_testnet), ); @@ -909,13 +908,17 @@ mod tests { _ => panic!("Couldn't parse result"), }; + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_buy_xmr_on_testnet_with_debug_then_debug_set() { + // given_buy_xmr_on_testnet_with_debug_then_debug_set let raw_ars = vec![ BINARY_NAME, "--testnet", @@ -932,7 +935,7 @@ mod tests { let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (true, true, false); - let (expected_config, expected_request) = ( + let (expected_config, mut expected_request) = ( Config::default(is_testnet, None, debug, json), Request::buy_xmr(is_testnet), ); @@ -942,19 +945,23 @@ mod tests { _ => panic!("Couldn't parse result"), }; + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_resume_on_mainnet_with_debug_then_debug_set() { + // given_resume_on_mainnet_with_debug_then_debug_set let raw_ars = vec![BINARY_NAME, "--debug", "resume", "--swap-id", SWAP_ID]; let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (false, true, false); - let (expected_config, expected_request) = ( + let (expected_config, mut expected_request) = ( Config::default(is_testnet, None, debug, json), Request::resume(), ); @@ -964,13 +971,17 @@ mod tests { _ => panic!("Couldn't parse result"), }; + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_resume_on_testnet_with_debug_then_debug_set() { + // given_resume_on_testnet_with_debug_then_debug_set let raw_ars = vec![ BINARY_NAME, "--testnet", @@ -995,11 +1006,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_buy_xmr_on_mainnet_with_json_then_json_set() { + // given_buy_xmr_on_mainnet_with_json_then_json_set let raw_ars = vec![ BINARY_NAME, "--json", @@ -1015,7 +1023,7 @@ mod tests { let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (false, false, true); - let (expected_config, expected_request) = ( + let (expected_config, mut expected_request) = ( Config::default(is_testnet, None, debug, json), Request::buy_xmr(is_testnet), ); @@ -1025,13 +1033,17 @@ mod tests { _ => panic!("Couldn't parse result"), }; + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_buy_xmr_on_testnet_with_json_then_json_set() { + // given_buy_xmr_on_testnet_with_json_then_json_set let raw_ars = vec![ BINARY_NAME, "--testnet", @@ -1047,7 +1059,7 @@ mod tests { let (is_testnet, debug, json) = (true, false, true); - let (expected_config, expected_request) = ( + let (expected_config, mut expected_request) = ( Config::default(is_testnet, None, debug, json), Request::buy_xmr(is_testnet), ); @@ -1058,13 +1070,17 @@ mod tests { _ => panic!("Couldn't parse result"), }; + if let Method::BuyXmr { ref mut swap_id, .. } = expected_request.cmd { + *swap_id = match actual_request.cmd { + Method::BuyXmr { swap_id, .. } => { swap_id }, + _ => panic!("Not the Method we expected") + } + }; + assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_resume_on_mainnet_with_json_then_json_set() { + // given_resume_on_mainnet_with_json_then_json_set let raw_ars = vec![BINARY_NAME, "--json", "resume", "--swap-id", SWAP_ID]; let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (is_testnet, debug, json) = (false, false, true); @@ -1081,11 +1097,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn given_resume_on_testnet_with_json_then_json_set() { + // given_resume_on_testnet_with_json_then_json_set let raw_ars = vec![ BINARY_NAME, "--testnet", @@ -1110,11 +1123,8 @@ mod tests { assert_eq!(actual_config, expected_config); assert_eq!(actual_request, Box::new(expected_request)); - } - #[tokio::test] - #[serial] - async fn only_bech32_addresses_mainnet_are_allowed() { + // only_bech32_addresses_mainnet_are_allowed let raw_ars = vec![ BINARY_NAME, "buy-xmr", @@ -1125,7 +1135,7 @@ mod tests { "--seller", MULTI_ADDRESS, ]; - let result = parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); + parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); let raw_ars = vec![ BINARY_NAME, @@ -1137,7 +1147,7 @@ mod tests { "--seller", MULTI_ADDRESS, ]; - let result = parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); + parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); let raw_ars = vec![ BINARY_NAME, @@ -1151,11 +1161,8 @@ mod tests { ]; let result = parse_args_and_apply_defaults(raw_ars).await.unwrap(); assert!(matches!(result, ParseResult::Context(_, _))); - } - #[tokio::test] - #[serial] - async fn only_bech32_addresses_testnet_are_allowed() { + // only_bech32_addresses_testnet_are_allowed let raw_ars = vec![ BINARY_NAME, "--testnet", @@ -1167,7 +1174,7 @@ mod tests { "--seller", MULTI_ADDRESS, ]; - let result = parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); + parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); let raw_ars = vec![ BINARY_NAME, @@ -1180,7 +1187,7 @@ mod tests { "--seller", MULTI_ADDRESS, ]; - let result = parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); + parse_args_and_apply_defaults(raw_ars).await.unwrap_err(); let raw_ars = vec![ BINARY_NAME, @@ -1196,12 +1203,4 @@ mod tests { let result = parse_args_and_apply_defaults(raw_ars).await.unwrap(); assert!(matches!(result, ParseResult::Context(_, _))); } - - fn data_dir_path_cli(is_testnet: bool) -> PathBuf { - if is_testnet { - system_data_dir().unwrap().join("cli").join("testnet") - } else { - system_data_dir().unwrap().join("cli").join("mainnet") - } - } } From 03be15b0691645bb46bed1406e3eb6b4e94d7fa9 Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Sun, 24 Sep 2023 17:30:05 +0200 Subject: [PATCH 3/3] WIP: RPC server integration tests --- swap/src/api.rs | 91 ++-- swap/src/api/request.rs | 16 +- swap/src/bitcoin.rs | 4 +- swap/src/bitcoin/wallet.rs | 1 + swap/src/rpc/methods.rs | 10 +- swap/tests/harness/mod.rs | 20 +- swap/tests/rpc.rs | 828 ++++++++++++++++++++----------------- 7 files changed, 554 insertions(+), 416 deletions(-) diff --git a/swap/src/api.rs b/swap/src/api.rs index 0f5805cd..62a14e8c 100644 --- a/swap/src/api.rs +++ b/swap/src/api.rs @@ -123,7 +123,7 @@ impl SwapLock { // workaround for warning over monero_rpc_process which we must own but not read #[allow(dead_code)] pub struct Context { - pub db: Arc, + db: Arc, bitcoin_wallet: Option>, monero_wallet: Option>, monero_rpc_process: Option, @@ -205,6 +205,36 @@ impl Context { Ok(context) } + + pub fn new( + db: Arc, + bitcoin_wallet: Option>, + monero_wallet: Option>, + monero_rpc_process: Option, + config: Config, + ) -> Self { + Self { + db, + bitcoin_wallet, + monero_wallet, + monero_rpc_process, + swap_lock: Arc::new(SwapLock::new()), + config, + } + } + + pub async fn for_harness(seed: Seed, env_config: EnvConfig, db_path: PathBuf, bob_bitcoin_wallet: Arc, bob_monero_wallet: Arc) -> Self { + let config = Config::for_harness(seed, env_config); + + Self { + bitcoin_wallet: Some(bob_bitcoin_wallet), + monero_wallet: Some(bob_monero_wallet), + config, + db: open_db(db_path).await.unwrap(), + monero_rpc_process: None, + swap_lock: Arc::new(SwapLock::new()), + } + } } impl fmt::Debug for Context { @@ -288,6 +318,27 @@ fn env_config_from(testnet: bool) -> EnvConfig { Mainnet::get_config() } } + +impl Config { + pub fn for_harness(seed: Seed, env_config: EnvConfig) -> Self { + let data_dir = data::data_dir_from(None, false).unwrap(); + + Self { + tor_socks5_port: None, + namespace: XmrBtcNamespace::from_is_testnet(false), + server_address: None, + env_config, + seed: Some(seed), + debug: false, + json: false, + is_testnet: false, + data_dir, + } + } +} + + + #[cfg(test)] pub mod api_test { use super::*; @@ -350,38 +401,30 @@ pub mod api_test { } }; - Request::new( - Method::BuyXmr { - seller, - bitcoin_change_address, - monero_receive_address, - swap_id: Uuid::new_v4(), - }, - ) + Request::new(Method::BuyXmr { + seller, + bitcoin_change_address, + monero_receive_address, + swap_id: Uuid::new_v4(), + }) } pub fn resume() -> Request { - Request::new( - Method::Resume { - swap_id: Uuid::from_str(SWAP_ID).unwrap(), - }, - ) + Request::new(Method::Resume { + swap_id: Uuid::from_str(SWAP_ID).unwrap(), + }) } pub fn cancel() -> Request { - Request::new( - Method::CancelAndRefund { - swap_id: Uuid::from_str(SWAP_ID).unwrap(), - }, - ) + Request::new(Method::CancelAndRefund { + swap_id: Uuid::from_str(SWAP_ID).unwrap(), + }) } pub fn refund() -> Request { - Request::new( - Method::CancelAndRefund { - swap_id: Uuid::from_str(SWAP_ID).unwrap(), - }, - ) + Request::new(Method::CancelAndRefund { + swap_id: Uuid::from_str(SWAP_ID).unwrap(), + }) } } } diff --git a/swap/src/api/request.rs b/swap/src/api/request.rs index 345b7c2f..9344d2a4 100644 --- a/swap/src/api/request.rs +++ b/swap/src/api/request.rs @@ -193,6 +193,9 @@ impl Request { .as_ref() .context("Could not get Bitcoin wallet")?; + let state = context.db.get_state(swap_id).await?; + let is_completed = state.swap_finished(); + let peerId = context .db .get_peer_id(swap_id) @@ -205,9 +208,6 @@ impl Request { .await .with_context(|| "Could not get addressess")?; - let state = context.db.get_state(swap_id).await?; - let is_completed = state.swap_finished(); - let start_date = context.db.get_swap_start_date(swap_id).await?; let swap_state: BobState = state.try_into()?; @@ -346,7 +346,7 @@ impl Request { let (event_loop, mut event_loop_handle) = EventLoop::new(swap_id, swarm, seller_peer_id)?; - let event_loop = tokio::spawn(event_loop.run().instrument(Span::current())); + let event_loop = tokio::spawn(event_loop.run().instrument(Span::none())); let max_givable = || bitcoin_wallet.max_giveable(TxLock::script_size()); let estimate_fee = |amount| bitcoin_wallet.estimate_fee(TxLock::weight(), amount); @@ -429,7 +429,7 @@ impl Request { .release_swap_lock() .await .expect("Could not release swap lock"); - }.instrument(Span::current())); + }.instrument(Span::none())); Ok(json!({ "swapId": swap_id.to_string(), @@ -483,7 +483,7 @@ impl Request { let (event_loop, event_loop_handle) = EventLoop::new(swap_id, swarm, seller_peer_id)?; - let handle = tokio::spawn(event_loop.run().instrument(Span::current())); + let handle = tokio::spawn(event_loop.run().instrument(Span::none())); let monero_receive_address = context.db.get_monero_address(swap_id).await?; let swap = Swap::from_db( @@ -529,7 +529,7 @@ impl Request { .release_swap_lock() .await .expect("Could not release swap lock"); - }.instrument(Span::current())); + }.instrument(Span::none())); Ok(json!({ "result": "ok", })) @@ -574,7 +574,7 @@ impl Request { Method::GetRawStates => { let raw_history = context.db.raw_all().await?; - Ok(json!({ "raw_history": raw_history })) + Ok(json!({ "raw_states": raw_history })) } Method::Config => { let data_dir_display = context.config.data_dir.display(); diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index 2ac0aa78..cffc8c9e 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -370,8 +370,8 @@ mod tests { use crate::env::{GetConfig, Regtest}; use crate::protocol::{alice, bob}; use rand::rngs::OsRng; - use uuid::Uuid; use std::matches; + use uuid::Uuid; #[test] fn lock_confirmations_le_to_cancel_timelock_no_timelock_expired() { @@ -400,7 +400,7 @@ mod tests { tx_cancel_status, ); - assert!(matches!(expired_timelock, ExpiredTimelocks::Cancel {..})); + assert!(matches!(expired_timelock, ExpiredTimelocks::Cancel { .. })); } #[test] diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index b133bb8c..6218fb6f 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -194,6 +194,7 @@ impl Wallet { tokio::time::sleep(Duration::from_secs(5)).await; } }.instrument(Span::current())); + }.instrument(Span::none())); Subscription { receiver, diff --git a/swap/src/rpc/methods.rs b/swap/src/rpc/methods.rs index c5fa461c..1ebd8824 100644 --- a/swap/src/rpc/methods.rs +++ b/swap/src/rpc/methods.rs @@ -219,11 +219,13 @@ async fn execute_request( cmd: Method, context: &Arc, ) -> Result { - let params_parsed = params + // If we fail to parse the params as a String HashMap, it's most likely because its an empty object + // In that case, we want to make sure not to fail the request, so we set the log_reference_id to None + // and swallow the error + let reference_id = params .parse::>() - .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))?; - - let reference_id = params_parsed.get("log_reference_id"); + .ok() + .and_then(|params_parsed| params_parsed.get("log_reference_id").cloned()); let request = Request::with_id(cmd, reference_id.map(|s| s.clone())); request diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index 4f3f5fee..436b8f9a 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -16,16 +16,16 @@ use std::sync::Arc; use std::time::Duration; use swap::asb::FixedRate; use swap::bitcoin::{CancelTimelock, PunishTimelock, TxCancel, TxPunish, TxRedeem, TxRefund}; -use swap::database::SqliteDatabase; +use swap::database::{SqliteDatabase}; use swap::env::{Config, GetConfig}; use swap::fs::ensure_directory_exists; use swap::network::rendezvous::XmrBtcNamespace; use swap::network::swarm; use swap::protocol::alice::{AliceState, Swap}; use swap::protocol::bob::BobState; -use swap::protocol::{alice, bob}; +use swap::protocol::{alice, bob, Database}; use swap::seed::Seed; -use swap::{asb, bitcoin, cli, env, monero}; +use swap::{api, asb, bitcoin, cli, env, monero}; use tempfile::{tempdir, NamedTempFile}; use testcontainers::clients::Cli; use testcontainers::{Container, Docker, RunArgs}; @@ -454,6 +454,8 @@ impl BobParams { } let db = Arc::new(SqliteDatabase::open(&self.db_path).await?); + db.insert_peer_id(swap_id, self.alice_peer_id).await?; + let swap = bob::Swap::new( db, swap_id, @@ -488,6 +490,7 @@ impl BobParams { .behaviour_mut() .add_address(self.alice_peer_id, self.alice_address.clone()); + cli::EventLoop::new(swap_id, swarm, self.alice_peer_id) } } @@ -534,6 +537,17 @@ pub struct TestContext { } impl TestContext { + + pub async fn get_bob_context(self) -> api::Context { + api::Context::for_harness( + self.bob_params.seed, + self.env_config, + self.bob_params.db_path, + self.bob_bitcoin_wallet, + self.bob_monero_wallet, + ).await + } + pub async fn restart_alice(&mut self) { self.alice_handle.abort(); diff --git a/swap/tests/rpc.rs b/swap/tests/rpc.rs index f034e7b1..9ac3523e 100644 --- a/swap/tests/rpc.rs +++ b/swap/tests/rpc.rs @@ -1,20 +1,33 @@ +pub mod harness; use anyhow::Result; -use jsonrpsee::rpc_params; use jsonrpsee::ws_client::WsClientBuilder; -use jsonrpsee_core::client::ClientT; +use jsonrpsee_core::client::{Client, ClientT}; use jsonrpsee_core::params::ObjectParams; use serial_test::serial; +use serde_json::{json, Value}; use std::collections::HashMap; +use std::net::SocketAddr; +use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; -use swap::api::request::{Method, Request }; -use swap::api::Context; +use tempfile::tempdir; +use swap::api::request::{Method, Request}; +use swap::api::{Config, Context, SwapLock}; use swap::cli::command::{Bitcoin, Monero}; +use tracing_subscriber::filter::LevelFilter; +use swap::tracing_ext::{capture_logs, MakeCapturingWriter}; use uuid::Uuid; +use swap::asb::FixedRate; +use swap::database::open_db; +use swap::network::rendezvous::XmrBtcNamespace; +use swap::protocol::{alice, bob}; +use crate::harness::{setup_test, SlowCancelConfig}; +use crate::harness::alice_run_until::is_xmr_lock_transaction_sent; +use crate::harness::bob_run_until::is_btc_locked; #[cfg(test)] @@ -27,419 +40,484 @@ const MONERO_ADDR: &str = "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAo const SELLER: &str = "/ip4/127.0.0.1/tcp/9939/p2p/12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi"; const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b"; +const SERVER_START_TIMEOUT_SECS: u64 = 50; -pub async fn initialize_context() -> (Arc, Request) { - let (is_testnet, debug, json) = (true, false, false); - // let data_dir = data::data_dir_from(None, is_testnet).unwrap(); - let server_address = None; +pub async fn initialize_daemon(context: Context) -> (Client, MakeCapturingWriter, Arc) { + let writer = capture_logs(LevelFilter::DEBUG); + let server_address: SocketAddr = SERVER_ADDRESS.parse().unwrap(); - let bitcoin = Bitcoin { - bitcoin_electrum_rpc_url: None, - bitcoin_target_block: None, - }; + let request = Request::new(Method::StartDaemon { + server_address: Some(server_address), + }); - let _monero = Monero { - monero_daemon_address: None, - }; + let context = Arc::new( + context + ); - let request = Request::new(Method::StartDaemon { server_address: None }); + let context_clone = context.clone(); - let context = Context::build( - Some(bitcoin), - None, - None, - None, - is_testnet, - debug, - json, - server_address, - ) - .await - .unwrap(); + tokio::spawn(async move { + if let Err(err) = request.call(context_clone).await { + println!("Failed to initialize daemon for testing: {}", err); + } + }); - (Arc::new(context), request) + for _ in 0..SERVER_START_TIMEOUT_SECS { + if writer.captured().contains("Started RPC server") { + let url = format!("ws://{}", SERVER_ADDRESS); + let client = WsClientBuilder::default().build(&url).await.unwrap(); + return (client, writer, context); + } + + tokio::time::sleep(Duration::from_secs(1)).await; + } + + panic!( + "Failed to start RPC server after {} seconds", + SERVER_START_TIMEOUT_SECS + ); } +fn assert_has_keys_serde(map: &serde_json::Map, keys: &[&str]) { + for &key in keys { + assert!(map.contains_key(key), "Key {} is missing", key); + } +} + +// Helper function for HashMap +fn assert_has_keys_hashmap(map: &HashMap, keys: &[&str]) { + for &key in keys { + assert!(map.contains_key(key), "Key {} is missing", key); + } +} + +/* #[tokio::test] #[serial] pub async fn can_start_server() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); - tokio::time::sleep(Duration::from_secs(3)).await; + initialize_context().await; assert!(true); } +*/ + #[tokio::test] #[serial] pub async fn get_bitcoin_balance() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); + setup_test(SlowCancelConfig, |harness_ctx| async move { + let context = harness_ctx.get_bob_context().await; + let (client, _, _) = initialize_daemon(context).await; - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; + let response: HashMap = client + .request("get_bitcoin_balance", ObjectParams::new()) + .await + .unwrap(); - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let response: HashMap = client - .request("get_bitcoin_balance", rpc_params!["id"]) - .await - .unwrap(); + assert_eq!(response, HashMap::from([("balance".to_string(), 10000000)])); - assert_eq!(response, HashMap::from([("balance".to_string(), 0)])); + Ok(()) + }).await; +} + +#[tokio::test] +#[serial] +pub async fn get_bitcoin_balance_with_log_reference_id() { + setup_test(SlowCancelConfig, |harness_ctx| async move { + let context = harness_ctx.get_bob_context().await; + let (client, writer, _) = initialize_daemon(context).await; + + let mut params = ObjectParams::new(); + params.insert("log_reference_id", "test_ref_id").unwrap(); + + let _: HashMap = client.request("get_bitcoin_balance", params).await.unwrap(); + + assert!(writer.captured().contains( + "log_reference_id=\"test_ref_id\"}: swap::api::request: Checked Bitcoin balance balance=0" + )); + + Ok(()) + }).await; } #[tokio::test] #[serial] pub async fn get_history() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); + setup_test(SlowCancelConfig, |mut harness_ctx| async move { + // Start a swap and wait for xmr lock transaction to be published (XmrLockTransactionSent) + let (bob_swap, _) = harness_ctx.bob_swap().await; + let bob_swap_id = bob_swap.id; + tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); + let alice_swap = harness_ctx.alice_next_swap().await; + alice::run_until( + alice_swap, + is_xmr_lock_transaction_sent, + FixedRate::default(), + ).await?; - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; + let context = harness_ctx.get_bob_context().await; + let (client, _, _) = initialize_daemon(context).await; - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); + let response: HashMap> = client + .request("get_history", ObjectParams::new()) + .await + .unwrap(); + let swaps: Vec<(Uuid, String)> = vec![(bob_swap_id, "btc is locked".to_string())]; - let response: HashMap> = - client.request("get_history", params).await.unwrap(); - let swaps: Vec<(Uuid, String)> = Vec::new(); + assert_eq!( + response, + HashMap::from([("swaps".to_string(), swaps)]) + ); - assert_eq!(response, HashMap::from([("swaps".to_string(), swaps)])); + Ok(()) + }).await; +} + + +#[tokio::test] +#[serial] +pub async fn get_raw_states() { + setup_test(SlowCancelConfig, |mut harness_ctx| async move { + // Start a swap and wait for xmr lock transaction to be published (XmrLockTransactionSent) + let (bob_swap, _) = harness_ctx.bob_swap().await; + let bob_swap_id = bob_swap.id; + tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); + let alice_swap = harness_ctx.alice_next_swap().await; + alice::run_until( + alice_swap, + is_xmr_lock_transaction_sent, + FixedRate::default(), + ).await?; + + let context = harness_ctx.get_bob_context().await; + let (client, _, _) = initialize_daemon(context).await; + + let response: HashMap>> = + client.request("get_raw_states", ObjectParams::new()).await.unwrap(); + + let response_raw_states = response.get("raw_states").unwrap(); + + assert!(response_raw_states.contains_key(&bob_swap_id)); + assert_eq!(response_raw_states.get(&bob_swap_id).unwrap().len(), 2); + + Ok(()) + }).await; } #[tokio::test] #[serial] -pub async fn get_raw_history() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); +pub async fn get_swap_info_valid_swap_id() { + setup_test(SlowCancelConfig, |mut harness_ctx| async move { + // Start a swap and wait for xmr lock transaction to be published (XmrLockTransactionSent) + let (bob_swap, _) = harness_ctx.bob_swap().await; + let bob_swap_id = bob_swap.id; + tokio::spawn(bob::run_until(bob_swap, is_btc_locked)); + let alice_swap = harness_ctx.alice_next_swap().await; + alice::run_until( + alice_swap, + is_xmr_lock_transaction_sent, + FixedRate::default(), + ).await?; + + let context = harness_ctx.get_bob_context().await; + let (client, _, _) = initialize_daemon(context).await; + + let mut params = ObjectParams::new(); + params.insert("swap_id", bob_swap_id).unwrap(); + let response: HashMap = + client.request("get_swap_info", params).await.unwrap(); + + // Check primary keys in response + assert_has_keys_hashmap( + &response, + &["txRefundFee", "swapId", "cancelTimelock", "timelock", "punishTimelock", + "stateName", "btcAmount", "startDate", "btcRefundAddress", "txCancelFee", + "xmrAmount", "completed", "txLockId", "seller"] + ); + + // Assert specific fields + assert_eq!(response.get("swapId").unwrap(), &bob_swap_id.to_string()); + assert_eq!(response.get("stateName").unwrap(), &"btc is locked".to_string()); + assert_eq!(response.get("completed").unwrap(), &Value::Bool(false)); + + // Check seller object and its keys + let seller = response.get("seller").expect("Field 'seller' is missing from response").as_object().expect("'seller' is not an object"); + assert_has_keys_serde(seller, &["peerId"]); + + // Check timelock object, nested 'None' object, and blocks_left + let timelock = response.get("timelock").expect("Field 'timelock' is missing from response").as_object().expect("'timelock' is not an object"); + let none_obj = timelock.get("None").expect("Field 'None' is missing from 'timelock'").as_object().expect("'None' is not an object in 'timelock'"); + let blocks_left = none_obj.get("blocks_left").expect("Field 'blocks_left' is missing from 'None'").as_i64().expect("'blocks_left' is not an integer"); + + // Validate blocks_left + assert!(blocks_left > 0 && blocks_left <= 180, "Field 'blocks_left' should be > 0 and <= 180 but got {}", blocks_left); + + Ok(()) + }).await; +} + + +#[tokio::test] +#[serial] +pub async fn swap_endpoints_invalid_or_missing_swap_id() { + setup_test(SlowCancelConfig, |harness_ctx| async move { + let context = harness_ctx.get_bob_context().await; + let (client, _, _) = initialize_daemon(context).await; + + for method in ["get_swap_info", "resume_swap", "cancel_refund_swap"].iter() { + let mut params = ObjectParams::new(); + params.insert("swap_id", "invalid_swap").unwrap(); + + let response: Result, _> = client.request(method, params).await; + response.expect_err(&format!( + "Expected an error when swap_id is invalid for method {}", + method + )); + + let params = ObjectParams::new(); + + let response: Result, _> = client.request(method, params).await; + response.expect_err(&format!( + "Expected an error when swap_id is missing for method {}", + method + )); + } + + Ok(()) + }).await; +} + + +#[tokio::test] +pub async fn list_sellers_missing_rendezvous_point() { + setup_test(SlowCancelConfig, |harness_ctx| async move { + let context = harness_ctx.get_bob_context().await; + let (client, _, _) = initialize_daemon(context).await; + + let params = ObjectParams::new(); + let result: Result, _> = client.request("list_sellers", params).await; + + result.expect_err("Expected an error when rendezvous_point is missing"); + + Ok(()) + }).await; +} + +/* +#[tokio::test] +#[serial] +pub async fn resume_swap_valid_swap_id() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params.insert("swap_id", SWAP_ID).unwrap(); + let response: Result, _> = client.request("resume_swap", params).await; + response.expect("Expected a HashMap, got an error"); +} + +#[tokio::test] +#[serial] +pub async fn withdraw_btc_missing_address() { + let (client, _, _) = initialize_context().await; + let params = ObjectParams::new(); + let response: Result, _> = client.request("withdraw_btc", params).await; + response.expect_err("Expected an error when withdraw_address is missing"); +} + +#[tokio::test] +#[serial] +pub async fn withdraw_btc_invalid_address() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params.insert("address", "invalid_address").unwrap(); + let response: Result, _> = client.request("withdraw_btc", params).await; + response.expect_err("Expected an error when withdraw_address is malformed"); +} + +#[tokio::test] +#[serial] +pub async fn withdraw_btc_zero_amount() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params.insert("address", BITCOIN_ADDR).unwrap(); + params.insert("amount", "0").unwrap(); + let response: Result, _> = client.request("withdraw_btc", params).await; + response.expect_err("Expected an error when amount is 0"); +} + +#[tokio::test] +#[serial] +pub async fn withdraw_btc_valid_params() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params.insert("address", BITCOIN_ADDR).unwrap(); + params.insert("amount", "0.1").unwrap(); + let response: Result, _> = client.request("withdraw_btc", params).await; + response.expect("Expected a HashMap, got an error"); +} + +#[tokio::test] +#[serial] +pub async fn buy_xmr_no_params() { + let (client, _, _) = initialize_context().await; + let params = ObjectParams::new(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when no params are given"); +} + +#[tokio::test] +#[serial] +pub async fn buy_xmr_missing_seller() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", BITCOIN_ADDR) + .unwrap(); + params + .insert("monero_receive_address", MONERO_ADDR) + .unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when seller is missing"); +} + +#[tokio::test] +#[serial] +pub async fn buy_xmr_missing_monero_address() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", BITCOIN_ADDR) + .unwrap(); + params.insert("seller", SELLER).unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when monero_receive_address is missing"); +} + +#[tokio::test] +#[serial] +pub async fn buy_xmr_missing_bitcoin_address() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params + .insert("monero_receive_address", MONERO_ADDR) + .unwrap(); + params.insert("seller", SELLER).unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when bitcoin_change_address is missing"); +} + +#[tokio::test] +#[serial] +pub async fn buy_xmr_malformed_bitcoin_address() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", "invalid_address") + .unwrap(); + params + .insert("monero_receive_address", MONERO_ADDR) + .unwrap(); + params.insert("seller", SELLER).unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when bitcoin_change_address is malformed"); +} + +#[tokio::test] +#[serial] +pub async fn buy_xmr_malformed_monero_address() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", BITCOIN_ADDR) + .unwrap(); + params + .insert("monero_receive_address", "invalid_address") + .unwrap(); + params.insert("seller", SELLER).unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when monero_receive_address is malformed"); +} + +#[tokio::test] +#[serial] +pub async fn buy_xmr_malformed_seller() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", BITCOIN_ADDR) + .unwrap(); + params + .insert("monero_receive_address", MONERO_ADDR) + .unwrap(); + params.insert("seller", "invalid_seller").unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect_err("Expected an error when seller is malformed"); +} + +#[tokio::test] +#[serial] +pub async fn buy_xmr_valid_params() { + let (client, _, _) = initialize_context().await; + let mut params = ObjectParams::new(); + params + .insert("bitcoin_change_address", BITCOIN_ADDR) + .unwrap(); + params + .insert("monero_receive_address", MONERO_ADDR) + .unwrap(); + params.insert("seller", SELLER).unwrap(); + let response: Result, _> = client.request("buy_xmr", params).await; + response.expect("Expected a HashMap, got an error"); +} + +#[tokio::test] +#[serial] +pub async fn suspend_current_swap_no_swap_running() { + let (client, _, _) = initialize_context().await; + let response: Result, _> = client + .request("suspend_current_swap", ObjectParams::new()) + .await; + response.expect_err("Expected an error when no swap is running"); +} + +#[tokio::test] +#[serial] +pub async fn suspend_current_swap_swap_running() { + let (client, _, ctx) = initialize_context().await; + ctx.swap_lock + .acquire_swap_lock(Uuid::parse_str(SWAP_ID).unwrap()) + .await + .unwrap(); + tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; + // Immediately release lock when suspend signal is received. Mocks a running swap that is then cancelled. + ctx.swap_lock + .listen_for_swap_force_suspension() + .await + .unwrap(); + ctx.swap_lock.release_swap_lock().await.unwrap(); }); - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; - - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); - let raw_history: HashMap = HashMap::new(); - - let response: HashMap> = - client.request("get_raw_history", params).await.unwrap(); - + let response: HashMap = client + .request("suspend_current_swap", ObjectParams::new()) + .await + .unwrap(); assert_eq!( response, - HashMap::from([("raw_history".to_string(), raw_history)]) + HashMap::from([("swapId".to_string(), SWAP_ID.to_string())]) ); } #[tokio::test] #[serial] -pub async fn get_seller() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); - - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; - - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); - - let response: Result, _> = client.request("get_seller", params).await; - - // We should ideally match the expected error and panic if it's different one, - // but the request returns a custom error (to investigate) - // Err(jsonrpsee_core::Error::Call(CallError::InvalidParams(e))) => (), - // Err(e) => panic!("ErrorType was not ParseError but {e:?}"), - - match response { - Err(e) => (), - _ => panic!("Expected an error when swap_id is missing"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", "invalid_swap"); - - let response: Result, _> = client.request("get_seller", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error swap_id is malformed"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", SWAP_ID); - - let response: Result, _> = client.request("get_seller", params).await; - - match response { - Ok(hash) => (), - Err(e) => panic!( - "Expected a HashMap with correct params, got an error: {}", - e - ), - } -} - -#[tokio::test] -#[serial] -pub async fn get_swap_start_date() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); - - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; - - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when swap_id is missing"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", "invalid_swap"); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when swap_id is malformed"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", SWAP_ID); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Ok(hash) => (), - Err(e) => panic!("Expected a HashMap, got an error: {}", e), - } -} - -#[tokio::test] -#[serial] -pub async fn resume_swap() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); - - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; - - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when swap_id is missing"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", "invalid_swap"); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when swap_id is malformed"), - } - - let mut params = ObjectParams::new(); - params.insert("swap_id", SWAP_ID); - - let response: Result, _> = - client.request("get_swap_start_date", params).await; - - match response { - Ok(hash) => (), - Err(e) => panic!("Expected a HashMap, got an error: {}", e), - } -} - -#[tokio::test] -#[serial] -pub async fn withdraw_btc() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); - - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; - - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); - - let response: Result, _> = client.request("withdraw_btc", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when withdraw_address is missing"), - } - - let mut params = ObjectParams::new(); - params.insert("address", "invalid_address"); - - let response: Result, _> = client.request("withdraw_btc", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when withdraw_address is malformed"), - } - - let mut params = ObjectParams::new(); - params.insert("address", BITCOIN_ADDR); - params.insert("amount", "0"); - - let response: Result, _> = client.request("withdraw_btc", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when amount is 0"), - } - - let mut params = ObjectParams::new(); - params.insert("address", BITCOIN_ADDR); - params.insert("amount", "0.1"); - - let response: Result, _> = client.request("withdraw_btc", params).await; - - match response { - Ok(hash) => (), - Err(e) => panic!("Expected a HashMap, got an error: {}", e), - } - -} - -#[tokio::test] -#[serial] -pub async fn buy_xmr() { - let (ctx, mut request) = initialize_context().await; - let move_ctx = Arc::clone(&ctx); - tokio::spawn(async move { - request.call(Arc::clone(&move_ctx)).await; - }); - - let url = format!("ws://{}", SERVER_ADDRESS); - tokio::time::sleep(Duration::from_secs(3)).await; - - let client = WsClientBuilder::default().build(&url).await.unwrap(); - let mut params = ObjectParams::new(); - - let response: Result, _> = client.request("buy_xmr", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when no params are given"), - } - - let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("monero_receive_address", MONERO_ADDR); - - let response: Result, _> = client.request("buy_xmr", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when seller is missing"), - } - - let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("seller", SELLER); - - let response: Result, _> = client.request("buy_xmr", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when monero_receive_address is missing"), - } - - let mut params = ObjectParams::new(); - params.insert("monero_receive_address", MONERO_ADDR); - params.insert("seller", SELLER); - - let response: Result, _> = client.request("buy_xmr", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when bitcoin_change_address is missing"), - } - - let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", "invalid_address"); - params.insert("monero_receive_address", MONERO_ADDR); - params.insert("seller", SELLER); - - let response: Result, _> = client.request("buy_xmr", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when bitcoin_change_address is malformed"), - } - - let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("monero_receive_address", "invalid_address"); - params.insert("seller", SELLER); - - let response: Result, _> = client.request("buy_xmr", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when monero_receive_address is malformed"), - } - - let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("monero_receive_address", MONERO_ADDR); - params.insert("seller", "invalid_seller"); - - let response: Result, _> = client.request("buy_xmr", params).await; - - match response { - Err(e) => (), - _ => panic!("Expected an error when seller is malformed"), - } - - let mut params = ObjectParams::new(); - params.insert("bitcoin_change_address", BITCOIN_ADDR); - params.insert("monero_receive_address", MONERO_ADDR); - params.insert("seller", SELLER); - - let response: Result, _> = client.request("buy_xmr", params).await; - - match response { - Ok(hash) => (), - Err(e) => panic!("Expected a HashMap, got an error: {}", e), - } +pub async fn suspend_current_swap_timeout() { + let (client, _, ctx) = initialize_context().await; + ctx.swap_lock + .acquire_swap_lock(Uuid::parse_str(SWAP_ID).unwrap()) + .await + .unwrap(); + let response: Result, _> = client + .request("suspend_current_swap", ObjectParams::new()) + .await; + response.expect_err("Expected an error when suspend signal times out"); } +*/ \ No newline at end of file