-
Notifications
You must be signed in to change notification settings - Fork 353
DAOS-17519 test: Automate dlck testing (basic/fault_injection) #17307
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e44ee36
1dfe0ef
a376c98
1f16a51
aa8ede9
5213ba6
0cea354
585528a
593f473
e4508aa
10920ac
2b4bc8a
4103769
2191472
fb11310
7284649
3b870dc
3c8a19a
68b4f6b
a30908f
6031604
1dcadf5
391e926
a0406f1
9c314c7
04898a8
903d016
7d3f84e
035fc95
47973fc
e0cba86
1e89fc4
c682b97
6eea9f3
e870619
becb001
890c976
3f038d8
b4dd96a
20b7cb7
50253bc
ee085bc
7fd7d82
5af0ef1
f9f6c02
067c4d1
0b0c783
edf4949
5178e62
09e6bd9
0a6b0be
e8a4309
f32bea4
82a724d
3d4781f
33590aa
3479901
e061e56
767de9a
0891a3c
db479c6
ee205a0
9c8b347
9d199de
f78c858
e48754d
0e72f41
e3234a0
3e60841
3627519
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| """ | ||
| Copyright 2026 Hewlett Packard Enterprise Development LP | ||
|
|
||
| SPDX-License-Identifier: BSD-2-Clause-Patent | ||
| """ | ||
| import os | ||
| import re | ||
|
|
||
| from dlck_test_base import DlckTestBase | ||
| from fault_config_utils import FaultInjection | ||
| from file_utils import distribute_files | ||
|
|
||
|
|
||
| class DlckBasicTest(DlckTestBase): | ||
| """Test class for dlck command line utility. | ||
|
|
||
| :avocado: recursive | ||
| """ | ||
| def check_dlck_result(self, result, fault_name): | ||
| """Check that dlck reported the expected error for an injected fault. | ||
| Args: | ||
| result (dict): The result object returned by the dlck command. | ||
| fault_name (str): The name of the injected fault. | ||
| """ | ||
| expected_errors = ("DER_INVAL", "DER_NONEXIST", "DER_ID_MISMATCH", | ||
| "DER_DF_INCOMPT", "DER_DF_INVAL", "WARNING:") | ||
| warning_pattern = r"\b[1-9]\d*\s+warning(?:\(s\)|s?)\b" | ||
| output = f"{result.joined_stdout}\n{result.joined_stderr}" | ||
| expected_error_found = any(error in output for error in expected_errors) | ||
| warning_found = re.search(warning_pattern, output) | ||
| if not (expected_error_found or warning_found): | ||
| return f"{fault_name}: no expected error found in dlck output: {output}" | ||
| return None | ||
|
|
||
| def test_dlck_basic(self): | ||
| """Basic Test: Run 'dlck' command | ||
|
|
||
| :avocado: tags=all,daily_regression | ||
| :avocado: tags=hw,medium | ||
| :avocado: tags=recovery,dlck_cmd | ||
| :avocado: tags=DlckBasicTest,test_dlck_basic | ||
| """ | ||
| dmg = self.get_dmg_command() | ||
| self.log_step("Create a pool to run dlck") | ||
| pool = self.get_pool() | ||
| dlck = self.get_dlck_command() | ||
| dlck.pool_uuid.value = pool.uuid | ||
| dlck.log_dir.value = self.test_env.log_dir | ||
| dlck.run_user = 'daos_server' | ||
| dlck.storage.value = self.server_managers[0].get_config_value("scm_mount") | ||
| if self.server_managers[0].manager.job.using_control_metadata: | ||
| dlck.nvme.value = os.path.join( | ||
| self.server_managers[0].get_config_value("path"), "daos_control", "engine0", | ||
| "daos_nvme.conf") | ||
|
|
||
| self.log_step("Perform dmg system stop to run dlck command") | ||
| dmg.system_stop() | ||
|
|
||
| self.log_step("Run dlck command to check the health of the pool and storage") | ||
| result = dlck.run() | ||
|
|
||
| self.log_step("Perform dmg system start after running dlck command") | ||
| dmg.system_start() | ||
| if not result.passed: | ||
| self.fail(f"dlck failed on {result.failed_hosts}") | ||
| self.log.info("dlck basic test passed with no errors") | ||
|
|
||
| def test_dlck_basic_fault(self): | ||
| """Basic Fault Test: Run 'dlck' injecting basic faults. | ||
|
|
||
| :avocado: tags=all,full_regression | ||
| :avocado: tags=hw,medium | ||
| :avocado: tags=recovery,dlck_cmd,faults | ||
| :avocado: tags=DlckBasicTest,test_dlck_basic_fault | ||
| """ | ||
| errors = [] | ||
| faults_object = FaultInjection() | ||
| faults_dict = faults_object.get_faults_dict() | ||
| fault_list = self.params.get("fault_list", '/run/dlck_test_faults/*') | ||
| self.log.info("Test log dir %s", self.test_env.log_dir) | ||
| fault_inject_file = os.path.join(self.test_env.log_dir, "fi.yaml") | ||
| self.log.info("Fault injection file: %s", fault_inject_file) | ||
| self.log.info("Faults: %s", fault_list) | ||
| self.log.info("Faults dict: %s", faults_dict) | ||
| dmg = self.get_dmg_command() | ||
| pool = self.get_pool() | ||
| dlck = self.get_dlck_command() | ||
| dlck.pool_uuid.value = pool.uuid | ||
| dlck.log_dir.value = self.test_env.log_dir | ||
| dlck.run_user = 'daos_server' | ||
| dlck.exit_status_exception = False | ||
| dlck.env["D_FI_CONFIG"] = fault_inject_file | ||
| dlck.storage.value = self.server_managers[0].get_config_value("scm_mount") | ||
| if self.server_managers[0].manager.job.using_control_metadata: | ||
| dlck.nvme.value = os.path.join( | ||
| self.server_managers[0].get_config_value("path"), "daos_control", "engine0", | ||
| "daos_nvme.conf") | ||
|
|
||
| self.log_step("Perform dmg system stop to run dlck command") | ||
| dmg.system_stop() | ||
|
|
||
| for test_fault in fault_list: | ||
| with open(fault_inject_file, 'w') as f: | ||
| f.write("fault_config:\n") | ||
| for count, (key, value) in enumerate(faults_dict[test_fault].items()): | ||
| if count == 0: | ||
| f.write(f"- {key}: \'{value}\'\n") | ||
| else: | ||
| f.write(f" {key}: \'{value}\'\n") | ||
|
Comment on lines
+103
to
+109
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just realized it makes little sense we generate a YAML file line by line when we could use the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe it would look like something like: fault_config = {
'fault_config': [
{key: str(value) for key, value in faults_dict[test_fault].items()}]}
with open(fault_inject_file, 'w') as f:
yaml.dump(fault_config, f, default_flow_style=False)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, you mean run all fault injection tests in a single dlck run? If so, does it mean DLCK will parse the YAML file and inject one fault at a time and run the testing.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. This is a limitation of the Fault Injection sub-system. No changes here. |
||
| self.log.info("Reading the updated fault injection file contents") | ||
| with open(fault_inject_file, 'r') as f: | ||
| file_data = f.read() | ||
| self.log.info("\n %s", file_data) | ||
| distribute_files(self.log, self.hostlist_servers, fault_inject_file, | ||
| fault_inject_file) | ||
| self.log_step("Run dlck command after injecting fault") | ||
| result = dlck.run() | ||
| error = self.check_dlck_result(result, test_fault) | ||
| if error: | ||
| errors.append(error) | ||
|
|
||
| self.log_step("Perform dmg system start after running dlck command") | ||
| dmg.system_start() | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no line break from beginning of the test to here. IMO, it would be easier to read by adding a few line breaks to separate many lines of code into blocks of code that runs similar tasks.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will do it later... Let the present PR run complete.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| if errors: | ||
| self.fail(f"dlck basic test failed with errors: {errors}") | ||
| self.log.info("dlck basic fault test passed with no errors") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| hosts: | ||
| test_servers: 1 | ||
| test_clients: 1 | ||
|
|
||
| timeout: 420 | ||
| server_config: | ||
| name: daos_server | ||
| engines_per_host: 1 | ||
| engines: | ||
| 0: | ||
| targets: 4 | ||
| storage: auto | ||
|
janekmi marked this conversation as resolved.
|
||
|
|
||
| pool: | ||
| size: 10% | ||
|
|
||
| dlck_test_faults: | ||
| fault_list: | ||
| - DLCK_FAULT_GETGRNAM | ||
| - DLCK_MOCK_NO_DAOS_SERVER_GROUP | ||
| - DLCK_FAULT_CREATE_POOL_DIR | ||
| - DLCK_FAULT_CREATE_LOG_DIR | ||
| - DLCK_FAULT_ENGINE_START | ||
| - DLCK_FAULT_ENGINE_JOIN | ||
| - DLCK_FAULT_ENGINE_STOP | ||
| - DAOS_FAULT_POOL_NVME_HEALTH | ||
| - DAOS_FAULT_POOL_OPEN_BIO | ||
| - DAOS_FAULT_POOL_OPEN_UMEM | ||
| - DAOS_FAULT_POOL_OPEN_MAGIC | ||
| - DAOS_FAULT_POOL_OPEN_VERSION | ||
| - DAOS_FAULT_POOL_OPEN_UUID | ||
| - DAOS_FAULT_BTREE_OPEN_INV_CLASS_28 | ||
| - DAOS_FAULT_BTREE_OPEN_INV_CLASS_29 | ||
| - DAOS_FAULT_BTREE_OPEN_UNREG_CLASS_28 | ||
| - DAOS_FAULT_BTREE_OPEN_UNREG_CLASS_29 | ||
| - DAOS_FAULT_BTREE_FEATURES_28 | ||
| - DAOS_FAULT_BTREE_FEATURES_29 | ||
| - DAOS_FAULT_POOL_EXT_PADDING | ||
| - DAOS_FAULT_POOL_EXT_RESERVED | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like a new default.