Browse Source

Merge pull request #532 from thesimplekid/refactor_itests

Refactor itests
thesimplekid 2 months ago
parent
commit
411ba61d16

+ 1 - 2
crates/cdk-integration-tests/Cargo.toml

@@ -14,6 +14,7 @@ rust-version = "1.63.0"
 http_subscription = ["cdk/http_subscription"]
 http_subscription = ["cdk/http_subscription"]
 
 
 [dependencies]
 [dependencies]
+async-trait = "0.1"
 axum = "0.6.20"
 axum = "0.6.20"
 rand = "0.8.5"
 rand = "0.8.5"
 bip39 = { version = "2.0", features = ["rand"] }
 bip39 = { version = "2.0", features = ["rand"] }
@@ -57,8 +58,6 @@ getrandom = { version = "0.2", features = ["js"] }
 instant = { version = "0.1", features = ["wasm-bindgen", "inaccurate"] }
 instant = { version = "0.1", features = ["wasm-bindgen", "inaccurate"] }
 
 
 [dev-dependencies]
 [dev-dependencies]
-async-trait = "0.1"
-rand = "0.8.5"
 bip39 = { version = "2.0", features = ["rand"] }
 bip39 = { version = "2.0", features = ["rand"] }
 anyhow = "1"
 anyhow = "1"
 cdk = { path = "../cdk", features = ["mint", "wallet"] }
 cdk = { path = "../cdk", features = ["mint", "wallet"] }

+ 0 - 0
crates/cdk-integration-tests/src/main.rs → crates/cdk-integration-tests/src/bin/regtest_mint.rs


+ 3 - 26
crates/cdk-integration-tests/src/init_fake_wallet.rs

@@ -2,16 +2,15 @@ use std::collections::{HashMap, HashSet};
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 use anyhow::Result;
 use anyhow::Result;
-use axum::Router;
 use bip39::Mnemonic;
 use bip39::Mnemonic;
 use cdk::cdk_database::{self, MintDatabase};
 use cdk::cdk_database::{self, MintDatabase};
 use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
 use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
 use cdk::nuts::{CurrencyUnit, PaymentMethod};
 use cdk::nuts::{CurrencyUnit, PaymentMethod};
 use cdk_fake_wallet::FakeWallet;
 use cdk_fake_wallet::FakeWallet;
-use tokio::sync::Notify;
-use tower_http::cors::CorsLayer;
 use tracing_subscriber::EnvFilter;
 use tracing_subscriber::EnvFilter;
 
 
+use crate::init_mint::start_mint;
+
 pub async fn start_fake_mint<D>(addr: &str, port: u16, database: D) -> Result<()>
 pub async fn start_fake_mint<D>(addr: &str, port: u16, database: D) -> Result<()>
 where
 where
     D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
     D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
@@ -58,29 +57,7 @@ where
 
 
     let mint = mint_builder.build().await?;
     let mint = mint_builder.build().await?;
 
 
-    let mint_arc = Arc::new(mint);
-
-    let v1_service = cdk_axum::create_mint_router(Arc::clone(&mint_arc))
-        .await
-        .unwrap();
-
-    let mint_service = Router::new()
-        .merge(v1_service)
-        .layer(CorsLayer::permissive());
-
-    let mint = Arc::clone(&mint_arc);
-
-    let shutdown = Arc::new(Notify::new());
-
-    tokio::spawn({
-        let shutdown = Arc::clone(&shutdown);
-        async move { mint.wait_for_paid_invoices(shutdown).await }
-    });
-
-    println!("Staring Axum server");
-    axum::Server::bind(&format!("{}:{}", addr, port).as_str().parse().unwrap())
-        .serve(mint_service.into_make_service())
-        .await?;
+    start_mint(addr, port, mint).await?;
 
 
     Ok(())
     Ok(())
 }
 }

+ 35 - 0
crates/cdk-integration-tests/src/init_mint.rs

@@ -0,0 +1,35 @@
+use std::sync::Arc;
+
+use anyhow::Result;
+use axum::Router;
+use cdk::mint::Mint;
+use tokio::sync::Notify;
+use tower_http::cors::CorsLayer;
+
+pub async fn start_mint(addr: &str, port: u16, mint: Mint) -> Result<()> {
+    let mint_arc = Arc::new(mint);
+
+    let v1_service = cdk_axum::create_mint_router(Arc::clone(&mint_arc))
+        .await
+        .unwrap();
+
+    let mint_service = Router::new()
+        .merge(v1_service)
+        .layer(CorsLayer::permissive());
+
+    let mint = Arc::clone(&mint_arc);
+
+    let shutdown = Arc::new(Notify::new());
+
+    tokio::spawn({
+        let shutdown = Arc::clone(&shutdown);
+        async move { mint.wait_for_paid_invoices(shutdown).await }
+    });
+
+    println!("Staring Axum server");
+    axum::Server::bind(&format!("{}:{}", addr, port).as_str().parse().unwrap())
+        .serve(mint_service.into_make_service())
+        .await?;
+
+    Ok(())
+}

