summaryrefslogtreecommitdiffstats
path: root/tests/nvme_copy_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/nvme_copy_test.py')
-rw-r--r--tests/nvme_copy_test.py113
1 files changed, 113 insertions, 0 deletions
diff --git a/tests/nvme_copy_test.py b/tests/nvme_copy_test.py
new file mode 100644
index 0000000..a547231
--- /dev/null
+++ b/tests/nvme_copy_test.py
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This file is part of nvme-cli
+#
+# Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
+#
+# Authors: Arunpandian J <apj.arun@samsung.com>
+# Joy Gu <jgu@purestorage.com>
+
+"""
+NVMe Copy Testcase:-
+
+ 1. Issue copy command on set of block; shall pass.
+ 2. If cross-namespace copy formats are supported, enable and test
+ cross-namespace copy formats.
+
+"""
+
+import subprocess
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeCopy(TestNVMe):
+
+ """
+ Represents NVMe Copy testcase.
+ - Attributes:
+ - ocfs : optional copy formats supported
+ - host_behavior_data : host behavior support data to restore during teardown
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeCopy """
+ super().setUp()
+ print("\nSetting up test...")
+ self.ocfs = self.get_ocfs()
+ 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)
+ # enable cross-namespace copy formats
+ if self.host_behavior_data[4] & cross_namespace_copy:
+ # skip if already enabled
+ print("Cross-namespace copy already enabled, skipping set-features")
+ 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))
+ proc = subprocess.Popen(set_features_cmd,
+ stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ 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])
+ self.setup_log_dir(self.__class__.__name__)
+
+ 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 = ["nvme", "set-feature", self.ctrl, "--feature-id=0x16", "--data-len=512"]
+ print("Running command:", " ".join(set_features_cmd))
+ proc = subprocess.Popen(set_features_cmd,
+ stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ proc.communicate(input=self.host_behavior_data)
+ super().tearDown()
+
+ def copy(self, sdlba, blocks, slbs, **kwargs):
+ """ Wrapper for nvme copy
+ - Args:
+ - sdlba : destination logical block address
+ - blocks : number of logical blocks (0-based)
+ - slbs : source range logical block address
+ - descriptor_format : copy descriptor format (optional)
+ - snsids : source namespace id (optional)
+ - sopts : source options (optional)
+ - Returns:
+ - None
+ """
+ # skip if descriptor format not supported (default format is 0)
+ desc_format = kwargs.get("descriptor_format", 0)
+ if not self.ocfs & (1 << desc_format):
+ 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}"
+ if "snsids" in kwargs:
+ copy_cmd += f" --snsids={kwargs['snsids']}"
+ 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)
+ self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid, sopts=0)
+ self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid)
+ self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid, sopts=0)