diff --git a/crates/tests-integration/src/integration_test_utils.rs b/crates/tests-integration/src/integration_test_utils.rs index 08e6c370..b1a3995e 100644 --- a/crates/tests-integration/src/integration_test_utils.rs +++ b/crates/tests-integration/src/integration_test_utils.rs @@ -14,6 +14,7 @@ use starknet_gateway::gateway::Gateway; use starknet_gateway::rpc_state_reader::RpcStateReaderFactory; use starknet_mempool_types::communication::SharedMempoolClient; use test_utils::starknet_api_test_utils::external_tx_to_json; +use tokio::net::TcpListener; use crate::state_reader::spawn_test_rpc_state_reader; @@ -28,7 +29,7 @@ pub async fn create_gateway( ..Default::default() }; - let socket: SocketAddr = "127.0.0.1:3000".parse().unwrap(); + let socket = get_available_socket().await; let network_config = GatewayNetworkConfig { ip: socket.ip(), port: socket.port() }; let stateful_tx_validator_config = StatefulTransactionValidatorConfig::create_for_testing(); @@ -91,3 +92,18 @@ fn spawn_test_rpc_state_reader_config(rpc_server_addr: SocketAddr) -> RpcStateRe json_rpc_version: JSON_RPC_VERSION.to_string(), } } + +/// Returns a unique IP address and port for testing purposes. +/// +/// Tests run in parallel, so servers (like RPC or web) running on separate tests must have +/// different ports, otherwise the server will fail with "address already in use". +pub async fn get_available_socket() -> SocketAddr { + // Dinamically select port. + // First, set the port to 0 (dynamic port). + TcpListener::bind("127.0.0.1:0") + .await + .expect("Failed to bind to address") + // Then, resolve to the actual selected port. + .local_addr() + .expect("Failed to get local address") +} diff --git a/crates/tests-integration/src/state_reader.rs b/crates/tests-integration/src/state_reader.rs index d3a9f520..d16dc7ec 100644 --- a/crates/tests-integration/src/state_reader.rs +++ b/crates/tests-integration/src/state_reader.rs @@ -34,6 +34,8 @@ use tempfile::tempdir; use test_utils::starknet_api_test_utils::{deploy_account_tx, deployed_account_contract_address}; use tokio::sync::RwLock; +use crate::integration_test_utils::get_available_socket; + type ContractClassesMap = (Vec<(ClassHash, DeprecatedContractClass)>, Vec<(ClassHash, CasmContractClass)>); @@ -294,7 +296,10 @@ fn get_test_pending_classes() -> Arc> { } async fn run_papyrus_rpc_server(storage_reader: StorageReader) -> SocketAddr { - let rpc_config = RpcConfig::default(); + let rpc_config = RpcConfig { + server_address: get_available_socket().await.to_string(), + ..Default::default() + }; let (addr, handle) = run_server( &rpc_config, get_test_highest_block(),