+ 223 - 0
crates/cdk-integration-tests/src/init_pure_tests.rs

@@ -0,0 +1,223 @@
+use std::collections::{HashMap, HashSet};
+use std::fmt::{Debug, Formatter};
+use std::str::FromStr;
+use std::sync::Arc;
+
+use async_trait::async_trait;
+use bip39::Mnemonic;
+use cdk::amount::SplitTarget;
+use cdk::cdk_database::mint_memory::MintMemoryDatabase;
+use cdk::cdk_database::WalletMemoryDatabase;
+use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
+use cdk::nuts::nut00::ProofsMethods;
+use cdk::nuts::{
+    CheckStateRequest, CheckStateResponse, CurrencyUnit, Id, KeySet, KeysetResponse,
+    MeltBolt11Request, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request,
+    MintBolt11Response, MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response, PaymentMethod,
+    RestoreRequest, RestoreResponse, SwapRequest, SwapResponse,
+};
+use cdk::util::unix_time;
+use cdk::wallet::client::MintConnector;
+use cdk::wallet::Wallet;
+use cdk::{Amount, Error, Mint};
+use cdk_fake_wallet::FakeWallet;
+use tokio::sync::Notify;
+use uuid::Uuid;
+
+use crate::wait_for_mint_to_be_paid;
+
+pub struct DirectMintConnection {
+    pub mint: Arc<Mint>,
+}
+
+impl DirectMintConnection {
+    pub fn new(mint: Arc<Mint>) -> Self {
+        Self { mint }
+    }
+}
+
+impl Debug for DirectMintConnection {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "DirectMintConnection {{ mint_info: {:?} }}",
+            self.mint.config.mint_info()
+        )
+    }
+}
+
+/// Implements the generic [MintConnector] (i.e. use the interface that expects to communicate
+/// to a generic mint, where we don't know that quote ID's are [Uuid]s) for [DirectMintConnection],
+/// where we know we're dealing with a mint that uses [Uuid]s for quotes.
+/// Convert the requests and responses between the [String] and [Uuid] variants as necessary.
+#[async_trait]
+impl MintConnector for DirectMintConnection {
+    async fn get_mint_keys(&self) -> Result<Vec<KeySet>, Error> {
+        self.mint.pubkeys().await.map(|pks| pks.keysets)
+    }
+
+    async fn get_mint_keyset(&self, keyset_id: Id) -> Result<KeySet, Error> {
+        self.mint
+            .keyset(&keyset_id)
+            .await
+            .and_then(|res| res.ok_or(Error::UnknownKeySet))
+    }
+
+    async fn get_mint_keysets(&self) -> Result<KeysetResponse, Error> {
+        self.mint.keysets().await
+    }
+
+    async fn post_mint_quote(
+        &self,
+        request: MintQuoteBolt11Request,
+    ) -> Result<MintQuoteBolt11Response<String>, Error> {
+        self.mint
+            .get_mint_bolt11_quote(request)
+            .await
+            .map(Into::into)
+    }
+
+    async fn get_mint_quote_status(
+        &self,
+        quote_id: &str,
+    ) -> Result<MintQuoteBolt11Response<String>, Error> {
+        let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
+        self.mint
+            .check_mint_quote(&quote_id_uuid)
+            .await
+            .map(Into::into)
+    }
+
+    async fn post_mint(
+        &self,
+        request: MintBolt11Request<String>,
+    ) -> Result<MintBolt11Response, Error> {
+        let request_uuid = request.try_into().unwrap();
+        self.mint.process_mint_request(request_uuid).await
+    }
+
+    async fn post_melt_quote(
+        &self,
+        request: MeltQuoteBolt11Request,
+    ) -> Result<MeltQuoteBolt11Response<String>, Error> {
+        self.mint
+            .get_melt_bolt11_quote(&request)
+            .await
+            .map(Into::into)
+    }
+
+    async fn get_melt_quote_status(
+        &self,
+        quote_id: &str,
+    ) -> Result<MeltQuoteBolt11Response<String>, Error> {
+        let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
+        self.mint
+            .check_melt_quote(&quote_id_uuid)
+            .await
+            .map(Into::into)
+    }
+
+    async fn post_melt(
+        &self,
+        request: MeltBolt11Request<String>,
+    ) -> Result<MeltQuoteBolt11Response<String>, Error> {
+        let request_uuid = request.try_into().unwrap();
+        self.mint.melt_bolt11(&request_uuid).await.map(Into::into)
+    }
+
+    async fn post_swap(&self, swap_request: SwapRequest) -> Result<SwapResponse, Error> {
+        self.mint.process_swap_request(swap_request).await
+    }
+
+    async fn get_mint_info(&self) -> Result<MintInfo, Error> {
+        Ok(self.mint.mint_info().clone().time(unix_time()))
+    }
+
+    async fn post_check_state(
+        &self,
+        request: CheckStateRequest,
+    ) -> Result<CheckStateResponse, Error> {
+        self.mint.check_state(&request).await
+    }
+
+    async fn post_restore(&self, request: RestoreRequest) -> Result<RestoreResponse, Error> {
+        self.mint.restore(request).await
+    }
+}
+
+pub async fn create_and_start_test_mint() -> anyhow::Result<Arc<Mint>> {
+    let mut mint_builder = MintBuilder::new();
+
+    let database = MintMemoryDatabase::default();
+
+    mint_builder = mint_builder.with_localstore(Arc::new(database));
+
+    let fee_reserve = FeeReserve {
+        min_fee_reserve: 1.into(),
+        percent_fee_reserve: 1.0,
+    };
+
+    let ln_fake_backend = Arc::new(FakeWallet::new(
+        fee_reserve.clone(),
+        HashMap::default(),
+        HashSet::default(),
+        0,
+    ));
+
+    mint_builder = mint_builder.add_ln_backend(
+        CurrencyUnit::Sat,
+        PaymentMethod::Bolt11,
+        MintMeltLimits::default(),
+        ln_fake_backend,
+    );
+
+    let mnemonic = Mnemonic::generate(12)?;
+
+    mint_builder = mint_builder
+        .with_name("pure test mint".to_string())
+        .with_mint_url("http://aa".to_string())
+        .with_description("pure test mint".to_string())
+        .with_quote_ttl(10000, 10000)
+        .with_seed(mnemonic.to_seed_normalized("").to_vec());
+
+    let mint = mint_builder.build().await?;
+
+    let mint_arc = Arc::new(mint);
+
+    let mint_arc_clone = Arc::clone(&mint_arc);
+    let shutdown = Arc::new(Notify::new());
+    tokio::spawn({
+        let shutdown = Arc::clone(&shutdown);
+        async move { mint_arc_clone.wait_for_paid_invoices(shutdown).await }
+    });
+
+    Ok(mint_arc)
+}
+
+pub fn create_test_wallet_for_mint(mint: Arc<Mint>) -> anyhow::Result<Arc<Wallet>> {
+    let connector = DirectMintConnection::new(mint);
+
+    let seed = Mnemonic::generate(12)?.to_seed_normalized("");
+    let mint_url = connector.mint.config.mint_url().to_string();
+    let unit = CurrencyUnit::Sat;
+    let localstore = WalletMemoryDatabase::default();
+    let mut wallet = Wallet::new(&mint_url, unit, Arc::new(localstore), &seed, None)?;
+
+    wallet.set_client(connector);
+
+    Ok(Arc::new(wallet))
+}
+
+/// Creates a mint quote for the given amount and checks its state in a loop. Returns when
+/// amount is minted.
+pub async fn fund_wallet(wallet: Arc<Wallet>, amount: u64) -> anyhow::Result<Amount> {
+    let desired_amount = Amount::from(amount);
+    let quote = wallet.mint_quote(desired_amount, None).await?;
+
+    wait_for_mint_to_be_paid(&wallet, &quote.id).await?;
+
+    Ok(wallet
+        .mint(&quote.id, SplitTarget::default(), None)
+        .await?
+        .total_amount()?)
+}

