From 09d9ca10e299b515a4084e1bc0368b06cf9556b5 Mon Sep 17 00:00:00 2001 From: Lorenzo Tucci Date: Mon, 12 Feb 2024 00:09:53 +0200 Subject: [PATCH] fix and merge rpc tests, parse uuuid and multiaddr from serde_json value --- swap/src/rpc/methods.rs | 62 ++++-- swap/tests/rpc.rs | 405 ++++++++-------------------------------- 2 files changed, 128 insertions(+), 339 deletions(-) diff --git a/swap/src/rpc/methods.rs b/swap/src/rpc/methods.rs index cb60af76..93e7db41 100644 --- a/swap/src/rpc/methods.rs +++ b/swap/src/rpc/methods.rs @@ -20,28 +20,38 @@ pub fn register_modules(context: Arc) -> Result> })?; module.register_async_method("get_swap_info", |params_raw, context| async move { - let params: HashMap = params_raw.parse()?; + let params: HashMap = params_raw.parse()?; let swap_id = params .get("swap_id") .ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()))?; + let swap_id = as_uuid(swap_id).ok_or_else( || jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?; + execute_request( params_raw, - Method::GetSwapInfo { swap_id: *swap_id }, + Method::GetSwapInfo { swap_id }, &context, ) .await })?; module.register_async_method("get_bitcoin_balance", |params_raw, context| async move { - let params: HashMap = params_raw.parse()?; - let force_refresh = *params.get("force_refresh").ok_or_else(|| { - jsonrpsee_core::Error::Custom("Does not contain force_refresh".to_string()) - })?; + let params: HashMap = params_raw.parse()?; - execute_request(params_raw, Method::Balance { force_refresh }, &context).await + let force_refresh = params.get("force_refresh") + .ok_or_else(|| { jsonrpsee_core::Error::Custom("Does not contain force_refresh".to_string())})? + .as_bool() + .ok_or_else(|| { jsonrpsee_core::Error::Custom("force_refesh is not a boolean".to_string())})?; + + + execute_request( + params_raw, + Method::Balance { force_refresh }, + &context + ) + .await })?; module.register_async_method("get_history", |params, context| async move { @@ -53,25 +63,29 @@ pub fn register_modules(context: Arc) -> Result> })?; module.register_async_method("resume_swap", |params_raw, context| async move { - let params: HashMap = params_raw.parse()?; + let params: HashMap = params_raw.parse()?; let swap_id = params .get("swap_id") .ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()))?; - execute_request(params_raw, Method::Resume { swap_id: *swap_id }, &context).await + let swap_id = as_uuid(swap_id).ok_or_else( || jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?; + + execute_request(params_raw, Method::Resume { swap_id }, &context).await })?; module.register_async_method("cancel_refund_swap", |params_raw, context| async move { - let params: HashMap = params_raw.parse()?; + let params: HashMap = params_raw.parse()?; let swap_id = params .get("swap_id") .ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()))?; + let swap_id = as_uuid(swap_id).ok_or_else( || jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?; + execute_request( params_raw, - Method::CancelAndRefund { swap_id: *swap_id }, + Method::CancelAndRefund { swap_id }, &context, ) .await @@ -80,15 +94,17 @@ pub fn register_modules(context: Arc) -> Result> module.register_async_method( "get_monero_recovery_info", |params_raw, context| async move { - let params: HashMap = params_raw.parse()?; + let params: HashMap = params_raw.parse()?; let swap_id = params.get("swap_id").ok_or_else(|| { jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()) })?; + let swap_id = as_uuid(swap_id).ok_or_else( || jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?; + execute_request( params_raw, - Method::MoneroRecovery { swap_id: *swap_id }, + Method::MoneroRecovery { swap_id }, &context, ) .await @@ -173,11 +189,17 @@ pub fn register_modules(context: Arc) -> Result> })?; module.register_async_method("list_sellers", |params_raw, context| async move { - let params: HashMap = params_raw.parse()?; + let params: HashMap = params_raw.parse()?; + let rendezvous_point = params.get("rendezvous_point").ok_or_else(|| { jsonrpsee_core::Error::Custom("Does not contain rendezvous_point".to_string()) })?; + let rendezvous_point = rendezvous_point + .as_str() + .and_then(|addr_str| Multiaddr::from_str(addr_str).ok()) + .ok_or_else(|| jsonrpsee_core::Error::Custom("Could not parse valid multiaddr".to_string()))?; + execute_request( params_raw, Method::ListSellers { @@ -195,6 +217,14 @@ pub fn register_modules(context: Arc) -> Result> Ok(module) } +fn as_uuid(json_value: &serde_json::Value) -> Option { + if let Some(uuid_str) = json_value.as_str() { + Uuid::parse_str(uuid_str).ok() + } else { + None + } +} + async fn execute_request( params: Params<'static>, cmd: Method, @@ -204,11 +234,11 @@ async fn execute_request( // 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::>() + .parse::>() .ok() .and_then(|params_parsed| params_parsed.get("log_reference_id").cloned()); - let request = Request::with_id(cmd, reference_id); + let request = Request::with_id(cmd, reference_id.map(|log_ref| log_ref.to_string())); request .call(Arc::clone(context)) .await diff --git a/swap/tests/rpc.rs b/swap/tests/rpc.rs index 4c30f585..a780f080 100644 --- a/swap/tests/rpc.rs +++ b/swap/tests/rpc.rs @@ -17,8 +17,8 @@ mod test { use std::time::Duration; use swap::api::request::{Method, Request}; use swap::api::Context; - use tracing_subscriber::filter::LevelFilter; + use tracing_subscriber::filter::LevelFilter; use crate::harness::alice_run_until::is_xmr_lock_transaction_sent; use crate::harness::bob_run_until::is_btc_locked; use crate::harness::{setup_test, SlowCancelConfig, TestContext}; @@ -29,7 +29,7 @@ mod test { const SERVER_ADDRESS: &str = "127.0.0.1:1234"; const SERVER_START_TIMEOUT_SECS: u64 = 50; - const BITCOIN_ADDR: &str = "tb1qr3em6k3gfnyl8r7q0v7t4tlnyxzgxma3lressv"; + const BITCOIN_ADDR: &str = "bcrt1qahvhjfc7vx5857zf8knxs8yp5lkm26jgyt0k76"; const MONERO_ADDR: &str = "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a"; const SELLER: &str = "/ip4/127.0.0.1/tcp/9939/p2p/12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi"; @@ -79,63 +79,16 @@ mod test { } // Helper function for HashMap - fn assert_has_keys_hashmap(map: &HashMap, keys: &[&str]) { + 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() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; - assert!(client.is_connected()); - Ok(()) - }) - .await; - } #[tokio::test] #[serial] - pub async fn get_bitcoin_balance() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; - - let response: HashMap = client - .request("get_bitcoin_balance", ObjectParams::new()) - .await - .unwrap(); - - assert_eq!(response, HashMap::from([("balance".to_string(), 10000000)])); - - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn get_bitcoin_balance_with_log_reference_id() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, writer, _) = setup_daemon(harness_ctx).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() { + pub async fn get_swap_info() { 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; @@ -159,29 +112,6 @@ mod test { 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 (client, _, _) = setup_daemon(harness_ctx).await; - let response: HashMap>> = client .request("get_raw_states", ObjectParams::new()) .await @@ -192,29 +122,6 @@ mod test { 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_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 (client, _, _) = setup_daemon(harness_ctx).await; - let mut params = ObjectParams::new(); params.insert("swap_id", bob_swap_id).unwrap(); let response: HashMap = @@ -288,9 +195,35 @@ mod test { #[tokio::test] #[serial] - pub async fn swap_endpoints_invalid_or_missing_swap_id() { + pub async fn test_rpc_calls() { setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; + let alice_addr = harness_ctx.bob_params.get_concentenated_alice_address(); + let (change_address, receive_address) = + harness_ctx.bob_params.get_change_receive_addresses().await; + + let (client, writer, _) = setup_daemon(harness_ctx).await; + assert!(client.is_connected()); + + let mut params = ObjectParams::new(); + + params.insert("force_refresh", false).unwrap(); + let response: HashMap = client + .request("get_bitcoin_balance", params) + .await + .unwrap(); + + assert_eq!(response, HashMap::from([("balance".to_string(), 10000000)])); + + + let mut params = ObjectParams::new(); + params.insert("log_reference_id", "test_ref_id").unwrap(); + params.insert("force_refresh", false).unwrap(); + + let _: HashMap = client.request("get_bitcoin_balance", params).await.unwrap(); + + assert!(writer.captured().contains( + r#"method{method_name="Balance" log_reference_id="\"test_ref_id\""}: swap::api::request: Current Bitcoin balance as of last sync balance=0.1 BTC"# + )); for method in ["get_swap_info", "resume_swap", "cancel_refund_swap"].iter() { let mut params = ObjectParams::new(); @@ -313,83 +246,29 @@ mod test { )); } - Ok(()) - }) - .await; - } - - #[tokio::test] - pub async fn list_sellers_missing_rendezvous_point() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).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() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).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 withdraw_btc_missing_address() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).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"); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn withdraw_btc_invalid_address() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).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"); - Ok(()) - }) - .await - } - - #[tokio::test] - #[serial] - pub async fn withdraw_btc_zero_amount() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; - let mut params = ObjectParams::new(); params.insert("address", BITCOIN_ADDR).unwrap(); params.insert("amount", "0").unwrap(); @@ -397,22 +276,11 @@ mod test { client.request("withdraw_btc", params).await; response.expect_err("Expected an error when amount is 0"); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn withdraw_btc_valid_params() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; - let mut params = ObjectParams::new(); params - .insert("address", "mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt") + .insert("address", BITCOIN_ADDR) .unwrap(); - params.insert("amount", 0.01).unwrap(); + params.insert("amount", "0.01").unwrap(); let response: HashMap = client .request("withdraw_btc", params) .await @@ -420,37 +288,15 @@ mod test { assert_has_keys_hashmap(&response, &["signed_tx", "amount", "txid"]); assert_eq!( - response.get("amount").unwrap().as_f64().unwrap(), - 1_000_000.0 + response.get("amount").unwrap().as_u64().unwrap(), + 1_000_000 ); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn buy_xmr_no_params() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).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"); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn buy_xmr_missing_seller() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; - let mut params = ObjectParams::new(); params .insert("bitcoin_change_address", BITCOIN_ADDR) @@ -462,17 +308,6 @@ mod test { client.request("buy_xmr", params).await; response.expect_err("Expected an error when seller is missing"); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn buy_xmr_missing_monero_address() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; - let mut params = ObjectParams::new(); params .insert("bitcoin_change_address", BITCOIN_ADDR) @@ -482,16 +317,6 @@ mod test { client.request("buy_xmr", params).await; response.expect_err("Expected an error when monero_receive_address is missing"); - Ok(()) - }) - .await; - } - #[tokio::test] - #[serial] - pub async fn buy_xmr_missing_bitcoin_address() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; - let mut params = ObjectParams::new(); params .insert("monero_receive_address", MONERO_ADDR) @@ -501,17 +326,6 @@ mod test { client.request("buy_xmr", params).await; response.expect_err("Expected an error when bitcoin_change_address is missing"); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn buy_xmr_malformed_bitcoin_address() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _writer, _) = setup_daemon(harness_ctx).await; - let mut params = ObjectParams::new(); params .insert("bitcoin_change_address", "invalid_address") @@ -524,17 +338,6 @@ mod test { client.request("buy_xmr", params).await; response.expect_err("Expected an error when bitcoin_change_address is malformed"); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn buy_xmr_malformed_monero_address() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; - let mut params = ObjectParams::new(); params .insert("bitcoin_change_address", BITCOIN_ADDR) @@ -547,16 +350,6 @@ mod test { client.request("buy_xmr", params).await; response.expect_err("Expected an error when monero_receive_address is malformed"); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn buy_xmr_malformed_seller() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; let mut params = ObjectParams::new(); params @@ -570,91 +363,11 @@ mod test { client.request("buy_xmr", params).await; response.expect_err("Expected an error when seller is malformed"); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn suspend_current_swap_no_swap_running() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, _) = setup_daemon(harness_ctx).await; - let response: Result, _> = client .request("suspend_current_swap", ObjectParams::new()) .await; response.expect_err("Expected an error when no swap is running"); - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn suspend_current_swap_swap_running() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, ctx) = setup_daemon(harness_ctx).await; - - ctx.swap_lock - .acquire_swap_lock(Uuid::parse_str(SWAP_ID).unwrap()) - .await - .unwrap(); - - tokio::spawn(async move { - // 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 response: HashMap = client - .request("suspend_current_swap", ObjectParams::new()) - .await - .unwrap(); - assert_eq!( - response, - HashMap::from([("swapId".to_string(), SWAP_ID.to_string())]) - ); - - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn suspend_current_swap_timeout() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let (client, _, ctx) = setup_daemon(harness_ctx).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"); - - Ok(()) - }) - .await; - } - - #[tokio::test] - #[serial] - pub async fn buy_xmr_valid_params() { - setup_test(SlowCancelConfig, |harness_ctx| async move { - let alice_addr = harness_ctx.bob_params.get_concentenated_alice_address(); - let (change_address, receive_address) = - harness_ctx.bob_params.get_change_receive_addresses().await; - let (client, _, _) = setup_daemon(harness_ctx).await; - let mut params = ObjectParams::new(); params .insert("bitcoin_change_address", change_address) @@ -675,4 +388,50 @@ mod test { }) .await; } + + #[tokio::test] + #[serial] + pub async fn suspend_current_swap_swap_running() { + setup_test(SlowCancelConfig, |harness_ctx| async move { + let (client, _, ctx) = setup_daemon(harness_ctx).await; + + ctx.swap_lock + .acquire_swap_lock(Uuid::parse_str(SWAP_ID).unwrap()) + .await + .unwrap(); + let cloned_ctx = ctx.clone(); + + tokio::spawn(async move { + // 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 response: HashMap = client + .request("suspend_current_swap", ObjectParams::new()) + .await + .unwrap(); + assert_eq!( + response, + HashMap::from([("swapId".to_string(), SWAP_ID.to_string())]) + ); + + cloned_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"); + + Ok(()) + }) + .await; + } + }