diff --git a/src/tests/ftest/util/pool_create_all_base.py b/src/tests/ftest/util/pool_create_all_base.py index 660626c2c8e..aef2e804908 100644 --- a/src/tests/ftest/util/pool_create_all_base.py +++ b/src/tests/ftest/util/pool_create_all_base.py @@ -1,6 +1,6 @@ """ (C) Copyright 2022-2024 Intel Corporation. -(C) Copyright 2025 Hewlett Packard Enterprise Development LP +(C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP SPDX-License-Identifier: BSD-2-Clause-Patent """ @@ -111,10 +111,11 @@ def check_pool_full_storage(self, scm_delta_bytes, nvme_delta_bytes=None, ranks= pool_idx = len(self.pool) - pool_count # pylint: disable-next=logging-format-truncated - self.log.info("Creating a pool with all the available storage: size=100%") - self.pool[pool_idx].size.update("100%", "pool[{}].size".format(pool_idx)) + self.log_step( + f"Creating a TestPool_{pool_idx + 1} with all the available storage: size=100%") + self.pool[pool_idx].size.update("100%", f"pool[{pool_idx}].size") if ranks is not None: - self.pool[pool_idx].target_list.update(ranks, "pool[{}].target_list".format(pool_idx)) + self.pool[pool_idx].target_list.update(ranks, f"pool[{pool_idx}].target_list") self.pool[pool_idx].create() self.pool[pool_idx].get_info() tier_bytes = self.pool[pool_idx].info.pi_space.ps_space.s_total @@ -125,8 +126,11 @@ def check_pool_full_storage(self, scm_delta_bytes, nvme_delta_bytes=None, ranks= self.assertListEqual( wait_ranks, got_ranks, - "Pool with invalid ranks: wait={} got={}".format(wait_ranks, got_ranks)) + f"Pool with invalid ranks: wait={wait_ranks} got={got_ranks}") self.log.info("Pool created: scm_size=%d, nvme_size=%d", *tier_bytes) + self.log_step(f"Verifying TestPool_{pool_idx + 1} default attributes") + self.pool[pool_idx].verify_props() + self.log_step(f"Destroying TestPool_{pool_idx + 1}") self.pool[pool_idx].destroy() pool_idx += 1 @@ -138,32 +142,33 @@ def check_pool_full_storage(self, scm_delta_bytes, nvme_delta_bytes=None, ranks= nvme_delta_bytes is None, "Invalid function call: no NVME delta with usable NVMe storage") - self.log.info( - "Creating a pool with all the available storage: scm_size=%d, nvme_size=%d", - dmg_scm_size, - dmg_nvme_size) - self.pool[pool_idx].scm_size.update(dmg_scm_size, "pool[{}].scm_size", pool_idx) + self.log_step( + f"Creating a pool with all the available storage: scm_size={dmg_scm_size}, " + f"nvme_size={dmg_nvme_size}") + self.pool[pool_idx].scm_size.update(dmg_scm_size, f"pool[{pool_idx}].scm_size") if dmg_nvme_size > 0: - self.pool[pool_idx].nvme_size.update(dmg_nvme_size, "pool[{}].nvme_size", pool_idx) + self.pool[pool_idx].nvme_size.update(dmg_nvme_size, f"pool[{pool_idx}].nvme_size") if ranks is not None: - self.pool[pool_idx].target_list.update(ranks, "pool[{}].target_list".format(pool_idx)) + self.pool[pool_idx].target_list.update(ranks, f"pool[{pool_idx}].target_list") self.pool[pool_idx].create() + self.log_step(f"Verifying TestPool_{pool_idx + 1} default attributes") + self.pool[pool_idx].verify_props() + self.log_step(f"Destroying TestPool_{pool_idx + 1}") self.pool[pool_idx].destroy() pool_idx += 1 - self.log.info( - "Creating a pool with SCM oversubscription: scm_size=%d nvme_size=%d", - dmg_scm_size + scm_delta_bytes, - dmg_nvme_size) + self.log_step( + f"Creating a pool with SCM oversubscription: scm_size={dmg_scm_size}, " + f"nvme_size={dmg_nvme_size}") self.pool[pool_idx].scm_size.update( dmg_scm_size + scm_delta_bytes, - "pool[{}].scm_size".format(pool_idx)) + f"pool[{pool_idx}].scm_size") if dmg_nvme_size > 0: self.pool[pool_idx].nvme_size.update( dmg_nvme_size, - "pool[{}].nvme_size".format(pool_idx)) + f"pool[{pool_idx}].nvme_size") if ranks is not None: - self.pool[pool_idx].target_list.update(ranks, "pool[{}].target_list".format(pool_idx)) + self.pool[pool_idx].target_list.update(ranks, f"pool[{pool_idx}].target_list") error_msg = r"Pool should not be created: SCM oversubscription" with self.assertRaises(TestFail, msg=error_msg) as context_manager: self.pool[pool_idx].create() @@ -174,18 +179,17 @@ def check_pool_full_storage(self, scm_delta_bytes, nvme_delta_bytes=None, ranks= pool_idx += 1 if dmg_nvme_size > 0: - self.log.info( - "Creating a pool with NVME oversubscription: scm_size=%d, nvme_size=%d", - dmg_scm_size, - dmg_nvme_size + nvme_delta_bytes) - self.pool[pool_idx].scm_size.update(dmg_scm_size, "pool[{}].scm_size".format(pool_idx)) + self.log_step( + f"Creating a pool with NVME oversubscription: scm_size={dmg_scm_size}, " + f"nvme_size={dmg_nvme_size + nvme_delta_bytes}") + self.pool[pool_idx].scm_size.update(dmg_scm_size, f"pool[{pool_idx}].scm_size") self.pool[pool_idx].nvme_size.update( dmg_nvme_size + nvme_delta_bytes, - "pool[{}].nvme_size".format(pool_idx)) + f"pool[{pool_idx}].nvme_size") if ranks is not None: self.pool[pool_idx].target_list.update( ranks, - "pool[{}].target_list".format(pool_idx)) + f"pool[{pool_idx}].target_list") error_msg = r"Pool should not be created: NVME oversubscription" with self.assertRaises(TestFail, msg=error_msg) as context_manager: self.pool[pool_idx].create() @@ -195,18 +199,20 @@ def check_pool_full_storage(self, scm_delta_bytes, nvme_delta_bytes=None, ranks= "Pool creation failed with invalid error message") pool_idx += 1 - self.log.info( - "Creating a pool with 100%% of the available storage: scm_size=%d, nvme_size=%d", - dmg_scm_size, - dmg_nvme_size) - self.pool[pool_idx].scm_size.update(dmg_scm_size, "pool[{}].scm_size".format(pool_idx)) + self.log_step( + f"Creating a pool with 100%% of the available storage: scm_size={dmg_scm_size}, " + f"nvme_size={dmg_nvme_size}") + self.pool[pool_idx].scm_size.update(dmg_scm_size, f"pool[{pool_idx}].scm_size") if dmg_nvme_size > 0: self.pool[pool_idx].nvme_size.update( dmg_nvme_size, - "pool[{}].nvme_size".format(pool_idx)) + f"pool[{pool_idx}].nvme_size") if ranks is not None: - self.pool[pool_idx].target_list.update(ranks, "pool[{}].target_list".format(pool_idx)) + self.pool[pool_idx].target_list.update(ranks, f"pool[{pool_idx}].target_list") self.pool[pool_idx].create() + self.log_step(f"Verifying TestPool_{pool_idx + 1} default attributes") + self.pool[pool_idx].verify_props() + self.log_step(f"Destroying TestPool_{pool_idx + 1}") self.pool[pool_idx].destroy() def check_pool_recycling(self, pool_count, scm_delta_bytes, nvme_delta_bytes=None): diff --git a/src/tests/ftest/util/test_utils_pool.py b/src/tests/ftest/util/test_utils_pool.py index 36539943abc..780b7c2daf9 100644 --- a/src/tests/ftest/util/test_utils_pool.py +++ b/src/tests/ftest/util/test_utils_pool.py @@ -21,6 +21,28 @@ POOL_NAMESPACE = "/run/pool/*" POOL_TIMEOUT_INCREMENT = 200 +DEFAULT_POOL_PROPS = { + "checkpoint": "timed", + "checkpoint_freq": 50, + "data_thresh": 4096, + "ec_cell_sz": 131072, # 128 KiB + "ec_pda": 1, + "global_version": 4, + "perf_domain": "root", + "rd_fac": 3, + "reclaim": "lazy", + "reintegration": "data_sync", + "rp_pda": 4294967295, + "scrub": "off", + "scrub_freq": 604800, + "scrub_thresh": 0, + "self_heal": "exclude;rebuild", + "space_rb": 5, + "svc_ops_enabled": 1, + "svc_ops_entry_age": 300, + "svc_rf": 2, + "upgrade_status": "not started" +} def add_pools(dmg, add_pool_kwargs, error_handler=None): @@ -1648,3 +1670,43 @@ def verify_query_targets_state(self, ranks, expected_target_state): raise AssertionError( f'Expected target {target} to be in state {expected_target_state}, ' f'but current state is {info["target_state"]}') + + # pylint: disable=dangerous-default-value + def verify_props(self, expected=DEFAULT_POOL_PROPS): + """Verify pool properties match expected values. + + Args: + expected (dict): Expected key/value pairs from pool properties. + Can be a subset of the full properties, where only expected keys are verified. + Defaults to DEFAULT_POOL_PROPS. + + Raises: + TestFail: If any of the default properties are missing or have invalid values. + """ + errors = { + "types": set(), + "details": [] + } + + try: + data = {} + for entry in self.get_prop()['response']: + data[entry['name']] = entry['value'] + for key, value in expected.items(): + if key not in data: + errors["types"].add("missing property") + errors["details"].append(f"Missing property: {key}") + continue + if data[key] != value: + errors["types"].add("property value") + errors["details"].append( + f"Invalid value for property: {key}, expected: {value}, got: {data[key]}") + except TestFail as error: + errors["types"].add("retrieval error") + errors["details"].append(f"Error retrieving pool properties: {str(error)}") + + if errors["types"]: + self.log.error("Errors detected verifying pool properties:") + for error in errors["details"]: + self.log.error(f" - {error}") + raise TestFail(f'Pool properties check failed - {", ".join(errors["types"])}')