from test_tools.disk_utils import Filesystem from test_utils.output import CmdException from test_utils.size import Size, Unit from tests.lazy_writes.recovery.recovery_tests_methods import create_test_files, copy_file, \ compare_files test_file_size = Size(0.5, Unit.GibiByte) mount_point = "/mnt" test_file_path = os.path.join(mount_point, "test_file") @pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand])) @pytest.mark.require_disk("core", DiskTypeLowerThan("cache")) @pytest.mark.parametrizex("cache_mode", CacheMode.with_traits(CacheModeTrait.LazyWrites)) @pytest.mark.parametrizex("cls", [CacheLineSize.LINE_4KiB, CacheLineSize.LINE_64KiB]) @pytest.mark.parametrizex("filesystem", Filesystem) @pytest.mark.parametrizex("direct", [True, False]) @pytest.mark.require_plugin("power_control") def test_recovery_unplug_cache_fs(cache_mode, cls, filesystem, direct): """ title: Test for recovery after cache drive removal - test with filesystem. description: | Verify that unflushed data can be safely recovered after, when SSD drive is removed after write completion - test with filesystem. pass_criteria: - CAS recovers successfully after cache drive unplug - No data corruption """
from storage_devices.device import Device from storage_devices.disk import DiskType, DiskTypeSet, DiskTypeLowerThan from core.test_run import TestRun from test_tools.dd import Dd from test_tools.disk_utils import Filesystem from test_tools.fs_utils import create_random_test_file, remove from test_tools.iostat import IOstatBasic from test_utils.filesystem.file import File from test_utils.os_utils import Udev, sync from test_utils.size import Size, Unit bs = Size(512, Unit.KibiByte) mnt_point = "/mnt/cas/" @pytest.mark.parametrizex("cache_mode", CacheMode.with_traits(CacheModeTrait.LazyWrites)) @pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand])) @pytest.mark.require_disk("core", DiskTypeLowerThan("cache")) def test_clean_stop_cache(cache_mode): """ title: Test of the ability to stop cache in modes with lazy writes. description: | Test if OpenCAS stops cache in modes with lazy writes without data loss. pass_criteria: - Cache stopping works properly. - Writes to exported object and core device during OpenCAS's work are equal - Data on core device is correct after cache is stopped. """ with TestRun.step("Prepare devices for cache and core."): cache_dev = TestRun.disks['cache'] cache_dev.create_partitions([Size(256, Unit.MebiByte)])
f"Discard request issued with wrong bytes count: {req.byte_count}, " f"expected: {non_meta_size} bytes") cas_fio.read_write(ReadWrite.read) non_cas_fio.read_write(ReadWrite.read) cas_fio.verification_with_pattern("0x00") cas_fio.offset(metadata_size) cas_fio.run() non_cas_fio.run() with TestRun.step("Stopping cache"): cache.stop() @pytest.mark.parametrizex("cache_mode", CacheMode.with_traits(CacheModeTrait.InsertWrite)) @pytest.mark.parametrizex("filesystem", Filesystem) @pytest.mark.parametrizex("cleaning_policy", CleaningPolicy) @pytest.mark.parametrizex("trim_support_cache_core", [(False, True), (True, False), (True, True)]) @pytest.mark.require_disk("ssd1", DiskTypeSet([DiskType.optane, DiskType.nand])) @pytest.mark.require_disk("ssd2", DiskTypeSet([DiskType.optane, DiskType.nand])) @pytest.mark.require_disk("hdd", DiskTypeSet([DiskType.hdd, DiskType.hdd4k])) def test_trim_device_discard_support(trim_support_cache_core, cache_mode, filesystem, cleaning_policy): """ title: Trim requests supported on various cache and core devices. description: |
if req.byte_count != non_meta_size: TestRun.fail(f"Discard request issued with wrong bytes count: {req.byte_count}, " f"expected: {non_meta_size} bytes") cas_fio.read_write(ReadWrite.read) non_cas_fio.read_write(ReadWrite.read) cas_fio.verification_with_pattern("0x00") cas_fio.offset(metadata_size) cas_fio.run() non_cas_fio.run() with TestRun.step("Stopping cache"): cache.stop() @pytest.mark.parametrizex("cache_mode", CacheMode.with_traits(CacheModeTrait.InsertWrite)) @pytest.mark.parametrizex("filesystem", Filesystem) @pytest.mark.parametrizex("cleaning_policy", CleaningPolicy) @pytest.mark.parametrizex("trim_support_cache_core", [(False, True), (True, False), (True, True)]) @pytest.mark.require_disk("ssd1", DiskTypeSet([DiskType.optane, DiskType.nand])) @pytest.mark.require_disk("ssd2", DiskTypeSet([DiskType.optane, DiskType.nand])) def test_trim_device_discard_support( trim_support_cache_core, cache_mode, filesystem, cleaning_policy): """ title: Trim requests supported on various cache and core devices. description: | Handling trim requests support when various combination of SSD and HDD are used as cache and core. pass_criteria: - No system crash. - Discards detected on CAS.
def validate_block_stats(stats, stats_perc, cache_mode, fail_message): fail_message += f"in 'block' stats" if stats.block_stats.core.reads.value != 0: TestRun.LOGGER.error( f"{fail_message} 'Core reads' is " f"{stats.block_stats.core.reads.value}, " f"should equal 0\n") if stats_perc.block_stats.core.reads != 0: TestRun.LOGGER.error( f"{fail_message} 'Core reads' percentage is " f"{stats_perc.block_stats.core.reads}, " f"should equal 0\n") if stats.block_stats.cache.reads.value != 0: TestRun.LOGGER.error( f"{fail_message} 'Cache reads' is " f"{stats.block_stats.cache.reads.value}, " f"should equal 0\n") if stats_perc.block_stats.cache.reads != 0: TestRun.LOGGER.error( f"{fail_message} 'Cache reads' percentage is " f"{stats_perc.block_stats.cache.reads}, " f"should equal 0\n") if stats.block_stats.exp_obj.reads.value != 0: TestRun.LOGGER.error( f"{fail_message} 'Exported object reads' is " f"{stats.block_stats.exp_obj.reads.value}, " f"should equal 0\n") if stats_perc.block_stats.exp_obj.reads != 0: TestRun.LOGGER.error( f"{fail_message} 'Exported object reads' percentage is " f"{stats_perc.block_stats.exp_obj.reads}, " f"should equal 0\n") if stats.block_stats.exp_obj.writes.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Exported object writes' is " f"{stats.block_stats.exp_obj.writes.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.exp_obj.writes != 100: TestRun.LOGGER.error( f"{fail_message} 'Exported object writes' percentage is " f"{stats_perc.block_stats.exp_obj.writes}, " f"should equal 100\n") if stats.block_stats.exp_obj.total.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Exported object total' is " f"{stats.block_stats.exp_obj.total.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.exp_obj.total != 100: TestRun.LOGGER.error( f"{fail_message} 'Exported object total' percentage is " f"{stats_perc.block_stats.exp_obj.total}, " f"should equal 100\n") if cache_mode not in CacheMode.with_traits(CacheModeTrait.InsertWrite): if stats.block_stats.core.writes.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Core writes' is " f"{stats.block_stats.core.writes.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.core.writes != 100: TestRun.LOGGER.error( f"{fail_message} 'Core writes' percentage is " f"{stats_perc.block_stats.core.writes}, " f"should equal 100\n") if stats.block_stats.core.total.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Core total' is " f"{stats.block_stats.core.total.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.core.total != 100: TestRun.LOGGER.error( f"{fail_message} 'Core total' percentage is " f"{stats_perc.block_stats.core.total}, " f"should equal 100\n") if stats.block_stats.cache.writes.value != 0: TestRun.LOGGER.error( f"{fail_message} 'Cache writes' is " f"{stats.block_stats.cache.writes.value}, " f"should equal 0\n") if stats_perc.block_stats.cache.writes != 0: TestRun.LOGGER.error( f"{fail_message} 'Cache writes' percentage is " f"{stats_perc.block_stats.cache.writes}, " f"should equal 0\n") if stats.block_stats.cache.total.value != 0: TestRun.LOGGER.error( f"{fail_message} 'Cache total' is " f"{stats.block_stats.cache.total.value}, " f"should equal 0\n") if stats_perc.block_stats.cache.total != 0: TestRun.LOGGER.error( f"{fail_message} 'Cache total' percentage is " f"{stats_perc.block_stats.cache.total}, " f"should equal 0\n") elif cache_mode in CacheMode.with_traits( CacheModeTrait.InsertWrite | CacheModeTrait.LazyWrites ): if stats.block_stats.core.writes.value != 0: TestRun.LOGGER.error( f"{fail_message} 'Core writes' is " f"{stats.block_stats.core.writes.value}, " f"should equal 0\n") if stats_perc.block_stats.core.writes != 0: TestRun.LOGGER.error( f"{fail_message} 'Core writes' percentage is " f"{stats_perc.block_stats.core.writes}, " f"should equal 0\n") if stats.block_stats.core.total.value != 0: TestRun.LOGGER.error( f"{fail_message} 'Core total' is " f"{stats.block_stats.core.total.value}, " f"should equal 0\n") if stats_perc.block_stats.core.total != 0: TestRun.LOGGER.error( f"{fail_message} 'Core total' percentage is " f"{stats_perc.block_stats.core.total}, " f"should equal 0\n") if stats.block_stats.cache.writes.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Cache writes' is " f"{stats.block_stats.cache.writes.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.cache.writes != 100: TestRun.LOGGER.error( f"{fail_message} 'Cache writes' percentage is " f"{stats_perc.block_stats.cache.writes}, " f"should equal 100\n") if stats.block_stats.cache.total.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Cache total' is " f"{stats.block_stats.cache.total.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.cache.total != 100: TestRun.LOGGER.error( f"{fail_message} 'Cache total' percentage is " f"{stats_perc.block_stats.cache.total}, " f"should equal 100\n") elif ( cache_mode in CacheMode.with_traits(CacheModeTrait.InsertWrite) and cache_mode not in CacheMode.with_traits(CacheModeTrait.LazyWrites) ): if stats.block_stats.core.writes.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Core writes' is " f"{stats.block_stats.core.writes.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.core.writes != 100: TestRun.LOGGER.error( f"{fail_message} 'Core writes' percentage is " f"{stats_perc.block_stats.core.writes}, " f"should equal 100\n") if stats.block_stats.core.total.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Core total' is " f"{stats.block_stats.core.total.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.core.total != 100: TestRun.LOGGER.error( f"{fail_message} 'Core total' percentage is " f"{stats_perc.block_stats.core.total}, " f"should equal 100\n") if stats.block_stats.cache.writes.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Cache writes' is " f"{stats.block_stats.cache.writes.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.cache.writes != 100: TestRun.LOGGER.error( f"{fail_message} 'Cache writes' percentage is " f"{stats_perc.block_stats.cache.writes}, " f"should equal 100\n") if stats.block_stats.cache.total.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'Cache total' is " f"{stats.block_stats.cache.total.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.block_stats.cache.total != 100: TestRun.LOGGER.error( f"{fail_message} 'Cache total' percentage is " f"{stats_perc.block_stats.cache.total}, " f"should equal 100\n")
def validate_request_stats(stats, stats_perc, cache_mode, fail_message): fail_message += f"in 'request' stats" if stats.request_stats.read.hits != 0: TestRun.LOGGER.error( f"{fail_message} 'Read hits' is " f"{stats.request_stats.read.hits}, " f"should equal 0\n") if stats_perc.request_stats.read.hits != 0: TestRun.LOGGER.error( f"{fail_message} 'Read hits' percentage is " f"{stats_perc.request_stats.read.hits}, " f"should equal 0\n") if stats.request_stats.read.part_misses != 0: TestRun.LOGGER.error( f"{fail_message} 'Read partial misses' is " f"{stats.request_stats.read.part_misses}, " f"should equal 0\n") if stats_perc.request_stats.read.part_misses != 0: TestRun.LOGGER.error( f"{fail_message} 'Read partial misses' percentage is " f"{stats_perc.request_stats.read.part_misses}, " f"should equal 0\n") if stats.request_stats.read.full_misses != 0: TestRun.LOGGER.error( f"{fail_message} 'Read full misses' is " f"{stats.request_stats.read.full_misses}, " f"should equal 0\n") if stats_perc.request_stats.read.full_misses != 0: TestRun.LOGGER.error( f"{fail_message} 'Read full misses' percentage is " f"{stats_perc.request_stats.read.full_misses}, " f"should equal 0\n") if stats.request_stats.read.total != 0: TestRun.LOGGER.error( f"{fail_message} 'Read total' is " f"{stats.request_stats.read.total}, " f"should equal 0\n") if stats_perc.request_stats.read.total != 0: TestRun.LOGGER.error( f"{fail_message} 'Read total' percentage is " f"{stats_perc.request_stats.read.total}, " f"should equal 0\n") if stats.request_stats.write.hits != 0: TestRun.LOGGER.error( f"{fail_message} 'Write hits' is " f"{stats.request_stats.write.hits}, " f"should equal 0\n") if stats_perc.request_stats.write.hits != 0: TestRun.LOGGER.error( f"{fail_message} 'Write hits' percentage is " f"{stats_perc.request_stats.write.hits}, " f"should equal 0\n") if stats.request_stats.write.part_misses != 0: TestRun.LOGGER.error( f"{fail_message} 'Write partial misses' is " f"{stats.request_stats.write.part_misses}, " f"should equal 0\n") if stats_perc.request_stats.write.part_misses != 0: TestRun.LOGGER.error( f"{fail_message} 'Write partial misses' percentage is " f"{stats_perc.request_stats.write.part_misses}, " f"should equal 0\n") if stats.request_stats.pass_through_reads != 0: TestRun.LOGGER.error( f"{fail_message} 'Pass-through reads' is " f"{stats.request_stats.pass_through_reads}, " f"should equal 0\n") if stats_perc.request_stats.pass_through_reads != 0: TestRun.LOGGER.error( f"{fail_message} 'Pass-through reads' percentage is " f"{stats_perc.request_stats.pass_through_reads}, " f"should equal 0\n") if stats.request_stats.requests_total != io_value: TestRun.LOGGER.error( f"{fail_message} 'Total requests' is " f"{stats.request_stats.requests_total}, " f"should equal IO size value: {io_value}\n") if stats_perc.request_stats.requests_total != 100: TestRun.LOGGER.error( f"{fail_message} 'Total requests' percentage is " f"{stats_perc.request_stats.requests_total}, " f"should equal 100\n") if cache_mode in CacheMode.with_traits(CacheModeTrait.InsertWrite): if stats.request_stats.write.full_misses != io_value: TestRun.LOGGER.error( f"{fail_message} 'Write full misses' is " f"{stats.request_stats.write.full_misses}, " f"should equal IO size value: {io_value}\n") if stats_perc.request_stats.write.full_misses != 100: TestRun.LOGGER.error( f"{fail_message} 'Write full misses' percentage is " f"{stats_perc.request_stats.write.full_misses}, " f"should equal 100\n") if stats.request_stats.write.total != io_value: TestRun.LOGGER.error( f"{fail_message} 'Write total' is " f"{stats.request_stats.write.total}, " f"should equal IO size value: {io_value}\n") if stats_perc.request_stats.write.total != 100: TestRun.LOGGER.error( f"{fail_message} 'Write total' percentage is " f"{stats_perc.request_stats.write.total}, " f"should equal 100\n") if stats.request_stats.pass_through_writes != 0: TestRun.LOGGER.error( f"{fail_message} 'Pass-through writes' is " f"{stats.request_stats.pass_through_writes}, " f"should equal 0\n") if stats_perc.request_stats.pass_through_writes != 0: TestRun.LOGGER.error( f"{fail_message} 'Pass-through writes' percentage is " f"{stats_perc.request_stats.pass_through_writes}, " f"should equal 0\n") if stats.request_stats.requests_serviced != io_value: TestRun.LOGGER.error( f"{fail_message} 'Serviced requests' is " f"{stats.request_stats.requests_serviced}, " f"should equal IO size value: {io_value}\n") if stats_perc.request_stats.requests_serviced != 100: TestRun.LOGGER.error( f"{fail_message} 'Serviced requests' percentage is " f"{stats_perc.request_stats.requests_serviced}, " f"should equal 100\n") else: if stats.request_stats.write.full_misses != 0: TestRun.LOGGER.error( f"{fail_message} 'Write full misses' is " f"{stats.request_stats.write.full_misses}, " f"should equal 0\n") if stats_perc.request_stats.write.full_misses != 0: TestRun.LOGGER.error( f"{fail_message} 'Write full misses' percentage is " f"{stats_perc.request_stats.write.full_misses}, " f"should equal 0\n") if stats.request_stats.write.total != 0: TestRun.LOGGER.error( f"{fail_message} 'Write total' is " f"{stats.request_stats.write.total}, " f"should equal 0\n") if stats_perc.request_stats.write.total != 0: TestRun.LOGGER.error( f"{fail_message} 'Write total' percentage is " f"{stats_perc.request_stats.write.total}, " f"should equal 0\n") if stats.request_stats.pass_through_writes != io_value: TestRun.LOGGER.error( f"{fail_message} 'Pass-through writes' is " f"{stats.request_stats.pass_through_writes}, " f"should equal IO size value: {io_value}\n") if stats_perc.request_stats.pass_through_writes != 100: TestRun.LOGGER.error( f"{fail_message} 'Pass-through writes' percentage is " f"{stats_perc.request_stats.pass_through_writes}, " f"should equal 100\n") if stats.request_stats.requests_serviced != 0: TestRun.LOGGER.error( f"{fail_message} 'Serviced requests' is " f"{stats.request_stats.requests_serviced}, " f"should equal 0\n") if stats_perc.request_stats.requests_serviced != 0: TestRun.LOGGER.error( f"{fail_message} 'Serviced requests' percentage is " f"{stats_perc.request_stats.requests_serviced}, " f"should equal 0\n")
def validate_usage_stats(stats, stats_perc, cache, cache_mode, fail_message): fail_message += f"in 'usage' stats" if cache_mode not in CacheMode.with_traits(CacheModeTrait.InsertWrite): if stats.usage_stats.occupancy.value != 0: TestRun.LOGGER.error( f"{fail_message} 'occupancy' is " f"{stats.usage_stats.occupancy.value}, " f"should equal 0\n") if stats_perc.usage_stats.occupancy != 0: TestRun.LOGGER.error( f"{fail_message} 'occupancy' percentage is " f"{stats_perc.usage_stats.occupancy}, " f"should equal 0\n") if stats.usage_stats.free != cache.size: TestRun.LOGGER.error( f"{fail_message} 'free' is " f"{stats.usage_stats.free.value}, " f"should equal cache size: {cache.size.value}\n") if stats_perc.usage_stats.free != 100: TestRun.LOGGER.error( f"{fail_message} 'free' percentage is " f"{stats_perc.usage_stats.free}, " f"should equal 100\n") if stats.usage_stats.clean.value != 0: TestRun.LOGGER.error( f"{fail_message} 'clean' is " f"{stats.usage_stats.clean.value}, " f"should equal 0\n") if stats_perc.usage_stats.clean != 0: TestRun.LOGGER.error( f"{fail_message} 'clean' percentage is " f"{stats_perc.usage_stats.clean}, " f"should equal 0\n") if stats.usage_stats.dirty.value != 0: TestRun.LOGGER.error( f"{fail_message} 'dirty' is " f"{stats.usage_stats.dirty.value}, " f"should equal 0\n") if stats_perc.usage_stats.dirty != 0: TestRun.LOGGER.error( f"{fail_message} 'dirty' percentage is " f"{stats_perc.usage_stats.dirty}, " f"should equal 0\n") else: occupancy_perc = round(100 * io_size.value / cache.size.value, 1) free = cache.size.value - io_size.value * cores_per_cache free_perc = round(100 * (cache.size.value - io_size.value * cores_per_cache) / cache.size.value, 1) if stats.usage_stats.occupancy.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'occupancy' is " f"{stats.usage_stats.occupancy.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.usage_stats.occupancy != occupancy_perc: TestRun.LOGGER.error( f"{fail_message} 'occupancy' percentage is " f"{stats_perc.usage_stats.occupancy}, " f"should equal {occupancy_perc}\n") if stats.usage_stats.free.value != free: TestRun.LOGGER.error( f"{fail_message} 'free' is " f"{stats.usage_stats.free.value}, " f"should equal {free}\n") if stats_perc.usage_stats.free != free_perc: TestRun.LOGGER.error( f"{fail_message} 'free' percentage is " f"{stats_perc.usage_stats.free}, " f"should equal {free_perc}\n") if cache_mode not in CacheMode.with_traits(CacheModeTrait.LazyWrites): if stats.usage_stats.clean.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'clean' is " f"{stats.usage_stats.clean.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.usage_stats.clean != 100: TestRun.LOGGER.error( f"{fail_message} 'clean' percentage is " f"{stats_perc.usage_stats.clean}, " f"should equal 100\n") if stats.usage_stats.dirty.value != 0: TestRun.LOGGER.error( f"{fail_message} 'dirty' is " f"{stats.usage_stats.dirty.value}, " f"should equal 0\n") if stats_perc.usage_stats.dirty != 0: TestRun.LOGGER.error( f"{fail_message} 'dirty' percentage is " f"{stats_perc.usage_stats.dirty}, " f"should equal 0\n") else: if stats.usage_stats.clean.value != 0: TestRun.LOGGER.error( f"{fail_message} 'clean' is " f"{stats.usage_stats.clean.value}, " f"should equal 0\n") if stats_perc.usage_stats.clean != 0: TestRun.LOGGER.error( f"{fail_message} 'clean' percentage is " f"{stats_perc.usage_stats.clean}, " f"should equal 0\n") if stats.usage_stats.dirty.value != io_size.value: TestRun.LOGGER.error( f"{fail_message} 'dirty' is " f"{stats.usage_stats.dirty.value}, " f"should equal IO size: {io_size.value}\n") if stats_perc.usage_stats.dirty != 100: TestRun.LOGGER.error( f"{fail_message} 'dirty' percentage is " f"{stats_perc.usage_stats.dirty}, " f"should equal 100\n")