+ 3 - 26
crates/cdk-integration-tests/src/init_regtest.rs

@@ -3,7 +3,6 @@ use std::path::PathBuf;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 use anyhow::Result;
 use anyhow::Result;
-use axum::Router;
 use bip39::Mnemonic;
 use bip39::Mnemonic;
 use cdk::cdk_database::{self, MintDatabase};
 use cdk::cdk_database::{self, MintDatabase};
 use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
 use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
@@ -14,8 +13,8 @@ use ln_regtest_rs::bitcoind::Bitcoind;
 use ln_regtest_rs::cln::Clnd;
 use ln_regtest_rs::cln::Clnd;
 use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
 use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
 use ln_regtest_rs::lnd::Lnd;
 use ln_regtest_rs::lnd::Lnd;
-use tokio::sync::Notify;
-use tower_http::cors::CorsLayer;
+
+use crate::init_mint::start_mint;
 
 
 const BITCOIND_ADDR: &str = "127.0.0.1:18443";
 const BITCOIND_ADDR: &str = "127.0.0.1:18443";
 const ZMQ_RAW_BLOCK: &str = "tcp://127.0.0.1:28332";
 const ZMQ_RAW_BLOCK: &str = "tcp://127.0.0.1:28332";
@@ -172,29 +171,7 @@ where
 
 
     let mint = mint_builder.build().await?;
     let mint = mint_builder.build().await?;
 
 
