Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 14 additions & 35 deletions .github/workflows/run-nightly-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,52 +9,40 @@ 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]*$//')
cat > tests/config.json << EOF
{
"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 \
Expand All @@ -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
3 changes: 0 additions & 3 deletions tests/nvme_attach_detach_ns_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
5. Delete Namespace.
"""

import time

from nvme_test import TestNVMe


Expand Down Expand Up @@ -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):
"""
Expand Down
8 changes: 4 additions & 4 deletions tests/nvme_compare_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
49 changes: 31 additions & 18 deletions tests/nvme_copy_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,45 +34,58 @@ 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
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
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))
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):
""" 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))
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()

Expand All @@ -94,18 +107,18 @@ 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:
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)
Expand Down
13 changes: 5 additions & 8 deletions tests/nvme_create_max_ns_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
5. Delete all Namespaces.
"""

import time

from nvme_test import TestNVMe


Expand Down Expand Up @@ -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):
"""
Expand All @@ -85,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()
2 changes: 1 addition & 1 deletion tests/nvme_ctrl_reset_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
7 changes: 3 additions & 4 deletions tests/nvme_dsm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions tests/nvme_flush_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ def nvme_flush(self):
- Returns:
- None
"""
flush_cmd = "nvme flush " + self.ctrl + " -n " + str(self.default_nsid)
print(flush_cmd)
flush_cmd = f"{self.nvme_bin} flush {self.ctrl} " + \
f"--namespace-id={str(self.default_nsid)}"
return self.exec_cmd(flush_cmd)

def test_nvme_flush(self):
Expand Down
65 changes: 27 additions & 38 deletions tests/nvme_format_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
- Delete Namespace.
"""

import json
import math
import subprocess
import time

from nvme_test import TestNVMe

Expand All @@ -55,9 +55,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.
"""

Expand All @@ -74,12 +72,9 @@ 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()
time.sleep(1)

def tearDown(self):
"""
Expand All @@ -106,50 +101,44 @@ 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\" \" \""
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 = "nvme id-ns " + self.ctrl + \
" -n1 | 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\" \" \""
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 """
# extract the supported format information.
self.attach_detach_primary_ns()

print("##### Testing lba formats:")
# 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()
Loading
Loading