From d4b3f2624148649fdbb264b37d0065a21c8c0403 Mon Sep 17 00:00:00 2001 From: klapinsk Date: Fri, 2 Apr 2021 08:53:16 +0200 Subject: [PATCH] Remove inactive commands tests and API update Signed-off-by: Daniel Madej --- test/functional/api/cas/cache.py | 5 +- test/functional/api/cas/casadm.py | 8 +++ test/functional/api/cas/cli.py | 8 +++ test/functional/api/cas/cli_messages.py | 10 ++-- test/functional/api/cas/core.py | 42 ++++++++------- test/functional/tests/conftest.py | 2 +- .../incremental_load/test_incremental_load.py | 54 +++++++++++++------ 7 files changed, 91 insertions(+), 38 deletions(-) diff --git a/test/functional/api/cas/cache.py b/test/functional/api/cas/cache.py index 4e3365e..345a0b6 100644 --- a/test/functional/api/cas/cache.py +++ b/test/functional/api/cas/cache.py @@ -121,9 +121,12 @@ class Cache: def add_core(self, core_dev, core_id: int = None): return casadm.add_core(self, core_dev, core_id) - def remove_core(self, core_id, force: bool = False): + def remove_core(self, core_id: int, force: bool = False): return casadm.remove_core(self.cache_id, core_id, force) + def remove_inactive_core(self, core_id: int, force: bool = False): + return casadm.remove_inactive(self.cache_id, core_id, force) + def reset_counters(self): return casadm.reset_counters(self.cache_id) diff --git a/test/functional/api/cas/casadm.py b/test/functional/api/cas/casadm.py index 7c29454..89ece01 100644 --- a/test/functional/api/cas/casadm.py +++ b/test/functional/api/cas/casadm.py @@ -69,6 +69,14 @@ def remove_core(cache_id: int, core_id: int, force: bool = False, shortcut: bool raise CmdException("Failed to remove core.", output) +def remove_inactive(cache_id: int, core_id: int, force: bool = False, shortcut: bool = False): + output = TestRun.executor.run( + remove_inactive_cmd( + cache_id=str(cache_id), core_id=str(core_id), force=force, shortcut=shortcut)) + if output.exit_code != 0: + raise CmdException("Failed to remove inactive core.", output) + + def remove_detached(core_device: Device, shortcut: bool = False): output = TestRun.executor.run( remove_detached_cmd(core_device=core_device.path, shortcut=shortcut)) diff --git a/test/functional/api/cas/cli.py b/test/functional/api/cas/cli.py index a76f36f..0cc9078 100644 --- a/test/functional/api/cas/cli.py +++ b/test/functional/api/cas/cli.py @@ -55,6 +55,14 @@ def remove_core_cmd(cache_id: str, core_id: str, force: bool = False, shortcut: return casadm_bin + command +def remove_inactive_cmd(cache_id: str, core_id: str, force: bool = False, shortcut: bool = False): + command = f" --remove-inactive {'-i' if shortcut else '--cache-id'} {cache_id} " \ + f"{'-j' if shortcut else '--core-id'} {core_id}" + if force: + command += " -f" if shortcut else " --force" + return casadm_bin + command + + def remove_detached_cmd(core_device: str, shortcut: bool = False): command = " --remove-detached" + (" -d " if shortcut else " --device ") + core_device return casadm_bin + command diff --git a/test/functional/api/cas/cli_messages.py b/test/functional/api/cas/cli_messages.py index 09a8d8f..aeb2855 100644 --- a/test/functional/api/cas/cli_messages.py +++ b/test/functional/api/cas/cli_messages.py @@ -30,9 +30,13 @@ reinitialize_with_force_or_recovery = [ r" discard on-disk metadata and start fresh cache instance\." ] -remove_inactive_core = [ - r"Error while removing core device \d+ from cache instance \d+", - r"Core device is in inactive state" +remove_inactive_core_with_remove_command = [ + r"Core is inactive\. To manage the inactive core use '--remove-inactive' command\." +] + +remove_inactive_dirty_core = [ + r"The cache contains dirty data assigned to the core\. If you want to ", + r"continue, please use --force option\.\nWarning: the data will be lost" ] stop_cache_incomplete = [ diff --git a/test/functional/api/cas/core.py b/test/functional/api/cas/core.py index 09035c5..9d3ba1d 100644 --- a/test/functional/api/cas/core.py +++ b/test/functional/api/cas/core.py @@ -2,14 +2,21 @@ # Copyright(c) 2019-2021 Intel Corporation # SPDX-License-Identifier: BSD-3-Clause-Clear # +from datetime import timedelta +from typing import List +from aenum import Enum -from api.cas.casadm_parser import * -from api.cas.cli import * +from api.cas import casadm +from api.cas.cache_config import SeqCutOffParameters, SeqCutOffPolicy +from api.cas.casadm_params import OutputFormat, StatsFilter +from api.cas.casadm_parser import get_statistics, get_seq_cut_off_parameters from api.cas.statistics import CoreStats, CoreIoClassStats +from core.test_run_utils import TestRun +from storage_devices.device import Device from test_tools import fs_utils, disk_utils -from test_utils.os_utils import * -from test_utils.os_utils import wait +from test_utils.os_utils import wait, sync +from test_utils.size import Unit, Size class CoreStatus(Enum): @@ -28,6 +35,7 @@ class Core(Device): self.core_device = Device(core_device) self.path = None core_info = self.__get_core_info() + # "-" is special case for cores in core pool if core_info["core_id"] != "-": self.core_id = int(core_info["core_id"]) if core_info["exp_obj"] != "-": @@ -37,20 +45,15 @@ class Core(Device): self.block_size = None def __get_core_info(self): - output = TestRun.executor.run( - list_cmd(OutputFormat.csv.name, by_id_path=False)) - if output.exit_code != 0: - raise Exception("Failed to execute list caches command.") - output_lines = output.stdout.splitlines() - for line in output_lines: - split_line = line.split(',') - if split_line[0] == "core" and ( - split_line[2] == os.path.join("/dev", self.core_device.get_device_id()) - or split_line[5] == self.path): - return {"core_id": split_line[1], - "core_device": split_line[2], - "status": split_line[3], - "exp_obj": split_line[5]} + output = casadm.list_caches(OutputFormat.csv, by_id_path=True) + split_line = next( + line.split(',') for line in output.stdout.splitlines() + if line.startswith("core") and self.core_device.path in line + ) + return {"core_id": split_line[1], + "core_device": split_line[2], + "status": split_line[3], + "exp_obj": split_line[5]} def create_filesystem(self, fs_type: disk_utils.Filesystem, force=True, blocksize=None): super().create_filesystem(fs_type, force, blocksize) @@ -104,6 +107,9 @@ class Core(Device): def remove_core(self, force: bool = False): return casadm.remove_core(self.cache_id, self.core_id, force) + def remove_inactive(self, force: bool = False): + return casadm.remove_inactive(self.cache_id, self.core_id, force) + def reset_counters(self): return casadm.reset_counters(self.cache_id, self.core_id) diff --git a/test/functional/tests/conftest.py b/test/functional/tests/conftest.py index 044c3e6..d8b037a 100644 --- a/test/functional/tests/conftest.py +++ b/test/functional/tests/conftest.py @@ -116,7 +116,7 @@ def pytest_runtest_teardown(): InitConfig.create_default_init_config() DeviceMapper.remove_all() except Exception as ex: - TestRun.LOGGER.warning(f"Exception occured during platform cleanup.\n" + TestRun.LOGGER.warning(f"Exception occurred during platform cleanup.\n" f"{str(ex)}\n{traceback.format_exc()}") TestRun.LOGGER.end() diff --git a/test/functional/tests/incremental_load/test_incremental_load.py b/test/functional/tests/incremental_load/test_incremental_load.py index 55a3ad7..6c68611 100644 --- a/test/functional/tests/incremental_load/test_incremental_load.py +++ b/test/functional/tests/incremental_load/test_incremental_load.py @@ -5,11 +5,13 @@ import time from random import shuffle + import pytest from api.cas import casadm, cli, cli_messages -from api.cas.cache_config import CacheStatus, SeqCutOffPolicy, CacheModeTrait -from api.cas.core import CoreStatus, CacheMode, CleaningPolicy, FlushParametersAlru, File +from api.cas.cache_config import CacheStatus, SeqCutOffPolicy, CacheModeTrait, CacheMode, \ + CleaningPolicy, FlushParametersAlru +from api.cas.core import CoreStatus from api.cas.init_config import InitConfig from api.cas.statistics import CacheStats from core.test_run import TestRun @@ -18,8 +20,8 @@ from test_tools.dd import Dd from test_tools.disk_utils import Filesystem from test_tools.fio.fio import Fio from test_tools.fio.fio_param import IoEngine, ReadWrite -from test_utils import os_utils -from test_utils.os_utils import Udev +from test_utils.filesystem.file import File +from test_utils.os_utils import Udev, sync from test_utils.output import CmdException from test_utils.size import Size, Unit from test_utils.time import Time @@ -326,7 +328,7 @@ def test_preserve_data_for_inactive_device(): .count(100) \ .block_size(Size(1, Unit.Blocks512)) dd.run() - os_utils.sync() + sync() md5_after_create = test_file.md5sum() cache_stats_before_stop = cache.get_statistics() core_stats_before_stop = core.get_statistics() @@ -498,7 +500,7 @@ def test_print_statistics_inactive(cache_mode): f"({inactive_stats_after.inactive_usage_stats.inactive_occupancy}).") with TestRun.step("Remove inactive core from cache and check if cache is in running state."): - cache.remove_core(second_core.core_id, force=True) + cache.remove_inactive_core(second_core.core_id) cache_status = cache.get_status() if cache_status != CacheStatus.running: TestRun.fail(f"Cache did not change status to 'running' after plugging core device. " @@ -640,27 +642,49 @@ def test_remove_inactive_devices(): TestRun.fail(f"Each core should be in inactive state. " f"Actual states:\n{casadm.list_caches().stdout}") - with TestRun.step("Try removing CAS device without ‘force’ option. Verify that for " - "dirty CAS devices operation is blocked, proper message is displayed " - "and device is still listed."): + with TestRun.step("Try removing CAS devices using remove command. " + "Operation should be blocked and proper message displayed."): + shuffle(cores) + for force in [False, True]: + for core in cores: + try: + core.remove_core(force) + TestRun.fail(f"Removing inactive CAS device should be possible by " + f"'remove-inactive' command only but it worked with 'remove' " + f"command with force option set to {force}.") + except CmdException as e: + TestRun.LOGGER.info(f"Remove core operation is blocked for inactive CAS device " + f"as expected. Force option set to: {force}") + cli_messages.check_stderr_msg( + e.output, cli_messages.remove_inactive_core_with_remove_command) + output = casadm.list_caches().stdout + if core.path not in output: + TestRun.fail( + f"CAS device is not listed in casadm list output but it should be." + f"\n{output}") + + with TestRun.step("Try removing CAS devices using remove-inactive command without ‘force’ " + "option. Verify that for dirty CAS devices operation is blocked, proper " + "message is displayed and device is still listed."): shuffle(cores) for core in cores: try: dirty_blocks = core.get_dirty_blocks() - core.remove_core() + core.remove_inactive() if dirty_blocks != Size.zero(): - TestRun.fail("Removing dirty CAS device should be impossible but remove " - "command executed without any error.") + TestRun.fail("Removing dirty inactive CAS device should be impossible without " + "force option but remove-inactive command executed without " + "any error.") TestRun.LOGGER.info("Removing core with force option skipped for clean CAS device.") except CmdException as e: - TestRun.LOGGER.info("Remove operation without force option is blocked for " + TestRun.LOGGER.info("Remove-inactive operation without force option is blocked for " "dirty CAS device as expected.") - cli_messages.check_stderr_msg(e.output, cli_messages.remove_inactive_core) + cli_messages.check_stderr_msg(e.output, cli_messages.remove_inactive_dirty_core) output = casadm.list_caches().stdout if core.path not in output: TestRun.fail(f"CAS device is not listed in casadm list output but it should be." f"\n{output}") - core.remove_core(force=True) + core.remove_inactive(force=True) with TestRun.step("Plug missing disk and stop cache."): plug_device.plug()