-    let mint_arc = Arc::new(mint);
-
-    let v1_service = cdk_axum::create_mint_router(Arc::clone(&mint_arc))
-        .await
-        .unwrap();
-
-    let mint_service = Router::new()
-        .merge(v1_service)
-        .layer(CorsLayer::permissive());
-
-    let mint = Arc::clone(&mint_arc);
-
-    let shutdown = Arc::new(Notify::new());
-
-    tokio::spawn({
-        let shutdown = Arc::clone(&shutdown);
-        async move { mint.wait_for_paid_invoices(shutdown).await }
-    });
-
-    println!("Staring Axum server");
-    axum::Server::bind(&format!("{}:{}", addr, port).as_str().parse().unwrap())
-        .serve(mint_service.into_make_service())
-        .await?;
+    start_mint(addr, port, mint).await?;
 
 
     Ok(())
     Ok(())
 }
 }

+ 24 - 100
crates/cdk-integration-tests/src/lib.rs

@@ -1,121 +1,26 @@
-use std::collections::{HashMap, HashSet};
 use std::str::FromStr;
 use std::str::FromStr;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 use anyhow::{bail, Result};
 use anyhow::{bail, Result};
-use axum::Router;
-use bip39::Mnemonic;
 use cdk::amount::{Amount, SplitTarget};
 use cdk::amount::{Amount, SplitTarget};
-use cdk::cdk_database::mint_memory::MintMemoryDatabase;
-use cdk::cdk_lightning::MintLightning;
 use cdk::dhke::construct_proofs;
 use cdk::dhke::construct_proofs;
-use cdk::mint::FeeReserve;
 use cdk::mint_url::MintUrl;
 use cdk::mint_url::MintUrl;
 use cdk::nuts::nut00::ProofsMethods;
 use cdk::nuts::nut00::ProofsMethods;
 use cdk::nuts::nut17::Params;
 use cdk::nuts::nut17::Params;
 use cdk::nuts::{
 use cdk::nuts::{
-    CurrencyUnit, Id, KeySet, MintBolt11Request, MintInfo, MintQuoteBolt11Request, MintQuoteState,
-    NotificationPayload, Nuts, PaymentMethod, PreMintSecrets, Proofs, State,
+    CurrencyUnit, Id, KeySet, MintBolt11Request, MintQuoteBolt11Request, MintQuoteState,
+    NotificationPayload, PreMintSecrets, Proofs, State,
 };
 };
-use cdk::types::{LnKey, QuoteTTL};
 use cdk::wallet::client::{HttpClient, MintConnector};
 use cdk::wallet::client::{HttpClient, MintConnector};
 use cdk::wallet::subscription::SubscriptionManager;
 use cdk::wallet::subscription::SubscriptionManager;
 use cdk::wallet::WalletSubscription;
 use cdk::wallet::WalletSubscription;
-use cdk::{Mint, Wallet};
-use cdk_fake_wallet::FakeWallet;
-use init_regtest::{get_mint_addr, get_mint_port, get_mint_url};
-use tokio::sync::Notify;
-use tower_http::cors::CorsLayer;
+use cdk::Wallet;
 
 
 pub mod init_fake_wallet;
 pub mod init_fake_wallet;
+pub mod init_mint;
+pub mod init_pure_tests;
 pub mod init_regtest;
 pub mod init_regtest;
 
 
