Skip to content

Commit

Permalink
Merge pull request #532 from thesimplekid/refactor_itests
Browse files Browse the repository at this point in the history
Refactor itests
  • Loading branch information
thesimplekid authored Jan 14, 2025
2 parents de4a2dc + 57a7aa0 commit 411ba61
Show file tree
Hide file tree
Showing 10 changed files with 334 additions and 440 deletions.
3 changes: 1 addition & 2 deletions crates/cdk-integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ rust-version = "1.63.0"
http_subscription = ["cdk/http_subscription"]

[dependencies]
async-trait = "0.1"
axum = "0.6.20"
rand = "0.8.5"
bip39 = { version = "2.0", features = ["rand"] }
Expand Down Expand Up @@ -57,8 +58,6 @@ getrandom = { version = "0.2", features = ["js"] }
instant = { version = "0.1", features = ["wasm-bindgen", "inaccurate"] }

[dev-dependencies]
async-trait = "0.1"
rand = "0.8.5"
bip39 = { version = "2.0", features = ["rand"] }
anyhow = "1"
cdk = { path = "../cdk", features = ["mint", "wallet"] }
Expand Down
File renamed without changes.
29 changes: 3 additions & 26 deletions crates/cdk-integration-tests/src/init_fake_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ use std::collections::{HashMap, HashSet};
use std::sync::Arc;

use anyhow::Result;
use axum::Router;
use bip39::Mnemonic;
use cdk::cdk_database::{self, MintDatabase};
use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
use cdk::nuts::{CurrencyUnit, PaymentMethod};
use cdk_fake_wallet::FakeWallet;
use tokio::sync::Notify;
use tower_http::cors::CorsLayer;
use tracing_subscriber::EnvFilter;

use crate::init_mint::start_mint;

pub async fn start_fake_mint<D>(addr: &str, port: u16, database: D) -> Result<()>
where
D: MintDatabase<Err = cdk_database::Error> + Send + Sync + 'static,
Expand Down Expand Up @@ -58,29 +57,7 @@ where

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(())
}
35 changes: 35 additions & 0 deletions crates/cdk-integration-tests/src/init_mint.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 223 additions & 0 deletions crates/cdk-integration-tests/src/init_pure_tests.rs
Original file line number Diff line number Diff line change
@@ -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()?)
}
29 changes: 3 additions & 26 deletions crates/cdk-integration-tests/src/init_regtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::path::PathBuf;
use std::sync::Arc;

use anyhow::Result;
use axum::Router;
use bip39::Mnemonic;
use cdk::cdk_database::{self, MintDatabase};
use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
Expand All @@ -14,8 +13,8 @@ use ln_regtest_rs::bitcoind::Bitcoind;
use ln_regtest_rs::cln::Clnd;
use ln_regtest_rs::ln_client::{ClnClient, LightningClient, LndClient};
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 ZMQ_RAW_BLOCK: &str = "tcp://127.0.0.1:28332";
Expand Down Expand Up @@ -172,29 +171,7 @@ where

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(())
}
Expand Down
Loading

0 comments on commit 411ba61

Please sign in to comment.