taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

commit 9df4ad89b8a4c8acbd06b0ebce398449ba4364df
parent f0e0fa6ba55894ad5bd63f1b3b94767eb42def2e
Author: Antoine A <>
Date:   Fri, 29 May 2026 13:58:06 +0200

common: make test routine more flexible

Diffstat:
Mcommon/taler-api/src/test.rs | 49+++++++++++++++++++++++++++++++++++++++++++------
Mcommon/taler-test-utils/src/routine.rs | 369++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mcommon/taler-test-utils/src/server.rs | 29+++++++++++++++++++++++++++--
Mtaler-cyclos/src/api.rs | 34++++++++++++++++++++++++++++------
Mtaler-magnet-bank/src/api.rs | 30+++++++++++++++++++++++-------
5 files changed, 298 insertions(+), 213 deletions(-)

diff --git a/common/taler-api/src/test.rs b/common/taler-api/src/test.rs @@ -201,14 +201,19 @@ async fn config() { #[tokio::test] async fn transfer() { let (server, _) = setup().await; - transfer_routine(&server, TransferState::success, &EXCHANGE).await; + transfer_routine( + &server.prefix("/taler-wire-gateway"), + TransferState::success, + &EXCHANGE, + ) + .await; } #[tokio::test] async fn outgoing_history() { let (server, _) = &setup().await; out_history_routine( - server, + &server.prefix("/taler-wire-gateway"), tasks!({ server .post("/taler-wire-gateway/transfer") @@ -230,19 +235,43 @@ async fn outgoing_history() { #[tokio::test] async fn admin_add_incoming() { let (server, _) = setup().await; - admin_add_incoming_routine(&server, &EXCHANGE, &EXCHANGE, true).await; + admin_add_incoming_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), + &EXCHANGE, + &EXCHANGE, + true, + ) + .await; } #[tokio::test] async fn in_history() { let (server, _) = setup().await; - in_history_routine(&server, &EXCHANGE, &EXCHANGE, true, tasks!(), tasks!()).await; + in_history_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), + &EXCHANGE, + &EXCHANGE, + true, + tasks!(), + tasks!(), + ) + .await; } #[tokio::test] async fn revenue() { let (server, _) = setup().await; - revenue_routine(&server, &EXCHANGE, true, tasks!(), tasks!()).await; + revenue_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-revenue"), + &EXCHANGE, + true, + tasks!(), + tasks!(), + ) + .await; } #[tokio::test] @@ -290,5 +319,13 @@ async fn check_in(pool: &PgPool) -> Vec<Status> { #[tokio::test] async fn registration() { let (server, pool) = setup().await; - registration_routine(&server, &EXCHANGE, &EXCHANGE, &UNKNOWN, || check_in(&pool)).await; + registration_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), + &EXCHANGE, + &EXCHANGE, + &UNKNOWN, + || check_in(&pool), + ) + .await; } diff --git a/common/taler-test-utils/src/routine.rs b/common/taler-test-utils/src/routine.rs @@ -93,8 +93,8 @@ impl Page for TransferList { } } -pub async fn latest_id<T: Page>(router: &Router, url: &str) -> i64 { - let res = router.get(format!("{url}?limit=-1")).await; +pub async fn latest_id<T: Page>(router: &Router) -> i64 { + let res = router.get("?limit=-1").await; if res.status == StatusCode::NO_CONTENT { 0 } else { @@ -104,23 +104,18 @@ pub async fn latest_id<T: Page>(router: &Router, url: &str) -> i64 { pub async fn routine_pagination<T: Page>( server: &Router, - url: &str, mut register: Tasks<impl AsyncFnMut(usize)>, ) { // Check supported - if !server.get(url).await.is_implemented() { + if !server.get("").await.is_implemented() { return; } // Check history is following specs - let assert_history = async |args: &str, size: usize| { - server - .get(format!("{url}?{args}")) - .await - .assert_ids::<T>(size) - }; + let assert_history = + async |args: &str, size: usize| server.get(format!("?{args}")).await.assert_ids::<T>(size); // Get latest registered id - let latest_id = async || latest_id::<T>(server, url).await; + let latest_id = async || latest_id::<T>(server).await; for i in 0..20 { (register.lambda)(i).await; @@ -151,7 +146,6 @@ pub async fn assert_time<R: Debug>(range: std::ops::Range<u128>, task: impl Futu pub async fn routine_history<T: Page>( server: &Router, - url: &str, mut register: Tasks<impl AsyncFnMut(usize)>, mut ignore: Tasks<impl AsyncFnMut(usize)>, ) { @@ -160,7 +154,7 @@ pub async fn routine_history<T: Page>( ($args:expr, $size:expr) => { async { server - .get(&format!("{url}?{}", $args)) + .get(&format!("?{}", $args)) .await .assert_ids::<T>($size) } @@ -266,7 +260,7 @@ pub async fn routine_history<T: Page>( } ); - routine_pagination::<T>(server, url, register).await; + routine_pagination::<T>(server, register).await; } impl TestResponse { @@ -315,7 +309,7 @@ impl TestResponse { // Get currency from config async fn get_currency(server: &Router) -> String { let config = server - .get("/taler-wire-gateway/config") + .get("/config") .await .assert_ok_json::<serde_json::Value>(); let currency = config["currency"].as_str().unwrap(); @@ -324,11 +318,11 @@ async fn get_currency(server: &Router) -> String { /// Test standard behavior of the transfer endpoints pub async fn transfer_routine( - server: &Router, + wire_gateway: &Router, default_status: TransferState, credit_account: &PaytoURI, ) { - let currency = &get_currency(server).await; + let currency = &get_currency(wire_gateway).await; let default_amount = amount(format!("{currency}:42")); let request_uid = HashCode::rand(); let wtid = ShortHashCode::rand(); @@ -342,15 +336,9 @@ pub async fn transfer_routine( // Check empty db { - server - .get("/taler-wire-gateway/transfers") - .await - .assert_no_content(); - server - .get(format!( - "/taler-wire-gateway/transfers?status={}", - default_status.as_ref() - )) + wire_gateway.get("/transfers").await.assert_no_content(); + wire_gateway + .get(format!("/transfers?status={}", default_status.as_ref())) .await .assert_no_content(); } @@ -359,14 +347,14 @@ pub async fn transfer_routine( let routine = async |req: &TransferRequest| { // Check OK - let first = server - .post("/taler-wire-gateway/transfer") + let first = wire_gateway + .post("/transfer") .json(req) .await .assert_ok_json::<TransferResponse>(); // Check idempotent - let second = server - .post("/taler-wire-gateway/transfer") + let second = wire_gateway + .post("/transfer") .json(req) .await .assert_ok_json::<TransferResponse>(); @@ -374,8 +362,8 @@ pub async fn transfer_routine( assert_eq!(first.timestamp, second.timestamp); // Check by id - let tx = server - .get(format!("/taler-wire-gateway/transfers/{}", first.row_id)) + let tx = wire_gateway + .get(format!("/transfers/{}", first.row_id)) .await .assert_ok_json::<TransferStatus>(); assert_eq!(default_status, tx.status); @@ -387,8 +375,8 @@ pub async fn transfer_routine( assert_eq!(credit_account, &tx.credit_account); // Check page - let list = server - .get("/taler-wire-gateway/transfers?limit=-1") + let list = wire_gateway + .get("/transfers?limit=-1") .await .assert_ok_json::<TransferList>(); let tx = &list.transfers[0]; @@ -421,16 +409,16 @@ pub async fn transfer_routine( // Check create transfer errors { // Check request uid reuse - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "wtid": ShortHashCode::rand() })) .await .assert_error(ErrorCode::BANK_TRANSFER_REQUEST_UID_REUSED); // Check wtid reuse - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "request_uid": HashCode::rand(), })) @@ -438,8 +426,8 @@ pub async fn transfer_routine( .assert_error(ErrorCode::BANK_TRANSFER_WTID_REUSED); // Check currency mismatch - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "amount": "BAD:42" })) @@ -447,29 +435,29 @@ pub async fn transfer_routine( .assert_error(ErrorCode::GENERIC_CURRENCY_MISMATCH); // Base Base32 - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "wtid": "I love chocolate" })) .await .assert_error(ErrorCode::GENERIC_JSON_INVALID); - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "wtid": Base32::<31>::rand() })) .await .assert_error(ErrorCode::GENERIC_JSON_INVALID); - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "request_uid": "I love chocolate" })) .await .assert_error(ErrorCode::GENERIC_JSON_INVALID); - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "request_uid": Base32::<65>::rand() })) @@ -477,8 +465,8 @@ pub async fn transfer_routine( .assert_error(ErrorCode::GENERIC_JSON_INVALID); // Missing receiver-name - let res = server - .post("/taler-wire-gateway/transfer") + let res = wire_gateway + .post("/transfer") .json(&json!(valid_req + { "credit_account": credit_account.as_ref().as_str().split('?').next().unwrap() })) @@ -488,14 +476,14 @@ pub async fn transfer_routine( } // Unsupported payto kind - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "credit_account": UNKNOWN })) .await .assert_error(ErrorCode::GENERIC_PAYTO_URI_MALFORMED); // Malformed payto - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "credit_account": "http://email@test.com" })) .await .assert_error(ErrorCode::GENERIC_JSON_INVALID); @@ -507,8 +495,8 @@ pub async fn transfer_routine( "no.transport.com/", "https://not.a/base/url", ] { - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "exchange_base_url": base_url })) .await .assert_error(ErrorCode::GENERIC_JSON_INVALID); @@ -516,8 +504,8 @@ pub async fn transfer_routine( // Malformed metadata for metadata in ["bad_id", "bad id", "bad@id.com", &"A".repeat(41)] { - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "metadata": metadata })) .await .assert_error(ErrorCode::GENERIC_JSON_INVALID); @@ -527,8 +515,8 @@ pub async fn transfer_routine( // Check transfer by id errors { // Check unknown transaction - server - .get("/taler-wire-gateway/transfers/42") + wire_gateway + .get("/transfers/42") .await .assert_error(ErrorCode::BANK_TRANSACTION_NOT_FOUND); } @@ -536,8 +524,8 @@ pub async fn transfer_routine( // Check transfer page { for _ in 0..4 { - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(&json!(valid_req + { "request_uid": HashCode::rand(), "wtid": ShortHashCode::rand(), @@ -546,18 +534,15 @@ pub async fn transfer_routine( .assert_ok_json::<TransferResponse>(); } { - let list = server - .get("/taler-wire-gateway/transfers") + let list = wire_gateway + .get("/transfers") .await .assert_ok_json::<TransferList>(); assert_eq!(list.transfers.len(), 6); assert_eq!( list, - server - .get(format!( - "/taler-wire-gateway/transfers?status={}", - default_status.as_ref() - )) + wire_gateway + .get(format!("/transfers?status={}", default_status.as_ref())) .await .assert_ok_json::<TransferList>() ) @@ -565,11 +550,10 @@ pub async fn transfer_routine( // Pagination test routine_pagination::<TransferList>( - server, - "/taler-wire-gateway/transfers", + &wire_gateway.suffix("/transfers"), crate::tasks!({ - server - .post("/taler-wire-gateway/transfer") + wire_gateway + .post("/transfer") .json(json!({ "request_uid": HashCode::rand(), "amount": amount(format!("{currency}:0.1")), @@ -586,22 +570,23 @@ pub async fn transfer_routine( } async fn add_incoming_routine( - server: &Router, + wire_gateway: &Router, + prepared_transfer: &Router, currency: &str, kind: IncomingType, debit_acount: &PaytoURI, credit_account: &PaytoURI, ) { let (path, key) = match kind { - IncomingType::reserve => ("/taler-wire-gateway/admin/add-incoming", "reserve_pub"), - IncomingType::kyc => ("/taler-wire-gateway/admin/add-kycauth", "account_pub"), - IncomingType::map => ("/taler-wire-gateway/admin/add-mapped", "authorization_pub"), + IncomingType::reserve => ("/admin/add-incoming", "reserve_pub"), + IncomingType::kyc => ("/admin/add-kycauth", "account_pub"), + IncomingType::map => ("/admin/add-mapped", "authorization_pub"), }; let key_pair = Ed25519KeyPair::generate().unwrap(); let pub_key = EddsaPublicKey::try_from(key_pair.public_key().as_ref()).unwrap(); // Valid - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(json!({ "credit_account": credit_account, "type": "reserve", @@ -621,12 +606,12 @@ async fn add_incoming_routine( }); // Check OK - server.post(path).json(&valid_req).await.assert_ok(); + wire_gateway.post(path).json(&valid_req).await.assert_ok(); match kind { IncomingType::reserve => { // Trigger conflict due to reused reserve_pub - server + wire_gateway .post(path) .json(&json!(valid_req + { "amount": format!("{currency}:44.1"), @@ -636,17 +621,17 @@ async fn add_incoming_routine( } IncomingType::kyc => { // Non conflict on reuse - server.post(path).json(&valid_req).await.assert_ok(); + wire_gateway.post(path).json(&valid_req).await.assert_ok(); } IncomingType::map => { // Trigger conflict due to reused authorization_pub - server + wire_gateway .post(path) .json(&valid_req) .await .assert_error(ErrorCode::BANK_TRANSFER_MAPPING_REUSED); // Trigger conflict due to unknown authorization_pub - server + wire_gateway .post(path) .json(&json!(valid_req + { key: EddsaPublicKey::rand() @@ -657,33 +642,33 @@ async fn add_incoming_routine( } // Currency mismatch - server + wire_gateway .post(path) .json(&json!(valid_req + { "amount": "BAD:33" })) .await .assert_error(ErrorCode::GENERIC_CURRENCY_MISMATCH); // Bad BASE32 reserve_pub - server + wire_gateway .post(path) .json(&json!(valid_req + { key: "I love chocolate" })) .await .assert_error(ErrorCode::GENERIC_JSON_INVALID); - server + wire_gateway .post(path) .json(&json!(valid_req + { key: Base32::<31>::rand() })) .await .assert_error(ErrorCode::GENERIC_JSON_INVALID); // Unsupported payto kind - server + wire_gateway .post(path) .json(&json!(valid_req + { "debit_account": UNKNOWN })) .await .assert_error(ErrorCode::GENERIC_PAYTO_URI_MALFORMED); // Malformed payto - server + wire_gateway .post(path) .json(&json!(valid_req + { "debit_account": "http://email@test.com" })) .await @@ -788,20 +773,20 @@ macro_rules! tasks { /// Test standard behavior of the revenue endpoints pub async fn revenue_routine( - server: &Router, + wire_gateway: &Router, + revenue_api: &Router, debit_acount: &PaytoURI, kyc: bool, register: Tasks<impl AsyncFnMut(usize)>, ignore: Tasks<impl AsyncFnMut(usize)>, ) { - let currency = &get_currency(server).await; + let currency = &get_currency(revenue_api).await; routine_history::<RevenueIncomingHistory>( - server, - "/taler-revenue/history", + &revenue_api.suffix("/history"), tasks!(register; { - server - .post("/taler-wire-gateway/admin/add-incoming") + wire_gateway + .post("/admin/add-incoming") .json(json!({ "amount": format!("{currency}:1"), "reserve_pub": EddsaPublicKey::rand(), @@ -811,8 +796,8 @@ pub async fn revenue_routine( .assert_ok_json::<TransferResponse>(); }, if kyc => { - server - .post("/taler-wire-gateway/admin/add-kycauth") + wire_gateway + .post("/admin/add-kycauth") .json(json!({ "amount": format!("{currency}:2"), "account_pub": EddsaPublicKey::rand(), @@ -829,38 +814,33 @@ pub async fn revenue_routine( /// Test standard behavior of the outgoing history endpoint pub async fn out_history_routine( - server: &Router, + wire_gateway: &Router, register: Tasks<impl AsyncFnMut(usize)>, ignore: Tasks<impl AsyncFnMut(usize)>, ) { - routine_history::<OutgoingHistory>( - server, - "/taler-wire-gateway/history/outgoing", - register, - ignore, - ) - .await; + routine_history::<OutgoingHistory>(&wire_gateway.suffix("/history/outgoing"), register, ignore) + .await; } /// Test standard behavior of the incoming history endpoint pub async fn in_history_routine( - server: &Router, + wire_gateway: &Router, + prepared_transfer: &Router, debit_account: &PaytoURI, credit_account: &PaytoURI, kyc: bool, register: Tasks<impl AsyncFnMut(usize)>, ignored: Tasks<impl AsyncFnMut(usize)>, ) { - let currency = &get_currency(server).await; + let currency = &get_currency(wire_gateway).await; let mut key = Ed25519KeyPair::generate().unwrap(); routine_history::<IncomingHistory>( - server, - "/taler-wire-gateway/history/incoming", + &wire_gateway.suffix("/history/incoming"), tasks!(register; { - server - .post("/taler-wire-gateway/admin/add-incoming") + wire_gateway + .post("/admin/add-incoming") .json(json!({ "amount": format!("{currency}:1"), "reserve_pub": EddsaPublicKey::rand(), @@ -874,8 +854,8 @@ pub async fn in_history_routine( let auth_pub = EddsaPublicKey::try_from(key.public_key().as_ref()).unwrap(); let reserve_pub = EddsaPublicKey::rand(); let amount = format!("{currency}:2"); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(json!({ "credit_account": credit_account, "credit_amount": amount, @@ -888,8 +868,8 @@ pub async fn in_history_routine( })) .await .assert_ok_json::<RegistrationResponse>(); - server - .post("/taler-wire-gateway/admin/add-mapped") + wire_gateway + .post("/admin/add-mapped") .json(json!({ "amount": amount, "authorization_pub": auth_pub, @@ -897,8 +877,8 @@ pub async fn in_history_routine( })) .await .assert_ok_json::<TransferResponse>(); - server - .post("/taler-wire-gateway/admin/add-mapped") + wire_gateway + .post("/admin/add-mapped") .json(json!({ "amount": amount, "authorization_pub": auth_pub, @@ -910,8 +890,8 @@ pub async fn in_history_routine( { let auth_pub = EddsaPublicKey::try_from(key.public_key().as_ref()).unwrap(); let reserve_pub = EddsaPublicKey::rand(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(json!({ "credit_account": credit_account, "credit_amount": format!("{currency}:3"), @@ -926,8 +906,8 @@ pub async fn in_history_routine( .assert_ok_json::<RegistrationResponse>(); }, if kyc => { - server - .post("/taler-wire-gateway/admin/add-kycauth") + wire_gateway + .post("/admin/add-kycauth") .json(json!({ "amount": format!("{currency}:4"), "account_pub": EddsaPublicKey::rand(), @@ -941,8 +921,8 @@ pub async fn in_history_routine( let auth_pub = EddsaPublicKey::try_from(key.public_key().as_ref()).unwrap(); let account_pub = EddsaPublicKey::rand(); let amount = format!("{currency}:5"); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(json!({ "credit_account": credit_account, "credit_amount": amount, @@ -955,8 +935,8 @@ pub async fn in_history_routine( })) .await .assert_ok_json::<RegistrationResponse>(); - server - .post("/taler-wire-gateway/admin/add-mapped") + wire_gateway + .post("/admin/add-mapped") .json(json!({ "amount": amount, "authorization_pub": auth_pub, @@ -964,8 +944,8 @@ pub async fn in_history_routine( })) .await .assert_ok_json::<TransferResponse>(); - server - .post("/taler-wire-gateway/admin/add-mapped") + wire_gateway + .post("/admin/add-mapped") .json(json!({ "amount": amount, "authorization_pub": auth_pub, @@ -977,8 +957,8 @@ pub async fn in_history_routine( if kyc => { let auth_pub = EddsaPublicKey::try_from(key.public_key().as_ref()).unwrap(); let account_pub = EddsaPublicKey::rand(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(json!({ "credit_account": credit_account, "credit_amount": format!("{currency}:6"), @@ -1000,14 +980,16 @@ pub async fn in_history_routine( /// Test standard behavior of the admin add incoming endpoints pub async fn admin_add_incoming_routine( - server: &Router, + wire_gateway: &Router, + prepared_transfer: &Router, debit_acount: &PaytoURI, credit_account: &PaytoURI, kyc: bool, ) { - let currency = &get_currency(server).await; + let currency = &get_currency(wire_gateway).await; add_incoming_routine( - server, + wire_gateway, + prepared_transfer, currency, IncomingType::reserve, debit_acount, @@ -1015,7 +997,8 @@ pub async fn admin_add_incoming_routine( ) .await; add_incoming_routine( - server, + wire_gateway, + prepared_transfer, currency, IncomingType::map, debit_acount, @@ -1024,7 +1007,8 @@ pub async fn admin_add_incoming_routine( .await; if kyc { add_incoming_routine( - server, + wire_gateway, + prepared_transfer, currency, IncomingType::kyc, debit_acount, @@ -1046,7 +1030,8 @@ pub enum Status { /// Test standard registration behavior of the registration endpoints pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( - server: &Router, + wire_gateway: &Router, + prepared_transfer: &Router, debit_acount: &PaytoURI, credit_account: &PaytoURI, unknown_account: &PaytoURI, @@ -1058,7 +1043,7 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( assert_eq!(state, current); }; - let currency = &get_currency(server).await; + let currency = &get_currency(wire_gateway).await; let amount = amount(format!("{currency}:42")); let key_pair1 = Ed25519KeyPair::generate().unwrap(); let auth_pub1 = EddsaPublicKey::try_from(key_pair1.public_key().as_ref()).unwrap(); @@ -1074,8 +1059,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( }); let register = async |auth_pub: &EddsaPublicKey| { - server - .post("/taler-wire-gateway/admin/add-mapped") + wire_gateway + .post("/admin/add-mapped") .json(json!({ "amount": format!("{currency}:42"), "authorization_pub": auth_pub, @@ -1097,8 +1082,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( "recurrent": recurrent }); // Valid - let res = server - .post("/taler-prepared-transfer/registration") + let res = prepared_transfer + .post("/registration") .json(&req) .await .assert_ok_json::<RegistrationResponse>(); @@ -1106,8 +1091,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( // Idempotent assert_eq!( res, - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&req) .await .assert_ok_json::<RegistrationResponse>() @@ -1133,36 +1118,36 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( } // Bad signature - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "authorization_sig": eddsa_sign(&key_pair1, b"lol")})) .await .assert_error(ErrorCode::BANK_BAD_SIGNATURE); // Unknown account - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "credit_account": unknown_account })) .await .assert_error(ErrorCode::BANK_UNKNOWN_CREDITOR); // Unsupported payto kind - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "credit_account": UNKNOWN })) .await .assert_error(ErrorCode::GENERIC_PAYTO_URI_MALFORMED); // Malformed payto - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + {"credit_account": "http://email@test.com" })) .await .assert_error(ErrorCode::GENERIC_JSON_INVALID); // Reserve pub reuse - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "account_pub": acc_pub1, "authorization_sig": eddsa_sign(&key_pair1, acc_pub1.as_ref()), @@ -1172,8 +1157,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( { let key_pair = Ed25519KeyPair::generate().unwrap(); let auth_pub = EddsaPublicKey::try_from(key_pair.public_key().as_ref()).unwrap(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "account_pub": acc_pub1, "authorization_pub": auth_pub, @@ -1184,8 +1169,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( } // Non recurrent accept one then bounce - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "account_pub": acc_pub1, "authorization_sig": eddsa_sign(&key_pair1, acc_pub1.as_ref()), @@ -1202,16 +1187,16 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( // Again without using mapping let acc_pub2 = EddsaPublicKey::rand(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "account_pub": acc_pub2, "authorization_sig": eddsa_sign(&key_pair1, acc_pub2.as_ref()), })) .await .assert_ok_json::<RegistrationResponse>(); - server - .post("/taler-wire-gateway/admin/add-incoming") + wire_gateway + .post("/admin/add-incoming") .json(json!({ "amount": amount, "reserve_pub": acc_pub2, @@ -1226,8 +1211,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( // Recurrent accept one and delay others let acc_pub3 = EddsaPublicKey::rand(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "account_pub": acc_pub3, "authorization_sig": eddsa_sign(&key_pair1, acc_pub3.as_ref()), @@ -1253,8 +1238,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( // Complete pending on recurrent update let acc_pub4 = EddsaPublicKey::rand(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "type": "kyc", "account_pub": acc_pub4, @@ -1263,8 +1248,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( })) .await .assert_ok_json::<RegistrationResponse>(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "account_pub": acc_pub4, "authorization_sig": eddsa_sign(&key_pair1, acc_pub4.as_ref()), @@ -1284,8 +1269,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( .await; // Kyc key reuse keep pending ones - server - .post("/taler-wire-gateway/admin/add-kycauth") + wire_gateway + .post("/admin/add-kycauth") .json(json!({ "amount": amount, "account_pub": acc_pub4, @@ -1308,8 +1293,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( // Switching to non recurrent cancel pending let auth_pair = Ed25519KeyPair::generate().unwrap(); let auth_pub2 = EddsaPublicKey::try_from(auth_pair.public_key().as_ref()).unwrap(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "account_pub": auth_pub2, "authorization_pub": auth_pub2, @@ -1337,8 +1322,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( Pending, ]) .await; - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "type": "kyc", "account_pub": auth_pub2, @@ -1365,8 +1350,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( // Recurrent reserve simple subject let acc_pub5 = EddsaPublicKey::rand(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "type": "reserve", "account_pub": acc_pub5, @@ -1376,8 +1361,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( })) .await .assert_ok_json::<RegistrationResponse>(); - server - .post("/taler-wire-gateway/admin/add-incoming") + wire_gateway + .post("/admin/add-incoming") .json(json!({ "amount": amount, "reserve_pub": acc_pub5, @@ -1406,8 +1391,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( .await; // Recurrent kyc simple subject - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "type": "kyc", "account_pub": acc_pub5, @@ -1417,8 +1402,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( })) .await .assert_ok_json::<RegistrationResponse>(); - server - .post("/taler-prepared-transfer/registration") + prepared_transfer + .post("/registration") .json(&json!(req + { "type": "kyc", "account_pub": acc_pub5, @@ -1428,8 +1413,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( })) .await .assert_ok_json::<RegistrationResponse>(); - server - .post("/taler-wire-gateway/admin/add-kycauth") + wire_gateway + .post("/admin/add-kycauth") .json(json!({ "amount": amount, "account_pub": acc_pub5, @@ -1471,8 +1456,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( }); // Delete - server - .post("/taler-prepared-transfer/unregistration") + prepared_transfer + .post("/unregistration") .json(&un_req) .await .assert_no_content(); @@ -1499,15 +1484,15 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( .await; // Idempotent - server - .post("/taler-prepared-transfer/unregistration") + prepared_transfer + .post("/unregistration") .json(&un_req) .await .assert_error(ErrorCode::BANK_TRANSACTION_NOT_FOUND); // Bad signature - server - .post("/taler-prepared-transfer/unregistration") + prepared_transfer + .post("/unregistration") .json(&json!(un_req + { "authorization_sig": eddsa_sign(&auth_pair, b"lol"), })) @@ -1516,8 +1501,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( // Old timestamp let now = (Timestamp::now() - SignedDuration::from_mins(10)).to_string(); - server - .post("/taler-prepared-transfer/unregistration") + prepared_transfer + .post("/unregistration") .json(json!({ "timestamp": now, "authorization_pub": auth_pub2, @@ -1528,8 +1513,8 @@ pub async fn registration_routine<F1: Future<Output = Vec<Status>>>( /* ----- API ----- */ - let history: Vec<_> = server - .get("/taler-wire-gateway/history/incoming?limit=20") + let history: Vec<_> = wire_gateway + .get("/history/incoming?limit=20") .await .assert_ok_json::<IncomingHistory>() .incoming_transactions diff --git a/common/taler-test-utils/src/server.rs b/common/taler-test-utils/src/server.rs @@ -37,6 +37,7 @@ use url::Url; pub trait TestServer { fn prefix(&self, prefix: &'static str) -> Self; + fn suffix(&self, suffix: &'static str) -> Self; fn request(&self, method: Method, path: impl AsRef<str>) -> TestRequest; @@ -67,8 +68,8 @@ impl TestServer for Router { let current_path = path_and_query.path(); let new_path_and_query = match path_and_query.query() { - Some(query) => format!("{prefix}{}?{}", current_path, query), - None => format!("{prefix}{}", current_path), + Some(query) => format!("{prefix}{current_path}?{query}"), + None => format!("{prefix}{current_path}"), }; let new_pq = PathAndQuery::from_maybe_shared(new_path_and_query).unwrap(); @@ -79,6 +80,30 @@ impl TestServer for Router { )) } + fn suffix(&self, suffix: &'static str) -> Self { + Router::new() + .fallback_service(self.clone().into_service()) + .layer(middleware::map_request_with_state( + suffix.trim_start_matches('/'), + async |State(suffix): State<&'static str>, mut req: Request| { + let uri = req.uri().clone(); + let mut parts = uri.into_parts(); + + let path_and_query = parts.path_and_query.unwrap(); + let current_path = path_and_query.path(); + + let new_path_and_query = match path_and_query.query() { + Some(query) => format!("{current_path}{suffix}?{query}"), + None => format!("{current_path}{suffix}"), + }; + let new_pq = PathAndQuery::from_maybe_shared(new_path_and_query).unwrap(); + parts.path_and_query = Some(new_pq); + *req.uri_mut() = Uri::from_parts(parts).unwrap(); + req + }, + )) + } + fn request(&self, method: Method, path: impl AsRef<str>) -> TestRequest { let url = format!("https://example{}", path.as_ref()); TestRequest { diff --git a/taler-cyclos/src/api.rs b/taler-cyclos/src/api.rs @@ -419,7 +419,12 @@ mod test { #[tokio::test] async fn transfer() { let (server, _) = setup().await; - transfer_routine(&server, TransferState::pending, &EXCHANGE).await; + transfer_routine( + &server.prefix("/taler-wire-gateway"), + TransferState::pending, + &EXCHANGE, + ) + .await; } static CODE: AtomicI64 = AtomicI64::new(0); @@ -490,7 +495,7 @@ mod test { let (server, db) = &setup().await; out_history_routine( - server, + &server.prefix("/taler-wire-gateway"), tasks!({ out_talerable(db).await }), tasks!( { out_bounce(db).await }, @@ -505,14 +510,22 @@ mod test { #[tokio::test] async fn admin_add_incoming() { let (server, _) = setup().await; - admin_add_incoming_routine(&server, &EXCHANGE, &EXCHANGE, true).await; + admin_add_incoming_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), + &EXCHANGE, + &EXCHANGE, + true, + ) + .await; } #[tokio::test] async fn in_history() { let (server, db) = &setup().await; in_history_routine( - server, + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), &EXCHANGE, &EXCHANGE, true, @@ -531,7 +544,8 @@ mod test { async fn revenue() { let (server, db) = &setup().await; revenue_routine( - server, + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-revenue"), &EXCHANGE, true, tasks!({ in_malformed(db).await }, { in_talerable(db).await },), @@ -577,6 +591,14 @@ mod test { #[tokio::test] async fn registration() { let (server, pool) = setup().await; - registration_routine(&server, &EXCHANGE, &EXCHANGE, &UNKNOWN, || check_in(&pool)).await; + registration_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), + &EXCHANGE, + &EXCHANGE, + &UNKNOWN, + || check_in(&pool), + ) + .await; } } diff --git a/taler-magnet-bank/src/api.rs b/taler-magnet-bank/src/api.rs @@ -388,7 +388,7 @@ mod test { async fn transfer() { let (server, _) = setup().await; transfer_routine( - &server, + &server.prefix("/taler-wire-gateway"), TransferState::pending, &payto("payto://iban/HU02162000031000164800000000?receiver-name=name"), ) @@ -458,9 +458,8 @@ mod test { #[tokio::test] async fn outgoing_history() { let (server, db) = &setup().await; - out_history_routine( - server, + &server.prefix("/taler-wire-gateway"), tasks!({ out_talerable(db).await }), tasks!( { out_bounce(db).await }, @@ -475,14 +474,22 @@ mod test { #[tokio::test] async fn admin_add_incoming() { let (server, _) = setup().await; - admin_add_incoming_routine(&server, &EXCHANGE, &EXCHANGE, true).await; + admin_add_incoming_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), + &EXCHANGE, + &EXCHANGE, + true, + ) + .await; } #[tokio::test] async fn in_history() { let (server, db) = &setup().await; in_history_routine( - server, + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), &EXCHANGE, &EXCHANGE, true, @@ -501,7 +508,8 @@ mod test { async fn revenue() { let (server, db) = &setup().await; revenue_routine( - server, + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-revenue"), &EXCHANGE, true, tasks!({ in_malformed(db).await }, { in_talerable(db).await },), @@ -547,6 +555,14 @@ mod test { #[tokio::test] async fn registration() { let (server, pool) = setup().await; - registration_routine(&server, &EXCHANGE, &EXCHANGE, &UNKNOWN, || check_in(&pool)).await; + registration_routine( + &server.prefix("/taler-wire-gateway"), + &server.prefix("/taler-prepared-transfer"), + &EXCHANGE, + &EXCHANGE, + &UNKNOWN, + || check_in(&pool), + ) + .await; } }