Merge pull request #972 from Deixx/multidut

Multidut execution and example
This commit is contained in:
Robert Baldyga 2022-02-17 13:27:29 +01:00 committed by GitHub
commit 9424df4e2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 91 additions and 34 deletions

View File

@ -35,6 +35,16 @@ class Opencas(metaclass=Singleton):
self.already_updated = False
def pytest_collection_modifyitems(config, items):
if config.option.collectonly:
for item in items:
multidut = next(item.iter_markers(name="multidut"), None)
if multidut:
number = multidut.args[0]
print(f"multidut {item.nodeid} {number}")
sys.stdout.flush()
def pytest_runtest_setup(item):
# There should be dut config file added to config package and
# pytest should be executed with option --dut-config=conf_name'.
@ -45,45 +55,60 @@ def pytest_runtest_setup(item):
# User can also have own test wrapper, which runs test prepare, cleanup, etc.
# Then it should be placed in plugins package
try:
with open(item.config.getoption('--dut-config')) as cfg:
dut_config = yaml.safe_load(cfg)
except Exception as ex:
raise Exception(f"{ex}\nYou need to specify DUT config. See the example_dut_config.py file")
test_name = item.name.split('[')[0]
TestRun.LOGGER = create_log(item.config.getoption('--log-path'), test_name)
dut_config['plugins_dir'] = os.path.join(os.path.dirname(__file__), "../lib")
dut_config['opt_plugins'] = {"test_wrapper": {}, "serial_log": {}, "power_control": {}}
dut_config['extra_logs'] = {"cas": "/var/log/opencas.log"}
duts = item.config.getoption('--dut-config')
required_duts = next(item.iter_markers(name="multidut"), None)
required_duts = required_duts.args[0] if required_duts is not None else 1
if required_duts > len(duts):
raise Exception(f"Test requires {required_duts} DUTs, only {len(duts)} DUT configs "
f"provided")
else:
duts = duts[:required_duts]
try:
TestRun.prepare(item, dut_config)
test_name = item.name.split('[')[0]
TestRun.LOGGER = create_log(item.config.getoption('--log-path'), test_name)
TestRun.presetup()
TestRun.duts = []
for dut in duts:
try:
TestRun.executor.wait_for_connection(timedelta(seconds=20))
except paramiko.AuthenticationException:
raise
except Exception:
with open(dut) as cfg:
dut_config = yaml.safe_load(cfg)
except Exception as ex:
raise Exception(f"{ex}\n"
f"You need to specify DUT config. See the example_dut_config.py file")
dut_config['plugins_dir'] = os.path.join(os.path.dirname(__file__), "../lib")
dut_config['opt_plugins'] = {"test_wrapper": {}, "serial_log": {}, "power_control": {}}
dut_config['extra_logs'] = {"cas": "/var/log/opencas.log"}
try:
TestRun.prepare(item, dut_config)
TestRun.presetup()
try:
TestRun.plugin_manager.get_plugin('power_control').power_cycle()
TestRun.executor.wait_for_connection()
TestRun.executor.wait_for_connection(timedelta(seconds=20))
except paramiko.AuthenticationException:
raise
except Exception:
raise Exception("Failed to connect to DUT.")
TestRun.setup()
except Exception as ex:
raise Exception(f"Exception occurred during test setup:\n"
f"{str(ex)}\n{traceback.format_exc()}")
try:
TestRun.plugin_manager.get_plugin('power_control').power_cycle()
TestRun.executor.wait_for_connection()
except Exception:
raise Exception("Failed to connect to DUT.")
TestRun.setup()
except Exception as ex:
raise Exception(f"Exception occurred during test setup:\n"
f"{str(ex)}\n{traceback.format_exc()}")
TestRun.usr = Opencas(
repo_dir=os.path.join(os.path.dirname(__file__), "../../.."),
working_dir=dut_config['working_dir'])
TestRun.usr = Opencas(
repo_dir=os.path.join(os.path.dirname(__file__), "../../.."),
working_dir=dut_config['working_dir'])
TestRun.LOGGER.info(f"DUT info: {TestRun.dut}")
TestRun.LOGGER.info(f"DUT info: {TestRun.dut}")
TestRun.dut.plugin_manager = TestRun.plugin_manager
TestRun.dut.executor = TestRun.executor
TestRun.duts.append(TestRun.dut)
base_prepare(item)
base_prepare(item)
TestRun.LOGGER.write_to_command_log("Test body")
TestRun.LOGGER.start_group("Test body")
@ -120,8 +145,12 @@ def pytest_runtest_teardown():
f"{str(ex)}\n{traceback.format_exc()}")
TestRun.LOGGER.end()
if TestRun.executor:
TestRun.LOGGER.get_additional_logs()
for dut in TestRun.duts:
with TestRun.use_dut(dut):
if TestRun.executor:
os.makedirs(os.path.join(TestRun.LOGGER.base_dir, "dut_info", dut.ip),
exist_ok=True)
TestRun.LOGGER.get_additional_logs()
Log.destroy()
TestRun.teardown()
@ -136,7 +165,7 @@ def pytest_generate_tests(metafunc):
def pytest_addoption(parser):
TestRun.addoption(parser)
parser.addoption("--dut-config", action="store", default="None")
parser.addoption("--dut-config", action="append", type=str)
parser.addoption("--log-path", action="store",
default=f"{os.path.join(os.path.dirname(__file__), '../results')}")
parser.addoption("--force-reinstall", action="store_true", default=False)

View File

@ -119,3 +119,31 @@ def test_create_example_files():
TestRun.LOGGER.info(f"Item {str(item)} - {type(item).__name__}")
with TestRun.step("Remove file"):
fs_utils.remove(file1.full_path, True)
@pytest.mark.require_disk("cache1", DiskTypeSet([DiskType.optane, DiskType.nand]))
@pytest.mark.require_disk("cache2", DiskTypeSet([DiskType.optane, DiskType.nand]))
@pytest.mark.multidut(2)
def test_example_multidut():
with TestRun.group("Run on all duts"):
for dut in TestRun.duts:
with TestRun.step("From TestRun.executor"):
with TestRun.use_dut(dut):
TestRun.dut.hostname = TestRun.executor.run_expect_success('uname -n').stdout
TestRun.LOGGER.info(TestRun.dut.hostname)
with TestRun.step("From returned executor"):
with TestRun.use_dut(dut) as executor:
i = executor.run_expect_success("uname -i").stdout
TestRun.LOGGER.info(i)
with TestRun.group("Run on single dut"):
dut1, dut2 = TestRun.duts
with TestRun.step(f"Run from TestRun.executor on dut {dut2.ip}"):
with TestRun.use_dut(dut2):
TestRun.LOGGER.info(TestRun.executor.run_expect_success("which casadm").stdout)
for name, disk in TestRun.disks.items():
TestRun.LOGGER.info(f"{name}: {disk.path}")
with TestRun.step(f"Run from returned executor on dut {dut1.ip}"):
with TestRun.use_dut(dut1) as dut1_ex:
TestRun.LOGGER.info(dut1_ex.run_expect_success("which casctl").stdout)
for name, disk in TestRun.disks.items():
TestRun.LOGGER.info(f"{name}: {disk.path}")