libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 135a9c1f8e4bb1dd6e84dd22a128ac2fff227d26
parent 383e645c13606f9705b3e507c08e9c0dfb17d592
Author: Antoine A <>
Date:   Thu,  1 Oct 2026 14:05:05 +0200

common: sync taler-rust

Diffstat:
MCargo.lock | 30++++++++++++++++--------------
Mlibeufin-bank/src/api.rs | 28+++++++++++++++-------------
Mlibeufin-bank/src/api/account.rs | 32+++++++++++++++++---------------
Mlibeufin-bank/src/api/cashout.rs | 8+++++---
Mlibeufin-bank/src/api/conversion.rs | 14++++++++------
Mlibeufin-bank/src/api/observability.rs | 8+++++---
Mlibeufin-bank/src/api/prepared.rs | 12++++++++----
Mlibeufin-bank/src/api/revenue.rs | 8+++++---
Mlibeufin-bank/src/api/tan.rs | 29++++++++++++++---------------
Mlibeufin-bank/src/api/token.rs | 14++++++++------
Mlibeufin-bank/src/api/tx.rs | 20+++++++++++---------
Mlibeufin-bank/src/api/wire.rs | 32+++++++++++++++++---------------
Mlibeufin-bank/src/api/withdrawal.rs | 8+++++---
Mlibeufin-bank/src/bench.rs | 8+++++---
Alibeufin-bank/src/constants.rs | 23+++++++++++++++++++++++
Mlibeufin-bank/src/db.rs | 20+++++++++++---------
Mlibeufin-bank/src/lib.rs | 6++----
Mlibeufin-bank/src/main.rs | 2+-
Mlibeufin-ebisync/src/config.rs | 5+----
Alibeufin-ebisync/src/constants.rs | 27+++++++++++++++++++++++++++
Mlibeufin-ebisync/src/db.rs | 16+++++-----------
Mlibeufin-ebisync/src/lib.rs | 18++++++++----------
Mlibeufin-ebisync/src/main.rs | 2+-
Mlibeufin-nexus/src/api.rs | 64++++++++++++++++++++++++++++------------------------------------
Mlibeufin-nexus/src/bench.rs | 8+++++---
Alibeufin-nexus/src/constants.rs | 28++++++++++++++++++++++++++++
Mlibeufin-nexus/src/db.rs | 14++++----------
Mlibeufin-nexus/src/db/initiated.rs | 21+++++++++------------
Mlibeufin-nexus/src/db/payment.rs | 51++++++++++++++++++++-------------------------------
Mlibeufin-nexus/src/fetch.rs | 62++++++++++++++++++++++++++++++--------------------------------
Mlibeufin-nexus/src/lib.rs | 12+++---------
Mlibeufin-nexus/src/list.rs | 10+++++-----
Mlibeufin-nexus/src/main.rs | 2+-
Mlibeufin-nexus/src/test.rs | 30+++++++++++++++++-------------
Mtestbench/Cargo.toml | 1+
Mtestbench/src/integration.rs | 35+++++++++++++++--------------------
Mtestbench/src/lib.rs | 10+++++++---
Mtestbench/src/main.rs | 4++--
38 files changed, 393 insertions(+), 329 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -1366,7 +1366,7 @@ dependencies = [ [[package]] name = "http-client" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326" +source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18" dependencies = [ "compact_str", "futures-util", @@ -1784,9 +1784,9 @@ checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" [[package]] name = "lazy_static" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb" dependencies = [ "spin", ] @@ -2442,9 +2442,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.18" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9746dbde176634f4f2f1faf2404e30a31b2bc1e9cafb5329c95d8177a18c9fc" +checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe" dependencies = [ "aws-lc-rs", "bytes", @@ -2465,9 +2465,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +checksum = "af66907df18639dcf4db56ca65490cabc4b27a97dbadd96f2926cca73298f016" dependencies = [ "cfg_aliases", "libc", @@ -3529,7 +3529,7 @@ dependencies = [ [[package]] name = "taler-api" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326" +source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18" dependencies = [ "aws-lc-rs", "axum", @@ -3547,6 +3547,7 @@ dependencies = [ "serde_urlencoded", "sqlx", "taler-common", + "taler-macros", "thiserror", "tokio", "tower-http 0.7.1", @@ -3558,12 +3559,12 @@ dependencies = [ [[package]] name = "taler-build" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326" +source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18" [[package]] name = "taler-common" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326" +source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18" dependencies = [ "anyhow", "aws-lc-rs", @@ -3593,7 +3594,7 @@ dependencies = [ [[package]] name = "taler-macros" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326" +source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18" dependencies = [ "proc-macro2", "quote", @@ -3603,7 +3604,7 @@ dependencies = [ [[package]] name = "taler-test-utils" version = "1.5.0" -source = "git+git://git.taler.net/taler-rust.git/#3f6a0fd79c5c9f294536810a2edb2f5419acf326" +source = "git+git://git.taler.net/taler-rust.git/#7bfaf2c5e3f7ee89c29cc9175da77ee7cb582b18" dependencies = [ "aws-lc-rs", "axum", @@ -3662,6 +3663,7 @@ dependencies = [ "sqlx", "taler-api", "taler-common", + "taler-macros", "taler-test-utils", "tokio", "tracing", @@ -4603,9 +4605,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", diff --git a/libeufin-bank/src/api.rs b/libeufin-bank/src/api.rs @@ -327,27 +327,27 @@ pub mod test { use compact_str::{CompactString, CompactStringExt}; use jiff::Timestamp; use rand::{random_range, seq::IndexedRandom}; - use sqlx::PgPool; + use sqlx::{PgPool, postgres::PgConnectOptions}; use taler_api::{api::TalerRouter, db::BindHelper}; use taler_common::{ api::{EddsaPublicKey, HashCode, ShortHashCode}, config::Config, - db::dbinit, + db::{dbinit, pool}, error_code::ErrorCode, types::{ amount::{Amount, Decimal, decimal}, payto::PaytoURI, }, }; + use taler_macros::db_test; use taler_test_utils::{ - db::db_test_setup_manual, json, server::{TestRequest, TestResponse, TestServer as _}, }; use uuid::Uuid; use crate::{ - CONFIG_SOURCE, TanChannel, + TanChannel, api::{ BankState, account::{ @@ -359,6 +359,7 @@ pub mod test { withdrawal::BankAccountCreateWithdrawalResponse, }, config::BankCfg, + constants::CONFIG_SOURCE, db::{self, account::CreationResult}, mfa::TALER_CHALLENGE_IDS, payto::BankPayto, @@ -653,11 +654,12 @@ pub mod test { } impl BankTestCtx { - pub async fn new(conf: &str) -> Self { + pub async fn new(options: PgConnectOptions, conf: &str) -> Self { let cfg = Config::load(CONFIG_SOURCE, Some(format!("conf/{conf}"))).unwrap(); let cfg = BankCfg::parse(&cfg).unwrap(); let dir = cfg.db_cfg.sql_dir.as_ref(); - let (mut conn, db) = db_test_setup_manual(dir, "libeufin-bank").await; + let db = pool(options, "libeufin_bank").await.unwrap(); + let mut conn = db.acquire().await.unwrap(); dbinit(&mut conn, dir, "libeufin-bank", true).await.unwrap(); dbinit(&mut conn, dir, "libeufin-nexus", true) .await @@ -927,12 +929,12 @@ pub mod test { } } - pub async fn bank_setup() -> BankTestCtx { - bank_setup_conf("test.conf").await + pub async fn bank_setup(db: PgConnectOptions) -> BankTestCtx { + bank_setup_conf(db, "test.conf").await } - pub async fn bank_setup_conf(conf: &str) -> BankTestCtx { - BankTestCtx::new(conf).await + pub async fn bank_setup_conf(db: PgConnectOptions, conf: &str) -> BankTestCtx { + BankTestCtx::new(db, conf).await } pub fn tan_code(info: &str) -> Option<CompactString> { @@ -1030,10 +1032,10 @@ pub mod test { } } - #[tokio::test] - async fn corebank() { + #[db_test(raw)] + async fn corebank(db: PgConnectOptions) { use crate::api::MonitorResponse; - let ctx = bank_setup().await; + let ctx = bank_setup(db).await; ctx.auth_routine(Method::GET, "/monitor", Auth::Admin).await; diff --git a/libeufin-bank/src/api/account.rs b/libeufin-bank/src/api/account.rs @@ -913,10 +913,12 @@ pub mod test { use axum::http::{Method, StatusCode}; use jiff::Timestamp; use serde::Serialize; + use sqlx::postgres::PgConnectOptions; use taler_common::{ error_code::ErrorCode, types::{amount::amount, payto::PaytoImpl}, }; + use taler_macros::db_test; use taler_test_utils::{json, server::TestServer as _}; use crate::{ @@ -934,9 +936,9 @@ pub mod test { payto::FullBankPayto, }; - #[tokio::test] - async fn create() { - let mut ctx = bank_setup().await; + #[db_test(raw)] + async fn create(db: PgConnectOptions) { + let mut ctx = bank_setup(db).await; let admin_only = async |body: serde_json::Value, error: ErrorCode| { // Check restricted @@ -1400,9 +1402,9 @@ pub mod test { .assert_ok(); } - #[tokio::test] - async fn delete() { - let mut ctx = bank_setup().await; + #[db_test(raw)] + async fn delete(db: PgConnectOptions) { + let mut ctx = bank_setup(db).await; ctx.auth_routine(Method::DELETE, "/accounts/merchant", Auth::UserOrAdmin) .await; @@ -1498,9 +1500,9 @@ pub mod test { .assert_no_content(); } - #[tokio::test] - async fn reconfig() { - let mut ctx = bank_setup().await; + #[db_test(raw)] + async fn reconfig(db: PgConnectOptions) { + let mut ctx = bank_setup(db).await; ctx.auth_routine(Method::PATCH, "/accounts/merchant", Auth::UserOrAdmin) .await; @@ -1722,9 +1724,9 @@ pub mod test { .assert_error(ErrorCode::BANK_TAN_CHANNEL_NOT_SUPPORTED); } - #[tokio::test] - async fn password() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn password(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.auth_routine(Method::PATCH, "/accounts/merchant/auth", Auth::UserOrAdmin) .await; @@ -1841,9 +1843,9 @@ pub mod test { .assert_no_content(); } - #[tokio::test] - async fn list() { - let ctx = bank_setup_conf("test_no_conversion.conf").await; + #[db_test(raw)] + async fn list(db: PgConnectOptions) { + let ctx = bank_setup_conf(db, "test_no_conversion.conf").await; ctx.auth_routine(Method::GET, "/accounts", Auth::Admin) .await; diff --git a/libeufin-bank/src/api/cashout.rs b/libeufin-bank/src/api/cashout.rs @@ -219,7 +219,9 @@ pub fn cashout_api(state: Arc<BankState>) -> Router<Arc<BankState>> { #[cfg(test)] pub mod test { use axum::http::Method; + use sqlx::postgres::PgConnectOptions; use taler_common::{api::ShortHashCode, error_code::ErrorCode, types::amount::amount}; + use taler_macros::db_test; use taler_test_utils::{ json, routine::{Page, routine_pagination}, @@ -233,9 +235,9 @@ pub mod test { test::{Auth, MfaRequest, bank_setup}, }; - #[tokio::test] - async fn cashout() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn cashout(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.auth_routine(Method::POST, "/accounts/merchant/cashouts", Auth::UserOnly) .await; diff --git a/libeufin-bank/src/api/conversion.rs b/libeufin-bank/src/api/conversion.rs @@ -586,7 +586,9 @@ pub fn conversion_api(state: Arc<BankState>) -> Router<Arc<BankState>> { pub mod test { use axum::http::Method; + use sqlx::postgres::PgConnectOptions; use taler_common::{error_code::ErrorCode, types::amount::amount}; + use taler_macros::db_test; use taler_test_utils::{json, server::TestServer}; use crate::api::{ @@ -597,9 +599,9 @@ pub mod test { test::{Auth, bank_setup}, }; - #[tokio::test] - async fn rates() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn rates(db: PgConnectOptions) { + let ctx = bank_setup(db).await; // Auth for path in [ @@ -867,9 +869,9 @@ pub mod test { } } - #[tokio::test] - async fn classes() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn classes(db: PgConnectOptions) { + let ctx = bank_setup(db).await; // Config for prefix in ["", "/conversion-rate-classes/1", "/accounts/merchant"] { diff --git a/libeufin-bank/src/api/observability.rs b/libeufin-bank/src/api/observability.rs @@ -62,13 +62,15 @@ pub fn observability_api() -> Router<Arc<BankState>> { #[cfg(test)] mod test { + use sqlx::postgres::PgConnectOptions; + use taler_macros::db_test; use taler_test_utils::server::TestServer as _; use crate::api::test::bank_setup; - #[tokio::test] - async fn observability() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn observability(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.get("/taler-observability/config").await.assert_ok(); ctx.get_admin("/taler-observability/metrics") diff --git a/libeufin-bank/src/api/prepared.rs b/libeufin-bank/src/api/prepared.rs @@ -125,7 +125,10 @@ pub fn prepared_api() -> Router<Arc<BankState>> { #[cfg(test)] mod test { use aws_lc_rs::signature::{Ed25519KeyPair, KeyPair as _}; - use sqlx::{Row as _, postgres::PgRow}; + use sqlx::{ + Row as _, + postgres::{PgConnectOptions, PgRow}, + }; use taler_api::db::TypeHelper as _; use taler_common::{ api::{ @@ -139,6 +142,7 @@ mod test { error_code::ErrorCode, types::amount::{Amount, Currency}, }; + use taler_macros::db_test; use taler_test_utils::{ json, routine::{Status, registration_routine}, @@ -147,9 +151,9 @@ mod test { use crate::api::test::bank_setup; - #[tokio::test] - async fn registration() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn registration(db: PgConnectOptions) { + let ctx = bank_setup(db).await; let key_pair = Ed25519KeyPair::generate().unwrap(); let auth_pub = EddsaPublicKey::try_from(key_pair.public_key().as_ref()).unwrap(); diff --git a/libeufin-bank/src/api/revenue.rs b/libeufin-bank/src/api/revenue.rs @@ -83,13 +83,15 @@ pub fn revenue_api() -> Router<Arc<BankState>> { #[cfg(test)] mod test { + use sqlx::postgres::PgConnectOptions; + use taler_macros::db_test; use taler_test_utils::{routine::revenue_routine, server::TestServer, tasks}; use crate::api::test::bank_setup; - #[tokio::test] - async fn revenue() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn revenue(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.set_max_debt("customer", "1000").await; let admin = ctx.admin_router().await; revenue_routine( diff --git a/libeufin-bank/src/api/tan.rs b/libeufin-bank/src/api/tan.rs @@ -173,7 +173,9 @@ pub fn tan_api() -> Router<Arc<BankState>> { #[cfg(test)] pub mod test { + use sqlx::postgres::PgConnectOptions; use taler_common::error_code::ErrorCode; + use taler_macros::db_test; use taler_test_utils::{json, server::TestResponse}; use uuid::Uuid; @@ -186,9 +188,9 @@ pub mod test { mfa::TALER_CHALLENGE_IDS, }; - #[tokio::test] - async fn send() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn send(db: PgConnectOptions) { + let ctx = bank_setup(db).await; let expect_mfa = async |res: TestResponse, and: bool, tans: &[(TanChannel, &str)]| { res.assert_challenge_check(&ctx, async |res| { @@ -416,9 +418,9 @@ pub mod test { .assert_error(ErrorCode::GENERIC_PATH_SEGMENT_MALFORMED); } - #[tokio::test] - async fn rate_limited() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn rate_limited(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.fill_tan_info("merchant").await; // TODO need transaction API @@ -479,9 +481,9 @@ pub mod test { .assert_error(ErrorCode::BANK_TAN_RATE_LIMITED); } - #[tokio::test] - async fn tan_err() { - let ctx = bank_setup_conf("test_tan_err.conf").await; + #[db_test(raw)] + async fn tan_err(db: PgConnectOptions) { + let ctx = bank_setup_conf(db, "test_tan_err.conf").await; ctx.fill_tan_info("merchant").await; let res: ChallengeResponse = ctx .patcha("/accounts/merchant") @@ -499,9 +501,9 @@ pub mod test { .assert_error(ErrorCode::BANK_TAN_CHANNEL_SCRIPT_FAILED); } - #[tokio::test] - async fn confirm() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn confirm(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.fill_tan_info("merchant").await; // Check simple case @@ -576,7 +578,4 @@ pub mod test { .assert_error(ErrorCode::BANK_TAN_CHALLENGE_EXPIRED); } } - - #[tokio::test] - async fn unique_challenge() {} } diff --git a/libeufin-bank/src/api/token.rs b/libeufin-bank/src/api/token.rs @@ -219,12 +219,14 @@ pub mod test { use axum::http::{Method, header::AUTHORIZATION}; use jiff::{SignedDuration, Timestamp}; + use sqlx::postgres::PgConnectOptions; use taler_api::db::TypeHelper; use taler_common::{ api::ErrorDetail, error_code::ErrorCode, types::{base32::Base32, time::TalerTimestamp}, }; + use taler_macros::db_test; use taler_test_utils::{json, server::TestServer}; use crate::{ @@ -239,9 +241,9 @@ pub mod test { mfa::TALER_CHALLENGE_IDS, }; - #[tokio::test] - async fn create_and_delete() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn create_and_delete(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.auth_routine(Method::POST, "/accounts/merchant/token", Auth::Token) .await; @@ -663,9 +665,9 @@ pub mod test { } } - #[tokio::test] - async fn get() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn get(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.auth_routine(Method::GET, "/accounts/merchant/tokens", Auth::UserOrAdmin) .await; diff --git a/libeufin-bank/src/api/tx.rs b/libeufin-bank/src/api/tx.rs @@ -201,6 +201,7 @@ pub fn tx_api() -> Router<Arc<BankState>> { pub mod test { use axum::http::Method; + use sqlx::postgres::PgConnectOptions; use taler_api::subject::{fmt_in_subject, fmt_out_subject}; use taler_common::{ api::{EddsaPublicKey, ShortHashCode}, @@ -208,6 +209,7 @@ pub mod test { error_code::ErrorCode, types::amount::amount, }; + use taler_macros::db_test; use taler_test_utils::{ json, routine::{Page, routine_history}, @@ -222,9 +224,9 @@ pub mod test { }, }; - #[tokio::test] - async fn tx() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn tx(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.auth_routine( Method::POST, @@ -480,9 +482,9 @@ pub mod test { .assert_error(ErrorCode::BANK_TRANSFER_REQUEST_UID_REUSED); } - #[tokio::test] - async fn tx_with_fee() { - let ctx = bank_setup_conf("test_with_fees.conf").await; + #[db_test(raw)] + async fn tx_with_fee(db: PgConnectOptions) { + let ctx = bank_setup_conf(db, "test_with_fees.conf").await; // Init state ctx.assert_balance("merchant", "0").await; @@ -534,9 +536,9 @@ pub mod test { } } - #[tokio::test] - async fn history() { - let ctx = &bank_setup().await; + #[db_test(raw)] + async fn history(db: PgConnectOptions) { + let ctx = &bank_setup(db).await; ctx.auth_routine( Method::POST, diff --git a/libeufin-bank/src/api/wire.rs b/libeufin-bank/src/api/wire.rs @@ -395,6 +395,7 @@ pub fn wire_api() -> Router<Arc<BankState>> { #[cfg(test)] pub mod test { use axum::http::Method; + use sqlx::postgres::PgConnectOptions; use taler_api::subject::fmt_out_subject; use taler_common::{ api::{ @@ -405,6 +406,7 @@ pub mod test { error_code::ErrorCode, types::amount::amount, }; + use taler_macros::db_test; use taler_test_utils::{ json, routine::{ @@ -416,9 +418,9 @@ pub mod test { use crate::api::test::{Auth, bank_setup}; - #[tokio::test] - async fn transfer() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn transfer(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.auth_routine( Method::POST, @@ -549,9 +551,9 @@ pub mod test { .assert_error(ErrorCode::BANK_TRANSACTION_NOT_FOUND); } - #[tokio::test] - async fn outgoing_history() { - let ctx = &bank_setup().await; + #[db_test(raw)] + async fn outgoing_history(db: PgConnectOptions) { + let ctx = &bank_setup(db).await; ctx.auth_routine( Method::GET, "/accounts/merchant/taler-wire-gateway/history/outgoing", @@ -598,9 +600,9 @@ pub mod test { .await; } - #[tokio::test] - async fn incoming_history() { - let ctx = &bank_setup().await; + #[db_test(raw)] + async fn incoming_history(db: PgConnectOptions) { + let ctx = &bank_setup(db).await; ctx.auth_routine( Method::GET, "/accounts/merchant/taler-wire-gateway/history/incoming", @@ -652,9 +654,9 @@ pub mod test { .await; } - #[tokio::test] - async fn admin_add_incoming() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn admin_add_incoming(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.auth_routine( Method::GET, "/accounts/merchant/taler-wire-gateway/history/incoming", @@ -705,9 +707,9 @@ pub mod test { .await; } - #[tokio::test] - async fn account_check() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn account_check(db: PgConnectOptions) { + let ctx = bank_setup(db).await; ctx.geta("/accounts/exchange/taler-wire-gateway/account/check") .await .assert_error(ErrorCode::GENERIC_PARAMETER_MISSING); diff --git a/libeufin-bank/src/api/withdrawal.rs b/libeufin-bank/src/api/withdrawal.rs @@ -466,11 +466,13 @@ mod test { use axum::http::{Method, StatusCode}; use serde::de::DeserializeOwned; + use sqlx::postgres::PgConnectOptions; use taler_common::{ api::EddsaPublicKey, error_code::ErrorCode, types::amount::{Currency, amount}, }; + use taler_macros::db_test; use taler_test_utils::{json, routine::assert_time, server::TestServer}; use tokio::join; use uuid::Uuid; @@ -604,9 +606,9 @@ mod test { ); } - #[tokio::test] - async fn withdrawal() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn withdrawal(db: PgConnectOptions) { + let ctx = bank_setup(db).await; let unknown = Uuid::new_v4(); ctx.auth_routine( diff --git a/libeufin-bank/src/bench.rs b/libeufin-bank/src/bench.rs @@ -23,6 +23,7 @@ use aws_lc_rs::signature::{Ed25519KeyPair, KeyPair as _}; use axum::http::header::AUTHORIZATION; use compact_str::{CompactString, format_compact}; use jiff::{Timestamp, Zoned, tz::TimeZone}; +use sqlx::postgres::PgConnectOptions; use taler_common::{ api::{ EddsaPublicKey, EddsaSignature, HashCode, ShortHashCode, @@ -37,6 +38,7 @@ use taler_common::{ time::TalerTimestamp, }, }; +use taler_macros::db_test; use taler_test_utils::{json, server::TestServer}; use uuid::Uuid; @@ -55,9 +57,9 @@ use crate::{ pw::PwCrypto, }; -#[tokio::test] -pub async fn bench_db() { - let mut ctx = bank_setup().await; +#[db_test(raw)] +pub async fn bench_db(db: PgConnectOptions) { + let mut ctx = bank_setup(db).await; let mut b = Bench::new(&ctx.state.db); // Skip 4 accounts created by bank_setup let skip = 4; diff --git a/libeufin-bank/src/constants.rs b/libeufin-bank/src/constants.rs @@ -0,0 +1,23 @@ +/* +* This file is part of LibEuFin. +* Copyright (C) 2026 Taler Systems S.A. + +* LibEuFin is free software; you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation; either version 3, or +* (at your option) any later version. + +* LibEuFin is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General +* Public License for more details. + +* You should have received a copy of the GNU Affero General Public +* License along with LibEuFin; see the file COPYING. If not, see +* <http://www.gnu.org/licenses/> +*/ + +use taler_common::config::parser::ConfigSource; + +pub const CONFIG_SOURCE: ConfigSource = + ConfigSource::new("libeufin", "libeufin-bank", "libeufin-bank"); diff --git a/libeufin-bank/src/db.rs b/libeufin-bank/src/db.rs @@ -233,6 +233,7 @@ mod test { use std::time::Duration; use jiff::Timestamp; + use sqlx::postgres::PgConnectOptions; use taler_common::{ error_code::ErrorCode::BANK_UNALLOWED_DEBIT, types::{ @@ -240,6 +241,7 @@ mod test { base32::Base32, }, }; + use taler_macros::db_test; use taler_test_utils::json; use uuid::Uuid; @@ -254,9 +256,9 @@ mod test { mfa::Operation, }; - #[tokio::test] - async fn amount_computation() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn amount_computation(db: PgConnectOptions) { + let ctx = bank_setup(db).await; sqlx::query( "UPDATE libeufin_bank.bank_accounts SET balance.val = 100000 WHERE internal_payto=$1", @@ -674,9 +676,9 @@ mod test { } } - #[tokio::test] - async fn statistics() { - let ctx = bank_setup().await; + #[db_test(raw)] + async fn statistics(db: PgConnectOptions) { + let ctx = bank_setup(db).await; for account in ["merchant", "exchange", "customer"] { ctx.set_max_debt(account, "1000").await; } @@ -771,13 +773,13 @@ mod test { monitor_cashout(3, "KUDOS:22.9", "EUR:28.83").await; } - #[tokio::test] - async fn tan_challenge() { + #[db_test(raw)] + async fn tan_challenge(db: PgConnectOptions) { const VALIDITY_PERIOD: Duration = Duration::from_hours(1); const RETRANSMISSION_PERIOD: Duration = Duration::from_mins(1); const RETRY_COUNTER: u16 = 3; - let ctx = bank_setup().await; + let ctx = bank_setup(db).await; let create = async |code: &str, now: &Timestamp| -> Uuid { tan::new( diff --git a/libeufin-bank/src/lib.rs b/libeufin-bank/src/lib.rs @@ -33,7 +33,7 @@ use taler_build::long_version; use taler_common::{ CommonArgs, cli::ConfigCmd, - config::{Config, parser::ConfigSource}, + config::Config, types::{ amount::Amount, base32::Base32, @@ -73,14 +73,12 @@ pub mod auth; #[cfg(test)] pub mod bench; pub mod config; +pub mod constants; pub mod db; pub mod mfa; pub mod payto; pub mod pw; -pub const CONFIG_SOURCE: ConfigSource = - ConfigSource::new("libeufin", "libeufin-bank", "libeufin-bank"); - #[derive(clap::Subcommand, Debug)] pub enum Cmd { /// Initialize libeufin-bank database diff --git a/libeufin-bank/src/main.rs b/libeufin-bank/src/main.rs @@ -18,7 +18,7 @@ */ use clap::Parser as _; -use libeufin_bank::{Args, CONFIG_SOURCE, run}; +use libeufin_bank::{Args, constants::CONFIG_SOURCE, run}; use taler_common::taler_main; fn main() { diff --git a/libeufin-ebisync/src/config.rs b/libeufin-ebisync/src/config.rs @@ -31,13 +31,10 @@ use taler_api::{ config::{AuthCfg, DbCfg}, }; use taler_common::{ - config::{CfgErr, Config, Section, parser::ConfigSource}, + config::{CfgErr, Config, Section}, map_config, }; -pub const CONFIG_SOURCE: ConfigSource = - ConfigSource::new("libeufin-ebisync", "ebisync", "libeufin-ebisync"); - pub fn parse_db_cfg(cfg: &Config) -> Result<DbCfg, CfgErr> { DbCfg::parse(cfg.section("ebisyncdb-postgres")) } diff --git a/libeufin-ebisync/src/constants.rs b/libeufin-ebisync/src/constants.rs @@ -0,0 +1,27 @@ +/* +* This file is part of LibEuFin. +* Copyright (C) 2026 Taler Systems S.A. + +* LibEuFin is free software; you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation; either version 3, or +* (at your option) any later version. + +* LibEuFin is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General +* Public License for more details. + +* You should have received a copy of the GNU Affero General Public +* License along with LibEuFin; see the file COPYING. If not, see +* <http://www.gnu.org/licenses/> +*/ + +use taler_common::config::parser::ConfigSource; + +pub const CONFIG_SOURCE: ConfigSource = + ConfigSource::new("libeufin-ebisync", "ebisync", "libeufin-ebisync"); + +// KV +pub const CHECKPOINT_KEY: &str = "checkpoint"; +pub const FETCH_TASK_KEY: &str = "fetch_task"; diff --git a/libeufin-ebisync/src/db.rs b/libeufin-ebisync/src/db.rs @@ -20,7 +20,7 @@ use sqlx::PgPool; use taler_api::config::DbCfg; -use crate::config::CONFIG_SOURCE; +use crate::constants::CONFIG_SOURCE; pub async fn pool(cfg: &DbCfg) -> anyhow::Result<PgPool> { let pool = taler_common::db::pool(cfg.cfg.clone(), CONFIG_SOURCE.component_name).await?; @@ -44,17 +44,11 @@ pub async fn dbinit(cfg: &DbCfg, reset: bool) -> anyhow::Result<PgPool> { pub mod test { use libeufin_ebics::db::test::ebics_routine; - use sqlx::{PgPool, Postgres, pool::PoolConnection}; + use sqlx::PgPool; + use taler_macros::db_test; - use crate::config::CONFIG_SOURCE; - - pub async fn db_setup() -> (PoolConnection<Postgres>, PgPool) { - taler_test_utils::db::db_test_setup(CONFIG_SOURCE).await - } - - #[tokio::test] - pub async fn ebics() { - let (_, db) = db_setup().await; + #[db_test] + pub async fn ebics(db: PgPool) { ebics_routine(&db).await; } } diff --git a/libeufin-ebisync/src/lib.rs b/libeufin-ebisync/src/lib.rs @@ -54,18 +54,16 @@ use crate::{ api::{EbisyncState, sync_api}, azure::AzureBlobStorage, config::{Destination, EbisyncCfg, Source, parse_db_cfg}, + constants::{CHECKPOINT_KEY, FETCH_TASK_KEY}, db::{dbinit, pool}, }; pub mod api; pub mod azure; pub mod config; +pub mod constants; pub mod db; -// KV -const CHECKPOINT_KEY: &str = "checkpoint"; -const FETCH_TASK_KEY: &str = "fetch_task"; - /// Testing helper commands #[derive(clap::Subcommand, Debug)] pub enum TestingCmd { @@ -555,8 +553,9 @@ mod ebics { use libeufin_ebics::test::{EbicsState, TestBank}; use sqlx::PgPool; use taler_common::config::Config; + use taler_macros::db_test; - use crate::{Args, config::CONFIG_SOURCE, db::test::db_setup, run}; + use crate::{Args, constants::CONFIG_SOURCE, run}; pub async fn ebisync_cmd(cfg: &Config, cmd: &str) -> anyhow::Result<()> { let parts = shlex::split(cmd).unwrap(); @@ -566,8 +565,7 @@ mod ebics { run(cfg, cmd.cmd).await } - async fn test_setup() -> (TestBank, Config, PgPool) { - let (_, db) = db_setup().await; + async fn test_setup(db: PgPool) -> (TestBank, Config, PgPool) { let test = TestBank::new().await; let cfg = Config::from_mem_with_env( CONFIG_SOURCE, @@ -605,8 +603,8 @@ mod ebics { (test, cfg, db) } - #[tokio::test] - async fn setup() { - test_setup().await; + #[db_test] + async fn setup(db: PgPool) { + test_setup(db).await; } } diff --git a/libeufin-ebisync/src/main.rs b/libeufin-ebisync/src/main.rs @@ -18,7 +18,7 @@ */ use clap::Parser as _; -use libeufin_ebisync::{Args, config::CONFIG_SOURCE, run}; +use libeufin_ebisync::{Args, constants::CONFIG_SOURCE, run}; use taler_common::taler_main; fn main() { diff --git a/libeufin-nexus/src/api.rs b/libeufin-nexus/src/api.rs @@ -65,7 +65,7 @@ use taler_common::{ use tokio::sync::watch::Sender; use crate::{ - FETCH_TASK_KEY, SUBMIT_TASK_KEY, + constants::{FETCH_TASK_KEY, SUBMIT_TASK_KEY}, db::{ self, exchange::{ @@ -428,9 +428,9 @@ pub mod test { revenue::RevenueConfig, wire::{TransferState, WireConfig}, }; + use taler_macros::db_test; use taler_test_utils::{ Router, - db::db_test_setup, routine::{ admin_add_incoming_routine, out_history_routine, registration_routine, revenue_routine, transfer_routine, @@ -440,27 +440,23 @@ pub mod test { }; use crate::{ - CONFIG_SOURCE, api::NexusApi, db::{payment::register_out_tx, test::check_in}, test::{CLIENT, CURR, EXCHANGE, UNKNOWN, gen_out_pay}, }; - pub async fn api_setup() -> (Router, PgPool) { - let (_, pool) = db_test_setup(CONFIG_SOURCE).await; - let api = Arc::new(NexusApi::start(pool.clone(), CURR, EXCHANGE.clone(), None).await); - let server = Router::new() + pub async fn api_setup(db: &PgPool) -> Router { + let api = Arc::new(NexusApi::start(db.clone(), CURR, EXCHANGE.clone(), None).await); + Router::new() .wire_gateway(api.clone(), AuthMethod::None) .prepared_transfer(api.clone()) .revenue(api, AuthMethod::None) - .finalize(); - - (server, pool) + .finalize() } - #[tokio::test] - async fn config() { - let (server, _) = api_setup().await; + #[db_test] + async fn config(db: PgPool) { + let server = api_setup(&db).await; server .get("/taler-wire-gateway/config") .await @@ -475,9 +471,9 @@ pub mod test { .assert_ok_json::<RevenueConfig>(); } - #[tokio::test] - async fn transfer() { - let (server, _) = api_setup().await; + #[db_test] + async fn transfer(db: PgPool) { + let server = api_setup(&db).await; transfer_routine( &server.prefix("/taler-wire-gateway"), TransferState::pending, @@ -496,28 +492,24 @@ pub mod test { }*/ } - #[tokio::test] - async fn outgoing_history() { - let (server, pool) = api_setup().await; + #[db_test] + async fn outgoing_history(db: PgPool) { + let server = api_setup(&db).await; out_history_routine( &server.prefix("/taler-wire-gateway"), tasks!({ - register_out_tx( - &pool, - &gen_out_pay("subject"), - Some(&OutgoingSubject::rand()), - ) - .await - .unwrap(); + register_out_tx(&db, &gen_out_pay("subject"), Some(&OutgoingSubject::rand())) + .await + .unwrap(); }), tasks!(), ) .await; } - #[tokio::test] - async fn admin_add_incoming() { - let (server, _) = api_setup().await; + #[db_test] + async fn admin_add_incoming(db: PgPool) { + let server = api_setup(&db).await; admin_add_incoming_routine( &server.prefix("/taler-wire-gateway"), &server.prefix("/taler-prepared-transfer"), @@ -527,9 +519,9 @@ pub mod test { .await; } - #[tokio::test] - async fn revenue() { - let (server, _) = api_setup().await; + #[db_test] + async fn revenue(db: PgPool) { + let server = api_setup(&db).await; revenue_routine( &server.prefix("/taler-wire-gateway"), &server.prefix("/taler-revenue"), @@ -540,16 +532,16 @@ pub mod test { .await; } - #[tokio::test] - async fn registration() { - let (server, pool) = api_setup().await; + #[db_test] + async fn registration(db: PgPool) { + let server = api_setup(&db).await; registration_routine( &server.prefix("/taler-wire-gateway"), &server.prefix("/taler-prepared-transfer"), &CLIENT.as_uri(), &EXCHANGE.as_uri(), &UNKNOWN, - || check_in(&pool), + || check_in(&db), ) .await; } diff --git a/libeufin-nexus/src/bench.rs b/libeufin-nexus/src/bench.rs @@ -23,6 +23,7 @@ use aws_lc_rs::signature::{Ed25519KeyPair, KeyPair as _}; use compact_str::{CompactString, format_compact}; use jiff::Timestamp; use serde_json::json; +use sqlx::PgPool; use taler_api::subject::subject_fmt_qr_bill; use taler_common::{ api::{ @@ -37,6 +38,7 @@ use taler_common::{ time::TalerTimestamp, }, }; +use taler_macros::db_test; use taler_test_utils::server::TestServer as _; use crate::{ @@ -49,9 +51,9 @@ use crate::{ }, }; -#[tokio::test] -pub async fn bench_db() { - let (server, db) = api_setup().await; +#[db_test] +pub async fn bench_db(db: PgPool) { + let server = api_setup(&db).await; let mut b = Bench::new(&db); let accounts_pubs: Vec<_> = (0..b.amount * 2) .map(|_| { diff --git a/libeufin-nexus/src/constants.rs b/libeufin-nexus/src/constants.rs @@ -0,0 +1,28 @@ +/* +* This file is part of LibEuFin. +* Copyright (C) 2026 Taler Systems S.A. + +* LibEuFin is free software; you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation; either version 3, or +* (at your option) any later version. + +* LibEuFin is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General +* Public License for more details. + +* You should have received a copy of the GNU Affero General Public +* License along with LibEuFin; see the file COPYING. If not, see +* <http://www.gnu.org/licenses/> +*/ + +use taler_common::config::parser::ConfigSource; + +// KV +pub const CHECKPOINT_KEY: &str = "checkpoint"; +pub const SUBMIT_TASK_KEY: &str = "submit_task"; +pub const FETCH_TASK_KEY: &str = "fetch_task"; + +pub const CONFIG_SOURCE: ConfigSource = + ConfigSource::new("libeufin", "libeufin-nexus", "libeufin-nexus"); diff --git a/libeufin-nexus/src/db.rs b/libeufin-nexus/src/db.rs @@ -62,17 +62,12 @@ pub async fn notification_listener( #[cfg(test)] pub mod test { use libeufin_ebics::db::test::ebics_routine; - use sqlx::{PgPool, Postgres, Row, pool::PoolConnection, postgres::PgRow}; + use sqlx::{PgPool, Row, postgres::PgRow}; use taler_api::db::TypeHelper; use taler_common::db::IncomingType; + use taler_macros::db_test; use taler_test_utils::routine::Status; - use crate::CONFIG_SOURCE; - - pub async fn db_setup() -> (PoolConnection<Postgres>, PgPool) { - taler_test_utils::db::db_test_setup(CONFIG_SOURCE).await - } - pub async fn check_count(db: &PgPool, nb_tx: usize, nb_bounce: usize) { assert_eq!( sqlx::query_as::<_, (i64, i64)>( @@ -159,9 +154,8 @@ pub mod test { assert_eq!(state, check_in(db).await); } - #[tokio::test] - pub async fn ebics() { - let (_, db) = db_setup().await; + #[db_test] + pub async fn ebics(db: PgPool) { ebics_routine(&db).await; } } diff --git a/libeufin-nexus/src/db/initiated.rs b/libeufin-nexus/src/db/initiated.rs @@ -472,26 +472,26 @@ mod test { use sqlx::{PgPool, Row as _, postgres::PgRow}; use taler_api::db::TypeHelper as _; use taler_common::{config::Config, types::utils::date_to_utc_ts}; + use taler_macros::db_test; use crate::{ - CONFIG_SOURCE, config::{NexusCfg, NexusIngestCfg}, + constants::CONFIG_SOURCE, db::{ initiated::{ PaymentInitiationResult, batch_initiated, batch_status_update, batch_sub_failure, batch_sub_success, initiated_submittable, order_failure, order_step, order_success, tx_status_update, }, - test::{check_count, db_setup}, + test::check_count, }, fetch::{register_outgoing, register_tx}, model::SubmissionState, test::{CURR, gen_in_pay, gen_initiate, gen_out_pay}, }; - #[tokio::test] - pub async fn initiated_skip() { - let (_, db) = db_setup().await; + #[db_test] + pub async fn initiated_skip(db: PgPool) { let cfg = Config::load(CONFIG_SOURCE, Some("conf/skip.conf")).unwrap(); let cfg = NexusCfg::parse(&cfg).unwrap(); let cfg = cfg.ingest().unwrap(); @@ -540,12 +540,10 @@ mod test { check_count(&db, 10, 2).await; } - #[tokio::test] - pub async fn initiated_status() { + #[db_test] + pub async fn initiated_status(db: PgPool) { use SubmissionState::*; - let (_, db) = db_setup().await; - let check_parts = async |batch_id: u64, batch_status: SubmissionState, batch_msg: &str, @@ -854,9 +852,8 @@ mod test { assert!(order_failure(&db, "ORDER_X").await.unwrap().is_none()); } - #[tokio::test] - pub async fn initiated_submittables() { - let (_, db) = db_setup().await; + #[db_test] + pub async fn initiated_submittables(db: PgPool) { let now = Timestamp::now(); for i in 0..6 { assert!(matches!( diff --git a/libeufin-nexus/src/db/payment.rs b/libeufin-nexus/src/db/payment.rs @@ -319,6 +319,7 @@ mod test { db::IncomingType, types::amount::amount, }; + use taler_macros::db_test; use taler_test_utils::routine::Status::*; use uuid::Uuid; @@ -330,16 +331,15 @@ mod test { InResult, IncomingBounceRegistrationResult, OutgoingRegistrationResult, register_in_malformed, }, - test::{check_in_count, check_in_state, check_out_count, db_setup}, + test::{check_in_count, check_in_state, check_out_count}, transfer::{RegistrationResult, transfer_register}, }, fetch::{register_incoming, register_outgoing, register_outgoing_batch}, test::{CURR, gen_in_pay, gen_initiate, gen_out_pay}, }; - #[tokio::test] - async fn out_tx() { - let (_, db) = db_setup().await; + #[db_test] + async fn out_tx(db: PgPool) { // Register initiated transactions for subject in [ "initiated by nexus".to_owned(), @@ -449,9 +449,8 @@ mod test { check_out_count(&db, 8, 3).await } - #[tokio::test] - async fn out_batch() { - let (_, db) = db_setup().await; + #[db_test] + async fn out_batch(db: PgPool) { // Init batch let wtid = ShortHashCode::rand(); for subject in [ @@ -529,10 +528,8 @@ mod test { check_out_count(&db, 7, 2).await; } - #[tokio::test] - async fn in_bounce() { - let (_, db) = db_setup().await; - + #[db_test] + async fn in_bounce(db: PgPool) { // Creating and bouncing one incoming transaction let payment = gen_in_pay("incoming and bounce"); let id = rand_ebics_id(); @@ -606,10 +603,8 @@ mod test { .unwrap(); } - #[tokio::test] - async fn in_simple() { - let (_, db) = db_setup().await; - + #[db_test] + async fn in_simple(db: PgPool) { let cfg = NexusIngestCfg::simple(AccountType::exchange, &CURR); // Register @@ -652,10 +647,8 @@ mod test { check_in_state(&db, &[Bounced, Bounced, Simple, Bounced]).await; } - #[tokio::test] - async fn in_talerable() { - let (_, db) = db_setup().await; - + #[db_test] + async fn in_talerable(db: PgPool) { let cfg = NexusIngestCfg::simple(AccountType::exchange, &CURR); let key = EddsaPublicKey::rand(); let subject = format!("test with {key} reserve pub"); @@ -703,9 +696,8 @@ mod test { check_in_state(&db, &[Reserve(key), Bounced, Bounced, Simple, Reserve(new)]).await; } - #[tokio::test] - async fn in_mapping() { - let (_, db) = db_setup().await; + #[db_test] + async fn in_mapping(db: PgPool) { let cfg = NexusIngestCfg::simple(AccountType::exchange, &CURR); let first = EddsaPublicKey::rand(); let auth_pub = EddsaPublicKey::rand(); @@ -828,9 +820,8 @@ mod test { .await; } - #[tokio::test] - async fn in_reference() { - let (_, db) = db_setup().await; + #[db_test] + async fn in_reference(db: PgPool) { let cfg = NexusIngestCfg::simple(AccountType::exchange, &CURR); let first = EddsaPublicKey::rand(); let auth_pub = EddsaPublicKey::rand(); @@ -952,9 +943,8 @@ mod test { .await; } - #[tokio::test] - async fn in_recover_info() { - let (_, db) = db_setup().await; + #[db_test] + async fn in_recover_info(db: PgPool) { let cfg = NexusIngestCfg::simple(AccountType::exchange, &CURR); async fn check_content(db: &PgPool, p: &InTx) { @@ -1077,9 +1067,8 @@ mod test { } } - #[tokio::test] - pub async fn in_horror() { - let (_, db) = db_setup().await; + #[db_test] + async fn in_horror(db: PgPool) { let cfg = NexusIngestCfg::simple(AccountType::exchange, &CURR); // Check we do not bounce already registered talerable transaction diff --git a/libeufin-nexus/src/fetch.rs b/libeufin-nexus/src/fetch.rs @@ -52,8 +52,8 @@ use tokio::{time::timeout, try_join}; use tracing::{debug, error, info, trace, warn}; use crate::{ - CHECKPOINT_KEY, FETCH_TASK_KEY, config::{AccountType, NexusCfg, NexusIngestCfg}, + constants::{CHECKPOINT_KEY, FETCH_TASK_KEY}, db::{ initiated::{ batch_status_update, order_failure, order_step, order_success, tx_status_update, @@ -684,14 +684,13 @@ pub mod test { utils::date_to_utc_ts, }, }; + use taler_macros::db_test; use crate::{ - CONFIG_SOURCE, batch_pain001, + batch_pain001, config::NexusCfg, - db::{ - initiated::{batch_initiated, batch_sub_success, initiate, initiated_submittable}, - test::db_setup, - }, + constants::CONFIG_SOURCE, + db::initiated::{batch_initiated, batch_sub_success, initiate, initiated_submittable}, fetch::register_file, gen_init_pay, model::{ @@ -700,15 +699,14 @@ pub mod test { }, }; - async fn setup() -> (PgPool, NexusCfg) { - setup_cfg("test.conf").await + fn setup() -> NexusCfg { + setup_cfg("test.conf") } - async fn setup_cfg(name: &str) -> (PgPool, NexusCfg) { + fn setup_cfg(name: &str) -> NexusCfg { let cfg = Config::load(CONFIG_SOURCE, Some(format!("conf/{name}"))).unwrap(); let cfg = NexusCfg::parse(&cfg).unwrap(); - let (_, pool) = db_setup().await; - (pool, cfg) + cfg } fn iban_payto(iban: impl AsRef<str>, name: impl AsRef<str>) -> PaytoURI { @@ -969,9 +967,9 @@ pub mod test { pretty_assertions::assert_eq!(bounced, bounced_tx) } - #[tokio::test] - async fn pain001() { - let (db, cfg) = setup().await; + #[db_test] + async fn pain001(db: PgPool) { + let cfg = setup(); let mut batches = batches( &db, &[( @@ -1005,9 +1003,9 @@ pub mod test { } /** HAC order id test */ - #[tokio::test] - async fn hac() { - let (db, cfg) = setup().await; + #[db_test] + async fn hac(db: PgPool) { + let cfg = setup(); batches( &db, &[ @@ -1056,9 +1054,9 @@ pub mod test { } /** CreditSuisse dialect test */ - #[tokio::test] - async fn cs() { - let (db, cfg) = setup().await; + #[db_test] + async fn cs(db: PgPool) { + let cfg = setup(); batches( &db, &[( @@ -1095,9 +1093,9 @@ pub mod test { } /** Valiant dialect test */ - #[tokio::test] - async fn valiant() { - let (db, cfg) = setup_cfg("valiant.conf").await; + #[db_test] + async fn valiant(db: PgPool) { + let cfg = setup_cfg("valiant.conf"); batches( &db, &[ @@ -1339,9 +1337,9 @@ pub mod test { } /** GLS dialect test */ - #[tokio::test] - async fn gls() { - let (db, cfg) = setup_cfg("gls.conf").await; + #[db_test] + async fn gls(db: PgPool) { + let cfg = setup_cfg("gls.conf"); batches( &db, &[ @@ -1548,9 +1546,9 @@ pub mod test { } /** Maerki Baumann dialect test */ - #[tokio::test] - async fn maerki_baumann() { - let (db, cfg) = setup_cfg("maerki_baumann.conf").await; + #[db_test] + async fn maerki_baumann(db: PgPool) { + let cfg = setup_cfg("maerki_baumann.conf"); batches( &db, &[( @@ -1764,9 +1762,9 @@ pub mod test { } /** PostFinance dialect test */ - #[tokio::test] - async fn postfinance() { - let (db, cfg) = setup_cfg("postfinance.conf").await; + #[db_test] + async fn postfinance(db: PgPool) { + let cfg = setup_cfg("postfinance.conf"); batches( &db, &[ diff --git a/libeufin-nexus/src/lib.rs b/libeufin-nexus/src/lib.rs @@ -42,7 +42,7 @@ use taler_build::long_version; use taler_common::{ CommonArgs, cli::ConfigCmd, - config::{Config, parser::ConfigSource}, + config::Config, types::{amount::Amount, payto::TransferIbanPayto, utils::date_to_utc_ts}, }; use taler_test_utils::Router; @@ -51,6 +51,7 @@ use tracing::{debug, error, info, warn}; use crate::{ api::NexusApi, config::{NexusCfg, NexusEbicsConfig, parse_db_cfg}, + constants::SUBMIT_TASK_KEY, db::{ dbinit, initiated::{ @@ -69,6 +70,7 @@ pub mod api; #[cfg(test)] pub mod bench; pub mod config; +pub mod constants; pub mod db; pub mod fetch; pub mod list; @@ -78,14 +80,6 @@ pub mod model; pub mod test; pub mod testing; -// KV -const CHECKPOINT_KEY: &str = "checkpoint"; -const SUBMIT_TASK_KEY: &str = "submit_task"; -const FETCH_TASK_KEY: &str = "fetch_task"; - -pub const CONFIG_SOURCE: ConfigSource = - ConfigSource::new("libeufin", "libeufin-nexus", "libeufin-nexus"); - #[derive(clap::Subcommand, Debug)] pub enum Cmd { /// Initialize libeufin-nexus database diff --git a/libeufin-nexus/src/list.rs b/libeufin-nexus/src/list.rs @@ -193,8 +193,10 @@ impl ListCmd { #[cfg(test)] mod test { + use sqlx::PgPool; + use taler_macros::db_test; + use crate::{ - db::test::db_setup, list::ListCmd, test::{ CURR, incomplete_out, malformed_completeted_in, malformed_in, malformed_incomplete_in, @@ -204,10 +206,8 @@ mod test { }, }; - #[tokio::test] - async fn check() { - let (_, db) = db_setup().await; - + #[db_test] + async fn check(db: PgPool) { let check = async || { for cmd in [ ListCmd::Outgoing, diff --git a/libeufin-nexus/src/main.rs b/libeufin-nexus/src/main.rs @@ -18,7 +18,7 @@ */ use clap::Parser as _; -use libeufin_nexus::{Args, CONFIG_SOURCE, run}; +use libeufin_nexus::{Args, constants::CONFIG_SOURCE, run}; use taler_common::taler_main; fn main() { diff --git a/libeufin-nexus/src/test.rs b/libeufin-nexus/src/test.rs @@ -301,8 +301,13 @@ mod ebics { use libeufin_ebics::test::{EbicsState, TestBank}; use sqlx::PgPool; use taler_common::config::Config; + use taler_macros::db_test; - use crate::{Args, CHECKPOINT_KEY, CONFIG_SOURCE, db::test::db_setup, run}; + use crate::{ + Args, + constants::{CHECKPOINT_KEY, CONFIG_SOURCE}, + run, + }; pub async fn nexus_cmd(cfg: &Config, cmd: &str) -> anyhow::Result<()> { let parts = shlex::split(cmd).unwrap(); @@ -312,8 +317,7 @@ mod ebics { run(cfg, cmd.cmd).await } - async fn test_setup() -> (TestBank, Config, PgPool) { - let (_, db) = db_setup().await; + async fn test_setup(db: &PgPool) -> (TestBank, Config) { let test = TestBank::new().await; let cfg = Config::from_mem_with_env( CONFIG_SOURCE, @@ -349,17 +353,17 @@ mod ebics { .await .unwrap(); - (test, cfg, db) + (test, cfg) } - #[tokio::test] - async fn setup() { - test_setup().await; + #[db_test] + async fn setup(db: PgPool) { + test_setup(&db).await; } - #[tokio::test] - async fn fetch_pinned_date() { - let (test, cfg, db) = test_setup().await; + #[db_test] + async fn fetch_pinned_date(db: PgPool) { + let (test, cfg) = test_setup(&db).await; let reset_checkpoint = async || { let res = sqlx::query("DELETE FROM kv WHERE key=$1") @@ -447,9 +451,9 @@ mod ebics { .unwrap(); } - #[tokio::test] - async fn close_pending_transaction() { - let (test, cfg, _) = test_setup().await; + #[db_test] + async fn close_pending_transaction(db: PgPool) { + let (test, cfg) = test_setup(&db).await; // Failure before first segment test.sequences(&[ diff --git a/testbench/Cargo.toml b/testbench/Cargo.toml @@ -16,6 +16,7 @@ clap.workspace = true taler-common.workspace = true taler-api.workspace = true taler-test-utils.workspace = true +taler-macros.workspace = true sqlx.workspace = true http-client.workspace = true axum.workspace = true diff --git a/testbench/src/integration.rs b/testbench/src/integration.rs @@ -32,7 +32,7 @@ use libeufin_nexus::{ config::{AccountType, NexusIngestCfg}, fetch::register_incoming, }; -use sqlx::postgres::PgRow; +use sqlx::postgres::{PgConnectOptions, PgRow}; use taler_api::db::TypeHelper; use taler_common::{ api::{ @@ -46,7 +46,8 @@ use taler_common::{ payto::{FullIbanPayto, PaytoImpl}, }, }; -use taler_test_utils::{cli::clap_parse, db::test_db, json, server::TestServer, setup_tracing}; +use taler_macros::db_test; +use taler_test_utils::{cli::clap_parse, json, server::TestServer}; use tokio::try_join; async fn nexus_cmd(cfg: &Config, cmd: &str) { @@ -76,12 +77,10 @@ pub async fn wait_for_http(url: &str) { panic!("{url} never becomed active") } -#[tokio::test] -async fn mini() { - setup_tracing(); - let db = test_db().await; +#[db_test(raw)] +async fn mini(db: PgConnectOptions) { let bank_cfg = Config::from_file_override( - libeufin_bank::CONFIG_SOURCE, + libeufin_bank::constants::CONFIG_SOURCE, Some("conf/mini.conf"), &format!( " @@ -93,7 +92,7 @@ async fn mini() { ) .unwrap(); let nexus_cfg = Config::from_file_override( - libeufin_nexus::CONFIG_SOURCE, + libeufin_nexus::constants::CONFIG_SOURCE, Some("conf/mini.conf"), &format!( " @@ -137,12 +136,10 @@ async fn mini() { bank_cmd(&bank_cfg, "gc").await; } -#[tokio::test] -async fn errors() { - setup_tracing(); - let db = test_db().await; +#[db_test(raw)] +async fn errors(db: PgConnectOptions) { let bank_cfg = Config::from_file_override( - libeufin_bank::CONFIG_SOURCE, + libeufin_bank::constants::CONFIG_SOURCE, Some("conf/integration.conf"), &format!( " @@ -155,7 +152,7 @@ async fn errors() { .unwrap(); let nexus_cfg = Config::from_file_override( - libeufin_nexus::CONFIG_SOURCE, + libeufin_nexus::constants::CONFIG_SOURCE, Some("conf/integration.conf"), &format!( " @@ -336,12 +333,10 @@ async fn errors() { check_count(4, 2, 2).await; } -#[tokio::test] -async fn conversion() { - setup_tracing(); - let db = test_db().await; +#[db_test(raw)] +async fn conversion(db: PgConnectOptions) { let bank_cfg = Config::from_file_override( - libeufin_bank::CONFIG_SOURCE, + libeufin_bank::constants::CONFIG_SOURCE, Some("conf/integration.conf"), &format!( " @@ -354,7 +349,7 @@ async fn conversion() { .unwrap(); let nexus_cfg = Config::from_file_override( - libeufin_nexus::CONFIG_SOURCE, + libeufin_nexus::constants::CONFIG_SOURCE, Some("conf/integration.conf"), &format!( " diff --git a/testbench/src/lib.rs b/testbench/src/lib.rs @@ -24,10 +24,14 @@ mod integration; pub fn full_cfg(base: &str, mem: &str) -> Config { let mut parser = taler_common::config::parser::Parser::empty(); - parser.load_env(libeufin_bank::CONFIG_SOURCE).unwrap(); - parser.load_env(libeufin_nexus::CONFIG_SOURCE).unwrap(); parser - .load_env(libeufin_ebisync::config::CONFIG_SOURCE) + .load_env(libeufin_bank::constants::CONFIG_SOURCE) + .unwrap(); + parser + .load_env(libeufin_nexus::constants::CONFIG_SOURCE) + .unwrap(); + parser + .load_env(libeufin_ebisync::constants::CONFIG_SOURCE) .unwrap(); parser.parse_file(base.into(), 0).unwrap(); parser.parse_str(mem).unwrap(); diff --git a/testbench/src/main.rs b/testbench/src/main.rs @@ -198,8 +198,8 @@ async fn main() -> anyhow::Result<()> { std::fs::read_to_string(format!("testbench/test/platform/{}.conf", cmd.platform)).unwrap(); let cfg = Config::from_mem_with_env( match cmd.component { - Component::Nexus => libeufin_nexus::CONFIG_SOURCE, - Component::Ebisync => libeufin_ebisync::config::CONFIG_SOURCE + Component::Nexus => libeufin_nexus::constants::CONFIG_SOURCE, + Component::Ebisync => libeufin_ebisync::constants::CONFIG_SOURCE } , &format!( r#"