From bcadb2a3f3c5e2bdd78f9b30ad0247323a67dc81 Mon Sep 17 00:00:00 2001 From: Martin Kourim Date: Fri, 17 Apr 2026 14:10:07 +0200 Subject: [PATCH] fix(cleanup): validate faucet args for non-framework testnets Replace the BOOTSTRAP_DIR-based precondition with a socket-path check so cleanup fails fast when run against a non-framework testnet without explicit faucet address and skey. Extract the CARDANO_NODE_SOCKET_PATH validation from conftest into helpers so it can be reused by testnet_cleanup and guarded against short paths. Add a faucet.addr existence check and a clearer error when inference is not possible. --- cardano_node_tests/testnet_cleanup.py | 4 ++-- cardano_node_tests/tests/conftest.py | 19 +----------------- cardano_node_tests/utils/helpers.py | 22 +++++++++++++++++++++ cardano_node_tests/utils/testnet_cleanup.py | 21 +++++++++++++++++--- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/cardano_node_tests/testnet_cleanup.py b/cardano_node_tests/testnet_cleanup.py index 1dc95ab33..bb5106811 100755 --- a/cardano_node_tests/testnet_cleanup.py +++ b/cardano_node_tests/testnet_cleanup.py @@ -58,9 +58,9 @@ def main() -> int: "Both address and skey file must be provided, or neither of them should be provided." ) return 1 - if not (args.address or os.environ.get("BOOTSTRAP_DIR")): + if not (args.address or testnet_cleanup.is_framework_testnet()): LOGGER.error( - "The address must be provided, or `BOOTSTRAP_DIR` environment variable must be set." + "The address and skey file must be provided when running with non-framework testnet." ) return 1 diff --git a/cardano_node_tests/tests/conftest.py b/cardano_node_tests/tests/conftest.py index 6f4bc9b7c..473e927c3 100644 --- a/cardano_node_tests/tests/conftest.py +++ b/cardano_node_tests/tests/conftest.py @@ -65,25 +65,8 @@ def pytest_addoption(parser: tp.Any) -> None: ) -def _check_cardano_node_socket_path() -> None: - """Check that `CARDANO_NODE_SOCKET_PATH` value is valid for use by testing framework.""" - socket_env = os.environ.get("CARDANO_NODE_SOCKET_PATH") - if not socket_env: - msg = "The `CARDANO_NODE_SOCKET_PATH` env variable is not set." - raise RuntimeError(msg) - - socket_path = pl.Path(socket_env).expanduser().resolve() - parts = socket_path.parts - if not parts[-2].startswith("state-cluster") or parts[-1] not in ( - "bft1.socket", - "relay1.socket", - ): - msg = "The `CARDANO_NODE_SOCKET_PATH` value is not valid for use by testing framework." - raise RuntimeError(msg) - - def pytest_configure(config: tp.Any) -> None: - _check_cardano_node_socket_path() + helpers.check_cardano_node_socket_path() # Don't bother collecting metadata if all tests are skipped if config.getvalue("skipall"): diff --git a/cardano_node_tests/utils/helpers.py b/cardano_node_tests/utils/helpers.py index cd10c33a8..c0579107b 100644 --- a/cardano_node_tests/utils/helpers.py +++ b/cardano_node_tests/utils/helpers.py @@ -360,3 +360,25 @@ def get_pool_param(key: str, *, pool_params: dict) -> tp.Any: val = pool_params.get(old_key) return val + + +def check_cardano_node_socket_path() -> None: + """Check that `CARDANO_NODE_SOCKET_PATH` value is valid for use by testing framework.""" + socket_env = os.environ.get("CARDANO_NODE_SOCKET_PATH") + if not socket_env: + msg = "The `CARDANO_NODE_SOCKET_PATH` env variable is not set." + raise ValueError(msg) + + socket_path = pl.Path(socket_env).expanduser().resolve() + parts = socket_path.parts + if ( + len(parts) < 2 + or not parts[-2].startswith("state-cluster") + or parts[-1] + not in ( + "bft1.socket", + "relay1.socket", + ) + ): + msg = "The `CARDANO_NODE_SOCKET_PATH` value is not valid for use by testing framework." + raise ValueError(msg) diff --git a/cardano_node_tests/utils/testnet_cleanup.py b/cardano_node_tests/utils/testnet_cleanup.py index c4b211740..17253a60d 100644 --- a/cardano_node_tests/utils/testnet_cleanup.py +++ b/cardano_node_tests/utils/testnet_cleanup.py @@ -307,8 +307,8 @@ def create_addr_record(*, addr_file: pl.Path) -> clusterlib.AddressRecord: skey_file = basedir / f"{f_name}.skey" if not (vkey_file.exists() and skey_file.exists()): - msg = f"{addr_file}: keys not available" - raise ValueError(msg) + err = f"{addr_file}: keys not available" + raise ValueError(err) addr_record = clusterlib.AddressRecord( address=clusterlib.read_address_from_file(addr_file), @@ -505,6 +505,15 @@ def _run(files: list[pl.Path], payment_addr: clusterlib.AddressRecord) -> None: ) +def is_framework_testnet() -> bool: + """Determine if the testnet is a testnet started by the testing framework.""" + try: + helpers.check_cardano_node_socket_path() + except ValueError: + return False + return True + + def _get_faucet_payment_rec( *, address: str = "", skey_file: clusterlib.FileType = "" ) -> clusterlib.AddressRecord: @@ -523,11 +532,17 @@ def _get_faucet_payment_rec( vkey_file=pl.Path("/nonexistent"), # We don't need this for faucet skey_file=pl.Path(skey_file), ) - else: + elif is_framework_testnet(): # Try to infer the faucet address and keys from cluster env cluster_env = cluster_nodes.get_cluster_env() faucet_addr_file = cluster_env.state_dir / "shelley" / "faucet.addr" + if not faucet_addr_file.exists(): + err = f"Faucet address file not found at '{faucet_addr_file}'." + raise FileNotFoundError(err) faucet_payment = create_addr_record(addr_file=faucet_addr_file) + else: + err = "Faucet address and keys need to be provided for non-framework testnets." + raise RuntimeError(err) return faucet_payment