From 073fdec2f569c5ad22e2c266f6e08aa24affd638 Mon Sep 17 00:00:00 2001 From: Dennis Maisenbacher Date: Wed, 6 Nov 2024 15:31:32 +0000 Subject: [PATCH 1/7] tests: Introduce configurable nvme binary path Introducing the `nvme_bin` config to point to a different nvme-cli binary. With this change all nvme cmd strings are reworked for uniformity. This includes using f-strings and expanding short options into long options. Signed-off-by: Dennis Maisenbacher --- tests/nvme_compare_test.py | 8 ++-- tests/nvme_copy_test.py | 45 ++++++++++++++------- tests/nvme_ctrl_reset_test.py | 2 +- tests/nvme_dsm_test.py | 7 ++-- tests/nvme_flush_test.py | 3 +- tests/nvme_format_test.py | 17 ++++---- tests/nvme_fw_log_test.py | 2 +- tests/nvme_get_features_test.py | 10 ++--- tests/nvme_get_lba_status_test.py | 12 +++--- tests/nvme_id_ns_test.py | 3 +- tests/nvme_lba_status_log_test.py | 2 +- tests/nvme_test.py | 65 ++++++++++++++++++------------- tests/nvme_test_io.py | 16 ++++---- tests/nvme_verify_test.py | 8 ++-- tests/nvme_writeuncor_test.py | 6 +-- tests/nvme_writezeros_test.py | 6 +-- 16 files changed, 121 insertions(+), 91 deletions(-) diff --git a/tests/nvme_compare_test.py b/tests/nvme_compare_test.py index a34df68e30..e6b2b75ab9 100644 --- a/tests/nvme_compare_test.py +++ b/tests/nvme_compare_test.py @@ -78,10 +78,10 @@ def nvme_compare(self, cmp_file): - Returns: - return code of the nvme compare command. """ - compare_cmd = "nvme compare " + self.ns1 + " --start-block=" + \ - str(self.start_block) + " --block-count=" + \ - str(self.block_count) + " --data-size=" + \ - str(self.data_size) + " --data=" + cmp_file + compare_cmd = f"{self.nvme_bin} compare {self.ns1} " + \ + f"--start-block={str(self.start_block)} " + \ + f"--block-count={str(self.block_count)} " + \ + f"--data-size={str(self.data_size)} --data={cmp_file}" return self.exec_cmd(compare_cmd) def test_nvme_compare(self): diff --git a/tests/nvme_copy_test.py b/tests/nvme_copy_test.py index 5d16b00dda..085c765053 100644 --- a/tests/nvme_copy_test.py +++ b/tests/nvme_copy_test.py @@ -40,9 +40,15 @@ def setUp(self): cross_namespace_copy = self.ocfs & 0xc if cross_namespace_copy: # get host behavior support data - get_features_cmd = ["nvme", "get-feature", self.ctrl, "--feature-id=0x16", "--data-len=512", "-b"] - print("Running command:", " ".join(get_features_cmd)) - self.host_behavior_data = subprocess.check_output(get_features_cmd) + get_features_cmd = f"{self.nvme_bin} get-feature {self.ctrl} " + \ + "--feature-id=0x16 --data-len=512 --raw-binary" + proc = subprocess.Popen(get_features_cmd, + shell=True, + stdout=subprocess.PIPE, + encoding='utf-8') + err = proc.wait() + self.assertEqual(err, 0, "ERROR : nvme get-feature failed") + self.host_behavior_data = proc.stdout.read() # enable cross-namespace copy formats if self.host_behavior_data[4] & cross_namespace_copy: # skip if already enabled @@ -50,17 +56,24 @@ def setUp(self): self.host_behavior_data = None else: data = self.host_behavior_data[:4] + cross_namespace_copy.to_bytes(2, 'little') + self.host_behavior_data[6:] - set_features_cmd = ["nvme", "set-feature", self.ctrl, "--feature-id=0x16", "--data-len=512"] - print("Running command:", " ".join(set_features_cmd)) + set_features_cmd = f"{self.nvme_bin} set-feature " + \ + f"{self.ctrl} --feature-id=0x16 --data-len=512" proc = subprocess.Popen(set_features_cmd, + shell=True, stdout=subprocess.PIPE, - stdin=subprocess.PIPE) + stdin=subprocess.PIPE, + encoding='utf-8') proc.communicate(input=data) self.assertEqual(proc.returncode, 0, "Failed to enable cross-namespace copy formats") - get_ns_id_cmd = ["nvme", "get-ns-id", self.ns1] - print("Running command:", " ".join(get_ns_id_cmd)) - output = subprocess.check_output(get_ns_id_cmd) - self.ns1_nsid = int(output.decode().strip().split(':')[-1]) + get_ns_id_cmd = f"{self.nvme_bin} get-ns-id {self.ns1}" + proc = subprocess.Popen(get_ns_id_cmd, + shell=True, + stdout=subprocess.PIPE, + encoding='utf-8') + err = proc.wait() + self.assertEqual(err, 0, "ERROR : nvme get-ns-id failed") + output = proc.stdout.read() + self.ns1_nsid = int(output.strip().split(':')[-1]) self.setup_log_dir(self.__class__.__name__) def tearDown(self): @@ -68,11 +81,13 @@ def tearDown(self): print("Tearing down test...") if self.host_behavior_data: # restore saved host behavior support data - set_features_cmd = ["nvme", "set-feature", self.ctrl, "--feature-id=0x16", "--data-len=512"] - print("Running command:", " ".join(set_features_cmd)) + set_features_cmd = f"{self.nvme_bin} set-feature {self.ctrl} " + \ + "--feature-id=0x16 --data-len=512" proc = subprocess.Popen(set_features_cmd, + shell=True, stdout=subprocess.PIPE, - stdin=subprocess.PIPE) + stdin=subprocess.PIPE, + encoding='utf-8') proc.communicate(input=self.host_behavior_data) super().tearDown() @@ -94,7 +109,9 @@ def copy(self, sdlba, blocks, slbs, **kwargs): print(f"Skip copy because descriptor format {desc_format} is not supported") return # build copy command - copy_cmd = f"nvme copy {self.ns1} --format={desc_format} --sdlba={sdlba} --blocks={blocks} --slbs={slbs}" + copy_cmd = f"{self.nvme_bin} copy {self.ns1} " + \ + f"--format={desc_format} --sdlba={sdlba} --blocks={blocks} " + \ + f"--slbs={slbs}" if "snsids" in kwargs: copy_cmd += f" --snsids={kwargs['snsids']}" if "sopts" in kwargs: diff --git a/tests/nvme_ctrl_reset_test.py b/tests/nvme_ctrl_reset_test.py index e2c8a00636..f32042e8a8 100644 --- a/tests/nvme_ctrl_reset_test.py +++ b/tests/nvme_ctrl_reset_test.py @@ -40,7 +40,7 @@ def ctrl_reset(self): - Returns: - return code for nvme controller reset. """ - ctrl_reset_cmd = "nvme reset " + self.ctrl + ctrl_reset_cmd = f"{self.nvme_bin} reset {self.ctrl}" return self.exec_cmd(ctrl_reset_cmd) def test_ctrl_reset(self): diff --git a/tests/nvme_dsm_test.py b/tests/nvme_dsm_test.py index d92bf58e59..4ad3e05ed5 100644 --- a/tests/nvme_dsm_test.py +++ b/tests/nvme_dsm_test.py @@ -45,10 +45,9 @@ def dsm(self): - Returns: - return code for nvme dsm command. """ - dsm_cmd = "nvme dsm " + self.ctrl + \ - " --namespace-id=" + str(self.namespace) + \ - " --blocks=" + str(self.range) + \ - " --slbs=" + str(self.start_block) + dsm_cmd = f"{self.nvme_bin} dsm {self.ctrl} " + \ + f"--namespace-id={str(self.namespace)} " + \ + f"--blocks={str(self.range)} --slbs={str(self.start_block)}" return self.exec_cmd(dsm_cmd) def test_dsm(self): diff --git a/tests/nvme_flush_test.py b/tests/nvme_flush_test.py index e4f127dac1..4c9e2b9e2f 100644 --- a/tests/nvme_flush_test.py +++ b/tests/nvme_flush_test.py @@ -53,7 +53,8 @@ def nvme_flush(self): - Returns: - None """ - flush_cmd = "nvme flush " + self.ctrl + " -n " + str(self.default_nsid) + flush_cmd = f"{self.nvme_bin} flush {self.ctrl} " + \ + f"--namespace-id={str(self.default_nsid)}" print(flush_cmd) return self.exec_cmd(flush_cmd) diff --git a/tests/nvme_format_test.py b/tests/nvme_format_test.py index 12bc128f9a..1c88913732 100644 --- a/tests/nvme_format_test.py +++ b/tests/nvme_format_test.py @@ -106,23 +106,24 @@ def attach_detach_primary_ns(self): self.dps), 0) self.assertEqual(self.attach_ns(self.ctrl_id, self.default_nsid), 0) # read lbaf information - id_ns = "nvme id-ns " + self.ctrl + \ - " -n1 | grep ^lbaf | awk '{print $2}' | tr -s \"\\n\" \" \"" + id_ns = f"{self.nvme_bin} id-ns {self.ctrl} " + \ + f"--namespace-id={self.default_nsid} " + \ + "| grep ^lbaf | awk '{print $2}' | tr -s \"\\n\" \" \"" proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE, encoding='utf-8') self.lba_format_list = proc.stdout.read().strip().split(" ") if proc.wait() == 0: # read lbads information - id_ns = "nvme id-ns " + self.ctrl + \ - " -n1 | grep ^lbaf | awk '{print $5}'" + \ - " | cut -f 2 -d ':' | tr -s \"\\n\" \" \"" + id_ns = f"{self.nvme_bin} id-ns {self.ctrl} " + \ + f"--namespace-id={self.default_nsid} " + \ + "| grep ^lbaf | awk '{print $5}' | cut -f 2 -d ':' | tr -s \"\\n\" \" \"" proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE, encoding='utf-8') self.lbads_list = proc.stdout.read().strip().split(" ") # read metadata information - id_ns = "nvme id-ns " + self.ctrl + \ - " -n1 | grep ^lbaf | awk '{print $4}'" + \ - " | cut -f 2 -d ':' | tr -s \"\\n\" \" \"" + id_ns = f"{self.nvme_bin} id-ns {self.ctrl} " + \ + f"--namespace-id={self.default_nsid} " + \ + "| grep ^lbaf | awk '{print $4}' | cut -f 2 -d ':' | tr -s \"\\n\" \" \"" proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE, encoding='utf-8') self.ms_list = proc.stdout.read().strip().split(" ") diff --git a/tests/nvme_fw_log_test.py b/tests/nvme_fw_log_test.py index b67067170c..11d79cddb3 100644 --- a/tests/nvme_fw_log_test.py +++ b/tests/nvme_fw_log_test.py @@ -58,7 +58,7 @@ def get_fw_log(self): - 0 on success, error code on failure. """ err = 0 - fw_log_cmd = "nvme fw-log " + self.ctrl + fw_log_cmd = f"{self.nvme_bin} fw-log {self.ctrl}" proc = subprocess.Popen(fw_log_cmd, shell=True, stdout=subprocess.PIPE, diff --git a/tests/nvme_get_features_test.py b/tests/nvme_get_features_test.py index fc3e5bfeb1..6edf332444 100644 --- a/tests/nvme_get_features_test.py +++ b/tests/nvme_get_features_test.py @@ -81,9 +81,9 @@ def get_mandatory_features(self, feature_id): """ if str(feature_id) == "0x09": for vector in range(self.vector_list_len): - get_feat_cmd = "nvme get-feature " + self.ctrl + \ - " --feature-id=" + str(feature_id) + \ - " --cdw11=" + str(vector) + " -H" + get_feat_cmd = f"{self.nvme_bin} get-feature {self.ctrl} " + \ + f"--feature-id={str(feature_id)} " + \ + f"--cdw11={str(vector)} --human-readable" proc = subprocess.Popen(get_feat_cmd, shell=True, stdout=subprocess.PIPE, @@ -92,8 +92,8 @@ def get_mandatory_features(self, feature_id): print(feature_output) self.assertEqual(proc.wait(), 0) else: - get_feat_cmd = "nvme get-feature " + self.ctrl + \ - " --feature-id=" + str(feature_id) + " -H" + get_feat_cmd = f"{self.nvme_bin} get-feature {self.ctrl} " + \ + f"--feature-id={str(feature_id)} --human-readable" if str(feature_id) == "0x05": get_feat_cmd += f" --namespace-id={self.default_nsid}" proc = subprocess.Popen(get_feat_cmd, diff --git a/tests/nvme_get_lba_status_test.py b/tests/nvme_get_lba_status_test.py index d9e543c5a4..7577f6d089 100644 --- a/tests/nvme_get_lba_status_test.py +++ b/tests/nvme_get_lba_status_test.py @@ -51,12 +51,12 @@ def get_lba_status(self): - 0 on success, error code on failure. """ err = 0 - get_lba_status_cmd = "nvme get-lba-status " + self.ctrl + \ - " --namespace-id=" + str(self.ns1) + \ - " --start-lba=" + str(self.start_lba) + \ - " --max-dw=" + str(self.max_dw) + \ - " --action=" + str(self.action) + \ - " --range-len=" + str(self.range_len) + get_lba_status_cmd = f"{self.nvme_bin} get-lba-status {self.ctrl} " + \ + f"--namespace-id={str(self.ns1)} " + \ + f"--start-lba={str(self.start_lba)} " + \ + f"--max-dw={str(self.max_dw)} " + \ + f"--action={str(self.action)} " + \ + f"--range-len={str(self.range_len)}" proc = subprocess.Popen(get_lba_status_cmd, shell=True, stdout=subprocess.PIPE, diff --git a/tests/nvme_id_ns_test.py b/tests/nvme_id_ns_test.py index 66e2f93adc..48ad92474a 100644 --- a/tests/nvme_id_ns_test.py +++ b/tests/nvme_id_ns_test.py @@ -61,7 +61,8 @@ def get_id_ns(self, nsid): - 0 on success, error code on failure. """ err = 0 - id_ns_cmd = "nvme id-ns " + self.ctrl + "n" + str(nsid) + id_ns_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \ + f"--namespace-id={str(nsid)}" proc = subprocess.Popen(id_ns_cmd, shell=True, stdout=subprocess.PIPE, diff --git a/tests/nvme_lba_status_log_test.py b/tests/nvme_lba_status_log_test.py index a50e211cec..8eca23bd0b 100644 --- a/tests/nvme_lba_status_log_test.py +++ b/tests/nvme_lba_status_log_test.py @@ -46,7 +46,7 @@ def get_lba_stat_log(self): - 0 on success, error code on failure. """ err = 0 - lba_stat_log_cmd = "nvme lba-status-log " + self.ctrl + lba_stat_log_cmd = f"{self.nvme_bin} lba-status-log {self.ctrl}" proc = subprocess.Popen(lba_stat_log_cmd, shell=True, stdout=subprocess.PIPE, diff --git a/tests/nvme_test.py b/tests/nvme_test.py index a13a9939f0..7c9101643a 100644 --- a/tests/nvme_test.py +++ b/tests/nvme_test.py @@ -58,6 +58,7 @@ def setUp(self): self.ctrl = "XXX" self.ns1 = "XXX" self.test_log_dir = "XXX" + self.nvme_bin = "nvme" self.do_validate_pci_device = True self.default_nsid = 0x1 self.config_file = 'tests/config.json' @@ -119,7 +120,10 @@ def load_config(self): self.ctrl = config['controller'] self.ns1 = config['ns1'] self.log_dir = config['log_dir'] - self.do_validate_pci_device = config.get('do_validate_pci_device', self.do_validate_pci_device) + self.nvme_bin = config.get('nvme_bin', self.nvme_bin) + print(f"\nUsing nvme binary '{self.nvme_bin}'") + self.do_validate_pci_device = config.get( + 'do_validate_pci_device', self.do_validate_pci_device) self.clear_log_dir = False if self.clear_log_dir is True: @@ -154,7 +158,7 @@ def nvme_reset_ctrl(self): - Returns: - None """ - nvme_reset_cmd = "nvme reset " + self.ctrl + nvme_reset_cmd = f"{self.nvme_bin} reset {self.ctrl}" err = subprocess.call(nvme_reset_cmd, shell=True, stdout=subprocess.PIPE, @@ -177,7 +181,8 @@ def get_ctrl_id(self): - Returns: - controller id. """ - get_ctrl_id = f"nvme list-ctrl {self.ctrl} --output-format=json" + get_ctrl_id = f"{self.nvme_bin} list-ctrl {self.ctrl} " + \ + "--output-format=json" proc = subprocess.Popen(get_ctrl_id, shell=True, stdout=subprocess.PIPE, @@ -197,7 +202,7 @@ def get_ns_list(self): - List of the namespaces. """ ns_list = [] - ns_list_cmd = "nvme list-ns " + self.ctrl + ns_list_cmd = f"{self.nvme_bin} list-ns {self.ctrl}" proc = subprocess.Popen(ns_list_cmd, shell=True, stdout=subprocess.PIPE, @@ -217,7 +222,7 @@ def get_max_ns(self): """ pattern = re.compile("^nn[ ]+: [0-9]", re.IGNORECASE) max_ns = -1 - max_ns_cmd = "nvme id-ctrl " + self.ctrl + max_ns_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl}" proc = subprocess.Popen(max_ns_cmd, shell=True, stdout=subprocess.PIPE, @@ -248,7 +253,8 @@ def get_lba_format_size(self): - Returns: - lba format size as a tuple of (data_size, metadata_size) in bytes. """ - nvme_id_ns_cmd = f"nvme id-ns {self.ns1} --output-format=json" + nvme_id_ns_cmd = f"{self.nvme_bin} id-ns {self.ns1} " + \ + "--output-format=json" proc = subprocess.Popen(nvme_id_ns_cmd, shell=True, stdout=subprocess.PIPE, @@ -278,7 +284,7 @@ def get_ncap(self): """ pattern = re.compile("^tnvmcap[ ]+: [0-9]", re.IGNORECASE) ncap = -1 - ncap_cmd = "nvme id-ctrl " + self.ctrl + ncap_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl}" proc = subprocess.Popen(ncap_cmd, shell=True, stdout=subprocess.PIPE, @@ -300,7 +306,8 @@ def get_id_ctrl_field_value(self, field): - Returns: - Filed value of the given field """ - id_ctrl_cmd = f"nvme id-ctrl {self.ctrl} --output-format=json" + id_ctrl_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl} " + \ + "--output-format=json" proc = subprocess.Popen(id_ctrl_cmd, shell=True, stdout=subprocess.PIPE, @@ -330,7 +337,8 @@ def get_format(self): """ # defaulting to 4K nvm_format = 4096 - nvm_format_cmd = "nvme id-ns " + self.ctrl + " -n1" + nvm_format_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \ + f"--namespace-id={self.default_nsid}" proc = subprocess.Popen(nvm_format_cmd, shell=True, stdout=subprocess.PIPE, @@ -351,9 +359,10 @@ def delete_all_ns(self): - Returns: - None """ - delete_ns_cmd = "nvme delete-ns " + self.ctrl + " -n 0xFFFFFFFF" + delete_ns_cmd = f"{self.nvme_bin} delete-ns {self.ctrl} " + \ + "--namespace-id=0xFFFFFFFF" self.assertEqual(self.exec_cmd(delete_ns_cmd), 0) - list_ns_cmd = "nvme list-ns " + self.ctrl + " --all | wc -l" + list_ns_cmd = f"{self.nvme_bin} list-ns {self.ctrl} --all | wc -l" proc = subprocess.Popen(list_ns_cmd, shell=True, stdout=subprocess.PIPE, @@ -371,9 +380,9 @@ def create_ns(self, nsze, ncap, flbas, dps): - Returns: - return code of the nvme create namespace command. """ - create_ns_cmd = "nvme create-ns " + self.ctrl + " --nsze=" + \ - str(nsze) + " --ncap=" + str(ncap) + \ - " --flbas=" + str(flbas) + " --dps=" + str(dps) + create_ns_cmd = f"{self.nvme_bin} create-ns {self.ctrl} " + \ + f"--nsze={str(nsze)} --ncap={str(ncap)} --flbas={str(flbas)} " + \ + f"--dps={str(dps)}" return self.exec_cmd(create_ns_cmd) def create_and_validate_ns(self, nsid, nsze, ncap, flbas, dps): @@ -390,7 +399,8 @@ def create_and_validate_ns(self, nsid, nsze, ncap, flbas, dps): err = self.create_ns(nsze, ncap, flbas, dps) if err == 0: time.sleep(2) - id_ns_cmd = "nvme id-ns " + self.ctrl + " -n " + str(nsid) + id_ns_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \ + f"--namespace-id={str(nsid)}" err = subprocess.call(id_ns_cmd, shell=True, stdout=subprocess.PIPE, @@ -405,9 +415,8 @@ def attach_ns(self, ctrl_id, ns_id): - Returns: - 0 on success, error code on failure. """ - attach_ns_cmd = "nvme attach-ns " + self.ctrl + \ - " --namespace-id=" + str(ns_id) + \ - " --controllers=" + ctrl_id + attach_ns_cmd = f"{self.nvme_bin} attach-ns {self.ctrl} " + \ + f"--namespace-id={str(ns_id)} --controllers={ctrl_id}" err = subprocess.call(attach_ns_cmd, shell=True, stdout=subprocess.PIPE, @@ -429,9 +438,8 @@ def detach_ns(self, ctrl_id, nsid): - Returns: - 0 on success, error code on failure. """ - detach_ns_cmd = "nvme detach-ns " + self.ctrl + \ - " --namespace-id=" + str(nsid) + \ - " --controllers=" + ctrl_id + detach_ns_cmd = f"{self.nvme_bin} detach-ns {self.ctrl} " + \ + f"--namespace-id={str(nsid)} --controllers={ctrl_id}" return subprocess.call(detach_ns_cmd, shell=True, stdout=subprocess.PIPE, @@ -445,7 +453,8 @@ def delete_and_validate_ns(self, nsid): - 0 on success, 1 on failure. """ # delete the namespace - delete_ns_cmd = "nvme delete-ns " + self.ctrl + " -n " + str(nsid) + delete_ns_cmd = f"{self.nvme_bin} delete-ns {self.ctrl} " + \ + f"--namespace-id={str(nsid)}" err = subprocess.call(delete_ns_cmd, shell=True, stdout=subprocess.PIPE, @@ -460,7 +469,8 @@ def get_smart_log(self, nsid): - Returns: - 0 on success, error code on failure. """ - smart_log_cmd = "nvme smart-log " + self.ctrl + " -n " + str(nsid) + smart_log_cmd = f"{self.nvme_bin} smart-log {self.ctrl} " + \ + f"--namespace-id={str(nsid)}" print(smart_log_cmd) proc = subprocess.Popen(smart_log_cmd, shell=True, @@ -480,9 +490,10 @@ def get_id_ctrl(self, vendor=False): - 0 on success, error code on failure. """ if not vendor: - id_ctrl_cmd = "nvme id-ctrl " + self.ctrl + id_ctrl_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl}" else: - id_ctrl_cmd = "nvme id-ctrl --vendor-specific " + self.ctrl + id_ctrl_cmd = f"{self.nvme_bin} id-ctrl " +\ + f"--vendor-specific {self.ctrl}" print(id_ctrl_cmd) proc = subprocess.Popen(id_ctrl_cmd, shell=True, @@ -500,7 +511,7 @@ def get_error_log(self): - 0 on success, error code on failure. """ pattern = re.compile(r"^ Entry\[[ ]*[0-9]+\]") - error_log_cmd = "nvme error-log " + self.ctrl + error_log_cmd = f"{self.nvme_bin} error-log {self.ctrl}" proc = subprocess.Popen(error_log_cmd, shell=True, stdout=subprocess.PIPE, @@ -547,7 +558,7 @@ def supp_check_id_ctrl(self, key): - Returns: - value for key requested. """ - id_ctrl = "nvme id-ctrl " + self.ctrl + id_ctrl = f"{self.nvme_bin} id-ctrl {self.ctrl}" print("\n" + id_ctrl) proc = subprocess.Popen(id_ctrl, shell=True, diff --git a/tests/nvme_test_io.py b/tests/nvme_test_io.py index bf30e0a4b0..e12d8c09d0 100644 --- a/tests/nvme_test_io.py +++ b/tests/nvme_test_io.py @@ -77,10 +77,10 @@ def nvme_write(self): - Returns: - return code for nvme write command. """ - write_cmd = "nvme write " + self.ns1 + " --start-block=" + \ - str(self.start_block) + " --block-count=" + \ - str(self.block_count) + " --data-size=" + \ - str(self.data_size) + " --data=" + self.write_file + write_cmd = f"{self.nvme_bin} write {self.ns1} " + \ + f"--start-block={str(self.start_block)} " + \ + f"--block-count={str(self.block_count)} " + \ + f"--data-size={str(self.data_size)} --data={self.write_file}" return self.exec_cmd(write_cmd) def nvme_read(self): @@ -90,9 +90,9 @@ def nvme_read(self): - Returns: - return code for nvme read command. """ - read_cmd = "nvme read " + self.ns1 + " --start-block=" + \ - str(self.start_block) + " --block-count=" + \ - str(self.block_count) + " --data-size=" + \ - str(self.data_size) + " --data=" + self.read_file + read_cmd = f"{self.nvme_bin} read {self.ns1} " + \ + f"--start-block={str(self.start_block)} " + \ + f"--block-count={str(self.block_count)} " + \ + f"--data-size={str(self.data_size)} --data={self.read_file}" print(read_cmd) return self.exec_cmd(read_cmd) diff --git a/tests/nvme_verify_test.py b/tests/nvme_verify_test.py index 7c30828f51..44c8942bff 100644 --- a/tests/nvme_verify_test.py +++ b/tests/nvme_verify_test.py @@ -44,10 +44,10 @@ def verify(self): - Returns: - return code for nvme verify command. """ - verify_cmd = "nvme verify " + self.ctrl + \ - " --namespace-id=" + str(self.namespace) + \ - " --start-block=" + str(self.start_block) + \ - " --block-count=" + str(self.block_count) + verify_cmd = f"{self.nvme_bin} verify {self.ctrl} " + \ + f"--namespace-id={str(self.namespace)} " + \ + f"--start-block={str(self.start_block)} " + \ + f"--block-count={str(self.block_count)}" return self.exec_cmd(verify_cmd) def test_verify(self): diff --git a/tests/nvme_writeuncor_test.py b/tests/nvme_writeuncor_test.py index 1083d46234..8e0b9a05b4 100644 --- a/tests/nvme_writeuncor_test.py +++ b/tests/nvme_writeuncor_test.py @@ -63,9 +63,9 @@ def write_uncor(self): - Returns: - return code of nvme write uncorrectable command. """ - write_uncor_cmd = "nvme write-uncor " + self.ns1 + \ - " --start-block=" + str(self.start_block) + \ - " --block-count=" + str(self.block_count) + write_uncor_cmd = f"{self.nvme_bin} write-uncor {self.ns1} " + \ + f"--start-block={str(self.start_block)} " + \ + f"--block-count={str(self.block_count)}" return self.exec_cmd(write_uncor_cmd) def test_write_uncor(self): diff --git a/tests/nvme_writezeros_test.py b/tests/nvme_writezeros_test.py index 3231e3dd9f..75d5687427 100644 --- a/tests/nvme_writezeros_test.py +++ b/tests/nvme_writezeros_test.py @@ -71,9 +71,9 @@ def write_zeroes(self): - Returns: - return code for nvme write command. """ - write_zeroes_cmd = "nvme write-zeroes " + self.ns1 + \ - " --start-block=" + str(self.start_block) + \ - " --block-count=" + str(self.block_count) + write_zeroes_cmd = f"{self.nvme_bin} write-zeroes {self.ns1} " + \ + f"--start-block={str(self.start_block)} " + \ + f"--block-count={str(self.block_count)}" return self.exec_cmd(write_zeroes_cmd) def validate_write_read(self): From 17b4c77152cc2276a1226703ec6c7b171c2caa7a Mon Sep 17 00:00:00 2001 From: Dennis Maisenbacher Date: Fri, 8 Nov 2024 07:10:47 +0000 Subject: [PATCH 2/7] tests: Use json output for parsing To make the parsing of nvme cmd output easier use the json output when possible. Refactoring code snippets that needed to be touched when adjusing for json output. Signed-off-by: Dennis Maisenbacher --- tests/nvme_format_test.py | 63 ++++++++++++---------------- tests/nvme_id_ns_test.py | 4 +- tests/nvme_smart_log_test.py | 8 ++-- tests/nvme_test.py | 80 ++++++++++-------------------------- 4 files changed, 54 insertions(+), 101 deletions(-) diff --git a/tests/nvme_format_test.py b/tests/nvme_format_test.py index 1c88913732..9faf3dc875 100644 --- a/tests/nvme_format_test.py +++ b/tests/nvme_format_test.py @@ -37,6 +37,7 @@ - Delete Namespace. """ +import json import math import subprocess import time @@ -55,9 +56,7 @@ class TestNVMeFormatCmd(TestNVMe): - nsze : namespace size. - ncap : namespace capacity. - ctrl_id : controller id. - - lba_format_list : lis of supported format. - - ms_list : list of metadat size per format. - - lbads_list : list of LBA data size per format. + - lba_format_list : json list of supported format. - test_log_dir : directory for logs, temp files. """ @@ -74,8 +73,6 @@ def setUp(self): self.nsze = ncap self.ctrl_id = self.get_ctrl_id() self.lba_format_list = [] - self.ms_list = [] - self.lbads_list = [] self.test_log_dir = self.log_dir + "/" + self.__class__.__name__ self.setup_log_dir(self.__class__.__name__) self.delete_all_ns() @@ -106,30 +103,21 @@ def attach_detach_primary_ns(self): self.dps), 0) self.assertEqual(self.attach_ns(self.ctrl_id, self.default_nsid), 0) # read lbaf information - id_ns = f"{self.nvme_bin} id-ns {self.ctrl} " + \ - f"--namespace-id={self.default_nsid} " + \ - "| grep ^lbaf | awk '{print $2}' | tr -s \"\\n\" \" \"" - proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE, + id_ns_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \ + f"--namespace-id={self.default_nsid} --output-format=json" + proc = subprocess.Popen(id_ns_cmd, + shell=True, + stdout=subprocess.PIPE, encoding='utf-8') - self.lba_format_list = proc.stdout.read().strip().split(" ") - if proc.wait() == 0: - # read lbads information - id_ns = f"{self.nvme_bin} id-ns {self.ctrl} " + \ - f"--namespace-id={self.default_nsid} " + \ - "| grep ^lbaf | awk '{print $5}' | cut -f 2 -d ':' | tr -s \"\\n\" \" \"" - proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE, - encoding='utf-8') - self.lbads_list = proc.stdout.read().strip().split(" ") - # read metadata information - id_ns = f"{self.nvme_bin} id-ns {self.ctrl} " + \ - f"--namespace-id={self.default_nsid} " + \ - "| grep ^lbaf | awk '{print $4}' | cut -f 2 -d ':' | tr -s \"\\n\" \" \"" - proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE, - encoding='utf-8') - self.ms_list = proc.stdout.read().strip().split(" ") - self.assertEqual(self.detach_ns(self.ctrl_id, self.default_nsid), 0) - self.assertEqual(self.delete_and_validate_ns(self.default_nsid), 0) - self.nvme_reset_ctrl() + err = proc.wait() + self.assertEqual(err, 0, "ERROR : nvme id-ns failed") + json_output = json.loads(proc.stdout.read()) + self.lba_format_list = json_output['lbafs'] + self.assertTrue(len(self.lba_format_list) > 0, + "ERROR : nvme id-ns could not find any lba formats") + self.assertEqual(self.detach_ns(self.ctrl_id, self.default_nsid), 0) + self.assertEqual(self.delete_and_validate_ns(self.default_nsid), 0) + self.nvme_reset_ctrl() def test_format_ns(self): """ Testcase main """ @@ -137,20 +125,21 @@ def test_format_ns(self): self.attach_detach_primary_ns() # iterate through all supported format - for i in range(0, len(self.lba_format_list)): - print("\nlba format " + str(self.lba_format_list[i]) + - " lbad " + str(self.lbads_list[i]) + - " ms " + str(self.ms_list[i])) - metadata_size = 1 if self.ms_list[i] == '8' else 0 + for flbas, lba_format in enumerate(self.lba_format_list): + ds = lba_format['ds'] + ms = lba_format['ms'] + print(f"\nlba format {str(flbas)}" + f"\nds {str(ds)}" + f"\nms {str(ms)}") + dps = 1 if str(ms) == '8' else 0 err = self.create_and_validate_ns(self.default_nsid, self.nsze, self.ncap, - self.lba_format_list[i], - metadata_size) + flbas, + dps) self.assertEqual(err, 0) self.assertEqual(self.attach_ns(self.ctrl_id, self.default_nsid), 0) - self.run_ns_io(self.default_nsid, self.lbads_list[i]) - time.sleep(5) + self.run_ns_io(self.default_nsid, int(ds)) self.assertEqual(self.detach_ns(self.ctrl_id, self.default_nsid), 0) self.assertEqual(self.delete_and_validate_ns(self.default_nsid), 0) self.nvme_reset_ctrl() diff --git a/tests/nvme_id_ns_test.py b/tests/nvme_id_ns_test.py index 48ad92474a..247f75365d 100644 --- a/tests/nvme_id_ns_test.py +++ b/tests/nvme_id_ns_test.py @@ -42,7 +42,7 @@ def setUp(self): """ Pre Section for TestNVMeIdentifyNamespace. """ super().setUp() self.setup_log_dir(self.__class__.__name__) - self.ns_list = self.get_ns_list() + self.nsid_list = self.get_nsid_list() def tearDown(self): """ @@ -81,7 +81,7 @@ def get_id_ns_all(self): - 0 on success, error code on failure. """ err = 0 - for namespace in self.ns_list: + for namespace in self.nsid_list: err = self.get_id_ns(str(namespace)) return err diff --git a/tests/nvme_smart_log_test.py b/tests/nvme_smart_log_test.py index 196998b860..ebc076c10d 100644 --- a/tests/nvme_smart_log_test.py +++ b/tests/nvme_smart_log_test.py @@ -76,14 +76,14 @@ def get_smart_log_all_ns(self): - Returns: - 0 on success, error code on failure. """ - ns_list = self.get_ns_list() - for nsid in range(0, len(ns_list)): - self.get_smart_log_ns(ns_list[nsid]) + nsid_list = self.get_nsid_list() + for nsid in nsid_list: + self.get_smart_log_ns(nsid) return 0 def test_smart_log(self): """ Testcase main """ self.assertEqual(self.get_smart_log_ctrl(), 0) - smlp = self.supp_check_id_ctrl("lpa") + smlp = int(self.get_id_ctrl_field_value("lpa"), 16) if smlp & 0x1: self.assertEqual(self.get_smart_log_all_ns(), 0) diff --git a/tests/nvme_test.py b/tests/nvme_test.py index 7c9101643a..0b2c325d2f 100644 --- a/tests/nvme_test.py +++ b/tests/nvme_test.py @@ -194,7 +194,7 @@ def get_ctrl_id(self): "ERROR : nvme list-ctrl could not find ctrl") return str(json_output['ctrl_list'][0]['ctrl_id']) - def get_ns_list(self): + def get_nsid_list(self): """ Wrapper for extracting the namespace list. - Args: - None @@ -202,14 +202,17 @@ def get_ns_list(self): - List of the namespaces. """ ns_list = [] - ns_list_cmd = f"{self.nvme_bin} list-ns {self.ctrl}" + ns_list_cmd = f"{self.nvme_bin} list-ns {self.ctrl} " + \ + "--output-format=json" proc = subprocess.Popen(ns_list_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') self.assertEqual(proc.wait(), 0, "ERROR : nvme list namespace failed") - for line in proc.stdout: - ns_list.append(line.split('x')[-1]) + json_output = json.loads(proc.stdout.read()) + + for ns in json_output['nsid_list']: + ns_list.append(ns['nsid']) return ns_list @@ -220,22 +223,16 @@ def get_max_ns(self): - Returns: - maximum number of namespaces supported. """ - pattern = re.compile("^nn[ ]+: [0-9]", re.IGNORECASE) - max_ns = -1 - max_ns_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl}" + max_ns_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl} " + \ + "--output-format=json" proc = subprocess.Popen(max_ns_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') err = proc.wait() self.assertEqual(err, 0, "ERROR : reading maximum namespace count failed") - - for line in proc.stdout: - if pattern.match(line): - max_ns = line.split(":")[1].strip() - break - print(max_ns) - return int(max_ns) + json_output = json.loads(proc.stdout.read()) + return int(json_output['nn']) def get_lba_status_supported(self): """ Check if 'Get LBA Status' command is supported by the device @@ -280,24 +277,9 @@ def get_ncap(self): - Args: - None - Returns: - - maximum number of namespaces supported. + - Total NVM capacity. """ - pattern = re.compile("^tnvmcap[ ]+: [0-9]", re.IGNORECASE) - ncap = -1 - ncap_cmd = f"{self.nvme_bin} id-ctrl {self.ctrl}" - proc = subprocess.Popen(ncap_cmd, - shell=True, - stdout=subprocess.PIPE, - encoding='utf-8') - err = proc.wait() - self.assertEqual(err, 0, "ERROR : reading nvm capacity failed") - - for line in proc.stdout: - if pattern.match(line): - ncap = line.split(":")[1].strip() - break - print(ncap) - return int(ncap) + return int(self.get_id_ctrl_field_value("tnvmcap")) def get_id_ctrl_field_value(self, field): """ Wrapper for extracting id-ctrl field values @@ -346,10 +328,11 @@ def get_format(self): err = proc.wait() self.assertEqual(err, 0, "ERROR : reading nvm capacity failed") + # Not using json output here because parsing flbas makes this less + # readable as the format index is split into lower and upper bits for line in proc.stdout: if "in use" in line: nvm_format = 2 ** int(line.split(":")[3].split()[0]) - print(nvm_format) return int(nvm_format) def delete_all_ns(self): @@ -362,13 +345,16 @@ def delete_all_ns(self): delete_ns_cmd = f"{self.nvme_bin} delete-ns {self.ctrl} " + \ "--namespace-id=0xFFFFFFFF" self.assertEqual(self.exec_cmd(delete_ns_cmd), 0) - list_ns_cmd = f"{self.nvme_bin} list-ns {self.ctrl} --all | wc -l" + list_ns_cmd = f"{self.nvme_bin} list-ns {self.ctrl} --all " + \ + "--output-format=json" proc = subprocess.Popen(list_ns_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - output = proc.stdout.read().strip() - self.assertEqual(output, '0', "ERROR : deleting all namespace failed") + self.assertEqual(proc.wait(), 0, "ERROR : nvme list-ns failed") + json_output = json.loads(proc.stdout.read()) + self.assertEqual(len(json_output['nsid_list']), 0, + "ERROR : deleting all namespace failed") def create_ns(self, nsze, ncap, flbas, dps): """ Wrapper for creating a namespace. @@ -518,6 +504,7 @@ def get_error_log(self): encoding='utf-8') err = proc.wait() self.assertEqual(err, 0, "ERROR : nvme error log failed") + # This sanity checkes the 'normal' output line = proc.stdout.readline() err_log_entry_count = int(line.split(" ")[5].strip().split(":")[1]) entry_count = 0 @@ -550,26 +537,3 @@ def run_ns_io(self, nsid, lbads, count=10): encoding='utf-8') run_io_result = run_io.communicate()[1] self.assertEqual(run_io_result, None) - - def supp_check_id_ctrl(self, key): - """ Wrapper for support check. - - Args: - - key : search key. - - Returns: - - value for key requested. - """ - id_ctrl = f"{self.nvme_bin} id-ctrl {self.ctrl}" - print("\n" + id_ctrl) - proc = subprocess.Popen(id_ctrl, - shell=True, - stdout=subprocess.PIPE, - encoding='utf-8') - err = proc.wait() - self.assertEqual(err, 0, "ERROR : nvme Identify controller Data \ - structure failed") - for line in proc.stdout: - if key in line: - key = line.replace(",", "", 1) - print(key) - val = (key.split(':'))[1].strip() - return int(val, 16) From 28323bd3944a239d3384b19a93686e579e379b67 Mon Sep 17 00:00:00 2001 From: Dennis Maisenbacher Date: Mon, 25 Nov 2024 12:42:02 +0000 Subject: [PATCH 3/7] tests: use current LBA format as I/O block size When running I/O use the current LBA format as default block size. Signed-off-by: Dennis Maisenbacher --- tests/nvme_test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/nvme_test.py b/tests/nvme_test.py index 0b2c325d2f..0bd10f552e 100644 --- a/tests/nvme_test.py +++ b/tests/nvme_test.py @@ -61,6 +61,7 @@ def setUp(self): self.nvme_bin = "nvme" self.do_validate_pci_device = True self.default_nsid = 0x1 + self.flbas = 0 self.config_file = 'tests/config.json' self.load_config() @@ -521,7 +522,8 @@ def run_ns_io(self, nsid, lbads, count=10): - Returns: - None """ - block_size = mmap.PAGESIZE if int(lbads) < 9 else 2 ** int(lbads) + (ds, _) = self.get_lba_format_size() + block_size = ds if int(lbads) < 9 else 2 ** int(lbads) ns_path = self.ctrl + "n" + str(nsid) io_cmd = "dd if=" + ns_path + " of=/dev/null" + " bs=" + \ str(block_size) + " count=" + str(count) + " > /dev/null 2>&1" From 1698bc4d2c9006a6e47d5bc173b2b7ea2bb6c1dd Mon Sep 17 00:00:00 2001 From: Dennis Maisenbacher Date: Fri, 8 Nov 2024 08:10:26 +0000 Subject: [PATCH 4/7] tests: Remove unneeded sleep statements Removing sleep statements, which improves the test cases runtime. Signed-off-by: Dennis Maisenbacher --- tests/nvme_attach_detach_ns_test.py | 3 --- tests/nvme_create_max_ns_test.py | 3 --- tests/nvme_format_test.py | 2 -- tests/nvme_test.py | 6 ------ 4 files changed, 14 deletions(-) diff --git a/tests/nvme_attach_detach_ns_test.py b/tests/nvme_attach_detach_ns_test.py index a0e6129d5d..f23630087a 100644 --- a/tests/nvme_attach_detach_ns_test.py +++ b/tests/nvme_attach_detach_ns_test.py @@ -29,8 +29,6 @@ 5. Delete Namespace. """ -import time - from nvme_test import TestNVMe @@ -59,7 +57,6 @@ def setUp(self): self.setup_log_dir(self.__class__.__name__) self.ctrl_id = self.get_ctrl_id() self.delete_all_ns() - time.sleep(1) def tearDown(self): """ diff --git a/tests/nvme_create_max_ns_test.py b/tests/nvme_create_max_ns_test.py index 76cd4d4a10..5cb7448e34 100644 --- a/tests/nvme_create_max_ns_test.py +++ b/tests/nvme_create_max_ns_test.py @@ -29,8 +29,6 @@ 5. Delete all Namespaces. """ -import time - from nvme_test import TestNVMe @@ -63,7 +61,6 @@ def setUp(self): self.max_ns = self.get_max_ns() self.ctrl_id = self.get_ctrl_id() self.delete_all_ns() - time.sleep(1) def tearDown(self): """ diff --git a/tests/nvme_format_test.py b/tests/nvme_format_test.py index 9faf3dc875..daf3574089 100644 --- a/tests/nvme_format_test.py +++ b/tests/nvme_format_test.py @@ -40,7 +40,6 @@ import json import math import subprocess -import time from nvme_test import TestNVMe @@ -76,7 +75,6 @@ def setUp(self): self.test_log_dir = self.log_dir + "/" + self.__class__.__name__ self.setup_log_dir(self.__class__.__name__) self.delete_all_ns() - time.sleep(1) def tearDown(self): """ diff --git a/tests/nvme_test.py b/tests/nvme_test.py index 0bd10f552e..8088ee2e93 100644 --- a/tests/nvme_test.py +++ b/tests/nvme_test.py @@ -30,7 +30,6 @@ import stat import subprocess import sys -import time import unittest from nvme_test_logger import TestNVMeLogger @@ -165,14 +164,12 @@ def nvme_reset_ctrl(self): stdout=subprocess.PIPE, encoding='utf-8') self.assertEqual(err, 0, "ERROR : nvme reset failed") - time.sleep(5) rescan_cmd = "echo 1 > /sys/bus/pci/rescan" proc = subprocess.Popen(rescan_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8') - time.sleep(5) self.assertEqual(proc.wait(), 0, "ERROR : pci rescan failed") def get_ctrl_id(self): @@ -385,7 +382,6 @@ def create_and_validate_ns(self, nsid, nsze, ncap, flbas, dps): """ err = self.create_ns(nsze, ncap, flbas, dps) if err == 0: - time.sleep(2) id_ns_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \ f"--namespace-id={str(nsid)}" err = subprocess.call(id_ns_cmd, @@ -408,11 +404,9 @@ def attach_ns(self, ctrl_id, ns_id): shell=True, stdout=subprocess.PIPE, encoding='utf-8') - time.sleep(5) if err == 0: # enumerate new namespace block device self.nvme_reset_ctrl() - time.sleep(5) # check if new namespace block device exists err = 0 if stat.S_ISBLK(os.stat(self.ns1).st_mode) else 1 return err From 4eb7a7ef4627198506a0c0751d6ab42fbcff3f92 Mon Sep 17 00:00:00 2001 From: Dennis Maisenbacher Date: Fri, 8 Nov 2024 09:25:29 +0000 Subject: [PATCH 5/7] tests: Refactor prints Remove unused prints and add some informative prints. Signed-off-by: Dennis Maisenbacher --- tests/nvme_copy_test.py | 4 ---- tests/nvme_create_max_ns_test.py | 10 +++++----- tests/nvme_flush_test.py | 1 - tests/nvme_format_test.py | 1 + tests/nvme_fw_log_test.py | 6 +----- tests/nvme_get_features_test.py | 4 ---- tests/nvme_get_lba_status_test.py | 6 +----- tests/nvme_id_ns_test.py | 6 +----- tests/nvme_lba_status_log_test.py | 6 +----- tests/nvme_test.py | 18 ++++++++++-------- tests/nvme_test_io.py | 1 - 11 files changed, 20 insertions(+), 43 deletions(-) diff --git a/tests/nvme_copy_test.py b/tests/nvme_copy_test.py index 085c765053..f73cd04b1e 100644 --- a/tests/nvme_copy_test.py +++ b/tests/nvme_copy_test.py @@ -34,7 +34,6 @@ class TestNVMeCopy(TestNVMe): def setUp(self): """ Pre Section for TestNVMeCopy """ super().setUp() - print("\nSetting up test...") self.ocfs = self.get_ocfs() self.host_behavior_data = None cross_namespace_copy = self.ocfs & 0xc @@ -78,7 +77,6 @@ def setUp(self): def tearDown(self): """ Post Section for TestNVMeCopy """ - print("Tearing down test...") if self.host_behavior_data: # restore saved host behavior support data set_features_cmd = f"{self.nvme_bin} set-feature {self.ctrl} " + \ @@ -117,12 +115,10 @@ def copy(self, sdlba, blocks, slbs, **kwargs): if "sopts" in kwargs: copy_cmd += f" --sopts={kwargs['sopts']}" # run and assert success - print("Running command:", copy_cmd) self.assertEqual(self.exec_cmd(copy_cmd), 0) def test_copy(self): """ Testcase main """ - print("Running test...") self.copy(0, 1, 2, descriptor_format=0) self.copy(0, 1, 2, descriptor_format=1) self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid) diff --git a/tests/nvme_create_max_ns_test.py b/tests/nvme_create_max_ns_test.py index 5cb7448e34..f4fa72c7bb 100644 --- a/tests/nvme_create_max_ns_test.py +++ b/tests/nvme_create_max_ns_test.py @@ -82,21 +82,21 @@ def test_attach_detach_ns(self): """ Testcase main """ print(f"##### Testing max_ns: {self.max_ns}") for nsid in range(1, self.max_ns + 1): - print("##### Creating " + str(nsid)) + print(f"##### Creating {nsid}") err = self.create_and_validate_ns(nsid, self.nsze, self.ncap, self.flbas, self.dps) self.assertEqual(err, 0) - print("##### Attaching " + str(nsid)) + print(f"##### Attaching {nsid}") self.assertEqual(self.attach_ns(self.ctrl_id, nsid), 0) - print("##### Running IOs in " + str(nsid)) + print(f"##### Running IOs in {nsid}") self.run_ns_io(nsid, 9, 1) for nsid in range(1, self.max_ns + 1): - print("##### Detaching " + str(nsid)) + print(f"##### Detaching {nsid}") self.assertEqual(self.detach_ns(self.ctrl_id, nsid), 0) - print("#### Deleting " + str(nsid)) + print(f"#### Deleting {nsid}") self.assertEqual(self.delete_and_validate_ns(nsid), 0) self.nvme_reset_ctrl() diff --git a/tests/nvme_flush_test.py b/tests/nvme_flush_test.py index 4c9e2b9e2f..0f2d3c52a8 100644 --- a/tests/nvme_flush_test.py +++ b/tests/nvme_flush_test.py @@ -55,7 +55,6 @@ def nvme_flush(self): """ flush_cmd = f"{self.nvme_bin} flush {self.ctrl} " + \ f"--namespace-id={str(self.default_nsid)}" - print(flush_cmd) return self.exec_cmd(flush_cmd) def test_nvme_flush(self): diff --git a/tests/nvme_format_test.py b/tests/nvme_format_test.py index daf3574089..68445ac843 100644 --- a/tests/nvme_format_test.py +++ b/tests/nvme_format_test.py @@ -122,6 +122,7 @@ def test_format_ns(self): # extract the supported format information. self.attach_detach_primary_ns() + print("##### Testing lba formats:") # iterate through all supported format for flbas, lba_format in enumerate(self.lba_format_list): ds = lba_format['ds'] diff --git a/tests/nvme_fw_log_test.py b/tests/nvme_fw_log_test.py index 11d79cddb3..e56953df8b 100644 --- a/tests/nvme_fw_log_test.py +++ b/tests/nvme_fw_log_test.py @@ -57,16 +57,12 @@ def get_fw_log(self): - Returns: - 0 on success, error code on failure. """ - err = 0 fw_log_cmd = f"{self.nvme_bin} fw-log {self.ctrl}" proc = subprocess.Popen(fw_log_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - fw_log_output = proc.communicate()[0] - print("\n" + fw_log_output + "\n") - err = proc.wait() - return err + return proc.wait() def test_fw_log(self): """ Testcase main """ diff --git a/tests/nvme_get_features_test.py b/tests/nvme_get_features_test.py index 6edf332444..d1bf6211f7 100644 --- a/tests/nvme_get_features_test.py +++ b/tests/nvme_get_features_test.py @@ -88,8 +88,6 @@ def get_mandatory_features(self, feature_id): shell=True, stdout=subprocess.PIPE, encoding='utf-8') - feature_output = proc.communicate()[0] - print(feature_output) self.assertEqual(proc.wait(), 0) else: get_feat_cmd = f"{self.nvme_bin} get-feature {self.ctrl} " + \ @@ -100,8 +98,6 @@ def get_mandatory_features(self, feature_id): shell=True, stdout=subprocess.PIPE, encoding='utf-8') - feature_output = proc.communicate()[0] - print(feature_output) self.assertEqual(proc.wait(), 0) def test_get_mandatory_features(self): diff --git a/tests/nvme_get_lba_status_test.py b/tests/nvme_get_lba_status_test.py index 7577f6d089..15842cfba8 100644 --- a/tests/nvme_get_lba_status_test.py +++ b/tests/nvme_get_lba_status_test.py @@ -50,7 +50,6 @@ def get_lba_status(self): - Returns: - 0 on success, error code on failure. """ - err = 0 get_lba_status_cmd = f"{self.nvme_bin} get-lba-status {self.ctrl} " + \ f"--namespace-id={str(self.ns1)} " + \ f"--start-lba={str(self.start_lba)} " + \ @@ -61,10 +60,7 @@ def get_lba_status(self): shell=True, stdout=subprocess.PIPE, encoding='utf-8') - get_lba_status_output = proc.communicate()[0] - print("\n" + get_lba_status_output + "\n") - err = proc.wait() - return err + return proc.wait() def test_get_lba_status(self): """ Testcase main """ diff --git a/tests/nvme_id_ns_test.py b/tests/nvme_id_ns_test.py index 247f75365d..46ed3eeffe 100644 --- a/tests/nvme_id_ns_test.py +++ b/tests/nvme_id_ns_test.py @@ -60,17 +60,13 @@ def get_id_ns(self, nsid): - Returns: - 0 on success, error code on failure. """ - err = 0 id_ns_cmd = f"{self.nvme_bin} id-ns {self.ctrl} " + \ f"--namespace-id={str(nsid)}" proc = subprocess.Popen(id_ns_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - id_ns_output = proc.communicate()[0] - print(id_ns_output + "\n") - err = proc.wait() - return err + return proc.wait() def get_id_ns_all(self): """ diff --git a/tests/nvme_lba_status_log_test.py b/tests/nvme_lba_status_log_test.py index 8eca23bd0b..079fe5c71c 100644 --- a/tests/nvme_lba_status_log_test.py +++ b/tests/nvme_lba_status_log_test.py @@ -45,16 +45,12 @@ def get_lba_stat_log(self): - Returns: - 0 on success, error code on failure. """ - err = 0 lba_stat_log_cmd = f"{self.nvme_bin} lba-status-log {self.ctrl}" proc = subprocess.Popen(lba_stat_log_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') - lba_stat_log_output = proc.communicate()[0] - print("\n" + lba_stat_log_output + "\n") - err = proc.wait() - return err + return proc.wait() def test_lba_stat_log(self): """ Testcase main """ diff --git a/tests/nvme_test.py b/tests/nvme_test.py index 8088ee2e93..923e6747c0 100644 --- a/tests/nvme_test.py +++ b/tests/nvme_test.py @@ -66,12 +66,18 @@ def setUp(self): self.load_config() if self.do_validate_pci_device: self.validate_pci_device() + print(f"\nsetup: ctrl: {self.ctrl}, ns1: {self.ns1}, default_nsid: {self.default_nsid}, flbas: {self.flbas}\n") def tearDown(self): """ Post Section for TestNVMe. """ if self.clear_log_dir is True: shutil.rmtree(self.log_dir, ignore_errors=True) self.create_and_attach_default_ns() + print(f"\nteardown: ctrl: {self.ctrl}, ns1: {self.ns1}, default_nsid: {self.default_nsid}, flbas: {self.flbas}\n") + + @classmethod + def tearDownClass(cls): + print("\n") def create_and_attach_default_ns(self): """ Creates a default namespace with the full capacity of the ctrls NVM @@ -104,8 +110,8 @@ def validate_pci_device(self): - None """ x1, x2, dev = self.ctrl.split('/') - cmd = cmd = "find /sys/devices -name \\*" + dev + " | grep -i pci" - err = subprocess.call(cmd, shell=True) + cmd = "find /sys/devices -name \\*" + dev + " | grep -i pci" + err = subprocess.call(cmd, shell=True, stdout=subprocess.DEVNULL) self.assertEqual(err, 0, "ERROR : Only NVMe PCI subsystem is supported") def load_config(self): @@ -452,15 +458,12 @@ def get_smart_log(self, nsid): """ smart_log_cmd = f"{self.nvme_bin} smart-log {self.ctrl} " + \ f"--namespace-id={str(nsid)}" - print(smart_log_cmd) proc = subprocess.Popen(smart_log_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') err = proc.wait() self.assertEqual(err, 0, "ERROR : nvme smart log failed") - smart_log_output = proc.communicate()[0] - print(f"{smart_log_output}") return err def get_id_ctrl(self, vendor=False): @@ -475,7 +478,6 @@ def get_id_ctrl(self, vendor=False): else: id_ctrl_cmd = f"{self.nvme_bin} id-ctrl " +\ f"--vendor-specific {self.ctrl}" - print(id_ctrl_cmd) proc = subprocess.Popen(id_ctrl_cmd, shell=True, stdout=subprocess.PIPE, @@ -521,14 +523,14 @@ def run_ns_io(self, nsid, lbads, count=10): ns_path = self.ctrl + "n" + str(nsid) io_cmd = "dd if=" + ns_path + " of=/dev/null" + " bs=" + \ str(block_size) + " count=" + str(count) + " > /dev/null 2>&1" - print(io_cmd) + print(f"Running io: {io_cmd}") run_io = subprocess.Popen(io_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') run_io_result = run_io.communicate()[1] self.assertEqual(run_io_result, None) io_cmd = "dd if=/dev/zero of=" + ns_path + " bs=" + \ str(block_size) + " count=" + str(count) + " > /dev/null 2>&1" - print(io_cmd) + print(f"Running io: {io_cmd}") run_io = subprocess.Popen(io_cmd, shell=True, stdout=subprocess.PIPE, encoding='utf-8') run_io_result = run_io.communicate()[1] diff --git a/tests/nvme_test_io.py b/tests/nvme_test_io.py index e12d8c09d0..6fac9db0f5 100644 --- a/tests/nvme_test_io.py +++ b/tests/nvme_test_io.py @@ -94,5 +94,4 @@ def nvme_read(self): f"--start-block={str(self.start_block)} " + \ f"--block-count={str(self.block_count)} " + \ f"--data-size={str(self.data_size)} --data={self.read_file}" - print(read_cmd) return self.exec_cmd(read_cmd) From b14dca5ccb645a8f1ba92f0513d0d9d3f2bf072f Mon Sep 17 00:00:00 2001 From: Dennis Maisenbacher Date: Fri, 8 Nov 2024 09:29:17 +0000 Subject: [PATCH 6/7] tests: Fix `subprosess.call` calls Don't use stdout=PIPE with subprocess.call as noted in the documentation: https://docs.python.org/3/library/subprocess.html#subprocess.call Signed-off-by: Dennis Maisenbacher --- tests/nvme_test.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/nvme_test.py b/tests/nvme_test.py index 923e6747c0..863fc023d4 100644 --- a/tests/nvme_test.py +++ b/tests/nvme_test.py @@ -167,8 +167,7 @@ def nvme_reset_ctrl(self): nvme_reset_cmd = f"{self.nvme_bin} reset {self.ctrl}" err = subprocess.call(nvme_reset_cmd, shell=True, - stdout=subprocess.PIPE, - encoding='utf-8') + stdout=subprocess.DEVNULL) self.assertEqual(err, 0, "ERROR : nvme reset failed") rescan_cmd = "echo 1 > /sys/bus/pci/rescan" proc = subprocess.Popen(rescan_cmd, @@ -392,8 +391,7 @@ def create_and_validate_ns(self, nsid, nsze, ncap, flbas, dps): f"--namespace-id={str(nsid)}" err = subprocess.call(id_ns_cmd, shell=True, - stdout=subprocess.PIPE, - encoding='utf-8') + stdout=subprocess.DEVNULL) return err def attach_ns(self, ctrl_id, ns_id): @@ -408,8 +406,7 @@ def attach_ns(self, ctrl_id, ns_id): f"--namespace-id={str(ns_id)} --controllers={ctrl_id}" err = subprocess.call(attach_ns_cmd, shell=True, - stdout=subprocess.PIPE, - encoding='utf-8') + stdout=subprocess.DEVNULL) if err == 0: # enumerate new namespace block device self.nvme_reset_ctrl() @@ -429,8 +426,7 @@ def detach_ns(self, ctrl_id, nsid): f"--namespace-id={str(nsid)} --controllers={ctrl_id}" return subprocess.call(detach_ns_cmd, shell=True, - stdout=subprocess.PIPE, - encoding='utf-8') + stdout=subprocess.DEVNULL) def delete_and_validate_ns(self, nsid): """ Wrapper for deleting and validating that namespace is deleted. @@ -444,8 +440,7 @@ def delete_and_validate_ns(self, nsid): f"--namespace-id={str(nsid)}" err = subprocess.call(delete_ns_cmd, shell=True, - stdout=subprocess.PIPE, - encoding='utf-8') + stdout=subprocess.DEVNULL) self.assertEqual(err, 0, "ERROR : delete namespace failed") return err From 9afc101a351513c4aadbe7af8ca447f8bec3c054 Mon Sep 17 00:00:00 2001 From: Dennis Maisenbacher Date: Mon, 11 Nov 2024 09:59:08 +0000 Subject: [PATCH 7/7] tests: Use container image to run nightly tests Using the pre-build linux-nvme/debian.python container to avoid installing dependencies every time which fails occasionally. Also drop clean up steps as this is part of the self-hosted runner now. Signed-off-by: Dennis Maisenbacher --- .github/workflows/run-nightly-tests.yml | 49 +++++++------------------ 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/.github/workflows/run-nightly-tests.yml b/.github/workflows/run-nightly-tests.yml index d525986a21..58fc2a7712 100644 --- a/.github/workflows/run-nightly-tests.yml +++ b/.github/workflows/run-nightly-tests.yml @@ -9,39 +9,25 @@ on: jobs: nightly-tests: runs-on: nvme-nvm + container: + image: ghcr.io/linux-nvme/debian.python:latest + #Expose all devices to the container through the `privileged` flag. + # + #BDEV0 is an environment variable of the self-hosted runner instance + #that contains a valid nvme ctrl name which is capable of the nvm + #command set. + options: '--privileged -e BDEV0' steps: - name: Output kernel version run: | uname -a - - name: Clean up test device - run: | - #BDEV0 is an environment variable of the self-hosted runner instance - #that contains a valid nvme ctrl name which is capable of the nvm - #command set. - CONTROLLER=$(echo /dev/${BDEV0} | sed 's/n[0-9]*$//') - sudo nvme delete-ns $CONTROLLER -n 0xffffffff - sudo nvme format $CONTROLLER -n 0xffffffff -l 0 -f - SIZE=$(sudo nvme id-ctrl $CONTROLLER --output-format=json | jq -r '{tnvmcap} | .[]' | awk '{print $1/512}') - sudo nvme create-ns -s $SIZE -c $SIZE -f 0 -d 0 --csi=0 $CONTROLLER - sudo nvme attach-ns $CONTROLLER -n 1 -c 0 - uses: actions/checkout@v4 - name: Install dependencies run: | - sudo apt-get update - sudo apt-get install --no-install-recommends -y \ - meson gcc pkg-config git libjson-c-dev libssl-dev libkeyutils-dev \ - libdbus-1-dev libpython3-dev pipx python3-dev swig xz-utils - pipx ensurepath - sudo PIPX_BIN_DIR=/usr/local/bin pipx install nose2 - sudo PIPX_BIN_DIR=/usr/local/bin pipx install flake8 - sudo PIPX_BIN_DIR=/usr/local/bin pipx install mypy - sudo PIPX_BIN_DIR=/usr/local/bin pipx install autopep8 - sudo PIPX_BIN_DIR=/usr/local/bin pipx install isort + PIPX_BIN_DIR=/usr/local/bin pipx install nose2 --force - name: Build and install nvme-cli run: | scripts/build.sh -b release -c gcc - sudo meson install -C .build-ci - sudo ldconfig /usr/local/lib64 - name: Overwrite test config run: | CONTROLLER=$(echo /dev/${BDEV0} | sed 's/n[0-9]*$//') @@ -49,12 +35,14 @@ jobs: { "controller" : "$CONTROLLER", "ns1": "/dev/${BDEV0}", - "log_dir": "tests/nvmetests/" + "log_dir": "tests/nvmetests/", + "nvme_bin": "$(pwd)/.build-ci/nvme" } EOF + cat tests/config.json - name: Run on device tests run: | - sudo nose2 --verbose --start-dir tests \ + nose2 --verbose --start-dir tests \ nvme_attach_detach_ns_test \ nvme_compare_test \ nvme_copy_test \ @@ -79,15 +67,6 @@ jobs: uses: actions/upload-artifact@v4 if: always() with: - name: logs files + name: nvme-cli-test-logs path: | ./tests/nvmetests/**/*.log - - name: Clean up test device - if: always() - run: | - CONTROLLER=$(echo /dev/${BDEV0} | sed 's/n[0-9]*$//') - sudo nvme delete-ns $CONTROLLER -n 0xffffffff - sudo nvme format $CONTROLLER -n 0xffffffff -l 0 -f - SIZE=$(sudo nvme id-ctrl $CONTROLLER --output-format=json | jq -r '{tnvmcap} | .[]' | awk '{print $1/512}') - sudo nvme create-ns -s $SIZE -c $SIZE -f 0 -d 0 --csi=0 $CONTROLLER - sudo nvme attach-ns $CONTROLLER -n 1 -c 0