Add test for devices' capabilities

Signed-off-by: Katarzyna Lapinska <katarzyna.lapinska@intel.com>
This commit is contained in:
Katarzyna Lapinska 2020-06-17 16:11:39 +02:00
parent ba5bbcf08e
commit b13403a9b9
4 changed files with 199 additions and 1 deletions

View File

@ -63,6 +63,13 @@ load_and_force = [
r"Use of \'load\' and \'force\' simultaneously is forbidden\."
]
try_add_core_sector_size_mismatch = [
r"Error while adding core device to cache instance \d+",
r"Cache device logical sector size is greater than core device logical sector size\.",
r"Consider changing logical sector size on current cache device",
r"or try other device with the same logical sector size as core device\."
]
def check_stderr_msg(output: Output, expected_messages):
return __check_string_msg(output.stderr, expected_messages)

@ -1 +1 @@
Subproject commit 7b8fb2ba6a3a1a293152f0dfef6568e103c86be4
Subproject commit 0156c9ff20db765c11f547a042a2146b3ce06ddc

View File

View File

@ -0,0 +1,191 @@
#
# Copyright(c) 2020 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause-Clear
#
import math
import pytest
import os
from api.cas import casadm, cli_messages
from core.test_run import TestRun
from storage_devices.disk import DiskTypeSet, DiskType, DiskTypeLowerThan
from storage_devices.partition import Partition
from test_tools import disk_utils, fs_utils
from test_utils.output import CmdException
from test_utils.size import Size, Unit
@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand]))
@pytest.mark.require_disk("core", DiskTypeLowerThan("cache"))
@pytest.mark.require_plugin("scsi_debug")
def test_device_capabilities():
"""
title: Test whether CAS device capabilities are properly set.
description: |
Test if CAS device takes into consideration differences between devices which are used to
create it.
pass_criteria:
- CAS device starts successfully using differently configured devices.
- CAS device capabilities are as expected.
"""
core_device = TestRun.disks['core']
max_io_size_path = os.path.join(disk_utils.get_sysfs_path(core_device.get_device_id()),
'queue/max_sectors_kb')
default_max_io_size = fs_utils.read_file(max_io_size_path)
iteration_settings = [{"device": "SCSI-debug module",
"dev_size_mb": 1024, "logical_block_size": 512, "max_sectors_kb": 1024},
{"device": "SCSI-debug module",
"dev_size_mb": 1024, "logical_block_size": 512, "max_sectors_kb": 256},
{"device": "SCSI-debug module",
"dev_size_mb": 1024, "logical_block_size": 512, "max_sectors_kb": 128},
{"device": "SCSI-debug module",
"dev_size_mb": 2048, "logical_block_size": 2048, "max_sectors_kb": 1024},
{"device": "standard core device",
"max_sectors_kb": int(default_max_io_size)},
{"device": "standard core device", "max_sectors_kb": 128}]
for i in range(0, 6):
device = iteration_settings[i]["device"]
group_title = f"{device} | "
if device == "SCSI-debug module":
group_title += f"dev_size_mb = {iteration_settings[i]['dev_size_mb']} | " \
f"logical_block_size = {iteration_settings[i]['logical_block_size']} | "
group_title += f"max_sectors_kb = {iteration_settings[i]['max_sectors_kb']}"
with TestRun.group(group_title):
with TestRun.step("Prepare devices."):
core_device = prepare_core_device(iteration_settings[i])
cache_device = TestRun.disks['cache']
with TestRun.step("Start cache and add prepared core device as core."):
cache, core, error_output = prepare_cas_device(cache_device, core_device)
with TestRun.step("Compare capabilities for CAS device, cache and core "
"(or check proper error if logical sector mismatch occurs)."):
compare_capabilities(cache_device, core_device, cache, core, error_output)
with TestRun.step("Recreate CAS device with switched cache and core devices."):
cache, core, error_output = prepare_cas_device(core_device, cache_device)
with TestRun.step("Compare capabilities for CAS device, cache and core "
"(or check proper error if logical sector mismatch occurs)."):
compare_capabilities(core_device, cache_device, cache, core, error_output)
# Methods used in test
def prepare_core_device(settings):
if settings["device"] == "SCSI-debug module":
core_device = create_scsi_debug_device(
settings["logical_block_size"], 4, settings["dev_size_mb"])
else:
core_device = TestRun.disks['core']
core_device.set_max_io_size(Size(settings["max_sectors_kb"], Unit.KibiByte))
return core_device
def create_scsi_debug_device(sector_size: int, physblk_exp: int, dev_size_mb=1024):
scsi_debug_params = {
"delay": "0",
"virtual_gb": "200",
"dev_size_mb": str(dev_size_mb),
"sector_size": str(sector_size),
"physblk_exp": str(physblk_exp)
}
scsi_debug = TestRun.plugin_manager.get_plugin('scsi_debug')
scsi_debug.params = scsi_debug_params
scsi_debug.reload()
return TestRun.scsi_debug_devices[0]
def prepare_cas_device(cache_device, core_device):
cache = casadm.start_cache(cache_device, force=True)
try:
cache_dev_bs = disk_utils.get_block_size(cache_device.get_device_id())
core_dev_bs = disk_utils.get_block_size(core_device.get_device_id())
core = cache.add_core(core_device)
if cache_dev_bs > core_dev_bs:
TestRun.LOGGER.error(
f"CAS device started with cache device logical block size ({cache_dev_bs}) "
f"greater than core device logical block size ({core_dev_bs})")
return cache, core, None
except CmdException as e:
if cache_dev_bs <= core_dev_bs:
TestRun.fail("Failed to create CAS device.")
TestRun.LOGGER.info("Cannot add core device with mismatching logical sector size. "
"Check output instead of capabilities.")
return cache, None, e.output
def method_min_not_zero(a, b):
return a if a != 0 and (a < b or b == 0) else b
def method_lcm_not_zero(a, b):
if a == 0 or b == 0:
return max([a, b])
# gcd - greatest common divisor
return a * b / math.gcd(a, b)
# device capabilities and their test comparison methods
capabilities = {"logical_block_size": max,
"max_hw_sectors_kb": None,
"max_integrity_segments": method_min_not_zero,
"max_sectors_kb": None,
"max_segments": None,
"minimum_io_size": max,
"optimal_io_size": method_lcm_not_zero,
"physical_block_size": max,
"write_same_max_bytes": min}
def measure_capabilities(dev):
dev_capabilities = {}
dev_id = dev.parent_device.get_device_id() if isinstance(dev, Partition) \
else dev.get_device_id()
for c in capabilities:
path = os.path.join(disk_utils.get_sysfs_path(dev_id), 'queue', c)
command = f"cat {path}"
output = TestRun.executor.run(command)
if output.exit_code == 0:
val = int(output.stdout)
dev_capabilities.update({c: val})
else:
TestRun.LOGGER.info(f"Could not measure capability: {c} for {dev_id}")
return dev_capabilities
def compare_capabilities(cache_device, core_device, cache, core, msg):
if core is None:
cli_messages.check_stderr_msg(msg,
cli_messages.try_add_core_sector_size_mismatch)
else:
core_dev_sectors_num = \
disk_utils.get_size(core_device.get_device_id()) / disk_utils.get_block_size(
core_device.get_device_id())
core_sectors_num = disk_utils.get_size(core.get_device_id()) / disk_utils.get_block_size(
core.get_device_id())
if core_dev_sectors_num != core_sectors_num:
TestRun.LOGGER.error(
"Number of sectors in CAS device and attached core device is different.")
cache.stop()
return
cas_capabilities = measure_capabilities(core)
cache_dev_capabilities = measure_capabilities(cache_device)
core_dev_capabilities = measure_capabilities(core_device)
for (capability, method) in capabilities.items():
cas_val = cas_capabilities[capability]
cache_val = cache_dev_capabilities[capability]
core_val = core_dev_capabilities[capability]
comparison_val = method(core_val, cache_val) if method is not None else core_val
if comparison_val != cas_val:
TestRun.LOGGER.error(f"Cas device {capability} is not set properly. Is: {cas_val}, "
f"should be {comparison_val} (cache: {cache_val}, "
f"core: {core_val})")
continue
TestRun.LOGGER.info(f"Cas device {capability} has proper value: {cas_val} "
f"(cache: {cache_val}, core: {core_val})")
cache.stop()