-pub fn create_backends_fake_wallet(
-) -> HashMap<LnKey, Arc<dyn MintLightning<Err = cdk::cdk_lightning::Error> + Sync + Send>> {
-    let fee_reserve = FeeReserve {
-        min_fee_reserve: 1.into(),
-        percent_fee_reserve: 1.0,
-    };
-    let mut ln_backends: HashMap<
-        LnKey,
-        Arc<dyn MintLightning<Err = cdk::cdk_lightning::Error> + Sync + Send>,
-    > = HashMap::new();
-    let ln_key = LnKey::new(CurrencyUnit::Sat, PaymentMethod::Bolt11);
-
-    let wallet = Arc::new(FakeWallet::new(
-        fee_reserve.clone(),
-        HashMap::default(),
-        HashSet::default(),
-        0,
-    ));
-
-    ln_backends.insert(ln_key, wallet.clone());
-
-    ln_backends
-}
-
-pub async fn start_mint(
-    ln_backends: HashMap<
-        LnKey,
-        Arc<dyn MintLightning<Err = cdk::cdk_lightning::Error> + Sync + Send>,
-    >,
-    supported_units: HashMap<CurrencyUnit, (u64, u8)>,
-) -> Result<()> {
-    let nuts = Nuts::new()
-        .nut07(true)
-        .nut08(true)
-        .nut09(true)
-        .nut10(true)
-        .nut11(true)
-        .nut12(true)
-        .nut14(true);
-
-    let mint_info = MintInfo::new().nuts(nuts);
-
-    let mnemonic = Mnemonic::generate(12)?;
-
-    let quote_ttl = QuoteTTL::new(10000, 10000);
-
-    let mint = Mint::new(
-        &get_mint_url(),
-        &mnemonic.to_seed_normalized(""),
-        mint_info,
-        quote_ttl,
-        Arc::new(MintMemoryDatabase::default()),
-        ln_backends.clone(),
-        supported_units,
-        HashMap::new(),
-    )
-    .await?;
-
-    let mint_arc = Arc::new(mint);
-
-    let v1_service = cdk_axum::create_mint_router(Arc::clone(&mint_arc)).await?;
-
-    let mint_service = Router::new()
-        .merge(v1_service)
-        .layer(CorsLayer::permissive());
-
-    let mint = Arc::clone(&mint_arc);
-
-    let shutdown = Arc::new(Notify::new());
-
-    tokio::spawn({
-        let shutdown = Arc::clone(&shutdown);
-        async move { mint.wait_for_paid_invoices(shutdown).await }
-    });
-
-    axum::Server::bind(
-        &format!("{}:{}", get_mint_addr(), get_mint_port())
-            .as_str()
-            .parse()?,
-    )
-    .serve(mint_service.into_make_service())
-    .await?;
-
-    Ok(())
-}
-
 pub async fn wallet_mint(
 pub async fn wallet_mint(
     wallet: Arc<Wallet>,
     wallet: Arc<Wallet>,
     amount: Amount,
     amount: Amount,
@@ -247,3 +152,22 @@ pub async fn attempt_to_swap_pending(wallet: &Wallet) -> Result<()> {
 
 
     Ok(())
     Ok(())
 }
 }
+
+// Keep polling the state of the mint quote id until it's paid
+pub async fn wait_for_mint_to_be_paid(wallet: &Wallet, mint_quote_id: &str) -> Result<()> {
+    let mut subscription = wallet
+        .subscribe(WalletSubscription::Bolt11MintQuoteState(vec![
+            mint_quote_id.to_owned(),
+        ]))
+        .await;
+
+    while let Some(msg) = subscription.recv().await {
+        if let NotificationPayload::MintQuoteBolt11Response(response) = msg {
+            if response.state == MintQuoteState::Paid {
+                break;
+            }
+        }
+    }
+
+    Ok(())
+}

+ 4 - 23
crates/cdk-integration-tests/tests/fake_wallet.rs

@@ -6,13 +6,13 @@ use cdk::amount::SplitTarget;
 use cdk::cdk_database::WalletMemoryDatabase;
 use cdk::cdk_database::WalletMemoryDatabase;
 use cdk::nuts::nut00::ProofsMethods;
 use cdk::nuts::nut00::ProofsMethods;
 use cdk::nuts::{
 use cdk::nuts::{
-    CurrencyUnit, MeltBolt11Request, MeltQuoteState, MintBolt11Request, MintQuoteState,
-    NotificationPayload, PreMintSecrets, SecretKey, State,
+    CurrencyUnit, MeltBolt11Request, MeltQuoteState, MintBolt11Request, PreMintSecrets, SecretKey,
+    State,
 };
 };
 use cdk::wallet::client::{HttpClient, MintConnector};
 use cdk::wallet::client::{HttpClient, MintConnector};
-use cdk::wallet::{Wallet, WalletSubscription};
+use cdk::wallet::Wallet;
 use cdk_fake_wallet::{create_fake_invoice, FakeInvoiceDescription};
 use cdk_fake_wallet::{create_fake_invoice, FakeInvoiceDescription};
-use cdk_integration_tests::attempt_to_swap_pending;
+use cdk_integration_tests::{attempt_to_swap_pending, wait_for_mint_to_be_paid};
 
 
 const MINT_URL: &str = "http://127.0.0.1:8086";
 const MINT_URL: &str = "http://127.0.0.1:8086";
 
 
@@ -477,22 +477,3 @@ async fn test_fake_mint_with_wrong_witness() -> Result<()> {
         Ok(_) => bail!("Minting should not have succeed without a witness"),
         Ok(_) => bail!("Minting should not have succeed without a witness"),
     }
     }
 }
 }
