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
25 changes: 2 additions & 23 deletions .github/workflows/run-nightly-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,11 @@ jobs:
set -e
set -x
uname -a
PIPX_BIN_DIR=/usr/local/bin pipx install nose2 --force
git clone https://github.com/${{ github.repository }} /nvme-cli
git config --global --add safe.directory /nvme-cli
cd /nvme-cli
git checkout ${{ github.sha }}
scripts/build.sh -b release -c gcc
scripts/build.sh -b release -c gcc tests
CONTROLLER=$(echo "${BDEV0}" | sed 's/n[0-9]*$//')
cat > tests/config.json << EOJ
{
Expand All @@ -112,27 +111,7 @@ jobs:
EOJ
cat tests/config.json

nose2 --verbose --start-dir tests \
nvme_attach_detach_ns_test \
nvme_compare_test \
nvme_copy_test \
nvme_create_max_ns_test \
nvme_ctrl_reset_test \
nvme_dsm_test \
nvme_error_log_test \
nvme_flush_test \
nvme_format_test \
nvme_fw_log_test \
nvme_get_features_test \
nvme_get_lba_status_test \
nvme_id_ctrl_test \
nvme_id_ns_test \
nvme_lba_status_log_test \
nvme_read_write_test \
nvme_smart_log_test \
nvme_verify_test \
nvme_writeuncor_test \
nvme_writezeros_test
meson tests -C .build-ci
EOF

sudo chmod +x test.sh
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ else
# Check for libdbus availability. Optional, only required for MCTP dbus scan
libdbus_dep = dependency(
'dbus-1',
required: true,
required: get_option('libdbus'),
fallback: ['dbus', 'libdbus_dep'],
default_options: [
'default_library=static',
Expand Down
9 changes: 9 additions & 0 deletions scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ usage() {
echo " static build a static binary"
echo " minimal_static build a static binary without fabrics support"
echo " libnvme build only libnvme"
echo " tests build for nightly build"
echo ""
echo "configs with muon:"
echo " [default] minimal static build"
Expand Down Expand Up @@ -241,6 +242,14 @@ config_meson_minimal_static() {
"${BUILDDIR}"
}

config_meson_tests() {
CC="${CC}" "${MESON}" setup \
--werror \
--buildtype="${BUILDTYPE}" \
-Dnvme-tests=true \
"${BUILDDIR}"
}

config_meson_libnvme() {
CC="${CC}" "${MESON}" setup \
--werror \
Expand Down
67 changes: 9 additions & 58 deletions tests/README
Original file line number Diff line number Diff line change
Expand Up @@ -16,59 +16,10 @@ nvmetests
DO NOT RUN THEM IF YOU DO NOT KNOW WHAT YOU ARE DOING!

You have been warned.

1. Common Package Dependencies
------------------------------

1. Python(>= 3.3)
2. nose2 (Installation guide http://nose2.readthedocs.io/)
3. flake8 (https://pypi.python.org/pypi/flake8)
4. mypy (https://pypi.org/project/mypy/)
5. autopep8 (https://pypi.org/project/autopep8/)
6. isort (https://pypi.org/project/isort/)

Python package management system pip can be used to install most of the
listed packages(https://pip.pypa.io/en/stable/installing/) :-
$ pip install nose2 flake8 mypy autopep8 isort

2. Overview
-----------

This framework follows simple class hierarchy. Each test file contains
one test. Each test is direct subclass or indirect subclass of TestNVMe
class which represents one testcase. To write a new testcase one can copy
existing template "nvme_simple_template_test.py" and start adding new
testcase specific functionality. For detailed information please look into
section 3.

For more information about tests, class hierarchy and code please refer :-

1. Documentation :- html/
2. Class Index :- html/index.html
3. Class Hierarchy :- html/class-tree.html

For each testcase it will create log directory mentioned in
configuration file. This directory will be used for a temporary files
and storing execution logs of each testcases. Current implementation stores
stdout and stderr for each testcase under log directory, e.g. :-

$ tree nvmetests/
nvmetests/
├── TestNVMeAttachDetachNSCmd
│   ├── stderr.log
│   └── stdout.log
├── TestNVMeFlushCmd
│   ├── stderr.log
│   └── stdout.log
└── TestNVMeFormatCmd
├── stderr.log
└── stdout.log
.
.
.

3. Walk-Through Example for writing a new testcase
--------------------------------------------------
Walk-Through Example for writing a new testcase
-----------------------------------------------
1. Copy simple test template file from current directory
with appropriate name, replace "simple_template" with testcase name
in new file name. Update config.json if necessary.
Expand All @@ -90,11 +41,11 @@ nvmetests
- Example "$ ninja -C .build format-python" will run autopep8 and
isort on all the python files in the current directory.

4. Running testcases with framework
-----------------------------------
1. Running single testcase (in the source tree) with nose2 :-
$ nose2 --verbose --start-dir tests nvme_writezeros_test
$ nose2 --verbose --start-dir tests nvme_read_write_test
Running testcases with framework
--------------------------------
1. Running single testcase :-
$ python3 tests/tap_runner.py --start-dir tests nvme_id_ctrl_test
$ meson test -C .build 'nvme-cli - nvme_id_ctrl_test'

2. Running all the testcases (in the build root directory) with ninja :-
$ ninja test -C .build
2. Running all the testcases (in the build root directory) :-
$ meson test -C .build
16 changes: 0 additions & 16 deletions tests/TODO

This file was deleted.

41 changes: 22 additions & 19 deletions tests/meson.build
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# This file is part of nvme.
# Copyright (c) 2026 SUSE LLC
#
# Authors: Daniel Wagner <[email protected]>

infra = [
'config.json',
'nvme_test.py',
'nvme_test_io.py',
'nvme_test_logger.py',
'nvme_simple_template_test.py',
'tap_runner.py',
]

tests = [
Expand All @@ -31,29 +37,26 @@ tests = [
'nvme_ctrl_reset_test.py',
]

runtests = find_program('nose2', required : false)

if runtests.found()
foreach file : infra + tests
configure_file(input: file, output: file, copy: true)
endforeach

foreach t : tests
t_name = t.split('.')[0]
test(
'nvme-cli - @0@'.format(t_name),
runtests,
args: ['--verbose', '--start-dir', meson.current_build_dir(), t_name],
env: ['PATH=' + meson.project_build_root() + ':/usr/bin:/usr/sbin'],
timeout: 500,
)
endforeach
endif

python_module = import('python')

python = python_module.find_installation('python3')

foreach t : tests
t_name = t.split('.')[0]
test(
'nvme-cli - @0@'.format(t_name),
python,
args: [
meson.current_source_dir() / 'tap_runner.py',
'--start-dir', meson.current_source_dir(),
t_name,
],
env: ['PATH=' + meson.project_build_root() + ':/usr/bin:/usr/sbin'],
timeout: 500,
protocol: 'tap',
)
endforeach

mypy = find_program(
'mypy',
required : false,
Expand Down
4 changes: 4 additions & 0 deletions tests/nvme_attach_detach_ns_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class TestNVMeAttachDetachNSCmd(TestNVMe):
def setUp(self):
""" Pre Section for TestNVMeAttachDetachNSCmd """
super().setUp()

if not self.ns_mgmt_supported:
self.skipTest("Namespace Management / Attach not supported by controller")

self.dps = 0
self.flbas = 0
(ds, ms) = self.get_lba_format_size()
Expand Down
4 changes: 4 additions & 0 deletions tests/nvme_create_max_ns_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class TestNVMeCreateMaxNS(TestNVMe):
def setUp(self):
""" Pre Section for TestNVMeAttachDetachNSCmd """
super().setUp()

if not self.ns_mgmt_supported:
self.skipTest("Namespace Management / Attach not supported by controller")

self.dps = 0
self.flbas = 0
(ds, ms) = self.get_lba_format_size()
Expand Down
4 changes: 4 additions & 0 deletions tests/nvme_format_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class TestNVMeFormatCmd(TestNVMe):
def setUp(self):
""" Pre Section for TestNVMeFormatCmd """
super().setUp()

if not self.ns_mgmt_supported:
self.skipTest("Namespace Management / Attach not supported by controller")

self.dps = 0
self.flbas = 0
# Assuming run_ns_io with 4KiB * 10 writes.
Expand Down
38 changes: 35 additions & 3 deletions tests/nvme_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ def to_decimal(value):
- Returns:
- Decimal integer
"""
return int(str(value), 0)
val = 0
try:
val = int(str(value), 0)
except (TypeError, ValueError):
raise ValueError(f"Invalid value: {value!r}")
return val


class TestNVMe(unittest.TestCase):
Expand Down Expand Up @@ -77,14 +82,17 @@ def setUp(self):
self.load_config()
if self.do_validate_pci_device:
self.validate_pci_device()
self.create_and_attach_default_ns()
self.ns_mgmt_supported = self.get_ns_mgmt_support()
if self.ns_mgmt_supported:
self.create_and_attach_default_ns()
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()
if self.ns_mgmt_supported:
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
Expand Down Expand Up @@ -209,6 +217,30 @@ 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_mgmt_support(self):
"""
Determine whether Namespace Management and Namespace Attachment
operations are supported by the controller.

This method reads the Optional Admin Command Support (OACS) field
from the Identify Controller data structure and evaluates specific
bits that indicate support for:
- Namespace Management (bit 3)
- Namespace Attachment (bit 4)

Both features must be supported for this function to return True.

Returns:
bool: True if both Namespace Management and Namespace Attachment
are supported, False otherwise.
"""
oacs = to_decimal(self.get_id_ctrl_field_value("oacs"))

ns_mgmt_supported = bool(oacs & (1 << 3))
ns_attach_supported = bool(oacs & (1 << 4))

return ns_mgmt_supported and ns_attach_supported

def get_nsid_list(self):
""" Wrapper for extracting the namespace list.
- Args:
Expand Down
Loading
Loading