iLO-manager first main commitgit status

This commit is contained in:
Jiří Stach committed 2026-02-03 15:56:53 +01:00
1 parent e6f4cc04ca
commit 599d8da562
3271 files changed
+550655

No files matched your search

Whitespace-only changes.
@@ -0,0 +1,66 @@
"""
conftest.py is used to set up shared fixtures, plugins, hooks, other config etc.
This is the global, root-level conftest.py loaded for all tests.
Sub-directories can have their own conftest.py that gets loaded locally for that sub-directory only.
http://docs.pytest.org/en/latest/writing_plugins.html#conftest-py-local-per-directory-plugins
"""
from __future__ import absolute_import
import os
import sys
from importlib import import_module
import pytest
# Add the 'src' directory to the module search path so our tests can import from it
SRC_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../ilorest'))
RDMC_FILE = os.path.join(SRC_DIR, 'rdmc.py')
sys.path.insert(0, SRC_DIR)
DisplayHelpers = import_module('extensions.PERSISTENT_MEMORY_COMMANDS.lib.DisplayHelpers')
ShowPmemCommand = import_module('extensions.PERSISTENT_MEMORY_COMMANDS.ShowPmemCommand')
RestHelpers = import_module('extensions.PERSISTENT_MEMORY_COMMANDS.lib.RestHelpers')
Mapper = import_module('extensions.PERSISTENT_MEMORY_COMMANDS.lib.Mapper')
MapperRenderers = import_module('extensions.PERSISTENT_MEMORY_COMMANDS.lib.MapperRenderers')
PmemHelpers = import_module('extensions.PERSISTENT_MEMORY_COMMANDS.lib.PmemHelpers')
ClearPendingConfigCommand = import_module('extensions.PERSISTENT_MEMORY_COMMANDS.ClearPendingConfigCommand')
ApplyPmemConfigCommand = import_module('extensions.PERSISTENT_MEMORY_COMMANDS.ApplyPmemConfigCommand')
def pytest_addoption(parser):
parser.addoption("--runquix", action="store_true", default=False,
help="Run tests associated with an open QuIX (which are skipped by default).")
parser.addoption("--skipincremental", action="store_true", default=False,
help="Skip incremental configuration tests (run by default).")
parser.addoption("--clear-nand-counters", action="store_true", default=False,
help="Clear all iLO NAND write counters using the iLO debugger.")
logging_group = parser.getgroup('logging', description='logging configuration')
logging_group.addoption("--ilodebug", metavar='path', help="log iLO debugger output to the specified file.")
logging_group.addoption("--vsp", metavar='path', help="log Virtual Serial Port output to the specified file.")
logging_group.addoption("--uefi-debug-level", choices=[0, 1, 2, 3], type=int,
help="set UEFI serial debug level when capturing Virtual Serial Port output: "
"0 (Disabled), 1 (ErrorsOnly), 2 (Medium), 3 (Verbose)")
def pytest_runtest_setup(item):
openquix_marker = item.get_marker("openquix")
if openquix_marker is not None:
if item.config.getoption("--runquix") is False:
pytest.skip("skipping test associated with an open QuIX")
def pytest_collection(session):
"""
Hook to use testpaths for a test root directory passed in as a pytest argument.
This allows using testpaths without having to execute pytest from the test root directory.
"""
args = session.config.args
testpaths = session.config.getini('testpaths')
currdir = session.startdir
rootdir = session.config.rootdir
if len(args) == 1 and testpaths:
testdir = args[0]
if currdir.join(testdir) == rootdir:
session.config.args = [os.path.join(testdir, testpath) for testpath in testpaths]
Whitespace-only changes.
@@ -0,0 +1,228 @@
"""
conftest.py is used to set up shared fixtures, plugins, hooks, other config etc.
This is the functional test conftest.py
http://docs.pytest.org/en/latest/writing_plugins.html#conftest-py-local-per-directory-plugins
"""
from __future__ import absolute_import
import os
import re
import sys
from contextlib import contextmanager
import pytest
import redfish
# For cross-compatibility between Python 2 and Python 3
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
from ..conftest import RDMC_FILE
from . import utils
from .ilomock import MockServer
@pytest.fixture(scope='session')
def mock_server():
with MockServer() as server:
yield server
@pytest.fixture
def dl360_large(mock_server):
"""Returns a mock server config:
- DL360 Gen10
- 1x AEP DIMM
- 1x DRAM DIMM
"""
data_dir = os.path.join(os.path.dirname(__file__), 'mockdata/dl360-large')
mock_server.load(data_dir)
return MockServerConfig(mock_server, username='rev', password='hpe123')
@pytest.fixture
def dl360_memfast_disabled(dl360_large):
"""Returns a dl360_configured config with MemFastTraining disabled
"""
dl360_large.patch('/redfish/v1/systems/1/bios/settings/', {'Attributes': {'MemFastTraining': 'Disabled'}})
return dl360_large
@pytest.fixture(scope='session')
def test_server():
"""Returns a server config specified by the TEST_SERVER environment variable.
TEST_SERVER should be a URL with optional auth, e.g. https://user:password@host:port
"""
if 'TEST_SERVER' not in os.environ:
pytest.skip("TEST_SERVER not set")
url, username, password = utils.urlparse_auth(os.getenv('TEST_SERVER'))
# If no credentials, then populate with hard-coded values. Credentials required by ilorest.
username = "orange" if username is None else username
password = "password" if password is None else password
return ServerConfig(url=url, username=username, password=password)
@pytest.fixture
def ilorest(tmpdir):
"""Returns an ilorest session (in scripting mode by default).
Each ilorest session receives its own unique temporary cache directory.
"""
yield Ilorest(cache_dir=tmpdir.dirname)
tmpdir.remove(ignore_errors=True)
class ServerConfig(object):
def __init__(self, url=None, username=None, password=None):
self.url = url
self.username = username
self.password = password
@property
def config(self):
return self.url, self.username, self.password
@property
def hostname(self):
parts = urlparse(self.url)
hostname = parts.hostname if parts.scheme else self.url
return hostname
class MockServerConfig(ServerConfig):
def __init__(self, server, username=None, password=None):
super(MockServerConfig, self).__init__(url=server.url, username=username, password=password)
self.server = server
def patch(self, path, data):
"""Patches a resource in the mock server."""
self.server.patch(path, data)
class Ilorest(object):
"""Wrapper for the iLO RESTful Interface Tool."""
def __init__(self, cache_dir=None):
"""Starts ilorest in scripting mode.
:param cache_dir: directory to use for caching instead of the default global location
"""
self.cache_dir = cache_dir
self.args = [sys.executable, RDMC_FILE]
if cache_dir:
self.args.append('--cache-dir={}'.format(cache_dir))
self.interactive = False
self.proc = None
self.prompt = "iLOrest > "
def run(self, args, sendline=None):
"""Runs an ilorest command.
:param args: list of command arguments
:param sendline: string to send after running (only used in interactive mode)
:return: results of the command as a named tuple: (stdout, stderr, retcode)
"""
if not self.interactive:
return utils.run_cmd(self.args + args)
# interactive mode
cmd_line = ' '.join(args)
self.proc.sendline(cmd_line)
if sendline:
self.proc.sendline(sendline)
stdout, stderr = self.proc.read(expect=self.prompt)
match = re.search("iLOrest return code: ([0-9]+)\n", stdout)
retcode = int(match.group(1)) if match else None
return utils.CommandResult(stdout=stdout, stderr=stderr, retcode=retcode)
def login(self, url=None, username=None, password=None):
"""Logs in to the server and establishes a secure session.
:param url: iLO server url if connecting remotely
:param username: iLO username. If no username specified, use "orange"
:param password: iLO password. If no password specified, use "password"
"""
args = ['login']
if url:
args.append(url)
if username:
args.extend(['-u', username])
if password:
args.extend(['-p', password])
results = self.run(args)
assert results.retcode == 0, "Failed to connect or log in"
def logout(self):
"""Ends the current session and disconnects from the server."""
self.run(['logout'])
@contextmanager
def session(self, url=None, username=None, password=None):
"""Establishes a session with an iLO server and logs out afterwards."""
self.login(url=url, username=username, password=password)
yield self
self.logout()
@contextmanager
def interactive_session(self, url=None, username=None, password=None):
"""Establishes an interactive session with an iLO server, and logs out and exits afterwards."""
with self.interactive_mode(), self.session(url=url, username=username, password=password):
yield self
@contextmanager
def interactive_mode(self):
"""Enters interactive mode and exits afterwards."""
# use --verbose to extract the return code
self.proc = utils.InteractivePopen(self.args + ['--verbose'])
self.proc.read(expect=self.prompt)
self.interactive = True
yield self
self.proc.communicate('exit')
self.interactive = False
class RestClient(object):
"""REST client for an iLO server."""
def __init__(self, url=None, username=None, password=None):
"""Initializes an iLO REST client.
:param url: iLO server url if connecting remotely
:param username: iLO username
:param password: iLO password
"""
# if no scheme/protocol defined, try https
if "://" not in url:
url = "https://" + url
self._client = redfish.redfish_client(base_url=url, username=username, password=password)
self._client.login(auth=redfish.AuthMethod.BASIC)
def get(self, path):
"""Sends a GET request."""
resp = self._client.get(path)
return resp.dict
def patch(self, path, body):
"""
Sends a PATCH request to the path with the given body
:param path: URI path
:param body: the body of the patch. For example dict:{ "Attributes": { "Prop1": true } }
:return: RestResponse status, RestResponse dictionary
"""
rest_response = self._client.patch(path=path, body=body)
return rest_response.status, rest_response.dict
@@ -0,0 +1,97 @@
"""ilomock module"""
from __future__ import absolute_import
import os
import subprocess
import sys
import requests
JAVA_BIN = os.getenv('JAVA_BIN', 'java')
ILOMOCK_JAR = os.getenv('ILOMOCK_JAR')
os.environ['NO_PROXY'] = 'localhost'
# ignore SSL warnings
# requests.packages.urllib3.disable_warnings()
class MockServerError(Exception):
"""An error occurred starting the mock server."""
class MockServer(object):
"""Wrapper for ilomock."""
def __init__(self, profile_dir=None, port=0):
"""Initializes a mock server.
:param profile_dir: path to the server profile to use
:param port: port to listen on
"""
self.profile_dir = profile_dir
self.port = port
self.url = None
self.proc = None
def start(self):
"""Starts the mock server.
:raises MockServerError: if the server failed to start
"""
if not ILOMOCK_JAR:
raise MockServerError("ILOMOCK_JAR must be set")
sys.stdout.write("Starting mock server on port {} with profile {}".format(self.port, self.profile_dir))
args = [JAVA_BIN, '-jar', ILOMOCK_JAR, '-p', str(self.port)]
if self.profile_dir:
args.extend(['-s', self.profile_dir])
if not os.path.exists(JAVA_BIN):
raise IOError("JAVA_BIN location does not exist: {}".format(JAVA_BIN))
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Block until the server starts or fails
output = []
for line in iter(proc.stdout.readline, ''):
output.append(line)
prefix = "Listening on port "
if line.startswith(prefix):
self.proc = proc
self.port = int(line[len(prefix):])
self.url = "https://localhost:{}".format(self.port)
return
proc.communicate()
output = ''.join(output)
raise MockServerError("Failed to start ilomock: {}\n{}".format(proc.returncode, output))
def stop(self):
"""Stops the running mock server."""
if self.proc:
self.proc.kill()
self.proc = None
self.url = None
def __enter__(self):
"""Starts the mock server and returns it."""
self.start()
return self
def __exit__(self, exc_type, exc_value, traceback):
"""Ensures the running mock server stops."""
self.stop()
def patch(self, path, data):
"""Patches a resource in the mock server."""
payload = {'path': path, 'data': data}
resp = requests.post(self.url + '/admin/patch', json=payload, verify=False)
assert resp.status_code == 200, "Failed to patch mock server: {}\n{}"\
.format(resp.status_code, resp.text)
def load(self, profile_dir):
"""Loads a new server profile while the mock server is running."""
config = {'serverProfile': profile_dir}
resp = requests.post(self.url + '/admin/load', json=config, verify=False)
assert resp.status_code == 200, "Failed to load mock server: {}\n{}"\
.format(resp.status_code, resp.text)
@@ -0,0 +1,37 @@
"""Module containing functional tests for the all flag"""
from __future__ import absolute_import
import sys
import pytest
from rdmc_helper import ReturnCodes
@pytest.mark.skip(reason="temporarily remove all flag")
class TestAllFlag(object):
"""Functional Tests for the --all | -a flag"""
@staticmethod
def test_all_flag(ilorest, dl360_large):
"""Test for --all flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--all'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_all_flag_with_json(ilorest, dl360_large):
"""Test for --all flag with --json flag specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--all', '--json'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@@ -0,0 +1,141 @@
"""Module containing functional tests for the 'applydcpmmconfig' command"""
from __future__ import absolute_import
import sys
from rdmc_helper import ReturnCodes
class TestApplyPmemConfigCommand(object):
"""Class for functional tests for the applydcpmmconfig command"""
@staticmethod
def test_show_invalid_flag(ilorest):
"""Test function call with invalid flag"""
results = ilorest.run(['applydcpmmconfig', '--bad-flag'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_show_help_flag(ilorest):
"""Test function call with help flag"""
results = ilorest.run(['applydcpmmconfig', '-h'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_no_flag(ilorest):
"""Test for the case when `applydcpmmconfig` command is run without any flag"""
results = ilorest.run(['applydcpmmconfig'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_force_flag_1(ilorest):
"""Test for the case when `applydcpmmconfig` command is run with force flag"""
results = ilorest.run(['applydcpmmconfig', '-f'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_force_flag_2(ilorest):
"""Test for the case when `applydcpmmconfig` command is run with force flag"""
results = ilorest.run(['applydcpmmconfig', '-L', '-f'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
# Cannot test for the positive case - mock server not accepting delete tasks.
@staticmethod
def test_with_force_flag_3(ilorest, dl360_large):
"""Test for the case when `applydcpmmconfig` command is run with force flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['applydcpmmconfig', '-C', 'MemoryMode', '-f'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.NO_CHANGES_MADE_OR_FOUND
@staticmethod
def test_with_config_flag_1(ilorest, dl360_large):
"""Test for the case when `applydcpmmconfig` command is run with config flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['applydcpmmconfig', '-C'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_config_flag_2(ilorest, dl360_large):
"""Test for the case when `applydcpmmconfig` command is run with config flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['applydcpmmconfig', '-C', 'xyz'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_config_flag_3(ilorest, dl360_large):
"""Test for the case when `applydcpmmconfig` command is run with config flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['applydcpmmconfig', '-C', 'AppDirectInterleaved'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.NO_CHANGES_MADE_OR_FOUND
@staticmethod
def test_with_list_flag(ilorest):
"""Test for the case when `applydcpmmconfig` command is run with list flag"""
results = ilorest.run(['applydcpmmconfig', '-L'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_extra_attributes_1(ilorest):
"""Test for the case when `applydcpmmconfig` command is run with extraneous attributes"""
results = ilorest.run(['applydcpmmconfig', '-L', '1qazxcsd'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_extra_attributes_2(ilorest, dl360_large):
"""Test for the case when `applydcpmmconfig` command is run with extraneous attributes"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['applydcpmmconfig', '-C', 'AppDirectInterleaved', '1qazxcsd'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@@ -0,0 +1,52 @@
"""Module containing functional tests for the 'cleardcpmmpendingconfig' command"""
from __future__ import absolute_import
import sys
from rdmc_helper import ReturnCodes
class TestClearDcpmmPendingConfigCommand(object):
"""Class for functional tests for the cleardcpmmpendingconfig command"""
@staticmethod
def test_show_invalid_flag(ilorest):
"""Test function call with invalid flag"""
results = ilorest.run(['cleardcpmmpendingconfig', '--bad-flag'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_show_help_flag(ilorest):
"""Test function call with help flag"""
results = ilorest.run(['cleardcpmmpendingconfig', '-h'])
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_without_flag(ilorest, dl360_large):
"""Test for the case when `cleardcpmmpendingconfig` command is run without any flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['cleardcpmmpendingconfig'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_extraneous_attributes(ilorest):
"""
Test for the case when `cleardcpmmpendingconfig` command is run with extraneous attributes
"""
results = ilorest.run(['cleardcpmmpendingconfig', 'testargument'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@@ -0,0 +1,88 @@
"""Module containing functional tests for the config flag"""
from __future__ import absolute_import
import sys
from rdmc_helper import ReturnCodes
class TestConfigFlag(object):
"""Functional Tests for the --config | -C flag"""
@staticmethod
def test_with_no_dimm_id(ilorest, dl360_large):
"""Test for --config flag with no DIMM IDs specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--config'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_valid_dimm_id(ilorest, dl360_large):
"""Test for --config flag with valid DIMM IDs specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--config', '--dimm', '1@2,2@3'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_non_pmem_dimm_id(ilorest, dl360_large):
"""Test for --config flag with valid non pmem DIMM IDs specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--config', '--dimm', '1@5'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_json_format_1(ilorest, dl360_large):
"""Test for --config flag with --json flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--config', '--dimm', '1@2,2@3', '-j'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_json_format_2(ilorest, dl360_large):
"""Test for --config flag with --json flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--config', '-j'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_invalid_member_dimm_id(ilorest, dl360_large):
"""Test for --config flag with invalid DIMM IDs specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--config', '--dimm', '8@15'])
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_invalid_dimm_id(ilorest):
"""Test for --config flag with invalid DIMM IDs specified"""
results = ilorest.run(['showdcpmm', '--config', '--dimm', '132,243,xyz'])
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@@ -0,0 +1,111 @@
"""Module containing functional tests for the device flag"""
from __future__ import absolute_import
import sys
from rdmc_helper import ReturnCodes
class TestDeviceFlag(object):
"""Functional Tests for the --device | -D flag"""
@staticmethod
def test_with_no_dimm_id(ilorest, dl360_large):
"""Test for --device flag with no DIMM IDs specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--device'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_valid_non_pmem_dimm_id(ilorest, dl360_large):
"""
Test for --device flag with valid DIMM IDs
which are not Persistent Memory Modules specified
"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--device', '--dimm', '1@1,2@3'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_invalid_dimm_id_1(ilorest):
"""
Test for --device flag with invalid DIMM IDs specified.
Fails at Validation.
"""
results = ilorest.run(['showdcpmm', '--device', '--dimm', '132,243,xyz'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_invalid_dimm_id_2(ilorest, dl360_large):
"""
Test for --device flag with invalid DIMM IDs specified
Passes Validation, Fails later when DIMM IDs not found
"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--device', '--dimm', '8@2,2@18'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_valid_pmem_dimm_id(ilorest, dl360_large):
"""
Test for --device flag with valid DIMM IDs
which are Persistent Memory Modules specified
"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--device', '--dimm', '1@2'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_valid_pmem_dimm_id_json(ilorest, dl360_large):
"""
Test for --device flag with valid DIMM IDs
which are Persistent Memory Modules specified
along with the --json flag
"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--device', '--dimm', '1@2', '--json'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_json(ilorest, dl360_large):
"""
Test for --device flag with valid DIMM IDs
which are Persistent Memory Modules specified
along with the --json flag
"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--device', '--json'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@@ -0,0 +1,62 @@
"""Module containing functional tests for the device flag"""
from __future__ import absolute_import
import sys
import pytest
from rdmc_helper import ReturnCodes
@pytest.mark.skip(reason="temporarily remove display flag")
class TestDisplayFlag(object):
"""Functional Tests for the --display | -d flag"""
@staticmethod
def test_with_no_display_attributes(ilorest):
"""Test for --display flag with no display attributes"""
results = ilorest.run(['showdcpmm', '--display'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_invalid_display_attributes(ilorest, dl360_large):
"""Test for --display flag with invalid display attributes"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--display', 'xyz,abc'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_valid_display_attributes(ilorest, dl360_large):
"""Test for --display flag with valid display attributes"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--display', 'DeviceLocator'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_valid_display_attributes_json(ilorest, dl360_large):
"""
Test for --display flag with valid display attributes
along with the --json flag
"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--display', 'DeviceLocator', '--json'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@@ -0,0 +1,44 @@
"""Module containing functional tests for the logical flag"""
from __future__ import absolute_import
import sys
from rdmc_helper import ReturnCodes
class TestLogicalFlag(object):
"""Functional Tests for the --logical | -L flag"""
@staticmethod
def test_with_no_attributes(ilorest, dl360_large):
"""Test for --logical flag with no attributes specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--logical'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_dimm_flag(ilorest):
"""Test for --logical flag with dimm flag specified"""
results = ilorest.run(['showdcpmm', '--logical', '--dimm', '1@2'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_json_flag(ilorest, dl360_large):
"""Test for --logical flag with --json flag specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--logical', '--json'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@@ -0,0 +1,133 @@
"""
Functional tests for the command to show the DCPMMs
"""
from __future__ import absolute_import
import sys
import pytest
from jsonpointer import resolve_pointer
from pmemtests.functional.conftest import RestClient
from rdmc_helper import ReturnCodes
class TestShowDcPmemCommand(object):
"""Class for functional tests for the command to enable and disable the scalable pmem feature"""
@staticmethod
def test_show_invalid_flag(ilorest):
""" test function call with invalid flag """
results = ilorest.run(['showdcpmm', '--bad-flag'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_show_help_flag(ilorest):
""" test function call with help flag """
results = ilorest.run(['showdcpmm', '-h'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_showdcpmm_no_flag(ilorest, dl360_large):
"""Test for the case when `showdcpmm` command is run without any flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_showdcpmm_dimm_flag_1(ilorest):
"""Test for the case when `showdcpmm` command is run with dimm flag"""
results = ilorest.run(['showdcpmm', '--dimm'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_showdcpmm_dimm_flag_2(ilorest, dl360_large):
"""Test for the case when `showdcpmm` command is run with dimm flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--dimm', '1@2'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_showdcpmm_dimm_flag_3(ilorest, dl360_large):
"""Test for the case when `showdcpmm` command is run with dimm flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--dimm', '1@2', '2@3'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
@pytest.mark.skip(reason="temporarily remove display flag")
def test_all_and_display_flags(ilorest):
"""Test for the case when --all and --display flags are specified together"""
results = ilorest.run(['showdcpmm', '--all', '--display', 'xyz'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_device_and_config_flags(ilorest):
"""Test for the case when --device and --config flags are specified together"""
results = ilorest.run(['showdcpmm', '--device', '--config'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_logical_and_summary_flags(ilorest):
"""Test for the case when --summary and --logical flags are specified together"""
results = ilorest.run(['showdcpmm', '--logical', '--summary'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_example(ilorest, dl360_large):
""" this is just an example to show using the RestClient """
url, username, password = dl360_large.config
# run ilorest rawget
with ilorest.session(url, username, password):
results = ilorest.run(['rawget', '/redfish/v1/systems/1/bios/settings'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
# check REST attributes
client = RestClient(url, username, password)
bios_settings = client.get('/redfish/v1/systems/1/bios/settings')
sys.stdout.write(str(bios_settings))
assert resolve_pointer(bios_settings, '/Attributes/MemFastTraining') == "Enabled"
@@ -0,0 +1,66 @@
"""Module containing functional tests for the showdcpmmpendingconfig command"""
from __future__ import absolute_import
import sys
from rdmc_helper import ReturnCodes
class TestShowDcpmmPendingConfigCommand(object):
"""Class for functional tests for the showdcpmmpendingconfig command"""
@staticmethod
def test_show_invalid_flag(ilorest):
"""Test function call with invalid flag"""
results = ilorest.run(['showdcpmmpendingconfig', '--bad-flag'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_show_help_flag(ilorest):
"""Test function call with help flag"""
results = ilorest.run(['showdcpmmpendingconfig', '-h'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_no_flag(ilorest, dl360_large):
"""Test for the case when `showdcpmmpendingconfig` command is run without any flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmmpendingconfig'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_json_flag(ilorest, dl360_large):
"""Test for the case when `showdcpmmpendingconfig` command is run with json flag"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmmpendingconfig', '-j'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_extraneous_attributes(ilorest):
"""
Test for the case when `showdcpmmpendingconfig` command is run with extraneous attributes
"""
results = ilorest.run(['showdcpmmpendingconfig', '1qazxcsd'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@@ -0,0 +1,44 @@
"""Module containing functional tests for the summary flag"""
from __future__ import absolute_import
import sys
from rdmc_helper import ReturnCodes
class TestSummaryFlag(object):
"""Functional Tests for the --summary | -M flag"""
@staticmethod
def test_with_no_attributes(ilorest, dl360_large):
"""Test for --summary flag with no attributes specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--summary'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@staticmethod
def test_with_dimm_flag(ilorest):
"""Test for --summary flag with dimm flag specified"""
results = ilorest.run(['showdcpmm', '--summary', '--dimm', '1@2'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.INVALID_COMMAND_LINE_ERROR
@staticmethod
def test_with_json_flag(ilorest, dl360_large):
"""Test for --summary flag with --json flag specified"""
url, username, password = dl360_large.config
with ilorest.session(url, username, password):
results = ilorest.run(['showdcpmm', '--summary', '--json'])
sys.stdout.write("results.stdout: ")
sys.stdout.write(results.stdout)
sys.stdout.write("results.stderr: ")
sys.stdout.write(results.stderr)
assert results.retcode == ReturnCodes.SUCCESS
@@ -0,0 +1,110 @@
"""Utilities for functional tests"""
from __future__ import absolute_import
import os
import subprocess
import tempfile
import time
from collections import namedtuple
# For cross-compatibility between Python 2 and Python 3
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
CommandResult = namedtuple('CommandResult', ('stdout', 'stderr', 'retcode'))
def run_cmd(args):
"""Runs a shell command.
:param args: list of command arguments
:return: results of the command as a named tuple: (stdout, stderr, retcode)
"""
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
retcode = proc.returncode
return CommandResult(stdout=stdout, stderr=stderr, retcode=retcode)
def urlparse_auth(url):
"""Extracts the auth section from a URL (e.g. https://user:password@host)."""
parts = urlparse(url)
username = parts.username
password = parts.password
netloc = parts.netloc.split('@')[-1]
url = parts._replace(netloc=netloc).geturl()
return url, username, password
class InteractivePopen(object):
"""Interactive subprocess Popen."""
def __init__(self, args):
"""Launches an interactive shell as a subprocess.
:param args: sequence of command arguments or a single string
"""
fout = tempfile.NamedTemporaryFile('wb', delete=False)
ferr = tempfile.NamedTemporaryFile('wb', delete=False)
self.fout = open(fout.name, 'r')
self.ferr = open(ferr.name, 'r')
self.proc = subprocess.Popen(args, stdout=fout, stderr=ferr, stdin=subprocess.PIPE)
def communicate(self, input=None):
"""Interacts with the process and waits for it to terminate.
:param input: data to send to stdin
:return: named tuple of (stdout, stderr, retcode)
"""
self.proc.communicate(input)
stdout, stderr = self.read()
retcode = self.proc.returncode
# clean up
self.fout.close()
self.ferr.close()
os.remove(self.fout.name)
os.remove(self.ferr.name)
return CommandResult(stdout=stdout, stderr=stderr, retcode=retcode)
def send(self, str):
"""Sends data to stdin."""
self.proc.stdin.write(str)
def sendline(self, line=""):
"""Sends a newline-terminated string to stdin."""
self.send(line + '\n')
def read(self, expect=None, timeout=60, poll_interval=0.1):
"""Reads from stdout and stderr.
The read is non-blocking unless 'expect' is specified.
:param expect: string to match in stdout before finishing the read
:param timeout: time to wait for the expected string, in seconds
:param poll_interval: poll interval, in seconds
:return: tuple of (stdout, stderr)
"""
stdout = ""
stderr = ""
time_timeout = time.time() + timeout
while True:
out = self.fout.read()
err = self.ferr.read()
if out:
stdout += out
if err:
stderr += err
if expect is None or expect in stdout:
break
if time.time() > time_timeout:
break
time.sleep(poll_interval)
return stdout, stderr
Whitespace-only changes.
@@ -0,0 +1,139 @@
"""
conftest.py is used to set up shared fixtures, plugins, hooks, other config etc.
This is the conftest.py for integration tests
http://docs.pytest.org/en/latest/writing_plugins.html#conftest-py-local-per-directory-plugins
"""
from __future__ import absolute_import
import logging
import re
import sys
import pytest
from ..functional.conftest import RestClient, ilorest, test_server
from .ilocli import IloCli
from .ilodebug import IloDebugger
ilo_debug_logger = logging.getLogger('ilodebug')
vsp_logger = logging.getLogger('vsp')
def pytest_configure(config):
# configure logging
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
ilo_debug_file = config.getoption('--ilodebug')
if ilo_debug_file:
sys.stdout.write("logging iLO debugger output to: {}".format(ilo_debug_file))
ilo_debug_logger.setLevel(logging.DEBUG)
fh = logging.FileHandler(ilo_debug_file, mode='wb+')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
ilo_debug_logger.addHandler(fh)
vsp_file = config.getoption('--vsp')
if vsp_file:
sys.stdout.write("logging iLO Virtual Serial Port output to: {}".format(vsp_file))
vsp_logger.setLevel(logging.DEBUG)
fh = logging.FileHandler(vsp_file, mode='wb+')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
vsp_logger.addHandler(fh)
def pytest_runtest_makereport(item, call):
# incremental testing marker
if "incremental" in item.keywords:
if call.excinfo is not None:
parent = item.parent
parent._previousfailed = item
def pytest_runtest_setup(item):
# incremental testing marker
if "incremental" in item.keywords:
previousfailed = getattr(item.parent, "_previousfailed", None)
if previousfailed is not None:
pytest.xfail("previous test failed (%s)" % previousfailed.name)
@pytest.fixture(scope='session', autouse=True)
def clear_nand_counters(test_server, request):
"""Clear all iLO NAND write counters using the iLO debugger."""
if request.config.getoption('--clear-nand-counters'):
with IloDebugger(test_server.hostname) as ilo_debugger:
sys.stdout.write("Clearing all iLO NAND write counters (setting timers to max)")
output = ilo_debugger.run("otmax all")
assert "Set daily timer to MAX value" in output, \
"Failed to clear NAND write counters:\n {}".format(output)
@pytest.fixture
def ilodebug(test_server, request):
"""Start an iLO debugger session and log all output."""
if request.config.getoption('--ilodebug'):
test_path = request.node.nodeid.replace('::()::', '::')
ilo_debug_logger.info(test_path)
with IloDebugger(test_server.hostname) as ilo_debugger:
# get current system time
output = ilo_debugger.run('id')
ilo_debug_logger.debug(output)
yield ilo_debugger
output = ilo_debugger.read()
if output:
ilo_debug_logger.debug('\n' + output)
else:
yield
@pytest.fixture
def vsp(test_server, request, set_uefi_debug):
"""Start an iLO Virtual Serial Port session and log all output."""
if request.config.getoption('--vsp'):
test_path = request.node.nodeid.replace('::()::', '::')
vsp_logger.info(test_path)
hostname = test_server.hostname
username, password = test_server.username, test_server.password
with IloCli(hostname, username, password) as cli:
if cli is None:
yield
else:
# get current system time
cli.sendline("time")
with cli.vsp_session():
yield cli
output = cli.read()
if output:
vsp_logger.debug('\n' + output)
else:
yield
@pytest.fixture
def set_uefi_debug(test_server, request):
"""Temporarily set the UEFI serial debug level using the iLO debugger.
The debug levels are: 0 (Disabled), 1 (ErrorsOnly), 2 (Medium), 3 (Verbose).
"""
new_dbg = request.config.getoption('--uefi-debug-level')
if new_dbg is not None:
with IloDebugger(test_server.hostname) as debugger:
# save the current debug level
output = debugger.run("evs name cqhdbg")
match = re.search('EVS NAME "CQHDBG".+\n.+([0-9]{2})', output)
current_dbg = "0x{}".format(match.group(1)) if match else None
sys.stdout.write("setting UEFI serial debug level to {} (current {})".format(new_dbg, current_dbg))
debugger.run("evs xset cqhdbg {}".format(new_dbg))
yield
# restore previous debug level
if current_dbg:
with IloDebugger(test_server.hostname) as debugger:
debugger.run("evs xset cqhdbg {}".format(current_dbg))
else:
yield
@@ -0,0 +1,82 @@
from __future__ import absolute_import
import sys
import time
from contextlib import contextmanager
import paramiko
class IloCli(object):
"""Wrapper for the iLO CLI (SMASH CLP)."""
def __init__(self, hostname, username=None, password=None, port=22, timeout=10, window_size=None):
"""Initialize an iLO CLI instance.
:param hostname: iLO hostname
:param username: iLO username
:param password: iLO password
:param port: SSH port
:param window_size: window size for the SSH session (max is used if not specified)
:param timeout: connection timeout, in seconds
"""
self.hostname = hostname
self.username = username
self.password = password
self.port = port
self.timeout = timeout
self.window_size = window_size if window_size else paramiko.common.MAX_WINDOW_SIZE
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.channel = None
def open(self):
"""Start an interactive iLO CLI session."""
self.ssh.connect(self.hostname, username=self.username, password=self.password,
port=self.port, timeout=self.timeout, look_for_keys=False)
transport = self.ssh.get_transport()
self.channel = transport.open_session(window_size=self.window_size)
self.channel.get_pty()
self.channel.invoke_shell()
def close(self):
"""End the iLO CLI session."""
if self.channel:
self.channel.close()
self.ssh.close()
def __enter__(self):
for _ in range(5):
try:
self.open()
return self
except paramiko.SSHException:
sys.stdout.write("SSHException: retrying connection")
time.sleep(30)
sys.stdout.write("SSH: Max retries attempted. No vsp will be captured.")
return None
def __exit__(self, exc_type, exc_value, traceback):
self.close()
def read(self):
"""Read all available output without blocking I/O."""
buf = []
while self.channel.recv_ready():
data = self.channel.recv(1024)
buf.append(data)
return "".join(buf)
def send(self, data):
self.channel.send(data)
def sendline(self, data):
self.send(data + '\n')
@contextmanager
def vsp_session(self):
"""Start a Virtual Serial Port session, returning to the CLI afterward."""
self.sendline("vsp")
yield self
self.send("\x1B(") # press 'ESC ('
@@ -0,0 +1,61 @@
from __future__ import absolute_import
from telnetlib import Telnet
class IloDebugger(object):
DEBUG_PORT = 8
def __init__(self, hostname, timeout=10):
"""Initialize an iLO debugger instance.
:param hostname: hostname of the iLO server
:param timeout: connection timeout, in seconds
"""
self.hostname = hostname
self.timeout = timeout
self.tn = None
self.prompt = '\r\n>'
def open(self):
"""Connect to the iLO debugger."""
self.tn = Telnet(self.hostname, self.DEBUG_PORT, self.timeout)
# wait until the debugger is ready and clear initial output
self.read_until(self.prompt)
def close(self):
"""Close the connection."""
if self.tn:
self.tn.close()
self.tn = None
def __enter__(self):
self.open()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.close()
def read(self):
"""Read all available output without blocking I/O."""
output = self.tn.read_very_eager()
# debugger occasionally outputs CRLFs with double CRs - just convert all to LFs
output = output.replace('\r', '')
return output
def read_until(self, expected, timeout=10):
"""Read until an expected string is encountered or the timeout, in seconds, has been reached."""
output = self.tn.read_until(expected, timeout)
output = output.replace('\r', '')
return output
def writeline(self, line):
"""Write a line to the iLO debugger."""
self.tn.write(line + '\n')
def run(self, cmd_line):
"""Run an iLO debugger command and capture output."""
self.read() # clear any previous output
self.writeline(cmd_line)
output = self.read_until(self.prompt)
return output
Whitespace-only changes.
@@ -0,0 +1,16 @@
"""
conftest.py is used to set up shared fixtures, plugins, hooks, other config etc.
This is the unit test conftest.py
http://docs.pytest.org/en/latest/writing_plugins.html#conftest-py-local-per-directory-plugins
"""
from __future__ import absolute_import
import pytest
from ..conftest import (
ClearPendingConfigCommand,
DisplayHelpers,
MapperRenderers,
RestHelpers,
ShowPmemCommand,
)
@@ -0,0 +1,511 @@
"""Module to Test the 'applydcpmmconfig' command"""
from __future__ import absolute_import
import pytest
from rdmc_base_classes import RdmcCommandBase
from rdmc_helper import (
InvalidCommandLineError,
NoChangesFoundOrMadeError,
NoContentsFoundForOperationError,
)
from ..conftest import ApplyPmemConfigCommand, RestHelpers
class MockData(object):
"""
Mock Data for 'applydcpmmconfig' command
"""
mock_tasks = [{
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 1",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm12/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/"
"MemoryChunks/?$expand=."
},
"TaskState": "New"
}, {
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 2",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm10/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/"
"MemoryChunks/?$expand=."
},
"TaskState": "Old"
}]
other_mock_tasks = [{
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 1",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm12/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/?$expand=."
},
"TaskState": "New"
}, {
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 2",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm10/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/?$expand=."
},
"TaskState": "Old"
}]
mock_chunks = [
{
"@odata.context": "/redfish/v1/$metadata#MemoryChunks.MemoryChunks",
"@odata.etag": "W/\"89E7F7C3\"",
"@odata.id": "/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/MemoryChunks/2/",
"@odata.type": "#MemoryChunks.v1_2_2.MemoryChunks",
"Id": "2",
"AddressRangeType": "PMEM",
"Description": "Memory Chunk",
"InterleaveSets": [
{
"Memory": {
"@odata.id": "/redfish/v1/Systems/1/Memory/proc1dimm7/"
},
"RegionId": "3",
"SizeMiB": 131072
}
],
"IsMirrorEnabled": False,
"IsSpare": False,
"MemoryChunkSizeMiB": 131072,
"Name": "MemoryChunk",
"Oem": {
"Hpe": {
"@odata.context": "/redfish/v1/$metadata#HpeMemoryChunksExt.HpeMemoryChunksExt",
"@odata.type": "#HpeMemoryChunksExt.v2_1_0.HpeMemoryChunksExt",
"MemoryChunkSizePercentage": 50
}
}
},
{
"@odata.context": "/redfish/v1/$metadata#MemoryChunks.MemoryChunks",
"@odata.etag": "W/\"89E7F7C3\"",
"@odata.id": "/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/MemoryChunks/1/",
"@odata.type": "#MemoryChunks.v1_2_2.MemoryChunks",
"Id": "1",
"AddressRangeType": "PMEM",
"Description": "Memory Chunk",
"InterleaveSets": [
{
"Memory": {
"@odata.id": "/redfish/v1/Systems/1/Memory/proc1dimm6/"
},
"RegionId": "1",
"SizeMiB": 131072
}
],
"IsMirrorEnabled": False,
"IsSpare": False,
"MemoryChunkSizeMiB": 131072,
"Name": "MemoryChunk",
"Oem": {
"Hpe": {
"@odata.context": "/redfish/v1/$metadata#HpeMemoryChunksExt.HpeMemoryChunksExt",
"@odata.type": "#HpeMemoryChunksExt.v2_1_0.HpeMemoryChunksExt",
"MemoryChunkSizePercentage": 50
}
}
}
]
mock_interleavable_set = [
{
"MemorySet": [
{
"@odata.id": "/redfish/v1/Systems/1/Memory/proc2dimm6/"
},
{
"@odata.id": "/redfish/v1/Systems/1/Memory/proc2dimm7/"
}
]
},
{
"MemorySet": [
{
"@odata.id": "/redfish/v1/Systems/1/Memory/proc2dimm6/"
}
]
},
{
"MemorySet": [
{
"@odata.id": "/redfish/v1/Systems/1/Memory/proc2dimm7/"
}
]
}
]
expect_post_bodies_app_direct_interleaved = [
{
'AddressRangeType': 'PMEM',
'Oem': {
'Hpe': {
'MemoryChunkSizePercentage': 100
}
},
'InterleaveSets': [
{
'Memory': {
'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm6/'
}
},
{
'Memory': {
'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm7/'
}
}
]
}
]
expected_post_bodies_app_direct_not_interleaved = [
{
'AddressRangeType': 'PMEM',
'Oem': {
'Hpe': {
'MemoryChunkSizePercentage': 100
}
},
'InterleaveSets': [
{
'Memory': {
'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm6/'
}
}
]
},
{
'AddressRangeType': 'PMEM',
'Oem': {
'Hpe': {
'MemoryChunkSizePercentage': 100
}
},
'InterleaveSets': [
{
'Memory': {
'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm7/'
}
}
]
}
]
expected_post_bodies_memory_mode = [
{
'AddressRangeType': 'PMEM',
'Oem': {
'Hpe': {
'MemoryChunkSizePercentage': 0
}
},
'InterleaveSets': [
{
'Memory': {
'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm6/'
}
},
{
'Memory': {
'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm7/'
}
}
]
}
]
def retrieve_memory_domains(self):
"""
Function to retrive memory domains
"""
memory_domains = [{
'Name': 'PROC1 Memory Domain',
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain',
'@odata.context': '/redfish/v1/$metadata#MemoryDomain.MemoryDomain',
'Id': 'PROC1MemoryDomain',
"InterleavableMemorySets":[{
"MemorySet":[
{
"@odata.id":"/redfish/v1/Systems/1/Memory/proc2dimm6/"
},
{
"@odata.id":"/redfish/v1/Systems/1/Memory/proc2dimm7/"
}
]
}, {
"MemorySet":[
{
"@odata.id":"/redfish/v1/Systems/1/Memory/proc2dimm6/"
}
]
}, {
"MemorySet":[
{
"@odata.id":"/redfish/v1/Systems/1/Memory/proc2dimm7/"
}
]
}],
"MemoryChunks":{
"@odata.id":"/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/MemoryChunks"}
}]
return [], memory_domains, []
class TestApplyPmemConfigCommand(object):
"""
Class for unit tests of 'applydcpmmconfig' command
"""
@staticmethod
@pytest.mark.parametrize('customparser, expected_result', [
('', None)
])
def test_define_arguments(customparser, expected_result):
"""
Branch Test for 'define_arguments()' when parser is not customparser
"""
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(
RdmcCommandBase)
result = pmem_command.define_arguments(customparser)
assert result == expected_result
@staticmethod
@pytest.mark.parametrize('memory_chunk_tasks, memory_chunks', [
([MockData.mock_tasks[0]], list()),
(list(), MockData.mock_chunks),
([MockData.mock_tasks[1]], MockData.mock_chunks),
([MockData.other_mock_tasks[0]], MockData.mock_chunks)
])
def test_warn_existing_chunks_and_tasks_fail(memory_chunk_tasks, memory_chunks):
"""
Tests for 'delete_existing_chunks_and_tasks' with invalid data
"""
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(RdmcCommandBase)
with pytest.raises(NoChangesFoundOrMadeError):
pmem_command.warn_existing_chunks_and_tasks(memory_chunk_tasks, memory_chunks)
@staticmethod
@pytest.mark.parametrize('memory_chunk_tasks, memory_chunks, expected_result', [
(list(), list(), None),
(None, list(), None)
])
def test_warn_existing_chunks_and_tasks_pass(memory_chunk_tasks,
memory_chunks, expected_result):
"""
Tests for 'delete_existing_chunks_and_tasks' with valid data
"""
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(RdmcCommandBase)
result = pmem_command.warn_existing_chunks_and_tasks(memory_chunk_tasks, memory_chunks)
assert result == expected_result
@staticmethod
@pytest.mark.parametrize('memory_chunk_tasks, memory_chunks, response, expected_result', [
([MockData.mock_tasks[0]], list(), 200, None),
([MockData.mock_tasks[0]], MockData.mock_chunks, 202, None),
(None, None, None, None),
(list(), list(), None, None)
])
def test_delete_existing_chunks_and_tasks_pass(memory_chunk_tasks, memory_chunks,
response, expected_result, monkeypatch):
"""
Tests for 'delete_existing_chunks_and_tasks' with valid data
"""
def get_response(*argv):
"""
Returns response codes
"""
#pylint: disable=unused-argument
return response
monkeypatch.setattr(RestHelpers.RestHelpers, "delete_resource", get_response)
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(RdmcCommandBase)
result = pmem_command.delete_existing_chunks_and_tasks(memory_chunk_tasks, memory_chunks)
assert result == expected_result
@staticmethod
@pytest.mark.parametrize('memory_chunk_tasks, memory_chunks', [
([MockData.mock_tasks[0]], MockData.mock_chunks),
(None, MockData.mock_chunks),
])
def test_delete_existing_chunks_and_tasks_fail(memory_chunk_tasks, memory_chunks, monkeypatch):
"""
Tests for 'delete_existing_chunks_and_tasks' with invalid data
"""
def get_response(*argv):
"""
Returns none
"""
#pylint: disable=unused-argument
return None
monkeypatch.setattr(RestHelpers.RestHelpers, "delete_resource", get_response)
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(RdmcCommandBase)
with pytest.raises(NoChangesFoundOrMadeError):
pmem_command.delete_existing_chunks_and_tasks(memory_chunk_tasks, memory_chunks)
class MockOptions(object):
"""
Class containing mock options for validation tests
"""
list = False
config = ""
force = False
@staticmethod
def set_options(list, config, force):
"""
Setter function for options
"""
MockOptions.list = list
MockOptions.config = config
MockOptions.force = force
class TestValidation(object):
"""
Class containing test for validation based on mock options
"""
@staticmethod
@pytest.mark.parametrize("list, config, force, expected_result", [
(True, False, False, None),
(False, "memorymode", False, None),
(False, "appdirectnotinterleaved", True, None),
(False, "appdirectinterleaved", True, None),
(False, "AppdirecTinterLeaveD", False, None),
(False, "APPDIRECTNOTINTERLEAVED", False, None),
])
def test_validate_options_pass(list, config, force, expected_result):
"""
Tests for 'validate_options' with valid options
"""
MockOptions.set_options(list, config, force)
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(RdmcCommandBase)
result = pmem_command.validate_options(MockOptions)
assert result == expected_result
@staticmethod
@pytest.mark.parametrize("list_flag, config, force", [
(False, "", False),
(True, "AppDirectInterleaved", False),
(False, "qwerty", True),
(True, "MemoryMode", True),
(False, None, True),
(True, None, True)
])
def test_validate_options_fail(list_flag, config, force):
"""
Tests for 'validate_options' with invalid options
"""
MockOptions.set_options(list_flag, config, force)
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(RdmcCommandBase)
with pytest.raises(InvalidCommandLineError):
pmem_command.validate_options(MockOptions)
@staticmethod
@pytest.mark.parametrize("list_flag, config, force", [
(False, "False", False),
(False, None, True),
(True, "args", True)
])
def test_validate_args(list_flag, config, force):
"""
Tests for 'validate_args'
"""
MockOptions.set_options(list_flag, config, force)
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(RdmcCommandBase)
with pytest.raises(InvalidCommandLineError):
pmem_command.validate_args(MockOptions)
@staticmethod
@pytest.mark.parametrize('mock_config_data, mock_interleavable_set, expected_result', [
(ApplyPmemConfigCommand.ApplyPmemConfigCommand.config_ids[0],
MockData.mock_interleavable_set,
MockData.expected_post_bodies_memory_mode),
(ApplyPmemConfigCommand.ApplyPmemConfigCommand.config_ids[1],
MockData.mock_interleavable_set,
MockData.expect_post_bodies_app_direct_interleaved),
(ApplyPmemConfigCommand.ApplyPmemConfigCommand.config_ids[2],
MockData.mock_interleavable_set,
MockData.expected_post_bodies_app_direct_not_interleaved)
])
def test_get_post_data(mock_config_data, mock_interleavable_set, expected_result):
"""
Test for get_post_data with MemoryMode, AppDirectInterleaved and AppDirectNotInterleaved
"""
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(
RdmcCommandBase)
result = pmem_command.get_post_data(mock_config_data, mock_interleavable_set)
assert result == expected_result
@staticmethod
def test_apply_predefined_err(monkeypatch):
"""
Test for apply_predefined_config with empty memory domains list
"""
def retrive_empty_mem_domains(*argv):
"""
returns empty list
"""
#pylint: disable=unused-argument
return [], [], []
MockOptions.set_options(False, "memorymode", True)
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(RdmcCommandBase)
monkeypatch.setattr(RestHelpers.RestHelpers, "retrieve_task_members_and_mem_domains",
retrive_empty_mem_domains)
with pytest.raises(NoContentsFoundForOperationError):
pmem_command.apply_predefined_config(MockOptions)
def test_apply_predefined_err3(self, monkeypatch):
"""
Test for apply_predefined_config with invalid post request
"""
def get_failure_resp(*argv):
"""
returns None
"""
#pylint: disable=unused-argument
return None
MockOptions.set_options(False, "appdirectinterleaved", True)
pmem_command = ApplyPmemConfigCommand.ApplyPmemConfigCommand(RdmcCommandBase)
monkeypatch.setattr(RestHelpers.RestHelpers, "retrieve_task_members_and_mem_domains",
MockData().retrieve_memory_domains)
monkeypatch.setattr(RestHelpers.RestHelpers, "post_resource", get_failure_resp)
with pytest.raises(NoChangesFoundOrMadeError):
pmem_command.apply_predefined_config(MockOptions)
@@ -0,0 +1,186 @@
"""Module to Test the 'cleardcpmmpendingconfig' command"""
from __future__ import absolute_import
import pytest
from rdmc_base_classes import RdmcCommandBase
from rdmc_helper import NoChangesFoundOrMadeError, NoContentsFoundForOperationError
from .conftest import ClearPendingConfigCommand, RestHelpers
class MockData(object):
"""
Mock Data for 'cleardcpmmpendingconfig' command
"""
task = None
resp = None
mock_tasks_1 = [{
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 1",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm12/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/"
"MemoryChunks/?$expand=."
},
"TaskState": "New"
}, {
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 2",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm10/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/"
"MemoryChunks/?$expand=."
},
"TaskState": "Old"
}]
mock_tasks_2 = [{
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 1",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm12/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/"
"MemoryChunks/?$expand=."
},
"TaskState": "New"
}]
mock_tasks_3 = [{
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 1",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm12/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/?$expand=."
},
"TaskState": "New"
}, {
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 2",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm10/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/?$expand=."
},
"TaskState": "Old"
}]
@staticmethod
def get_resource_tasks(*argv):
"""
Returns mock tasks
"""
return MockData.task
@staticmethod
def get_response_code(*argv):
"""
Returns mock response codes
"""
return MockData.resp
class TestDeleteTasks(object):
"""
Class for unit tests of 'cleardcpmmpendingconfig' command
"""
@staticmethod
@pytest.mark.parametrize("tasks, expected_result", [
(MockData.mock_tasks_1, [MockData.mock_tasks_1[0]]),
([MockData.mock_tasks_2[0]], [MockData.mock_tasks_2[0]])
])
def test_get_memory_chunk_tasks_pass(tasks, expected_result, monkeypatch):
"""
Tests for 'get_memory_chunk_tasks' with valid data
"""
MockData.task = tasks
monkeypatch.setattr(RestHelpers.RestHelpers,
"retrieve_task_members", MockData.get_resource_tasks)
pmem_command = ClearPendingConfigCommand.ClearPendingConfigCommand(RdmcCommandBase)
result = pmem_command.get_memory_chunk_tasks()
assert result == expected_result
@staticmethod
@pytest.mark.parametrize("tasks", [
(MockData.mock_tasks_3),
([MockData.mock_tasks_3[0]]),
([MockData.mock_tasks_3[1]]),
([MockData.mock_tasks_1[1]])
])
def test_get_memory_chunk_tasks_fail(tasks, monkeypatch):
"""
Tests for 'get_memory_chunk_tasks' with invalid data
"""
MockData.task = tasks
monkeypatch.setattr(RestHelpers.RestHelpers, "retrieve_task_members",
MockData.get_resource_tasks)
pmem_command = ClearPendingConfigCommand.ClearPendingConfigCommand(RdmcCommandBase)
with pytest.raises(NoContentsFoundForOperationError):
pmem_command.get_memory_chunk_tasks()
@staticmethod
@pytest.mark.parametrize("resp, verbose", [
(200, False),
(200, True)
])
def test_delete_tasks_pass(resp, verbose, monkeypatch):
"""
Tests for 'delete_tasks' with valid data
"""
MockData.resp = resp
monkeypatch.setattr(RestHelpers.RestHelpers, "delete_resource",
MockData.get_response_code)
pmem_command = ClearPendingConfigCommand.ClearPendingConfigCommand(RdmcCommandBase)
result = pmem_command.delete_tasks(MockData.mock_tasks_3, verbose)
assert result is None
@staticmethod
@pytest.mark.parametrize("resp, verbose", [
(None, False),
(None, True)
])
def test_delete_tasks_fail(resp, verbose, monkeypatch):
"""
Tests for 'delete_tasks' with invalid data
"""
MockData.resp = resp
monkeypatch.setattr(RestHelpers.RestHelpers, "delete_resource",
MockData.get_response_code)
pmem_command = ClearPendingConfigCommand.ClearPendingConfigCommand(RdmcCommandBase)
with pytest.raises(NoChangesFoundOrMadeError):
pmem_command.delete_tasks(MockData.mock_tasks_3, verbose)
@@ -0,0 +1,165 @@
"""Module to test the DisplayHelpers Class"""
from __future__ import absolute_import
import ast
import sys
import pytest
# For cross-compatibility between Python 2 and Python 3
from six import StringIO
from .conftest import DisplayHelpers
class TestDisplayHelpers(object):
"""
Class to test methods from the DisplayHelpers class
"""
output_format = DisplayHelpers.OutputFormats
@staticmethod
def capture_stdout(func, data, out_format, prop_id=None):
"""
Function to capture the standard output stream
"""
old_stdout = sys.stdout
capturer = StringIO()
sys.stdout = capturer
func(data, out_format, prop_id)
sys.stdout = old_stdout
output = capturer.getvalue()
return output
@pytest.mark.parametrize('table_data, expected_output', [
# Tests with empty input
(None, ""),
([], ""),
# Single object test
(["ItemId:ID1\nProperty1:Value1"], "ItemId Property1 ID1 Value1"),
# Test to check truncation of string
(["ItemId:ID1\nProp2:Value of property2\nProp1:Value1"],
"ItemId Prop2 Prop1 ID1 Value of.. Value1"),
# Multiple objects test
(["ItemId:ID1\nProperty1: ", "ItemId:ID2\nProperty1:LongPropertyValue"],
"ItemId Property1 ID1 ID2 LongProp..")
])
def test_printtable_withwidth(self, table_data, expected_output):
"""
Test for printtable with a custom specified width
"""
display_helpers = DisplayHelpers.DisplayHelpers(10)
out = TestDisplayHelpers.capture_stdout(
display_helpers.display_data, table_data, self.output_format.table, None)
assert [str(x) for x in out.split()] == expected_output.split()
@pytest.mark.parametrize('table_data, expected_output', [
# Tests with empty input
(None, ""),
([], ""),
# Single object test
(["ItemId:ID1\nProperty1:Value1"], "ItemId Property1 ID1 Value1"),
# Test to check truncation of string
(["ItemId:ID1\nProp2:Value of property2\nProp1:Value1"],
"ItemId Prop2 Prop1 ID1 Value of property2 Value1"),
# Converting redfish property to friendly name test
(["Property2:Value2\nFWVersion:2.1"], " Property2 FWVersion Value2 2.1"),
# Multiple objects test
(["ItemId:ID1\nProperty1: ", "ItemId:ID2\nProperty1:LongPropertyValue"],
"ItemId Property1 ID1 ID2 LongPropertyValue")
])
def test_printtable(self, table_data, expected_output):
"""
Test for printtable with the default width
"""
display_helpers = DisplayHelpers.DisplayHelpers()
out = TestDisplayHelpers.capture_stdout(
display_helpers.display_data, table_data, self.output_format.table, None)
assert out.split() == expected_output.split()
@pytest.mark.parametrize('table_data, expected_output', [
# Tests with empty input
(None, ""),
([], ""),
# Single object test
(["ItemId:ID1\nProperty1:Value1"],
"--- 1 ---\nItemId: ID1\nProperty1: Value1"),
# Converting redfish property to friendly name test
(["FWVersion:2.1\nItemId:ID1"], "--- 1 ---\nFWVersion: 2.1\nItemId: ID1"),
# Multiple objects test
(["ItemId:ID1\nProperty1:", "ItemId:ID2\nProperty1:Value1"],
"--- 1 ---\nItemId: ID1\nProperty1: \n\n--- 2 ---\nItemId: ID2\nProperty1: Value1")
])
def test_printlist(self, table_data, expected_output):
"""
Test for the printlist function that produces output in list form
"""
display_helpers = DisplayHelpers.DisplayHelpers()
out = TestDisplayHelpers.capture_stdout(
display_helpers.display_data, table_data, self.output_format.list, None)
assert out.strip() == expected_output.strip()
@pytest.mark.parametrize('table_data, expected_output', [
# Tests with empty input
(None, ""),
([], ""),
# Single object test
(["ItemId:ID1\nProperty1:Value1"],
"--- ItemId: ID1 ---\nProperty1: Value1"),
# Converting redfish property to friendly name test
(["ItemId:ID1\nFWVersion:2.1"], "--- ItemId: ID1 ---\nFWVersion: 2.1"),
# Multiple objects test
(["ItemId:ID1\nProperty1:", "ItemId:ID2\nProperty1:Value1"],
"--- ItemId: ID1 ---\nProperty1: \n\n--- ItemId: ID2 ---\nProperty1: Value1")
])
def test_printlist_withid(self, table_data, expected_output):
"""
Test for the printlist function that produces output in list form with custom ID
"""
display_helpers = DisplayHelpers.DisplayHelpers()
out = TestDisplayHelpers.capture_stdout(
display_helpers.display_data, table_data, self.output_format.list, "ItemId")
assert out.strip() == expected_output.strip()
@pytest.mark.parametrize('table_data, expected_output', [
# Tests with empty input
(None, ""),
([], ""),
# Single object test
([{"ItemId": "ID1", "Property1": "Value1"}],
[{"ItemId": "ID1", "Property1": "Value1"}]),
# Converting redfish property to friendly name test
([{"FWVersion": 2.1, "Property2": "Value2"}],
[{"Property2": "Value2", "FWVersion": 2.1}]),
# Multiple objects test
([{"ItemId": "ID1", "Property1": ""}, {"ItemId": "ID2", "Property1": "LongPropertyValue"}],
[{"ItemId": "ID1", "Property1": ""}, {"ItemId": "ID2", "Property1": "LongPropertyValue"}])
])
def test_printjson(self, table_data, expected_output):
"""
Test for the printjson function that produces output in json form
"""
display_helpers = DisplayHelpers.DisplayHelpers()
out = TestDisplayHelpers.capture_stdout(
display_helpers.display_data, table_data, self.output_format.json, None)
if expected_output == "":
assert out == expected_output
else:
out = ast.literal_eval("".join(out.split()))
assert out == expected_output
@staticmethod
@pytest.mark.parametrize('string, maxlen, expected_output', [
("Banana", 10, "Banana"),
("Hot Tamale", 10, "Hot Tamale"),
("Antidisestablishmentarianism", 10, "Antidise.."),
("hippopotomonstrosesquipedaliophobia", 18, "hippopotomonstro.."),
(None, 10, "")
])
def test_truncate_lengthy(string, maxlen, expected_output):
"""
Test for the truncate_lengthy method
"""
display_helpers = DisplayHelpers.DisplayHelpers()
out = display_helpers.truncate_lengthy(string, maxlen)
assert out == expected_output
@@ -0,0 +1,297 @@
"""
This module contains tests for MapperRenderers
"""
from __future__ import absolute_import
import pytest
from .conftest import MapperRenderers
class TestMapperRenderes(object):
"""
class to test functions in MapperRenderers
"""
mock_data = [
{
"DeviceLocator": "PROC 1 DIMM 1",
"CapacityMiB": 123456,
"PersistentRegionSizeLimitMiB": 24680,
"SizeMiB": "xyz",
"VolatileRegionSizeLimitMiB": 45678,
},
{
"DeviceLocator": "PROC 2 DIMM 12",
"CapacityMiB": 987654,
"PersistentRegionSizeLimitMiB": 13579,
"SizeMiB": "abc@123",
"VolatileRegionSizeLimitMiB": 90123,
}]
tasks = [
{
"Payload": {
"JsonBody": {
}
}
},
{
"Payload": {
"JsonBody": {
"MemoryChunkSizeMiB": 250
}
}
},
{
"Payload": {
"JsonBody": {
"Oem": {
"Hpe": {
"MemoryChunkSizePercentage": 40
}
}
}
}
},
{
"Payload": {
"JsonBody": {
"MemoryChunkSizeMiB": 700,
"Oem": {
"Hpe": {
"MemoryChunkSizePercentage": 25
}
}
}
}
},
{
"Payload": {
"JsonBody": {
"Oem": {
"Hpe": {
"MemoryChunkSizePercentage": 0
}
}
}
}
},
{
"Payload": {
"JsonBody": {
"MemoryChunkSizeMiB": 0,
"Oem": {
"Hpe": {
"MemoryChunkSizePercentage": 10
}
}
}
}
}
]
@staticmethod
@pytest.mark.parametrize("num, expected_output", [
(0, "0.0 GiB"),
(20, "0.02 GiB"),
(400, "0.39 GiB"),
(1024, "1.0 GiB"),
(2000, "1.95 GiB"),
(18499, "18.07 GiB")
])
def test_format_num(num, expected_output):
"""
Test for format_num()
:param num: any number
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.format_num(num)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("num, expected_output", [
(0, {"Units": "GiB", "Value": 0.0}),
(20, {"Units": "GiB", "Value": 0.02}),
(400, {"Units": "GiB", "Value": 0.39}),
(1024, {"Units": "GiB", "Value": 1.0}),
(2000, {"Units": "GiB", "Value": 1.95}),
(18499, {"Units": "GiB", "Value": 18.07})
])
def test_format_num_json(num, expected_output):
"""
Test for format_num_json()
:param num: any number
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.format_num_json(num)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("members, expected_output", [
([], "0.0 GiB"),
([mock_data[0]], "120.56 GiB"),
([mock_data[1]], "964.51 GiB"),
(mock_data, "1085.07 GiB")
])
def test_calculate_total_capacity(members, expected_output):
"""
Test for calculate_total_capacity()
:param members: members for which total capacity needs to be calculated
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.calculate_total_capacity(members)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("members, expected_output", [
([], {"Units": "GiB", "Value": 0.0}),
([mock_data[0]], {"Units": "GiB", "Value": 120.56}),
([mock_data[1]], {"Units": "GiB", "Value": 964.51}),
(mock_data, {"Units": "GiB", "Value": 1085.07})
])
def test_calculate_total_capacity_json(members, expected_output):
"""
Test for calculate_total_capacity_json()
:param members: members for which total capacity needs to be calculated
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.calculate_total_capacity_json(members)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("members, expected_output", [
([], "0.0 GiB"),
([mock_data[0]], "44.61 GiB"),
([mock_data[1]], "88.01 GiB"),
(mock_data, "132.62 GiB")
])
def test_calculate_total_volatile(members, expected_output):
"""
Test for calculate_total_volatile()
:param members: members for which total volatile size needs to be calculated
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.calculate_total_volatile(members)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("members, expected_output", [
([], {"Units": "GiB", "Value": 0.0}),
([mock_data[0]], {"Units": "GiB", "Value": 44.61}),
([mock_data[1]], {"Units": "GiB", "Value": 88.01}),
(mock_data, {"Units": "GiB", "Value": 132.62})
])
def test_calculate_total_volatile_json(members, expected_output):
"""
Test for calculate_total_volatile_json()
:param members: members for which total volatile size needs to be calculated
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.calculate_total_volatile_json(members)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("members, expected_output", [
([], "0.0 GiB"),
([mock_data[0]], "24.1 GiB"),
([mock_data[1]], "13.26 GiB"),
(mock_data, "37.36 GiB")
])
def test_calculate_total_appdirect(members, expected_output):
"""
Test for calculate_total_appdirect()
:param members: members for which total appdirect size needs to be calculated
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.calculate_total_appdirect(members)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("members, expected_output", [
([], {"Units": "GiB", "Value": 0.0}),
([mock_data[0]], {"Units": "GiB", "Value": 24.10}),
([mock_data[1]], {"Units": "GiB", "Value": 13.26}),
(mock_data, {"Units": "GiB", "Value": 37.36})
])
def test_calculate_total_appdirect_json(members, expected_output):
"""
Test for calculate_total_appdirect_json()
:param members: members for which total appdirect size needs to be calculated
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.calculate_total_appdirect_json(members)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("temp, expected_output", [
# neither MemoryChunkSizeMiB nor MemoryChunkSizPercentage is present
({"Task": tasks[0], "TotalCapacity": 1000}, "1000.0 GiB"),
# Only MemoryChunkSizeMiB is present
({"Task": tasks[1], "TotalCapacity": 1000}, "250.0 GiB"),
# Only MemoryChunkSizePercentage is present
({"Task": tasks[2], "TotalCapacity": 1000}, "400.0 GiB"),
# Both MemoryChunkSizeMiB and MemoryChunkSizePercentage are present
({"Task": tasks[3], "TotalCapacity": 1000}, "700.0 GiB"),
# MemoryChunkSizePercentage is 0
({"Task": tasks[4], "TotalCapacity": 1000}, "0.0 GiB"),
# MemoryChunkSizeMiB is 0
({"Task": tasks[4], "TotalCapacity": 1000}, "0.0 GiB")
])
def test_calculate_task_pmem_size(temp, expected_output):
"""
Test for calculate_task_pmem_size()
:param temp: dictionary with task and total capacity of the task as keys
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.calculate_task_pmem_size(temp)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("temp, expected_output", [
# neither MemoryChunkSizeMiB nor MemoryChunkSizPercentage is present
({"Task": tasks[0], "TotalCapacity": 1000}, "1000.0 GiB"),
# Only MemoryChunkSizeMiB is present
({"Task": tasks[1], "TotalCapacity": 1000}, "750.0 GiB"),
# Only MemoryChunkSizePercentage is present
({"Task": tasks[2], "TotalCapacity": 1000}, "600.0 GiB"),
# Both MemoryChunkSizeMiB and MemoryChunkSizePercentage are present
({"Task": tasks[3], "TotalCapacity": 1000}, "300.0 GiB"),
# MemoryChunkSizePercentage is 0
({"Task": tasks[4], "TotalCapacity": 1000}, "1000.0 GiB"),
# MemoryChunkSizeMiB is 0
({"Task": tasks[4], "TotalCapacity": 1000}, "1000.0 GiB")
])
def test_calculate_task_volatile_size(temp, expected_output):
"""
Test for calculate_task_volatile_size()
:param temp: dictionary with task and total capacity of the task as keys
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.calculate_task_volatile_size(temp)
assert out == expected_output
@staticmethod
@pytest.mark.parametrize("operation, expected_output", [
("post", "post"),
("POST", "CREATE"),
("GET", "GET"),
("get", "get")
])
def test_map_operation(operation, expected_output):
"""
Test for map_operation()
:param operation: HTTP operation
:param expected_output: expected output of the test
"""
renderers = MapperRenderers.MapperRenderers()
out = renderers.map_operation(operation)
assert out == expected_output
@@ -0,0 +1,179 @@
"""
This module contains tests for PmemHelpers
"""
from __future__ import absolute_import
import pytest
from ..conftest import PmemHelpers
class TestPmemHelpers(object):
"""
Class to test functions in PmemHelpers
"""
mem_members = [
{
"@odata.id": "/redfish/v1/Systems/1/Memory/proc1dimm1/",
"DeviceLocator": "PROC 1 DIMM 1",
"MemoryType": "NVDIMM_P",
"Oem": {
"Hpe": {
"@odata.context": "/redfish/v1/$metadata#HpeMemoryExt.HpeMemoryExt",
"@odata.type": "#HpeMemoryExt.v2_1_0.HpeMemoryExt",
"ProductName": "Intel Optane Memory"
}
}
},
{
"@odata.id": "/redfish/v1/Systems/1/Memory/proc1dimm2/",
"DeviceLocator": "PROC 1 DIMM 2",
"MemoryType": "DRAM",
"Oem": {
"Hpe": {
"@odata.context": "/redfish/v1/$metadata#HpeMemoryExt.HpeMemoryExt",
"@odata.type": "#HpeMemoryExt.v2_1_0.HpeMemoryExt",
"DIMMStatus": "NotPresent"
}
}
}
]
chunks = [
{
"InterleaveSets": [
{
"Memory": {
"@odata.id": "/redfish/v1/Systems/1/Memory/proc1dimm1/"
}
}
]
},
{
"InterleaveSets": [
{
"Memory": {
"@odata.id": "/redfish/v1/Systems/1/Memory/proc1dimm12/"
}
}
]
},
{
"InterleaveSets": [
{
"Memory": {
"@odata.id": "/redfish/v1/Systems/1/Memory/proc2dimm1/"
}
},
{
"Memory": {
"@odata.id": "/redfish/v1/Systems/1/Memory/proc2dimm12/"
},
}
]
}
]
@staticmethod
@pytest.mark.parametrize('dimm_id_list, expected_output', [
(['1@2', '2@3', '3@4'], ['PROC 1 DIMM 2', 'PROC 2 DIMM 3', 'PROC 3 DIMM 4']),
(['2@12'], ['PROC 2 DIMM 12'])
])
def test_parse_dimm_id(dimm_id_list, expected_output):
"""
Test for parse_dimm_id()
:param dimm_id_list: DIMM IDs in the 'X@Y' format
:param expected_output: expected output of the test
"""
result = PmemHelpers.PmemHelpers.parse_dimm_id(dimm_id_list)
assert result == expected_output
@staticmethod
@pytest.mark.parametrize("memory_members, expected_output", [
(mem_members, ([{'MemoryType': 'NVDIMM_P',
'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm1/',
'Oem': {
'Hpe':
{'@odata.type': '#HpeMemoryExt.v2_1_0.HpeMemoryExt',
'@odata.context': '/redfish/v1/$metadata#HpeMemoryExt.'
'HpeMemoryExt',
'ProductName': 'Intel Optane Memory'}
},
'DeviceLocator': 'PROC 1 DIMM 1'}],
set(['PROC 1 DIMM 1']))),
([mem_members[0]], ([{'MemoryType': 'NVDIMM_P',
'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm1/',
'Oem': {
'Hpe':
{'@odata.type': '#HpeMemoryExt.v2_1_0.HpeMemoryExt',
'@odata.context': '/redfish/v1/$metadata#HpeMemoryExt.'
'HpeMemoryExt',
'ProductName': 'Intel Optane Memory'}
},
'DeviceLocator': 'PROC 1 DIMM 1'}],
set(['PROC 1 DIMM 1']))),
([mem_members[1]], ([], set([]))),
([], ([], set([])))
])
def test_get_pmem_members(memory_members, expected_output):
"""
Test for get_pmem_members()
:param memory_members: members of memory collection resource
:param expected_output: expected output of the test
"""
result = PmemHelpers.PmemHelpers.get_pmem_members(memory_members)
assert result == expected_output
@staticmethod
@pytest.mark.parametrize("data_id, chunks, expected_output", [
("/redfish/v1/Systems/1/Memory/proc1dimm1/", chunks, False),
("/redfish/v1/Systems/1/Memory/proc2dimm1/", chunks, True),
("/redfish/v1/Systems/1/Memory/proc2dimm1/", [], None),
("/redfish/v1/Systems/1/Memory/proc1dimm4/", chunks, None)])
def test_is_interleave_set(data_id, chunks, expected_output):
"""
Test for is_interleave_set()
:param data_id: @odata.id of the memory to be checked
:param chunks: list of chunks
:param expected_output: expected output of the test
"""
result = PmemHelpers.PmemHelpers.is_interleave_set(data_id, chunks)
assert result == expected_output
@staticmethod
@pytest.mark.parametrize('location_list, expected_output', [
(['PROC X DIMM Y'], ('X@Y', 'PROC X')),
(['PROC A DIMM B', 'PROC A DIMM C', 'PROC A DIMM D'], ('A@B, A@C, A@D', 'PROC A'))
])
def test_location_format_converter(location_list, expected_output):
"""
Test for location_format_converter()
:param location_list: list of locations of the format 'PROC X DIMM Y'
:param expected_output: expected output of the test
"""
result = PmemHelpers.PmemHelpers.location_format_converter(location_list)
assert result == expected_output
@staticmethod
@pytest.mark.parametrize("id1, id2, expected_output", [
("/redfish/v1/Systems/1/Memory/proc1dimm1", "/redfish/v1/Systems/1/Memory/proc1dimm1",
True),
("/redfish/v1/Systems/1/Memory/proc1dimm1/", "/redfish/v1/Systems/1/Memory/proc1dimm1",
True),
("/redfish/v1/Systems/1/Memory/proc1dimm1", "/redfish/v1/Systems/1/Memory/proc1dimm1/",
True),
("/redfish/v1/Systems/1/Memory/proc1dimm1/", "/redfish/v1/Systems/1/Memory/proc1dimm1/",
True),
("/redfish/v1/Systems/1/Memory/proc1dimm2/", "/redfish/v1/Systems/1/Memory/proc1dimm1/",
False)
])
def test_compare_id(id1, id2, expected_output):
"""
Test for compare_id()
:param id1: first id to be compared
:param id2: second id to be compared
:param expected_output:
:return: expected output of the test
"""
result = PmemHelpers.PmemHelpers.compare_id(id1, id2)
assert result == expected_output
@@ -0,0 +1,409 @@
"""Module to Test the Rest Helpers Class"""
from __future__ import absolute_import
import pytest
from rdmc_base_classes import RdmcCommandBase
from .conftest import RestHelpers
class MockMemoryDomainResource(object):
"""
Class to mock Memory Domain Resources
"""
def __init__(self):
self.status = 200
self.dict = {"@odata.context": "/redfish/v1/$metadata#MemoryDomainCollection"
".MemoryDomainCollection",
"@odata.etag": "W\"92240A75\"",
"@odata.id": "/redfish/v1/Systems/1/MemoryDomains/",
"@odata.type": "#MemoryDomainCollection.MemoryDomainCollection",
"Description": "Memory Domains Collection",
"Members": [{"@odata.context": "/redfish/v1/$metadata#MemoryDomain."
"MemoryDomain",
"@odata.id": "/redfish/v1/Systems/1/MemoryDomains/"
"PROC1MemoryDomain/",
"@odata.type": "#MemoryDomain.v1_0_0.MemoryDomain",
"Id": "PROC1MemoryDomain",
"InterleavableMemorySets": [
{"MemorySet": [{"@odata.id": "/redfish/v1/Systems/1/Memory/"
"proc1dimm6/"},
{"@odata.id": "/redfish/v1/Systems/1/Memory/"
"proc1dimm7/"}]},
{"MemorySet": [{"@odata.id": "/redfish/v1/Systems/1/Memory/"
"proc1dimm6/"}]},
{"MemorySet": [{"@odata.id": "/redfish/v1/Systems/1/Memory/"
"proc1dimm7/"}]}],
"MemoryChunks": {
"@odata.id": "/redfish/v1/Systems/1/MemoryDomains/"
"PROC1MemoryDomain/MemoryChunks/"},
"Name": "PROC1 Memory Domain"},
{
"@odata.context": "/redfish/v1/$metadata#MemoryDomain"
".MemoryDomain",
"@odata.id": "/redfish/v1/Systems/1/MemoryDomains"
"/PROC2MemoryDomain/",
"@odata.type": "#MemoryDomain.v1_0_0.MemoryDomain",
"Id": "PROC2MemoryDomain",
"InterleavableMemorySets": [
{"MemorySet": [
{"@odata.id": "/redfish/v1/Systems/1/Memory/"
"proc2dimm6/"},
{"@odata.id": "/redfish/v1/Systems/1/Memory/"
"proc2dimm7/"}]},
{"MemorySet": [
{"@odata.id": "/redfish/v1/Systems/1/Memory/"
"proc2dimm6/"}]},
{"MemorySet": [
{"@odata.id": "/redfish/v1/Systems/1/Memory/"
"proc2dimm7/"}]}],
"MemoryChunks": {
"@odata.id": "/redfish/v1/Systems/1/MemoryDomains/"
"PROC2MemoryDomain/MemoryChunks/"},
"Name": "PROC2 Memory Domain"}],
"Members@odata.count": 2,
"Name": "Memory Domains Collection"}
def get_obj(self, *argv):
"""
Returns dict
"""
return self.dict
class MockTaskResources(object):
"""
Class to mock Task Resources
"""
Tasks = [{
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 1",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm12/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/"
"MemoryChunks/?$expand=."
},
"TaskState": "New"
}, {
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 2",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm10/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/"
"MemoryChunks/?$expand=."
},
"TaskState": "Old"
}]
Other_Tasks = [{
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 1",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc1dimm12/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/?$expand=."
},
"TaskState": "New"
}, {
"@odata.context": "/redfish/v1/$metadata#Task.Task",
"Name": "Task 2",
"Payload": {
"HttpOperation": "POST",
"JsonBody": "{\"AddressRangeType\": \"PMEM\","
"\"InterleaveSets\": "
"[{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm1/\"}},"
"{\"Memory\": "
"{\"@odata.id\": \"/redfish/v1/Systems/1/Memory/proc2dimm10/\"}}],"
"\"Oem\": {\"Hpe\": {\"MemoryChunkSizePercentage\": 0}}}",
"TargetUri": "/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/?$expand=."
},
"TaskState": "Old"
}]
@staticmethod
def get_resource_tasks(*argv):
"""
Returns valid Task resources
"""
return {"Members": MockTaskResources.Tasks}
@staticmethod
def get_resource_empty(*argv):
"""
Returns empty Task Resources
"""
return {"Members": []}
@staticmethod
def get_resource_none(*argv):
"""
returns None
"""
return None
class TestRestHelpers(object):
"""
Class to test methods from the RestHelpers class
"""
@staticmethod
def test_retrieve_mem_domain_resources(monkeypatch):
"""
Test for retrieving Memory Domain Resources
"""
monkeypatch.setattr(RestHelpers.RestHelpers,
"get_resource", MockMemoryDomainResource().get_obj)
rest_helpers = RestHelpers.RestHelpers(RdmcCommandBase)
resp = rest_helpers.retrieve_mem_domain_resources()
assert resp == ([{'@odata.context': '/redfish/v1/$metadata#MemoryDomain.MemoryDomain',
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/',
'@odata.type': '#MemoryDomain.v1_0_0.MemoryDomain',
'Id': 'PROC1MemoryDomain',
'InterleavableMemorySets': [
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm6/'},
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm7/'}]},
{'MemorySet': [{
'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm6/'}]},
{'MemorySet': [{
'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm7/'}]}],
'MemoryChunks': {
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain'
'/MemoryChunks/'},
'Name': 'PROC1 Memory Domain'},
{'@odata.context': '/redfish/v1/$metadata#MemoryDomain.MemoryDomain',
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/',
'@odata.type': '#MemoryDomain.v1_0_0.MemoryDomain',
'Id': 'PROC2MemoryDomain',
'InterleavableMemorySets': [
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm6/'},
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm7/'}]},
{'MemorySet': [{
'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm6/'}]},
{'MemorySet': [{
'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm7/'}]}],
'MemoryChunks': {
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain'
'/MemoryChunks/'},
'Name': 'PROC2 Memory Domain'}],
[{'@odata.context': '/redfish/v1/$metadata#MemoryDomain.MemoryDomain',
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/',
'@odata.type': '#MemoryDomain.v1_0_0.MemoryDomain',
'Id': 'PROC1MemoryDomain',
'InterleavableMemorySets': [
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm6/'},
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm7/'}]},
{'MemorySet': [
{
'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm6/'}]},
{'MemorySet': [
{
'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm7/'}]}],
'MemoryChunks': {
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain'
'/MemoryChunks/'},
'Name': 'PROC1 Memory Domain'},
{'@odata.context': '/redfish/v1/$metadata#MemoryDomain.MemoryDomain',
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/',
'@odata.type': '#MemoryDomain.v1_0_0.MemoryDomain',
'Id': 'PROC2MemoryDomain',
'InterleavableMemorySets': [
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm6/'},
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm7/'}]},
{'MemorySet': [
{
'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm6/'}]},
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm7/'}]}],
'MemoryChunks': {
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain'
'/MemoryChunks/'},
'Name': 'PROC2 Memory Domain'},
{'@odata.context': '/redfish/v1/$metadata#MemoryDomain.MemoryDomain',
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain/',
'@odata.type': '#MemoryDomain.v1_0_0.MemoryDomain',
'Id': 'PROC1MemoryDomain',
'InterleavableMemorySets': [
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm6/'},
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm7/'}]},
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm6/'}]},
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc1dimm7/'}]}],
'MemoryChunks': {
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC1MemoryDomain'
'/MemoryChunks/'},
'Name': 'PROC1 Memory Domain'},
{'@odata.context': '/redfish/v1/$metadata#MemoryDomain.MemoryDomain',
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain/',
'@odata.type': '#MemoryDomain.v1_0_0.MemoryDomain',
'Id': 'PROC2MemoryDomain',
'InterleavableMemorySets': [
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm6/'},
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm7/'}]},
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm6/'}]},
{'MemorySet': [
{'@odata.id': '/redfish/v1/Systems/1/Memory/proc2dimm7/'}]}],
'MemoryChunks': {
'@odata.id': '/redfish/v1/Systems/1/MemoryDomains/PROC2MemoryDomain'
'/MemoryChunks/'},
'Name': 'PROC2 Memory Domain'}])
@staticmethod
@pytest.mark.parametrize('mock_get_resource, expected_output', [
(MockTaskResources.get_resource_tasks, MockTaskResources.Tasks),
(MockTaskResources.get_resource_empty, []),
(MockTaskResources.get_resource_none, [])
])
def test_retrieve_task_members(mock_get_resource, expected_output, monkeypatch):
"""
Tests for retrieving task members
"""
monkeypatch.setattr(RestHelpers.RestHelpers,
"get_resource", mock_get_resource)
rest_helpers = RestHelpers.RestHelpers(RdmcCommandBase)
resp = rest_helpers.retrieve_task_members()
assert resp == expected_output
@staticmethod
@pytest.mark.parametrize("task_members, expected_output", [
(MockTaskResources.Tasks, [MockTaskResources.Tasks[0]]),
([MockTaskResources.Tasks[1]], []),
(MockTaskResources.Other_Tasks, []),
([MockTaskResources.Other_Tasks[0]], []),
([MockTaskResources.Other_Tasks[1]], []),
([], [])
])
def test_filter_task_members(task_members, expected_output):
"""
Tests for filtering task members
"""
rest_helpers = RestHelpers.RestHelpers(RdmcCommandBase)
resp = rest_helpers.filter_task_members(task_members)
assert resp == expected_output
class MockDeleteResponse(object):
"""
Class to Mock Delete Response
"""
@staticmethod
def get_success_resp(*argv):
"""
Returns a success response code (200)
"""
return 200
@staticmethod
def get_failure_resp(*argv):
"""
Returns a failure response code (200)
"""
return 400
class TestDeleteResponse(object):
"""
Class to Test Delete Response
"""
@staticmethod
def test_delete_success(monkeypatch):
"""
Test where deletion is successful
"""
monkeypatch.setattr(RestHelpers.RestHelpers, "delete_resource",
MockDeleteResponse().get_success_resp)
rest_helpers = RestHelpers.RestHelpers(RdmcCommandBase)
resp = rest_helpers.delete_resource("/redfish/v1/TaskService/Tasks/1")
assert resp == 200
@staticmethod
def test_delete_failure(monkeypatch):
"""
Test where deletion fails
"""
monkeypatch.setattr(RestHelpers.RestHelpers, "delete_resource",
MockDeleteResponse().get_failure_resp)
rest_helpers = RestHelpers.RestHelpers(RdmcCommandBase)
resp = rest_helpers.delete_resource("/redfish/v1/TaskService/Tasks/1")
assert resp == 400
class MockPostResponse(object):
"""
Class to Mock Post Response
"""
@staticmethod
def get_success_resp(*argv):
"""
Returns a success response code (202)
"""
return 202
@staticmethod
def get_failure_resp(*argv):
"""
Returns a failure response code (402)
"""
return 402
class TestPostResponse(object):
"""
Class to Test Post Response
"""
@staticmethod
def test_post_success(monkeypatch):
"""
Test where POST succeds
"""
monkeypatch.setattr(RestHelpers.RestHelpers,
"post_resource", MockPostResponse().get_success_resp)
rest_helpers = RestHelpers.RestHelpers(RdmcCommandBase)
resp = rest_helpers.post_resource(
"/redfish/v1/TaskService/Tasks/1", {"default": "testing"})
assert resp == 202
@staticmethod
def test_post_failure(monkeypatch):
"""
Test where POST fails
"""
monkeypatch.setattr(RestHelpers.RestHelpers,
"post_resource", MockPostResponse().get_failure_resp)
rest_helpers = RestHelpers.RestHelpers(RdmcCommandBase)
resp = rest_helpers.post_resource(
"/redfish/v1/TaskService/Tasks/1", {"default": "testing"})
assert resp == 402
@@ -0,0 +1,332 @@
"""
This module contains tests for ShowPmemCommand
"""
from __future__ import absolute_import
import pytest
from rdmc_base_classes import RdmcCommandBase
from rdmc_helper import InvalidCommandLineError
from ..conftest import ShowPmemCommand
class CustomOptions(object):
"""
Class to mock different options
"""
def __init__(self):
self.all = True
self.display_attributes = None
self.json = False
def all_flag(self):
"""
Function to set --all flag to true
:return: CustomOptions object
"""
self.all = True
return self
def no_flag(self):
"""
Function to reset flags
:return: CustomOptions object
"""
self.all = False
self.display_attributes = None
return self
def display_flag(self):
"""
Function to set --display flag
:return: CustomOptions object
"""
self.all = False
self.display_attributes = ["RandomNestedKey1"]
return self
def wrong_display_flag(self):
"""
Function to set --display flag with wrong attributes
:return: CustomOptions object
"""
self.all = False
self.display_attributes = ["aBc", "xYz"]
return self
@staticmethod
def get_default(flag):
"""
Function to return default attributes
:return: list of attributes
"""
if flag == "device":
return ["Location", "SizeMiB"]
if flag == "config":
return ["Location", "Capacity"]
return []
@staticmethod
def get_all(flag):
"""
Function to return attributes for --all flag
:return: list of attributes
"""
if flag == "device":
return ["Location", "SizeMiB", "RandomNestedKey1"]
if flag == "config":
return ["Location", "Capacity", "RandomNestedKey1"]
return []
class MockMappingTable(object):
"""
class to mock mapping table
"""
memory = {'Capacity': {'path': '/CapacityMiB', 'redfishName': 'CapacityMiB'},
'Location': {'path': '/DeviceLocator', 'redfishName': 'DeviceLocator'},
'RandomAttribute': {'path': "/RandomAttribute",
'redfishName': 'RandomAttribute'},
'RandomNestedKey1': {'path': "/RandomAttribute/RandomNestedKey1",
'redfishName': 'RandomNestedKey1'},
'SizeMiB': {'path': '/Regions/SizeMiB', 'redfishName': 'SizeMiB'}}
memorychunk = {'Capacity': {'path': '/CapacityMiB', 'redfishName': 'CapacityMiB'},
'Location': {'path': '/DeviceLocator', 'redfishName': 'DeviceLocator'},
'RandomAttribute': {'path': "/RandomAttribute",
'redfishName': 'RandomAttribute'},
'RandomNestedKey1': {'path': "/RandomAttribute/RandomNestedKey1",
'redfishName': 'RandomNestedKey1'},
'SizeMiB': {'path': '/Regions/SizeMiB', 'redfishName': 'SizeMiB'}}
class TestShowPmemCommands(object):
"""
Class to test functions in ShowPmemCommands
"""
mock_data = [
{
'DeviceLocator': 'PROC 1 DIMM 1',
'CapacityMiB': 123456,
'SizeMiB': 'xyz',
'RandomAttribute': {
'RandomNestedKey1': 'RandomNestedValue1.1',
'RandomNestedKey2': [
'RandomNestedValue2.1',
'RandomNestedValue2.2'
],
'RandomNestedKey4': [
{
'RandomNestedKey5': 'RandomNestedValue5.1'
}
]
}
},
{
'DeviceLocator': 'PROC 2 DIMM 12',
'CapacityMiB': 987654,
'SizeMiB': 'abc@123',
'RandomAttribute': {
'RandomNestedKey1': 'RandomNestedValue1.2',
'RandomNestedKey2': [
'RandomNestedValue2.3',
'RandomNestedValue2.4'
],
'RandomNestedKey4': [
{
'RandomNestedKey5': 'RandomNestedValue5.2'
}
]
}
}]
custom_options_obj = CustomOptions()
@pytest.mark.parametrize('members, options, flag, expected_output', [
# display flag
(mock_data, CustomOptions().display_flag(), "device",
['\nRandomNestedKey1: RandomNestedValue1.1', '\nRandomNestedKey1: RandomNestedValue1.2']),
(mock_data, CustomOptions().display_flag(), "config",
['\nRandomNestedKey1: RandomNestedValue1.1', '\nRandomNestedKey1: RandomNestedValue1.2']),
# no flag
([mock_data[1]], CustomOptions().no_flag(), "device",
['\nLocation: PROC 2 DIMM 12\nSizeMiB: None']),
([mock_data[0]], CustomOptions().no_flag(), "config",
['\nLocation: PROC 1 DIMM 1\nCapacity: 123456'])
])
@pytest.mark.skip(reason="temporarily remove display flag")
def test_generate_display_output_pass(self, members, options, flag, expected_output,
monkeypatch):
"""
Tests for generate_display_output() with valid input
:param members: list of members returned as a result of GET request
:param options: command options
:param flag: name of flag
:param expected_output: expected output of the test
"""
monkeypatch.setattr(ShowPmemCommand, "get_default_attributes",
self.custom_options_obj.get_default)
pmem_command = ShowPmemCommand.ShowPmemCommand(RdmcCommandBase)
result = pmem_command.generate_display_output(members, options, flag,
MockMappingTable.memory)
assert result == expected_output
@staticmethod
@pytest.mark.parametrize('members, options, flag, expected_output', [
([mock_data[0]], CustomOptions().wrong_display_flag(), "device",
["\nNo match found for 'aBc'\nNo match found for 'xYz'"]),
([mock_data[1]], CustomOptions().wrong_display_flag(), "config",
["\nNo match found for 'aBc'\nNo match found for 'xYz'"]),
(mock_data, CustomOptions().wrong_display_flag(), "config",
["\nNo match found for 'aBc'\nNo match found for 'xYz'",
"\nNo match found for 'aBc'\nNo match found for 'xYz'"]),
])
@pytest.mark.skip(reason="temporarily remove display flag")
def test_generate_display_output_fail(members, options, flag, expected_output):
"""
Tests for generate_display_output() with invalid input
:param members: list of members returned as a result of GET request
:param options: command options
:param flag: name of flag
:param expected_output: expected output of the test
"""
pmem_command = ShowPmemCommand.ShowPmemCommand(RdmcCommandBase)
result = pmem_command.generate_display_output(members, options, flag,
MockMappingTable.memory)
assert result == expected_output
@staticmethod
@pytest.mark.parametrize('customparser, expected_output', [
('', None)
])
def test_define_arguments(customparser, expected_output):
"""
Branch Test for definearguments() when parser is not customparser
:param customparser: command line input
:param expected_output: expected output of the test
"""
pmem_command = ShowPmemCommand.ShowPmemCommand(RdmcCommandBase)
result = pmem_command.definearguments(customparser)
assert result == expected_output
@staticmethod
@pytest.mark.parametrize("flag, expected_output", [
("device", ShowPmemCommand.DefaultAttributes.device.value),
("config", ShowPmemCommand.DefaultAttributes.config.value),
("summary", None),
("abc", None)])
def test_get_default_attributes(flag, expected_output):
"""
Test for get_default_attributes()
:param flag: name of flag
:param expected_output: expected output of the test
"""
result = ShowPmemCommand.get_default_attributes(flag)
assert result == expected_output
class MockOptions(object):
"""
Class containing mock options for validation tests
"""
device = False
config = False
summary = False
logical = False
dimm = None
@staticmethod
def set_options(device, config, logical, summary, dimm):
"""
Setter method for Mock options
"""
MockOptions.device = device
MockOptions.config = config
MockOptions.logical = logical
MockOptions.summary = summary
MockOptions.dimm = dimm
class TestValidation(object):
"""
Class containing validation tests
"""
@staticmethod
@pytest.mark.parametrize("device, config, logical, summary, dimm, expected_result", [
(False, False, False, False, None, None),
(False, False, False, False, ["1@1", "2@10"], None),
(True, False, False, False, None, None),
(True, False, False, False, ["3@12", "4@8"], None),
(False, True, False, False, None, None),
(True, False, False, False, ["4@4", "3@3"], None),
(True, False, False, False, ["9@19"], None),
(False, False, True, False, None, None),
(False, False, False, True, None, None)
])
def test_validate_show_pmem_options_pass(device, config, logical,
summary, dimm, expected_result):
"""
Tests for 'validate_options' with valid options
"""
MockOptions.set_options(device, config, logical, summary, dimm)
pmem_command = ShowPmemCommand.ShowPmemCommand(RdmcCommandBase)
result = pmem_command.validate_show_pmem_options(MockOptions)
assert result == expected_result
@staticmethod
@pytest.mark.parametrize("device, config, logical, summary, dimm", [
(True, True, True, True, None),
(True, True, True, False, None),
(True, True, False, True, None),
(True, False, True, True, None),
(False, True, True, True, None),
(True, True, False, False, None),
(True, False, True, False, None),
(True, False, False, True, None),
(False, False, True, True, None),
(False, True, False, True, None),
(False, True, True, False, None),
(True, False, False, False, ["0@0"]),
(True, False, False, False, ["0@8"]),
(True, False, False, False, ["4@0"]),
(True, False, False, False, ["4@20"]),
(True, False, False, False, ["10@20"]),
(True, False, False, False, ["10@2"]),
(True, False, False, False, ["3)12", "438"]),
(True, False, False, False, ["4#4", "3!3"]),
(True, False, False, False, ["3)12", "438"]),
(False, False, False, False, ["1@1", "2@=10"]),
(False, False, True, False, ["3@12", "4@8"]),
(False, False, False, True, ["4@4", "3@3"])
])
def test_validate_show_pmem_options_fail(device, config, logical, summary, dimm):
"""
Tests for 'validate_options' with invalid options
"""
MockOptions.set_options(device, config, logical, summary, dimm)
pmem_command = ShowPmemCommand.ShowPmemCommand(RdmcCommandBase)
with pytest.raises(InvalidCommandLineError):
pmem_command.validate_show_pmem_options(MockOptions)
@staticmethod
@pytest.mark.parametrize("device, config, logical, summary, dimm", [
(False, False, False, False, None),
(False, False, False, False, ["1@2"]),
(True, False, False, False, None),
(True, False, False, False, ["4#4", "3!3"]),
(False, True, False, False, None),
(False, True, False, False, ["4@4", "3@3"]),
(False, False, True, False, None),
(False, False, True, False, ["1@1", "2@=10"]),
(False, False, False, True, None),
(False, False, False, True, ["1@1", "2@10"])
])
def test_validate_args(device, config, logical, summary, dimm):
"""
Tests for 'validate_args'
"""
MockOptions.set_options(device, config, logical, summary, dimm)
pmem_command = ShowPmemCommand.ShowPmemCommand(RdmcCommandBase)
with pytest.raises(InvalidCommandLineError):
pmem_command.validate_args(MockOptions)