-
-// Keep polling the state of the mint quote id until it's paid
-async fn wait_for_mint_to_be_paid(wallet: &Wallet, mint_quote_id: &str) -> Result<()> {
-    let mut subscription = wallet
-        .subscribe(WalletSubscription::Bolt11MintQuoteState(vec![
-            mint_quote_id.to_owned(),
-        ]))
-        .await;
-
-    while let Some(msg) = subscription.recv().await {
-        if let NotificationPayload::MintQuoteBolt11Response(response) = msg {
-            if response.state == MintQuoteState::Paid {
-                break;
-            }
-        }
-    }
-
-    Ok(())
-}

+ 39 - 261
crates/cdk-integration-tests/tests/integration_tests_pure.rs

@@ -1,267 +1,45 @@
-#[cfg(test)]
-mod integration_tests_pure {
-    use std::assert_eq;
-    use std::collections::HashMap;
-    use std::fmt::{Debug, Formatter};
-    use std::str::FromStr;
-    use std::sync::Arc;
-
-    use async_trait::async_trait;
-    use cdk::amount::SplitTarget;
-    use cdk::cdk_database::mint_memory::MintMemoryDatabase;
-    use cdk::cdk_database::WalletMemoryDatabase;
-    use cdk::nuts::nut00::ProofsMethods;
-    use cdk::nuts::{
-        CheckStateRequest, CheckStateResponse, CurrencyUnit, Id, KeySet, KeysetResponse,
-        MeltBolt11Request, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request,
-        MintBolt11Response, MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response,
-        MintQuoteState, Nuts, RestoreRequest, RestoreResponse, SwapRequest, SwapResponse,
-    };
-    use cdk::types::QuoteTTL;
-    use cdk::util::unix_time;
-    use cdk::wallet::client::MintConnector;
-    use cdk::{Amount, Error, Mint, Wallet};
-    use cdk_integration_tests::create_backends_fake_wallet;
-    use rand::random;
-    use tokio::sync::Notify;
-    use uuid::Uuid;
-
-    struct DirectMintConnection {
-        mint: Arc<Mint>,
-    }
-
-    impl Debug for DirectMintConnection {
-        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-            write!(
-                f,
-                "DirectMintConnection {{ mint_info: {:?} }}",
-                self.mint.config.mint_info()
-            )
-        }
-    }
-
-    /// Implements the generic [MintConnector] (i.e. use the interface that expects to communicate
-    /// to a generic mint, where we don't know that quote ID's are [Uuid]s) for [DirectMintConnection],
-    /// where we know we're dealing with a mint that uses [Uuid]s for quotes.
-    /// Convert the requests and responses between the [String] and [Uuid] variants as necessary.
-    #[async_trait]
-    impl MintConnector for DirectMintConnection {
-        async fn get_mint_keys(&self) -> Result<Vec<KeySet>, Error> {
-            self.mint.pubkeys().await.map(|pks| pks.keysets)
-        }
-
-        async fn get_mint_keyset(&self, keyset_id: Id) -> Result<KeySet, Error> {
-            self.mint
-                .keyset(&keyset_id)
-                .await
-                .and_then(|res| res.ok_or(Error::UnknownKeySet))
-        }
-
-        async fn get_mint_keysets(&self) -> Result<KeysetResponse, Error> {
-            self.mint.keysets().await
-        }
-
-        async fn post_mint_quote(
-            &self,
-            request: MintQuoteBolt11Request,
-        ) -> Result<MintQuoteBolt11Response<String>, Error> {
-            self.mint
-                .get_mint_bolt11_quote(request)
-                .await
-                .map(Into::into)
-        }
-
-        async fn get_mint_quote_status(
-            &self,
-            quote_id: &str,
-        ) -> Result<MintQuoteBolt11Response<String>, Error> {
-            let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
-            self.mint
-                .check_mint_quote(&quote_id_uuid)
-                .await
-                .map(Into::into)
-        }
-
-        async fn post_mint(
-            &self,
-            request: MintBolt11Request<String>,
-        ) -> Result<MintBolt11Response, Error> {
-            let request_uuid = request.try_into().unwrap();
-            self.mint.process_mint_request(request_uuid).await
-        }
-
-        async fn post_melt_quote(
-            &self,
-            request: MeltQuoteBolt11Request,
-        ) -> Result<MeltQuoteBolt11Response<String>, Error> {
-            self.mint
-                .get_melt_bolt11_quote(&request)
-                .await
-                .map(Into::into)
-        }
-
-        async fn get_melt_quote_status(
-            &self,
-            quote_id: &str,
-        ) -> Result<MeltQuoteBolt11Response<String>, Error> {
-            let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
-            self.mint
-                .check_melt_quote(&quote_id_uuid)
-                .await
-                .map(Into::into)
-        }
-
-        async fn post_melt(
-            &self,
-            request: MeltBolt11Request<String>,
-        ) -> Result<MeltQuoteBolt11Response<String>, Error> {
-            let request_uuid = request.try_into().unwrap();
-            self.mint.melt_bolt11(&request_uuid).await.map(Into::into)
-        }
-
-        async fn post_swap(&self, swap_request: SwapRequest) -> Result<SwapResponse, Error> {
-            self.mint.process_swap_request(swap_request).await
-        }
-
-        async fn get_mint_info(&self) -> Result<MintInfo, Error> {
-            Ok(self.mint.mint_info().clone().time(unix_time()))
-        }
-
-        async fn post_check_state(
-            &self,
-            request: CheckStateRequest,
-        ) -> Result<CheckStateResponse, Error> {
-            self.mint.check_state(&request).await
-        }
-
-        async fn post_restore(&self, request: RestoreRequest) -> Result<RestoreResponse, Error> {
-            self.mint.restore(request).await
-        }
-    }
-
-    fn get_mint_connector(mint: Arc<Mint>) -> DirectMintConnection {
-        DirectMintConnection { mint }
-    }
-
-    async fn create_and_start_test_mint() -> anyhow::Result<Arc<Mint>> {
-        let fee: u64 = 0;
-        let mut supported_units = HashMap::new();
-        supported_units.insert(CurrencyUnit::Sat, (fee, 32));
-
-        let nuts = Nuts::new()
-            .nut07(true)
-            .nut08(true)
-            .nut09(true)
-            .nut10(true)
-            .nut11(true)
-            .nut12(true)
-            .nut14(true);
-
-        let mint_info = MintInfo::new().nuts(nuts);
-
-        let quote_ttl = QuoteTTL::new(10000, 10000);
-
-        let mint_url = "http://aaa";
-
-        let seed = random::<[u8; 32]>();
-        let mint: Mint = Mint::new(
-            mint_url,
-            &seed,
-            mint_info,
-            quote_ttl,
-            Arc::new(MintMemoryDatabase::default()),
-            create_backends_fake_wallet(),
-            supported_units,
-            HashMap::new(),
+use std::assert_eq;
+
+use cdk::amount::SplitTarget;
+use cdk::nuts::nut00::ProofsMethods;
+use cdk::wallet::SendKind;
+use cdk::Amount;
+use cdk_integration_tests::init_pure_tests::{
+    create_and_start_test_mint, create_test_wallet_for_mint, fund_wallet,
+};
+
+#[tokio::test]
+async fn test_swap_to_send() -> anyhow::Result<()> {
+    let mint_bob = create_and_start_test_mint().await?;
+    let wallet_alice = create_test_wallet_for_mint(mint_bob.clone())?;
+
+    // Alice gets 64 sats
+    fund_wallet(wallet_alice.clone(), 64).await?;
+    let balance_alice = wallet_alice.total_balance().await?;
+    assert_eq!(Amount::from(64), balance_alice);
+
+    // Alice wants to send 40 sats, which internally swaps
+    let token = wallet_alice
+        .send(
+            Amount::from(40),
+            None,
+            None,
+            &SplitTarget::None,
+            &SendKind::OnlineExact,
+            false,
         )
         )
         .await?;
         .await?;
+    assert_eq!(Amount::from(40), token.proofs().total_amount()?);
+    assert_eq!(Amount::from(24), wallet_alice.total_balance().await?);
 
 
-        let mint_arc = Arc::new(mint);
-
-        let mint_arc_clone = Arc::clone(&mint_arc);
-        let shutdown = Arc::new(Notify::new());
-        tokio::spawn({
-            let shutdown = Arc::clone(&shutdown);
-            async move { mint_arc_clone.wait_for_paid_invoices(shutdown).await }
-        });
-
-        Ok(mint_arc)
-    }
-
-    fn create_test_wallet_for_mint(mint: Arc<Mint>) -> anyhow::Result<Arc<Wallet>> {
-        let connector = get_mint_connector(mint);
-
-        let seed = random::<[u8; 32]>();
-        let mint_url = connector.mint.config.mint_url().to_string();
-        let unit = CurrencyUnit::Sat;
-
-        let localstore = WalletMemoryDatabase::default();
-        let mut wallet = Wallet::new(&mint_url, unit, Arc::new(localstore), &seed, None)?;
-
-        wallet.set_client(connector);
-
-        Ok(Arc::new(wallet))
-    }
-
-    /// Creates a mint quote for the given amount and checks its state in a loop. Returns when
-    /// amount is minted.
-    async fn receive(wallet: Arc<Wallet>, amount: u64) -> anyhow::Result<Amount> {
-        let desired_amount = Amount::from(amount);
-        let quote = wallet.mint_quote(desired_amount, None).await?;
-
-        loop {
-            let status = wallet.mint_quote_state(&quote.id).await?;
-            if status.state == MintQuoteState::Paid {
-                break;
-            }
-        }
-
-        Ok(wallet
-            .mint(&quote.id, SplitTarget::default(), None)
-            .await?
-            .total_amount()?)
-    }
-
-    mod nut03 {
-        use cdk::nuts::nut00::ProofsMethods;
-        use cdk::wallet::SendKind;
-
-        use crate::integration_tests_pure::*;
-
-        #[tokio::test]
-        async fn test_swap_to_send() -> anyhow::Result<()> {
-            let mint_bob = create_and_start_test_mint().await?;
-            let wallet_alice = create_test_wallet_for_mint(mint_bob.clone())?;
-
-            // Alice gets 64 sats
-            receive(wallet_alice.clone(), 64).await?;
-            let balance_alice = wallet_alice.total_balance().await?;
-            assert_eq!(Amount::from(64), balance_alice);
-
-            // Alice wants to send 40 sats, which internally swaps
-            let token = wallet_alice
-                .send(
-                    Amount::from(40),
-                    None,
-                    None,
-                    &SplitTarget::None,
-                    &SendKind::OnlineExact,
-                    false,
-                )
-                .await?;
-            assert_eq!(Amount::from(40), token.proofs().total_amount()?);
-            assert_eq!(Amount::from(24), wallet_alice.total_balance().await?);
-
-            // Alice sends cashu, Carol receives
-            let wallet_carol = create_test_wallet_for_mint(mint_bob.clone())?;
-            let received_amount = wallet_carol
-                .receive_proofs(token.proofs(), SplitTarget::None, &[], &[])
-                .await?;
+    // Alice sends cashu, Carol receives
+    let wallet_carol = create_test_wallet_for_mint(mint_bob.clone())?;
+    let received_amount = wallet_carol
+        .receive_proofs(token.proofs(), SplitTarget::None, &[], &[])
+        .await?;
 
 
-            assert_eq!(Amount::from(40), received_amount);
-            assert_eq!(Amount::from(40), wallet_carol.total_balance().await?);
+    assert_eq!(Amount::from(40), received_amount);
+    assert_eq!(Amount::from(40), wallet_carol.total_balance().await?);
 
 
-            Ok(())
-        }
-    }
+    Ok(())
 }
 }

+ 2 - 2
misc/itests.sh

@@ -45,8 +45,8 @@ echo "Temp directory created: $cdk_itests"
 export MINT_DATABASE="$1";
 export MINT_DATABASE="$1";
 
 
 cargo build -p cdk-integration-tests 
 cargo build -p cdk-integration-tests 
-cargo build --bin cdk-integration-tests 
-cargo run --bin cdk-integration-tests &
+cargo build --bin regtest_mint 
+cargo run --bin regtest_mint &
 # Capture its PID
 # Capture its PID
 CDK_ITEST_MINT_BIN_PID=$!
 CDK_ITEST_MINT_BIN_PID=$!