Skip to content

Commit

Permalink
Add http_agent to TestServices and fetch ohttp keys
Browse files Browse the repository at this point in the history
Add http_agent: Arc<Client> and a corresponding getter since we
initialize an agent in every V2 test, and helpers to wait until all
services are ready and to fetch OHTTP keys.
  • Loading branch information
spacebear21 committed Jan 20, 2025
1 parent 8334a93 commit 77a4012
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 90 deletions.
1 change: 1 addition & 0 deletions Cargo-minimal.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1672,6 +1672,7 @@ dependencies = [
"log",
"ohttp-relay",
"once_cell",
"payjoin",
"payjoin-directory",
"rcgen",
"reqwest",
Expand Down
1 change: 1 addition & 0 deletions Cargo-recent.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1672,6 +1672,7 @@ dependencies = [
"log",
"ohttp-relay",
"once_cell",
"payjoin",
"payjoin-directory",
"rcgen",
"reqwest",
Expand Down
30 changes: 7 additions & 23 deletions payjoin-cli/tests/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,11 @@ mod e2e {
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn send_receive_payjoin() {
use std::path::PathBuf;
use std::sync::Arc;

use payjoin_test_utils::{
http_agent, init_tracing, wait_for_service_ready, BoxError, TestServices,
};
use payjoin_test_utils::{init_tracing, BoxError, TestServices};
use testcontainers::clients::Cli;
use testcontainers_modules::redis::Redis;
use tokio::process::Child;
use url::Url;

type Result<T> = std::result::Result<T, BoxError>;

Expand All @@ -155,36 +151,24 @@ mod e2e {
let result: Result<()> = tokio::select! {
res = services.take_ohttp_relay_handle().unwrap() => Err(format!("Ohttp relay is long running: {:?}", res).into()),
res = services.take_directory_handle().unwrap() => Err(format!("Directory server is long running: {:?}", res).into()),
res = send_receive_cli_async(services.ohttp_relay_url(), services.directory_url(), services.cert(), receiver_db_path.clone(), sender_db_path.clone()) => res.map_err(|e| format!("send_receive failed: {:?}", e).into()),
res = send_receive_cli_async(&services, receiver_db_path.clone(), sender_db_path.clone()) => res.map_err(|e| format!("send_receive failed: {:?}", e).into()),
};

cleanup_temp_file(&receiver_db_path).await;
cleanup_temp_file(&sender_db_path).await;
assert!(result.is_ok(), "{}", result.unwrap_err());

async fn send_receive_cli_async(
ohttp_relay: Url,
directory: Url,
cert: Vec<u8>,
services: &TestServices,
receiver_db_path: PathBuf,
sender_db_path: PathBuf,
) -> Result<()> {
let (bitcoind, _sender, _receiver) = init_bitcoind_sender_receiver(None, None)?;
let temp_dir = env::temp_dir();
let cert_path = temp_dir.join("localhost.der");
tokio::fs::write(&cert_path, cert.clone()).await?;
let agent = Arc::new(http_agent(cert.clone()).unwrap());
wait_for_service_ready(ohttp_relay.clone(), agent.clone()).await?;
wait_for_service_ready(directory.clone(), agent).await?;

// fetch for setup here since ohttp_relay doesn't know the certificate for the directory
// so payjoin-cli is set up with the mock_ohttp_relay which is the directory
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay.clone(),
directory.clone(),
cert.clone(),
)
.await?;
tokio::fs::write(&cert_path, services.cert()).await?;
services.wait_for_services_ready().await?;
let ohttp_keys = services.fetch_ohttp_keys().await?;
let ohttp_keys_path = temp_dir.join("ohttp_keys");
tokio::fs::write(&ohttp_keys_path, ohttp_keys.encode()?).await?;

Expand All @@ -194,7 +178,7 @@ mod e2e {

let payjoin_cli = env!("CARGO_BIN_EXE_payjoin-cli");

let directory = directory.as_str();
let directory = &services.directory_url().to_string();
// Mock ohttp_relay since the ohttp_relay's http client doesn't have the certificate for the directory
let mock_ohttp_relay = directory;

Expand Down
1 change: 1 addition & 0 deletions payjoin-test-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ http = "1"
log = "0.4.7"
ohttp-relay = { version = "0.0.9", features = ["_test-util"] }
once_cell = "1"
payjoin = { path = "../payjoin", features = ["io", "_danger-local-https"] }
payjoin-directory = { path = "../payjoin-directory", features = ["_danger-local-https"] }
rcgen = "0.11"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }
Expand Down
17 changes: 17 additions & 0 deletions payjoin-test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use bitcoind::bitcoincore_rpc::{self, RpcApi};
use http::StatusCode;
use log::{log_enabled, Level};
use once_cell::sync::OnceCell;
use payjoin::io::{fetch_ohttp_keys_with_cert, Error as IOError};
use payjoin::OhttpKeys;
use reqwest::{Client, ClientBuilder};
use tokio::task::JoinHandle;
use tracing_subscriber::{EnvFilter, FmtSubscriber};
Expand All @@ -36,6 +38,7 @@ pub struct TestServices {
cert_key: (Vec<u8>, Vec<u8>),
directory: (u16, Option<JoinHandle<Result<(), BoxSendSyncError>>>),
ohttp_relay: (u16, Option<JoinHandle<Result<(), BoxSendSyncError>>>),
http_agent: Arc<Client>,
}

impl TestServices {
Expand All @@ -45,10 +48,12 @@ impl TestServices {
let gateway_origin =
http::Uri::from_str(&format!("https://localhost:{}", directory.0)).unwrap();
let ohttp_relay = ohttp_relay::listen_tcp_on_free_port(gateway_origin).await?;
let http_agent: Arc<Client> = Arc::new(http_agent(cert_key.0.clone()).unwrap());
Ok(Self {
cert_key,
directory: (directory.0, Some(directory.1)),
ohttp_relay: (ohttp_relay.0, Some(ohttp_relay.1)),
http_agent,
})
}

Expand All @@ -69,6 +74,18 @@ impl TestServices {
pub fn take_ohttp_relay_handle(&mut self) -> Option<JoinHandle<Result<(), BoxSendSyncError>>> {
self.ohttp_relay.1.take()
}

pub fn http_agent(&self) -> Arc<Client> { self.http_agent.clone() }

pub async fn wait_for_services_ready(&self) -> Result<(), &'static str> {
wait_for_service_ready(self.ohttp_relay_url(), self.http_agent()).await?;
wait_for_service_ready(self.directory_url(), self.http_agent()).await?;
Ok(())
}

pub async fn fetch_ohttp_keys(&self) -> Result<OhttpKeys, IOError> {
fetch_ohttp_keys_with_cert(self.ohttp_relay_url(), self.directory_url(), self.cert()).await
}
}

pub async fn init_directory(
Expand Down
97 changes: 30 additions & 67 deletions payjoin/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ mod integration {
use payjoin::receive::v2::{PayjoinProposal, Receiver, UncheckedProposal};
use payjoin::send::v2::SenderBuilder;
use payjoin::{OhttpKeys, PjUri, UriExt};
use payjoin_test_utils::{http_agent, wait_for_service_ready, TestServices};
use payjoin_test_utils::TestServices;
use reqwest::{Client, Error, Response};
use testcontainers_modules::redis::Redis;
use testcontainers_modules::testcontainers::clients::Cli;
Expand All @@ -194,7 +194,7 @@ mod integration {
let mut services = TestServices::initialize(db_host).await.unwrap();
tokio::select!(
err = services.take_directory_handle().unwrap() => panic!("Directory server exited early: {:?}", err),
res = try_request_with_bad_keys(services.directory_url(), bad_ohttp_keys, services.cert()) => {
res = try_request_with_bad_keys(&services, bad_ohttp_keys) => {
assert_eq!(
res.unwrap().headers().get("content-type").unwrap(),
"application/problem+json"
Expand All @@ -203,12 +203,12 @@ mod integration {
);

async fn try_request_with_bad_keys(
directory: Url,
services: &TestServices,
bad_ohttp_keys: OhttpKeys,
cert_der: Vec<u8>,
) -> Result<Response, Error> {
let agent = Arc::new(http_agent(cert_der.clone()).unwrap());
wait_for_service_ready(directory.clone(), agent.clone()).await.unwrap();
let agent = services.http_agent();
services.wait_for_services_ready().await.unwrap();
let directory = services.directory_url();
let mock_ohttp_relay = directory.clone(); // pass through to directory
let mock_address = Address::from_str("tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4")
.unwrap()
Expand All @@ -234,25 +234,15 @@ mod integration {
tokio::select!(
err = services.take_ohttp_relay_handle().unwrap() => panic!("Ohttp relay exited early: {:?}", err),
err = services.take_directory_handle().unwrap() => panic!("Directory server exited early: {:?}", err),
res = do_expiration_tests(services.ohttp_relay_url(), services.directory_url(), services.cert()) => assert!(res.is_ok(), "v2 send receive failed: {:#?}", res)
res = do_expiration_tests(&services) => assert!(res.is_ok(), "v2 send receive failed: {:#?}", res)
);

async fn do_expiration_tests(
ohttp_relay: Url,
directory: Url,
cert_der: Vec<u8>,
) -> Result<(), BoxError> {
async fn do_expiration_tests(services: &TestServices) -> Result<(), BoxError> {
let (_bitcoind, sender, receiver) = init_bitcoind_sender_receiver(None, None)?;
let agent = Arc::new(http_agent(cert_der.clone())?);
wait_for_service_ready(ohttp_relay.clone(), agent.clone()).await.unwrap();
wait_for_service_ready(directory.clone(), agent.clone()).await.unwrap();
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay.clone(),
directory.clone(),
cert_der,
)
.await?;

services.wait_for_services_ready().await?;
let directory = services.directory_url();
let ohttp_relay = services.ohttp_relay_url();
let ohttp_keys = services.fetch_ohttp_keys().await?;
// **********************
// Inside the Receiver:
let address = receiver.get_new_address(None, None)?.assume_checked();
Expand Down Expand Up @@ -295,24 +285,15 @@ mod integration {
tokio::select!(
err = services.take_ohttp_relay_handle().unwrap() => panic!("Ohttp relay exited early: {:?}", err),
err = services.take_directory_handle().unwrap() => panic!("Directory server exited early: {:?}", err),
res = do_v2_send_receive(services.ohttp_relay_url(), services.directory_url(), services.cert()) => assert!(res.is_ok(), "v2 send receive failed: {:#?}", res)
res = do_v2_send_receive(&services) => assert!(res.is_ok(), "v2 send receive failed: {:#?}", res)
);

async fn do_v2_send_receive(
ohttp_relay: Url,
directory: Url,
cert_der: Vec<u8>,
) -> Result<(), BoxError> {
async fn do_v2_send_receive(services: &TestServices) -> Result<(), BoxError> {
let (_bitcoind, sender, receiver) = init_bitcoind_sender_receiver(None, None)?;
let agent = Arc::new(http_agent(cert_der.clone())?);
wait_for_service_ready(ohttp_relay.clone(), agent.clone()).await.unwrap();
wait_for_service_ready(directory.clone(), agent.clone()).await.unwrap();
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay.clone(),
directory.clone(),
cert_der.clone(),
)
.await?;
let agent = services.http_agent();
services.wait_for_services_ready().await?;
let directory = services.directory_url();
let ohttp_keys = services.fetch_ohttp_keys().await?;
// **********************
// Inside the Receiver:
let address = receiver.get_new_address(None, None)?.assume_checked();
Expand Down Expand Up @@ -422,24 +403,15 @@ mod integration {
tokio::select!(
err = services.take_ohttp_relay_handle().unwrap() => panic!("Ohttp relay exited early: {:?}", err),
err = services.take_directory_handle().unwrap() => panic!("Directory server exited early: {:?}", err),
res = do_v2_send_receive(services.ohttp_relay_url(), services.directory_url(), services.cert()) => assert!(res.is_ok(), "v2 send receive failed: {:#?}", res)
res = do_v2_send_receive(&services) => assert!(res.is_ok(), "v2 send receive failed: {:#?}", res)
);

async fn do_v2_send_receive(
ohttp_relay: Url,
directory: Url,
cert_der: Vec<u8>,
) -> Result<(), BoxError> {
async fn do_v2_send_receive(services: &TestServices) -> Result<(), BoxError> {
let (bitcoind, sender, receiver) = init_bitcoind_sender_receiver(None, None)?;
let agent = Arc::new(http_agent(cert_der.clone())?);
wait_for_service_ready(ohttp_relay.clone(), agent.clone()).await.unwrap();
wait_for_service_ready(directory.clone(), agent.clone()).await.unwrap();
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay.clone(),
directory.clone(),
cert_der,
)
.await?;
let agent = services.http_agent();
services.wait_for_services_ready().await?;
let directory = services.directory_url();
let ohttp_keys = services.fetch_ohttp_keys().await?;
// **********************
// Inside the Receiver:
// make utxos with different script types
Expand Down Expand Up @@ -629,24 +601,15 @@ mod integration {
tokio::select!(
err = services.take_ohttp_relay_handle().unwrap() => panic!("Ohttp relay exited early: {:?}", err),
err = services.take_directory_handle().unwrap() => panic!("Directory server exited early: {:?}", err),
res = do_v1_to_v2(services.ohttp_relay_url(), services.directory_url(), services.cert()) => assert!(res.is_ok(), "v2 send receive failed: {:#?}", res)
res = do_v1_to_v2(&services) => assert!(res.is_ok(), "v2 send receive failed: {:#?}", res)
);

async fn do_v1_to_v2(
ohttp_relay: Url,
directory: Url,
cert_der: Vec<u8>,
) -> Result<(), BoxError> {
async fn do_v1_to_v2(services: &TestServices) -> Result<(), BoxError> {
let (_bitcoind, sender, receiver) = init_bitcoind_sender_receiver(None, None)?;
let agent: Arc<Client> = Arc::new(http_agent(cert_der.clone())?);
wait_for_service_ready(ohttp_relay.clone(), agent.clone()).await?;
wait_for_service_ready(directory.clone(), agent.clone()).await?;
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay.clone(),
directory.clone(),
cert_der.clone(),
)
.await?;
let agent = services.http_agent();
services.wait_for_services_ready().await?;
let directory = services.directory_url();
let ohttp_keys = services.fetch_ohttp_keys().await?;
let address = receiver.get_new_address(None, None)?.assume_checked();

let mut session =
Expand Down

0 comments on commit 77a4012

Please sign in to comment.