diff --git a/cmd/crates/stellar-ledger/tests/test/emulator_tests.rs b/cmd/crates/stellar-ledger/tests/test/emulator_tests.rs index 228fc4409..4483296bb 100644 --- a/cmd/crates/stellar-ledger/tests/test/emulator_tests.rs +++ b/cmd/crates/stellar-ledger/tests/test/emulator_tests.rs @@ -4,6 +4,7 @@ use soroban_env_host::xdr::{self, Operation, OperationBody, Uint256}; use soroban_env_host::xdr::{Hash, Transaction}; use std::vec; +use std::net::TcpListener; use stellar_ledger::hd_path::HdPath; use stellar_ledger::{Blob, Error, LedgerSigner}; @@ -14,7 +15,7 @@ use stellar_xdr::curr::{ Memo, MuxedAccount, PaymentOp, Preconditions, SequenceNumber, TransactionExt, }; -use testcontainers::clients; +use testcontainers::{clients, core::Port, RunnableImage}; use tokio::time::sleep; pub const TEST_NETWORK_PASSPHRASE: &[u8] = b"Test SDF Network ; September 2015"; @@ -44,11 +45,9 @@ use test_helpers::test::{ #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_get_public_key(ledger_device_model: String) { - let args = Args { - ledger_device_model, - }; + let runnable_image = get_runnable_image(ledger_device_model.clone()); let docker = clients::Cli::default(); - let node = docker.run((Speculos::new(), args)); + let node = docker.run(runnable_image); let host_port = node.get_host_port_ipv4(9998); let ui_host_port: u16 = node.get_host_port_ipv4(5000); wait_for_emulator_start_text(ui_host_port).await; @@ -78,11 +77,9 @@ async fn test_get_public_key(ledger_device_model: String) { #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_get_app_configuration(ledger_device_model: String) { - let args = Args { - ledger_device_model, - }; + let runnable_image = get_runnable_image(ledger_device_model.clone()); let docker = clients::Cli::default(); - let node = docker.run((Speculos::new(), args)); + let node = docker.run(runnable_image); let host_port = node.get_host_port_ipv4(9998); let ui_host_port: u16 = node.get_host_port_ipv4(5000); wait_for_emulator_start_text(ui_host_port).await; @@ -108,11 +105,9 @@ async fn test_get_app_configuration(ledger_device_model: String) { #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_sign_tx(ledger_device_model: String) { - let args = Args { - ledger_device_model, - }; + let runnable_image = get_runnable_image(ledger_device_model.clone()); let docker = clients::Cli::default(); - let node = docker.run((Speculos::new(), args.clone())); + let node = docker.run(runnable_image); let host_port = node.get_host_port_ipv4(9998); let ui_host_port: u16 = node.get_host_port_ipv4(5000); wait_for_emulator_start_text(ui_host_port).await; @@ -175,7 +170,7 @@ async fn test_sign_tx(ledger_device_model: String) { let ledger = Arc::clone(&ledger); async move { ledger.sign_transaction(path, tx, test_network_hash()).await } }); - let approve = tokio::task::spawn(approve_tx_signature(ui_host_port, args.ledger_device_model)); + let approve = tokio::task::spawn(approve_tx_signature(ui_host_port, ledger_device_model)); let result = sign.await.unwrap(); let _ = approve.await.unwrap(); @@ -199,12 +194,9 @@ async fn test_sign_tx(ledger_device_model: String) { #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_sign_tx_hash_when_hash_signing_is_not_enabled(ledger_device_model: String) { - let args = Args { - ledger_device_model, - }; - + let runnable_image = get_runnable_image(ledger_device_model.clone()); let docker = clients::Cli::default(); - let node = docker.run((Speculos::new(), args)); + let node = docker.run(runnable_image); let host_port = node.get_host_port_ipv4(9998); let ui_host_port: u16 = node.get_host_port_ipv4(5000); wait_for_emulator_start_text(ui_host_port).await; @@ -231,11 +223,9 @@ async fn test_sign_tx_hash_when_hash_signing_is_not_enabled(ledger_device_model: #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_sign_tx_hash_when_hash_signing_is_enabled(ledger_device_model: String) { - let args = Args { - ledger_device_model, - }; + let runnable_image = get_runnable_image(ledger_device_model.clone()); let docker = clients::Cli::default(); - let node = docker.run((Speculos::new(), args.clone())); + let node = docker.run(runnable_image); let host_port = node.get_host_port_ipv4(9998); let ui_host_port: u16 = node.get_host_port_ipv4(5000); @@ -262,10 +252,7 @@ async fn test_sign_tx_hash_when_hash_signing_is_enabled(ledger_device_model: Str let ledger = Arc::clone(&ledger); async move { ledger.sign_transaction_hash(path, &test_hash).await } }); - let approve = tokio::task::spawn(approve_tx_hash_signature( - ui_host_port, - args.ledger_device_model, - )); + let approve = tokio::task::spawn(approve_tx_hash_signature(ui_host_port, ledger_device_model)); let response = sign.await.unwrap(); let _ = approve.await.unwrap(); @@ -338,6 +325,37 @@ struct EventsResponse { events: Vec, } +fn get_runnable_image(ledger_device_model: String) -> RunnableImage { + let args = Args { + ledger_device_model, + }; + let runnable_image: RunnableImage = (Speculos::new(), args).into(); + + // doing this to randomize the ports on the host so that parallel tests don't clobber each other + let (tcp_port_1, tcp_port_2) = get_available_ports(); + runnable_image + .with_mapped_port(Port { + local: tcp_port_1, + internal: 9998, + }) + .with_mapped_port(Port { + local: tcp_port_2, + internal: 5000, + }) +} + +fn get_available_ports() -> (u16, u16) { + let listener1 = TcpListener::bind("127.0.0.1:0").unwrap(); + let listener2 = TcpListener::bind("127.0.0.1:0").unwrap(); + println!("listener1: {:?}", listener1); + let port_1 = listener1.local_addr().unwrap().port(); + let port_2 = listener2.local_addr().unwrap().port(); + drop(listener1); + drop(listener2); + + (port_1, port_2) +} + fn get_http_transport(host: &str, port: u16) -> Result { Ok(EmulatorHttpTransport::new(host, port)) }