From 3522457457608c25ddbf633eb4441156dac47544 Mon Sep 17 00:00:00 2001 From: Kamil Gierszewski Date: Wed, 23 Apr 2025 02:07:23 +0200 Subject: [PATCH 1/5] tests: refactor data_integrity test Signed-off-by: Kamil Gierszewski --- .../data_integrity/test_data_integrity_5d.py | 169 ++++++++++-------- 1 file changed, 98 insertions(+), 71 deletions(-) diff --git a/test/functional/tests/data_integrity/test_data_integrity_5d.py b/test/functional/tests/data_integrity/test_data_integrity_5d.py index 71e12ce7a..d5a353d0a 100644 --- a/test/functional/tests/data_integrity/test_data_integrity_5d.py +++ b/test/functional/tests/data_integrity/test_data_integrity_5d.py @@ -16,8 +16,13 @@ from api.cas.cache_config import CacheMode from api.cas.ioclass_config import IoClass from core.test_run import TestRun -from test_tools.fs_tools import Filesystem, create_directory, check_if_directory_exists, \ - read_file, crc32sum +from test_tools.fs_tools import ( + Filesystem, + create_directory, + check_if_directory_exists, + read_file, + crc32sum, +) from test_tools.fio.fio import Fio from test_tools.fio.fio_param import ReadWrite, IoEngine, VerifyMethod from storage_devices.disk import DiskType, DiskTypeSet, DiskTypeLowerThan @@ -53,11 +58,13 @@ def test_data_integrity_5d_with_io_classification(filesystems): runtime = datetime.timedelta(days=5) with TestRun.step("Prepare cache and core devices"): - cache_device = TestRun.disks['cache'] - core_devices = [TestRun.disks['core1'], - TestRun.disks['core2'], - TestRun.disks['core3'], - TestRun.disks['core4']] + cache_device = TestRun.disks["cache"] + core_devices = [ + TestRun.disks["core1"], + TestRun.disks["core2"], + TestRun.disks["core3"], + TestRun.disks["core4"], + ] cache_device.create_partitions([Size(50, Unit.GibiByte)] * len(core_devices)) @@ -76,8 +83,7 @@ def test_data_integrity_5d_with_io_classification(filesystems): with TestRun.step("Add one core to each cache"): cores = [ - cache.add_core(core_dev=core_part) - for cache, core_part in zip(caches, core_partitions) + cache.add_core(core_dev=core_part) for cache, core_part in zip(caches, core_partitions) ] with TestRun.step("Load default I/O class config for each cache"): @@ -90,41 +96,52 @@ def test_data_integrity_5d_with_io_classification(filesystems): with TestRun.step("Mount cached volumes"): for core in cores: - mount_point = core.path.replace('/dev/', '/mnt/') - if not check_if_directory_exists(mount_point): - create_directory(mount_point) - core.mount(mount_point) + mount_point = core.path.replace("/dev/", "/mnt/") + if not check_if_directory_exists(path=mount_point): + create_directory(path=mount_point) + core.mount(mount_point=mount_point) sync() - with TestRun.step("Prepare fio workload config"): + with TestRun.step("Prepare I/O workload config"): template_io_classes = IoClass.csv_to_list(read_file(template_config_path)) config_max_file_sizes = [ - int(re.search(r'\d+', io_class.rule).group()) - for io_class in template_io_classes if io_class.rule.startswith("file_size:le") + int(re.search(r"\d+", io_class.rule).group()) + for io_class in template_io_classes + if io_class.rule.startswith("file_size:le") ] config_max_file_sizes.append(config_max_file_sizes[-1] * 2) io_class_section_size = Size( - int(core_size.get_value(Unit.GibiByte) / len(config_max_file_sizes)), - Unit.GibiByte + int(core_size.get_value(Unit.GibiByte) / len(config_max_file_sizes)), Unit.GibiByte ) - fio = Fio() - fio_run = fio.create_command() - fio.base_cmd_parameters.set_param( - 'alloc-size', int(Size(1, Unit.GiB).get_value(Unit.KiB)) + ''' + Fio has a bug when verifying randrw. + If someone would like to switch to randrw in the future, + Fio will return the error "verify: bad header rand_seed ..., wanted ..." + It's recommended to verify the status of bug https://github.com/axboe/fio/issues/1049 + in that case. + + ''' + + fio_run = ( + Fio() + .create_command() + .io_engine(IoEngine.libaio) + .direct() + .time_based() + .do_verify() + .verify(VerifyMethod.md5) + .verify_dump() + .run_time(runtime) + .read_write(ReadWrite.randwrite) + .open_files(1000) + .io_depth(128) + .blocksize_range( + [(Size(512, Unit.Byte).get_value(), Size(128, Unit.KibiByte).get_value())] + ) ) - - fio_run.io_engine(IoEngine.libaio) - fio_run.direct() - fio_run.time_based() - fio_run.do_verify() - fio_run.verify(VerifyMethod.md5) - fio_run.verify_dump() - fio_run.run_time(runtime) - fio_run.read_write(ReadWrite.randrw) - fio_run.io_depth(128) - fio_run.blocksize_range( - [(Size(512, Unit.Byte).get_value(), Size(128, Unit.KibiByte).get_value())] + fio_run.fio.base_cmd_parameters.set_param( + "alloc-size", int(Size(1, Unit.GibiByte).get_value(Unit.KibiByte)) ) for core in cores: @@ -146,23 +163,25 @@ def test_data_integrity_5d_with_io_classification(filesystems): for core in cores: core.unmount() - with TestRun.step("Calculate crc32 for each core"): - core_crc32s = [crc32sum(core.path, timeout=timedelta(hours=4)) for core in cores] + with TestRun.step("Calculate checksum for each core"): + core_crc32s = [crc32sum(file=core.path, timeout=timedelta(hours=4)) for core in cores] with TestRun.step("Stop caches"): for cache in caches: cache.stop() - with TestRun.step("Calculate crc32 for each core"): - dev_crc32s = [crc32sum(dev.path, timeout=timedelta(hours=4)) for dev in core_devices] + with TestRun.step("Calculate checksum for each core device"): + dev_crc32s = [crc32sum(file=dev.path, timeout=timedelta(hours=4)) for dev in core_devices] - with TestRun.step("Compare crc32 sums for cores and core devices"): - for core_crc32, dev_crc32, mode, fs in zip( - core_crc32s, dev_crc32s, cache_modes, filesystems + with TestRun.step("Compare checksum for cores and core devices"): + for core_crc32, dev_crc32, cache_mode, filesystem in zip( + core_crc32s, dev_crc32s, cache_modes, filesystems ): if core_crc32 != dev_crc32: - TestRun.fail("Crc32 sums of core and core device do not match! " - f"Cache mode: {mode} Filesystem: {fs}") + TestRun.fail( + "Checksum of core and core device do not match!\n" + f"Cache mode: {cache_mode} Filesystem: {filesystem}" + ) @pytest.mark.os_dependent @@ -186,11 +205,13 @@ def test_data_integrity_5d(): runtime = datetime.timedelta(days=5) with TestRun.step("Prepare cache and core devices"): - cache_device = TestRun.disks['cache'] - core_devices = [TestRun.disks['core1'], - TestRun.disks['core2'], - TestRun.disks['core3'], - TestRun.disks['core4']] + cache_device = TestRun.disks["cache"] + core_devices = [ + TestRun.disks["core1"], + TestRun.disks["core2"], + TestRun.disks["core3"], + TestRun.disks["core4"], + ] cache_device.create_partitions([Size(50, Unit.GibiByte)] * len(core_devices)) @@ -202,30 +223,34 @@ def test_data_integrity_5d(): with TestRun.step("Start caches, each in different cache mode"): caches = [ - casadm.start_cache(cache_device, cache_mode, force=True) + casadm.start_cache(cache_dev=cache_device, cache_mode=cache_mode, force=True) for cache_device, cache_mode in zip(cache_device.partitions, cache_modes) ] with TestRun.step("Add one core to each cache"): cores = [ - casadm.add_core(cache, core_dev=core_device) + casadm.add_core(cache=cache, core_dev=core_device) for cache, core_device in zip(caches, core_devices) ] - with TestRun.step("Prepare fio workload config"): - fio_run = Fio().create_command() - fio_run.io_engine(IoEngine.libaio) - fio_run.direct() - fio_run.time_based() - fio_run.do_verify() - fio_run.verify(VerifyMethod.md5) - fio_run.verify_dump() - fio_run.run_time(runtime) - fio_run.read_write(ReadWrite.randrw) - fio_run.io_depth(128) - fio_run.blocksize_range( - [(Size(512, Unit.Byte).get_value(), Size(128, Unit.KibiByte).get_value())] + with TestRun.step("Prepare I/O workload config"): + fio_run = ( + Fio() + .create_command() + .io_engine(IoEngine.libaio) + .direct() + .time_based() + .do_verify() + .verify(VerifyMethod.md5) + .verify_dump() + .run_time(runtime) + .read_write(ReadWrite.randrw) + .io_depth(128) + .blocksize_range( + [(Size(512, Unit.Byte).get_value(), Size(128, Unit.KibiByte).get_value())] + ) ) + for core in cores: fio_job = fio_run.add_job() fio_job.target(core) @@ -233,18 +258,20 @@ def test_data_integrity_5d(): with TestRun.step("Run test workload with data verification"): fio_run.run(fio_timeout=runtime + datetime.timedelta(hours=2)) - with TestRun.step("Calculate crc32 for each core"): - core_crc32s = [crc32sum(core.path, timeout=timedelta(hours=4)) for core in cores] + with TestRun.step("Calculate checksum for each core"): + core_crc32s = [crc32sum(file=core.path, timeout=timedelta(hours=4)) for core in cores] with TestRun.step("Stop caches"): for cache in caches: cache.stop() - with TestRun.step("Calculate crc32 for each core"): - dev_crc32s = [crc32sum(dev.path, timeout=timedelta(hours=4)) for dev in core_devices] + with TestRun.step("Calculate checksum for each core device"): + dev_crc32s = [crc32sum(file=dev.path, timeout=timedelta(hours=4)) for dev in core_devices] - with TestRun.step("Compare crc32 sums for cores and core devices"): - for core_crc32, dev_crc32, mode in zip(core_crc32s, dev_crc32s, cache_modes): + with TestRun.step("Compare checksum for cores and core devices"): + for core_crc32, dev_crc32, cache_mode in zip(core_crc32s, dev_crc32s, cache_modes): if core_crc32 != dev_crc32: - TestRun.fail("Crc32 sums of core and core device do not match! " - f"Cache mode: {mode}") + TestRun.fail( + "Checksum sums of core and core device do not match!\n" + f"Cache mode with wrong checksum: {cache_mode}" + ) From 76b41bffdeca2b6c4ea6becf08802816517ecd01 Mon Sep 17 00:00:00 2001 From: Kamil Gierszewski Date: Tue, 8 Apr 2025 11:30:18 +0200 Subject: [PATCH 2/5] tests: refactor test_trim + adjust offset due to updated kernel asynchronous read of the device Signed-off-by: Kamil Gierszewski --- test/functional/tests/io/trim/test_trim.py | 64 ++++++++++++++-------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/test/functional/tests/io/trim/test_trim.py b/test/functional/tests/io/trim/test_trim.py index 7ee8b9888..de14f27c1 100644 --- a/test/functional/tests/io/trim/test_trim.py +++ b/test/functional/tests/io/trim/test_trim.py @@ -1,6 +1,6 @@ # # Copyright(c) 2020-2022 Intel Corporation -# Copyright(c) 2024 Huawei Technologies Co., Ltd. +# Copyright(c) 2024-2025 Huawei Technologies Co., Ltd. # SPDX-License-Identifier: BSD-3-Clause # @@ -36,12 +36,13 @@ def test_trim_start_discard(): - Partition used for cache is discarded. - Second partition is untouched - written pattern is preserved. """ + with TestRun.step("Clearing dmesg"): TestRun.executor.run_expect_success("dmesg -C") with TestRun.step("Preparing cache device"): dev = TestRun.disks["cache"] - dev.create_partitions([Size(500, Unit.MebiByte), Size(500, Unit.MebiByte)]) + dev.create_partitions([Size(500, Unit.MebiByte)] * 2) cas_part = dev.partitions[0] non_cas_part = dev.partitions[1] @@ -116,7 +117,7 @@ def test_trim_propagation(): - No data corruption after power failure. """ - with TestRun.step(f"Create partitions"): + with TestRun.step("Prepare cache and core devices"): TestRun.disks["ssd1"].create_partitions([Size(43, Unit.MegaByte)]) TestRun.disks["ssd2"].create_partitions([Size(512, Unit.KiloByte)]) @@ -131,36 +132,52 @@ def test_trim_propagation(): with TestRun.step(f"Disable udev"): Udev.disable() - with TestRun.step(f"Prepare cache instance in WB with one core"): + with TestRun.step("Start cache in Write-Back mode and add core device"): cache = casadm.start_cache(cache_dev, CacheMode.WB, force=True) core = cache.add_core(core_dev) - cache.set_cleaning_policy(CleaningPolicy.nop) + + with TestRun.step("Disable cleaning policy and sequential cutoff"): cache.set_seq_cutoff_policy(SeqCutOffPolicy.never) + cache.set_cleaning_policy(CleaningPolicy.nop) + + with TestRun.step("Purge cache and reset cache counters"): cache.purge_cache() + cache.reset_counters() - with TestRun.step(f"Fill exported object with dirty data"): + with TestRun.step("Run I/O to fill exported object with dirty data"): core_size_4k = core.get_statistics().config_stats.core_size.get_value(Unit.Blocks4096) - core_size_4k = int(core_size_4k) - cas_fio = write_pattern(core.path) - cas_fio.verification_with_pattern("0xdeadbeef") - cas_fio.run() + fio = ( + Fio() + .create_command() + .io_engine(IoEngine.libaio) + .read_write(ReadWrite.write) + .target(core.path) + .direct() + .verification_with_pattern() + ) + fio.verification_with_pattern("0xdeadbeef") - dirty_4k = cache.get_statistics().usage_stats.dirty.get_value(Unit.Blocks4096) + fio.run() + with TestRun.step("Check if exported object was filled with dirty data"): + dirty_4k = cache.get_statistics().usage_stats.dirty.get_value(Unit.Blocks4096) if dirty_4k != core_size_4k: TestRun.fail( - f"Failed to fill cache. Expected dirty blocks: {core_size_4k}, " - f"actual value {dirty_4k}" + "Failed to fill cache with dirty data\n" + f"Expected dirty blocks: {core_size_4k}\n" + f"Actual value: {dirty_4k}" ) - with TestRun.step(f"Discard 4k of data on exported object"): - TestRun.executor.run_expect_success(f"blkdiscard {core.path} --length 4096 --offset 0") + with TestRun.step("Discard 4k of data on exported object"): + TestRun.executor.run_expect_success(f"blkdiscard {core.path} --length 4096 --offset 4096") old_occupancy = cache.get_statistics().usage_stats.occupancy.get_value(Unit.Blocks4096) - with TestRun.step("Power cycle"): + with TestRun.step("Power cycle DUT"): power_control = TestRun.plugin_manager.get_plugin("power_control") - power_control.power_cycle() + power_control.power_cycle(wait_for_connection=True) + + with TestRun.step("Disable udev after power cycle"): Udev.disable() with TestRun.step("Load cache"): @@ -170,14 +187,15 @@ def test_trim_propagation(): new_occupancy = cache.get_statistics().usage_stats.occupancy.get_value(Unit.Blocks4096) if new_occupancy != old_occupancy: TestRun.LOGGER.error( - f"Expected occupancy after dirty shutdown: {old_occupancy}. " - f"Actuall: {new_occupancy})" + "Wrong number of occupancy blocks after power cycle\n" + f"Expected occupancy after dirty shutdown: {old_occupancy}\n" + f"Actual: {new_occupancy}" ) - with TestRun.step("Verify data after dirty shutdown"): - cas_fio.read_write(ReadWrite.read) - cas_fio.offset(Unit.Blocks4096) - cas_fio.run() + with TestRun.step("Verify data after power cycle"): + fio.read_write(ReadWrite.read) + fio.offset(Unit.Blocks4096) + fio.run() @pytest.mark.os_dependent From aa24e92cb29059815747bad1924f14935660f146 Mon Sep 17 00:00:00 2001 From: Kamil Gierszewski Date: Tue, 15 Apr 2025 11:04:22 +0200 Subject: [PATCH 3/5] tests: refactor flush_huge_dirty_data test Signed-off-by: Kamil Gierszewski --- .../lazy_writes/test_flush_huge_dirty_data.py | 166 ++++++++++-------- 1 file changed, 94 insertions(+), 72 deletions(-) diff --git a/test/functional/tests/lazy_writes/test_flush_huge_dirty_data.py b/test/functional/tests/lazy_writes/test_flush_huge_dirty_data.py index 0aa6b35a3..c248e9845 100644 --- a/test/functional/tests/lazy_writes/test_flush_huge_dirty_data.py +++ b/test/functional/tests/lazy_writes/test_flush_huge_dirty_data.py @@ -1,6 +1,6 @@ # # Copyright(c) 2020-2021 Intel Corporation -# Copyright(c) 2024 Huawei Technologies +# Copyright(c) 2024-2025 Huawei Technologies # SPDX-License-Identifier: BSD-3-Clause # @@ -16,118 +16,134 @@ from storage_devices.disk import DiskType, DiskTypeLowerThan, DiskTypeSet from test_tools.fio.fio import Fio from test_tools.fio.fio_param import IoEngine, ReadWrite -from test_tools.fs_tools import remove, Filesystem +from test_tools.fs_tools import Filesystem from test_utils.filesystem.file import File -from test_tools.os_tools import sync +from test_tools.os_tools import sync, drop_caches, DropCachesMode from test_tools.udev import Udev from type_def.size import Size, Unit file_size = Size(640, Unit.GiB) required_disk_size = file_size * 1.02 -bs = Size(64, Unit.MebiByte) -mnt_point = "/mnt/cas/" -@pytest.mark.parametrizex("fs", Filesystem) @pytest.mark.parametrizex("cache_mode", CacheMode.with_traits(CacheModeTrait.LazyWrites)) +@pytest.mark.parametrizex("filesystem", Filesystem) @pytest.mark.require_disk("separate_dev", DiskTypeSet([DiskType.optane, DiskType.nand])) @pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand])) @pytest.mark.require_disk("core", DiskTypeLowerThan("cache")) -def test_flush_over_640_gibibytes_with_fs(cache_mode, fs): +def test_flush_over_640_gibibytes_with_fs(cache_mode: CacheMode, filesystem: Filesystem): """ - title: Test of the ability to flush huge amount of dirty data on device with filesystem. - description: | - Flush cache when amount of dirty data in cache with core with filesystem exceeds 640 GiB. - pass_criteria: - - Flushing completes successfully without any errors. + title: Test of the ability to flush huge amount of dirty data on device with filesystem. + description: | + Flush cache when amount of dirty data in cache with core with filesystem exceeds 640 GiB. + pass_criteria: + - Flushing completes successfully without any errors. """ + exported_object_mount_point_path = "/mnt/flush_640G_test" + separate_device_mount_point_path = "/mnt/cas/" + with TestRun.step("Prepare devices for cache and core."): - separate_dev = TestRun.disks['separate_dev'] + cache_dev = TestRun.disks["cache"] + core_dev = TestRun.disks["core"] + separate_dev = TestRun.disks["separate_dev"] + check_disk_size(separate_dev) - cache_dev = TestRun.disks['cache'] check_disk_size(cache_dev) + check_disk_size(core_dev) + cache_dev.create_partitions([required_disk_size]) + cache_part = cache_dev.partitions[0] - core_dev = TestRun.disks['core'] - check_disk_size(core_dev) + + with TestRun.step("Disable udev"): Udev.disable() - with TestRun.step(f"Start cache in {cache_mode} mode."): - cache = casadm.start_cache(cache_part, cache_mode) + with TestRun.step("Drop caches"): + sync() + drop_caches(DropCachesMode.ALL) + + with TestRun.step(f"Start cache in {cache_mode} mode"): + cache = casadm.start_cache(cache_dev=cache_part, cache_mode=cache_mode) - with TestRun.step(f"Add core with {fs.name} filesystem to cache and mount it."): - core_dev.create_filesystem(fs) - core = cache.add_core(core_dev) - core.mount(mnt_point) + with TestRun.step(f"Create {filesystem.name} filesystem on core disk"): + core_dev.create_filesystem(fs_type=filesystem) - with TestRun.step("Disable cleaning and sequential cutoff."): - cache.set_cleaning_policy(CleaningPolicy.nop) - cache.set_seq_cutoff_policy(SeqCutOffPolicy.never) + with TestRun.step("Add core with filesystem"): + core = cache.add_core(core_dev=core_dev) + + with TestRun.step("Mount exported object"): + core.mount(mount_point=separate_device_mount_point_path) + + with TestRun.step("Disable cleaning and sequential cutoff"): + cache.set_cleaning_policy(cleaning_policy=CleaningPolicy.nop) + cache.set_seq_cutoff_policy(policy=SeqCutOffPolicy.never) + + with TestRun.step(f"Create {filesystem.name} filesystem on separate disk"): + separate_dev.create_filesystem(fs_type=filesystem) + + with TestRun.step("Mount separate disk"): + separate_dev.mount(mount_point=exported_object_mount_point_path) with TestRun.step("Create a test file on a separate disk"): - src_dir_path = "/mnt/flush_640G_test" - separate_dev.create_filesystem(fs) - separate_dev.mount(src_dir_path) + test_file_main = File.create_file(path=f"{exported_object_mount_point_path}/test_file_main") - test_file_main = File.create_file(f"{src_dir_path}/test_file_main") + with TestRun.step("Run I/O to separate disk test file"): fio = ( - Fio().create_command() + Fio() + .create_command() .io_engine(IoEngine.libaio) .read_write(ReadWrite.write) - .block_size(bs) + .block_size(Size(2, Unit.MebiByte)) .direct() .io_depth(256) .target(test_file_main.full_path) .size(file_size) ) fio.default_run_time = timedelta(hours=4) # timeout for non-time-based fio + fio.run() + + with TestRun.step("Validate test file and read its checksum"): test_file_main.refresh_item() - with TestRun.step("Validate test file and read its crc32 sum."): if test_file_main.size != file_size: - TestRun.LOGGER.error(f"Expected test file size {file_size}. Got {test_file_main.size}") + TestRun.LOGGER.error( + f"Expected test file size: {file_size}.\n" + f"Actual test file size: {test_file_main.size}" + ) + test_file_crc32sum_main = test_file_main.crc32sum(timeout=timedelta(hours=4)) - with TestRun.step("Write data to exported object."): + with TestRun.step("Write data to exported object"): test_file_copy = test_file_main.copy( - mnt_point + "test_file_copy", timeout=timedelta(hours=4) + separate_device_mount_point_path + "test_file_copy", timeout=timedelta(hours=4) ) test_file_copy.refresh_item() sync() - with TestRun.step(f"Check if dirty data exceeded {file_size * 0.98} GiB."): + with TestRun.step(f"Check if dirty data exceeded {file_size * 0.98} GiB"): minimum_4KiB_blocks = int((file_size * 0.98).get_value(Unit.Blocks4096)) actual_dirty_blocks = int(cache.get_statistics().usage_stats.dirty) + if actual_dirty_blocks < minimum_4KiB_blocks: TestRun.LOGGER.error( - f"Expected at least: {minimum_4KiB_blocks} dirty blocks." - f"Got {actual_dirty_blocks}" + f"Expected at least: {minimum_4KiB_blocks} dirty blocks.\n" + f"Actual dirty blocks: {actual_dirty_blocks}" ) - with TestRun.step("Unmount core and stop cache with flush."): + with TestRun.step("Unmount core and stop cache with flush"): core.unmount() + # this operation could take a few hours, depending on the core disk output = TestRun.executor.run(stop_cmd(str(cache.cache_id)), timedelta(hours=12)) if output.exit_code != 0: TestRun.fail(f"Stopping cache with flush failed!\n{output.stderr}") - with TestRun.step("Mount core device and check crc32 sum of test file copy."): - core_dev.mount(mnt_point) - if test_file_crc32sum_main != test_file_copy.crc32sum(timeout=timedelta(hours=4)): - TestRun.LOGGER.error("Md5 sums should be equal.") - - with TestRun.step("Delete test files."): - test_file_main.remove(True) - test_file_copy.remove(True) + with TestRun.step("Mount core device and check crc32 sum of test file copy"): + core_dev.mount(separate_device_mount_point_path) - with TestRun.step("Unmount core device."): - core_dev.unmount() - remove(mnt_point, True, True, True) - - with TestRun.step("Unmount the additional device."): - separate_dev.unmount() - remove(src_dir_path, True, True, True) + if test_file_crc32sum_main != test_file_copy.crc32sum(timeout=timedelta(hours=4)): + TestRun.fail("Crc32 sums should be equal.") @pytest.mark.parametrizex("cache_mode", CacheMode.with_traits(CacheModeTrait.LazyWrites)) @@ -135,44 +151,50 @@ def test_flush_over_640_gibibytes_with_fs(cache_mode, fs): @pytest.mark.require_disk("core", DiskTypeLowerThan("cache")) def test_flush_over_640_gibibytes_raw_device(cache_mode): """ - title: Test of the ability to flush huge amount of dirty data on raw device. - description: | - Flush cache when amount of dirty data in cache exceeds 640 GiB. - pass_criteria: - - Flushing completes successfully without any errors. + title: Test of the ability to flush huge amount of dirty data on raw device. + description: | + Flush cache when amount of dirty data in cache exceeds 640 GiB. + pass_criteria: + - Flushing completes successfully without any errors. """ - with TestRun.step("Prepare devices for cache and core."): - cache_dev = TestRun.disks['cache'] + + with TestRun.step("Prepare devices for cache and core"): + cache_dev = TestRun.disks["cache"] + core_dev = TestRun.disks["core"] + check_disk_size(cache_dev) + check_disk_size(core_dev) + cache_dev.create_partitions([required_disk_size]) cache_part = cache_dev.partitions[0] - core_dev = TestRun.disks['core'] - check_disk_size(core_dev) + + with TestRun.step("Disable udev"): Udev.disable() - with TestRun.step(f"Start cache in {cache_mode} mode."): - cache = casadm.start_cache(cache_part, cache_mode) + with TestRun.step(f"Start cache in {cache_mode} mode"): + cache = casadm.start_cache(cache_dev=cache_part, cache_mode=cache_mode) - with TestRun.step(f"Add core to cache."): - core = cache.add_core(core_dev) + with TestRun.step("Add core to cache"): + core = cache.add_core(core_dev=core_dev) - with TestRun.step("Disable cleaning and sequential cutoff."): - cache.set_cleaning_policy(CleaningPolicy.nop) - cache.set_seq_cutoff_policy(SeqCutOffPolicy.never) + with TestRun.step("Disable cleaning and sequential cutoff"): + cache.set_cleaning_policy(cleaning_policy=CleaningPolicy.nop) + cache.set_seq_cutoff_policy(policy=SeqCutOffPolicy.never) - with TestRun.step("Create test file"): + with TestRun.step("Run I/O to separate disk test file"): fio = ( Fio() .create_command() .io_engine(IoEngine.libaio) .read_write(ReadWrite.write) - .block_size(bs) + .block_size(Size(2, Unit.MebiByte)) .direct() .io_depth(256) .target(core) .size(file_size) ) fio.default_run_time = timedelta(hours=4) # timeout for non-time-based fio + fio.run() with TestRun.step(f"Check if dirty data exceeded {file_size * 0.98} GiB."): From 2400ba8fa3a38e212bf6eaa6a0f37c650df7f7eb Mon Sep 17 00:00:00 2001 From: Kamil Gierszewski Date: Thu, 10 Apr 2025 12:13:29 +0200 Subject: [PATCH 4/5] tests: rename + refactor test Signed-off-by: Kamil Gierszewski --- .../tests/stress/test_stress_attach_detach.py | 54 ------------------- .../stress/test_stress_attach_detach_core.py | 52 ++++++++++++++++++ 2 files changed, 52 insertions(+), 54 deletions(-) delete mode 100644 test/functional/tests/stress/test_stress_attach_detach.py create mode 100644 test/functional/tests/stress/test_stress_attach_detach_core.py diff --git a/test/functional/tests/stress/test_stress_attach_detach.py b/test/functional/tests/stress/test_stress_attach_detach.py deleted file mode 100644 index 8b5492bbb..000000000 --- a/test/functional/tests/stress/test_stress_attach_detach.py +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright(c) 2020-2021 Intel Corporation -# Copyright(c) 2024 Huawei Technologies Co., Ltd. -# SPDX-License-Identifier: BSD-3-Clause -# - -import pytest -import random - -from api.cas import casadm -from core.test_run import TestRun -from storage_devices.disk import DiskTypeSet, DiskType, DiskTypeLowerThan -from type_def.size import Size, Unit - - -@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand])) -@pytest.mark.require_disk("core", DiskTypeLowerThan("cache")) -def test_stress_attach_detach(): - """ - title: Stress test for attaching and detaching multiple core devices. - description: | - Validate the ability of CAS to attach and detach core devices using script commands. - pass_criteria: - - No system crash. - - Core devices are successfully attached and detached. - """ - iterations_number = 50 - - with TestRun.step("Prepare devices."): - cache_disk = TestRun.disks['cache'] - cache_disk.create_partitions([Size(100, Unit.MebiByte)]) - cache_part = cache_disk.partitions[0] - - core_disk = TestRun.disks['core'] - core_disk.create_partitions([Size(5, Unit.GibiByte)] * 8) - core_devices = core_disk.partitions - - with TestRun.step("Start cache."): - cache = casadm.start_cache(cache_part) - cores = [] - for dev in core_devices: - cores.append(cache.add_core(dev)) - - with TestRun.step("Attach and detach core devices in a loop."): - for _ in TestRun.iteration(range(0, iterations_number)): - TestRun.LOGGER.info("Detaching all core devices.") - for core in cores: - casadm.detach_core(cache.cache_id, core.core_id) - - random.shuffle(cores) - - TestRun.LOGGER.info("Attaching all core devices.") - for core in cores: - casadm.try_add(core.core_device, cache.cache_id, core.core_id) diff --git a/test/functional/tests/stress/test_stress_attach_detach_core.py b/test/functional/tests/stress/test_stress_attach_detach_core.py new file mode 100644 index 000000000..10f4f7485 --- /dev/null +++ b/test/functional/tests/stress/test_stress_attach_detach_core.py @@ -0,0 +1,52 @@ +# +# Copyright(c) 2020-2021 Intel Corporation +# Copyright(c) 2024-2025 Huawei Technologies Co., Ltd. +# SPDX-License-Identifier: BSD-3-Clause +# + +import pytest +import random + +from api.cas import casadm +from core.test_run import TestRun +from storage_devices.disk import DiskTypeSet, DiskType, DiskTypeLowerThan +from type_def.size import Size, Unit + + +@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand])) +@pytest.mark.require_disk("core", DiskTypeLowerThan("cache")) +def test_stress_attach_detach_core(): + """ + title: Stress test for attaching and detaching multiple core devices. + description: | + Validate the ability of CAS to attach and detach core devices using script commands. + pass_criteria: + - No system crash. + - Core devices are successfully attached and detached. + """ + iterations_number = 50 + + with TestRun.step("Prepare devices"): + cache_disk = TestRun.disks["cache"] + core_disk = TestRun.disks["core"] + + cache_disk.create_partitions([Size(100, Unit.MebiByte)]) + core_disk.create_partitions([Size(5, Unit.GibiByte)] * 5) + + cache_part = cache_disk.partitions[0] + core_part_list = core_disk.partitions + + with TestRun.step("Start cache and add cores"): + cache = casadm.start_cache(cache_part) + cores = [cache.add_core(core_part) for core_part in core_part_list] + + for _ in TestRun.iteration(range(0, iterations_number)): + with TestRun.step("Detach all core devices in random order"): + random.shuffle(cores) + for core in cores: + casadm.detach_core(cache.cache_id, core.core_id) + + with TestRun.step("Attach all core devices in random order"): + random.shuffle(cores) + for core in cores: + casadm.try_add(core.core_device, cache.cache_id, core.core_id) From 237e25d9a948750c39c5f5465c11e26d17f20d90 Mon Sep 17 00:00:00 2001 From: Kamil Gierszewski Date: Thu, 10 Apr 2025 06:30:14 +0200 Subject: [PATCH 5/5] tests: refactor io_class_pinning test Signed-off-by: Kamil Gierszewski --- .../tests/io_class/test_io_class_pinning_eviction.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/functional/tests/io_class/test_io_class_pinning_eviction.py b/test/functional/tests/io_class/test_io_class_pinning_eviction.py index d44a0e0f2..58028bf6b 100644 --- a/test/functional/tests/io_class/test_io_class_pinning_eviction.py +++ b/test/functional/tests/io_class/test_io_class_pinning_eviction.py @@ -1,6 +1,6 @@ # # Copyright(c) 2022 Intel Corporation -# Copyright(c) 2024-2025 Huawei Technologies +# Copyright(c) 2024-2025 Huawei Technologies Co., Ltd. # SPDX-License-Identifier: BSD-3-Clause # @@ -9,6 +9,7 @@ from collections import namedtuple from math import isclose +from api.cas.casadm_params import StatsFilter from storage_devices.disk import DiskType, DiskTypeSet, DiskTypeLowerThan from api.cas.ioclass_config import IoClass, default_config_file_path from test_tools.fs_tools import Filesystem, create_directory @@ -142,6 +143,7 @@ def test_pinned_ioclasses_eviction(): with TestRun.step("Prepare devices"): cache, core = prepare(core_size=core_size, cache_size=cache_size) cache_line_count = cache.get_statistics().config_stats.cache_size + cache_free_block = cache.get_statistics(stat_filter=[StatsFilter.usage]).usage_stats.free with TestRun.step("Mount filesystem"): core.create_filesystem(Filesystem.xfs) @@ -190,7 +192,7 @@ def test_pinned_ioclasses_eviction(): with TestRun.step(f"Trigger IO to first pinned class directory"): run_io_dir( f"{io_classes[0].dir_path}/tmp_file", - int((io_classes[0].max_occupancy * cache_size) / Unit.Blocks4096), + int(io_classes[0].max_occupancy * cache_free_block.get_value(Unit.Blocks4096)), ) first_io_pinned_occupancy = get_io_class_occupancy(cache, io_classes[0].id)