def test_simple_wt_write(pyocf_ctx): cache_device = Volume(S.from_MiB(100)) core_device = Volume(S.from_MiB(200)) cache = Cache.start_on_device(cache_device) core = Core.using_device(core_device) queue = Queue(cache) cache.add_core(core) cache_device.reset_stats() core_device.reset_stats() write_data = Data.from_string("This is test data") io = core.new_io() io.set_data(write_data) io.configure(20, write_data.size, IoDir.WRITE, 0, 0) io.set_queue(queue) io.submit() assert cache_device.get_stats()[IoDir.WRITE] == 1 stats = cache.get_stats() assert stats["req"]["wr_full_misses"]["value"] == 1 assert stats["usage"]["occupancy"]["value"] == 1 assert core.exp_obj_md5() == core_device.md5()
def test_neg_core_set_seq_cut_off_policy(pyocf_ctx, cm, cls): """ Test whether it is possible to change core seq cut-off policy to invalid value :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with :return: """ # Start cache device cache_device = Volume(S.from_MiB(30)) cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls) # Create core device core_device = Volume(S.from_MiB(10)) core = Core.using_device(core_device) # Add core cache.add_core(core) # Change core seq cut off policy to invalid one and check if failed for i in RandomGenerator(DefaultRanges.UINT32): if i in [item.value for item in SeqCutOffPolicy]: continue with pytest.raises(OcfError, match="Error setting core seq cut off policy"): core.set_seq_cut_off_policy(i) print(f"\n{i}")
def test_start_write_first_and_check_mode(pyocf_ctx, mode: CacheMode, cls: CacheLineSize): """Test starting cache in different modes with different cache line sizes. After start check proper cache mode behaviour, starting with write operation. """ cache_device = Volume(Size.from_MiB(40)) core_device = Volume(Size.from_MiB(10)) cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) core_exported = Core.using_device(core_device) cache.add_core(core_exported) logger.info("[STAGE] Initial write to exported object") cache_device.reset_stats() core_device.reset_stats() test_data = Data.from_string("This is test data") io_to_core(core_exported, test_data, Size.from_sector(1).B) check_stats_write_empty(core_exported, mode, cls) logger.info("[STAGE] Read from exported object after initial write") io_from_exported_object(core_exported, test_data.size, Size.from_sector(1).B) check_stats_read_after_write(core_exported, mode, cls, True) logger.info("[STAGE] Write to exported object after read") cache_device.reset_stats() core_device.reset_stats() test_data = Data.from_string("Changed test data") io_to_core(core_exported, test_data, Size.from_sector(1).B) check_stats_write_after_read(core_exported, mode, cls) check_md5_sums(core_exported, mode)
def test_add_remove_30core(pyocf_ctx): # Start cache device cache_device = Volume(S.from_MiB(30)) cache = Cache.start_on_device(cache_device) core_devices = [] core_amount = 30 # Add 50 cores and check stats after each addition for i in range(0, core_amount): stats = cache.get_stats() assert stats["conf"]["core_count"] == i core_device = Volume(S.from_MiB(10)) core = Core.using_device(core_device) core_devices.append(core) cache.add_core(core) # Remove 50 cores and check stats before each removal for i in range(0, core_amount): stats = cache.get_stats() assert stats["conf"]["core_count"] == core_amount - i cache.remove_core(core_devices[i]) # Check statistics stats = cache.get_stats() assert stats["conf"]["core_count"] == 0
def test_adding_core_already_used(pyocf_ctx, cache_mode, cls): # Start first cache device cache_device1 = Volume(S.from_MiB(30)) cache1 = Cache.start_on_device(cache_device1, cache_mode=cache_mode, cache_line_size=cls) # Start second cache device cache_device2 = Volume(S.from_MiB(30)) cache2 = Cache.start_on_device(cache_device2, cache_mode=cache_mode, cache_line_size=cls) # Create core device core_device = Volume(S.from_MiB(10)) core = Core.using_device(core_device) # Add core to first cache cache1.add_core(core) # Check that it is not possible to add core to second cache with pytest.raises(OcfError): cache2.add_core(core) # Check that core count is as expected stats = cache1.get_stats() assert stats["conf"]["core_count"] == 1 stats = cache2.get_stats() assert stats["conf"]["core_count"] == 0
def test_adding_to_random_cache(pyocf_ctx): cache_devices = [] core_devices = {} cache_amount = 5 core_amount = 30 # Create 5 cache devices for i in range(0, cache_amount): cache_device = Volume(S.from_MiB(30)) cache = Cache.start_on_device(cache_device) cache_devices.append(cache) # Create 50 core devices and add to random cache for i in range(0, core_amount): core_device = Volume(S.from_MiB(10)) core = Core.using_device(core_device) core_devices[core] = randint(0, cache_amount - 1) cache_devices[core_devices[core]].add_core(core) # Count expected number of cores per cache count_dict = {} for i in range(0, cache_amount): count_dict[i] = sum(k == i for k in core_devices.values()) # Check if cache statistics are as expected for i in range(0, cache_amount): stats = cache_devices[i].get_stats() assert stats["conf"]["core_count"] == count_dict[i]
def test_neg_cache_set_seq_cut_off_threshold(pyocf_ctx, cm, cls): """ Test whether it is possible to change cache seq cut-off threshold to invalid value :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with :return: """ # Start cache device cache_device = Volume(S.from_MiB(30)) cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls) # Create 2 core devices core_device1 = Volume(S.from_MiB(10)) core1 = Core.using_device(core_device1, name="core1") core_device2 = Volume(S.from_MiB(10)) core2 = Core.using_device(core_device2, name="core2") # Add cores cache.add_core(core1) cache.add_core(core2) # Change cache seq cut off policy to invalid one and check if failed for i in RandomGenerator(DefaultRanges.UINT32): if i in ConfValidValues.seq_cutoff_threshold_rage: continue with pytest.raises( OcfError, match="Error setting cache seq cut off policy threshold"): cache.set_seq_cut_off_threshold(i) print(f"\n{i}")
def test_eviction_two_cores(pyocf_ctx, mode: CacheMode, cls: CacheLineSize): """Test if eviction works correctly when remapping cachelines between distinct cores.""" cache_device = Volume(Size.from_MiB(20)) core_device1 = Volume(Size.from_MiB(40)) core_device2 = Volume(Size.from_MiB(40)) cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER) cache_size = cache.get_stats()["conf"]["size"] core_exported1 = Core.using_device(core_device1, name="core1") core_exported2 = Core.using_device(core_device2, name="core2") cache.add_core(core_exported1) cache.add_core(core_exported2) valid_io_size = Size.from_B(cache_size.B) test_data = Data(valid_io_size) send_io(core_exported1, test_data) send_io(core_exported2, test_data) stats1 = core_exported1.get_stats() stats2 = core_exported2.get_stats() # IO to the second core should evict all the data from the first core assert stats1["usage"]["occupancy"]["value"] == 0 assert stats2["usage"]["occupancy"]["value"] == valid_io_size.blocks_4k
def test_10add_remove_with_io(pyocf_ctx): # Start cache device cache_device = Volume(S.from_MiB(30)) cache = Cache.start_on_device(cache_device) # Create core device core_device = Volume(S.from_MiB(10)) core = Core.using_device(core_device) # Add and remove core 10 times in a loop with io in between for i in range(0, 10): cache.add_core(core) stats = cache.get_stats() assert stats["conf"]["core_count"] == 1 write_data = Data.from_string("Test data") io = core.new_io() io.set_data(write_data) io.configure(20, write_data.size, IoDir.WRITE, 0, 0) io.set_queue(cache.get_default_queue()) cmpl = OcfCompletion([("err", c_int)]) io.callback = cmpl.callback io.submit() cmpl.wait() cache.remove_core(core) stats = cache.get_stats() assert stats["conf"]["core_count"] == 0
def test_cache_change_seq_cut_off_policy(pyocf_ctx, cm, cls): # Start cache device cache_device = Volume(S.from_MiB(30)) cache = Cache.start_on_device( cache_device, cache_mode=cm, cache_line_size=cls ) # Create 2 core devices core_device1 = Volume(S.from_MiB(10)) core1 = Core.using_device(core_device1, name="core1") core_device2 = Volume(S.from_MiB(10)) core2 = Core.using_device(core_device2, name="core2") # Add cores cache.add_core(core1) cache.add_core(core2) # Check all possible seq cut off policy switches for seq_from in SeqCutOffPolicy: for seq_to in SeqCutOffPolicy: cache.set_seq_cut_off_policy(seq_from.value) # Check if seq cut off policy is correct stats = core1.get_stats() assert stats["seq_cutoff_policy"] == seq_from.value stats = core2.get_stats() assert stats["seq_cutoff_policy"] == seq_from.value cache.set_seq_cut_off_policy(seq_to.value) # Check if seq cut off policy is correct stats = core1.get_stats() assert stats["seq_cutoff_policy"] == seq_to.value stats = core2.get_stats() assert stats["seq_cutoff_policy"] == seq_to.value
def test_surprise_shutdown_swap_core(pyocf_ctx): core_device_1 = RamVolume(S.from_MiB(10), uuid="dev1") core_device_2 = RamVolume(S.from_MiB(10), uuid="dev2") core1 = Core.using_device(core_device_1, name="core1") core2 = Core.using_device(core_device_2, name="core2") def prepare(cache): cache.add_core(core1) cache.save() cache.remove_core(core1) cache.save() def tested_func(cache): cache.add_core(core2) def check_func(cache, error_triggered): stats = cache.get_stats() assert stats["conf"]["core_count"] == (0 if error_triggered else 1) with pytest.raises(OcfError): core1 = cache.get_core_by_name("core1") if error_triggered: with pytest.raises(OcfError): core2 = cache.get_core_by_name("core2") else: core2 = cache.get_core_by_name("core2") assert core2.device.uuid == "dev2" mngmt_op_surprise_shutdown_test(pyocf_ctx, tested_func, prepare, check_func)
def test_stop(pyocf_ctx, mode: CacheMode, cls: CacheLineSize, with_flush: bool): """Stopping cache. Check if cache is stopped properly in different modes with or without preceding flush operation. """ cache_device = Volume(Size.from_MiB(20)) core_device = Volume(Size.from_MiB(5)) cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) core_exported = Core.using_device(core_device) cache.add_core(core_exported) cls_no = 10 run_io_and_cache_data_if_possible(core_exported, mode, cls, cls_no) stats = cache.get_stats() assert int(stats["conf"]["dirty"]) == (cls_no if mode.lazy_write() else 0),\ "Dirty data before MD5" md5_exported_core = core_exported.exp_obj_md5() if with_flush: cache.flush() cache.stop() if mode.lazy_write() and not with_flush: assert core_device.md5() != md5_exported_core, \ "MD5 check: core device vs exported object with dirty data" else: assert core_device.md5() == md5_exported_core, \ "MD5 check: core device vs exported object with clean data"
def test_simple_wt_write(pyocf_ctx): cache_device = Volume(S.from_MiB(30)) core_device = Volume(S.from_MiB(30)) cache = Cache.start_on_device(cache_device) core = Core.using_device(core_device) cache.add_core(core) cache_device.reset_stats() core_device.reset_stats() write_data = Data.from_string("This is test data") io = core.new_io(cache.get_default_queue(), S.from_sector(1).B, write_data.size, IoDir.WRITE, 0, 0) io.set_data(write_data) cmpl = OcfCompletion([("err", c_int)]) io.callback = cmpl.callback io.submit() cmpl.wait() assert cmpl.results["err"] == 0 assert cache_device.get_stats()[IoDir.WRITE] == 1 stats = cache.get_stats() assert stats["req"]["wr_full_misses"]["value"] == 1 assert stats["usage"]["occupancy"]["value"] == 1 assert core.exp_obj_md5() == core_device.md5() cache.stop()
def test_load_with_changed_core_size(pyocf_ctx, cache_mode, cls): """ Test changing volume size before load :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with """ # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=cache_mode, cache_line_size=cls) # Add core to cache core_device = RamVolume(S.from_MiB(10)) core = Core.using_device(core_device) cache.add_core(core) # Stop cache cache.stop() # Change core device size core_device.resize(S.from_MiB(12)) # Load cache with changed core size with pytest.raises(OcfError, match="OCF_ERR_CORE_SIZE_MISMATCH"): cache = Cache.load_from_device(cache_device)
def test_partial_hit_promotion(pyocf_ctx): """ Check if NHIT promotion policy doesn't prevent partial hits from getting promoted to cache 1. Create core/cache pair with promotion policy ALWAYS 2. Issue one-sector IO to cache to insert partially valid cache line 3. Set NHIT promotion policy with trigger=0 (always triggered) and high insertion threshold 4. Issue a request containing partially valid cache line and next cache line * occupancy should rise - partially hit request should bypass nhit criteria """ # Step 1 cache_device = Volume(Size.from_MiB(30)) core_device = Volume(Size.from_MiB(30)) cache = Cache.start_on_device(cache_device) core = Core.using_device(core_device) cache.add_core(core) # Step 2 comp = OcfCompletion([("error", c_int)]) write_data = Data(Size.from_sector(1)) io = core.new_io(cache.get_default_queue(), 0, write_data.size, IoDir.READ, 0, 0) io.set_data(write_data) io.callback = comp.callback io.submit() comp.wait() stats = cache.get_stats() cache_lines = stats["conf"]["size"] assert stats["usage"]["occupancy"]["value"] == 1 # Step 3 cache.set_promotion_policy(PromotionPolicy.NHIT) cache.set_promotion_policy_param( PromotionPolicy.NHIT, NhitParams.TRIGGER_THRESHOLD, 0 ) cache.set_promotion_policy_param( PromotionPolicy.NHIT, NhitParams.INSERTION_THRESHOLD, 100 ) # Step 4 comp = OcfCompletion([("error", c_int)]) write_data = Data(2 * cache_lines.line_size) io = core.new_io(cache.get_default_queue(), 0, write_data.size, IoDir.WRITE, 0, 0) io.set_data(write_data) io.callback = comp.callback io.submit() comp.wait() stats = cache.get_stats() assert ( stats["usage"]["occupancy"]["value"] == 2 ), "Second cache line should be mapped"
def test_io_flags(pyocf_ctx, cache_mode): """ Verify that I/O flags provided at the top volume interface are propagated down to bottom volumes for all associated I/Os (including metadata writes to cache volume). """ flags = 0x239482 block_size = 4096 data = bytes(block_size) cache_device = FlagsValVolume(Size.from_MiB(50), flags) core_device = FlagsValVolume(Size.from_MiB(50), flags) cache = Cache.start_on_device(cache_device, cache_mode=cache_mode) core = Core.using_device(core_device) cache.add_core(core) vol = CoreVolume(core, open=True) cache_device.set_check(True) core_device.set_check(True) # write miss io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.WRITE, flags) assert not cache_device.fail assert not core_device.fail # read miss io_to_exp_obj(core, block_size * 1, block_size, data, 0, IoDir.READ, flags) assert not cache_device.fail assert not core_device.fail # "dirty" read hit io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.READ, flags) assert not cache_device.fail assert not core_device.fail # "clean" read hit io_to_exp_obj(core, block_size * 1, block_size, data, 0, IoDir.READ, flags) assert not cache_device.fail assert not core_device.fail # "dirty" write hit io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.WRITE, flags) assert not cache_device.fail assert not core_device.fail # "clean" write hit io_to_exp_obj(core, block_size * 1, block_size, data, 0, IoDir.WRITE, flags) assert not cache_device.fail assert not core_device.fail
def test_adding_core_twice(pyocf_ctx): cache_device = Volume(S.from_MiB(200)) core_device = Volume(S.from_MiB(400)) cache = Cache.start_on_device(cache_device) core = Core.using_device(core_device) cache.add_core(core) with pytest.raises(OcfError): cache.add_core(core)
def test_write_size_greater_than_cache(pyocf_ctx, mode: CacheMode, cls: CacheLineSize): """Test if eviction does not occur when IO greater than cache size is submitted. """ cache_device = Volume(Size.from_MiB(20)) core_device = Volume(Size.from_MiB(5)) cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) cache_size = cache.get_stats()['conf']['size'] core_exported = Core.using_device(core_device) cache.add_core(core_exported) cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER) valid_io_size = Size.from_B(cache_size.B // 2) test_data = Data(valid_io_size) send_io(core_exported, test_data) stats = core_exported.cache.get_stats() first_block_sts = stats['block'] first_usage_sts = stats['usage'] pt_writes_first = stats['req']['wr_pt'] assert stats["usage"]["occupancy"]["value"] == (valid_io_size.B / Size.from_KiB(4).B),\ "Occupancy after first IO" prev_writes_to_core = stats["block"]["core_volume_wr"]["value"] # Anything below 5 MiB is a valid size (less than core device size) # Writing over cache size (to the offset above first io) in this case should go # directly to core and shouldn't trigger eviction io_size_bigger_than_cache = Size.from_MiB(2) io_offset = valid_io_size test_data = Data(io_size_bigger_than_cache) send_io(core_exported, test_data, io_offset) if mode is not CacheMode.WT: # Flush first write cache.flush() stats = core_exported.cache.get_stats() second_block_sts = stats['block'] second_usage_sts = stats['usage'] pt_writes_second = stats['req']['wr_pt'] # Second write shouldn't affect cache and should go directly to core. # Cache occupancy shouldn't change # Second IO should go in PT assert first_usage_sts['occupancy'] == \ second_usage_sts['occupancy'] assert pt_writes_first['value'] == 0 assert pt_writes_second['value'] == 1 assert second_block_sts['cache_volume_wr'][ 'value'] == valid_io_size.blocks_4k assert second_block_sts['core_volume_wr']['value'] == valid_io_size.blocks_4k + \ io_size_bigger_than_cache.blocks_4k
def test_neg_size_unaligned(pyocf_ctx, c_uint16_randomize): """ Check that write operations are blocked when IO size is not aligned """ vol, queue = prepare_cache_and_core(Size.from_MiB(2)) data = Data(int(Size.from_B(c_uint16_randomize))) if c_uint16_randomize % 512 != 0: with pytest.raises(Exception): vol.new_io(queue, 0, data.size, IoDir.WRITE, 0, 0)
def test_adding_cores(pyocf_ctx): cache_device = Volume(S.from_MiB(200)) core1_device = Volume(S.from_MiB(400)) core2_device = Volume(S.from_MiB(400)) cache = Cache.start_on_device(cache_device) core1 = Core.using_device(core1_device) core2 = Core.using_device(core2_device) cache.add_core(core1) cache.add_core(core2)
def test_neg_offset_unaligned(pyocf_ctx, c_int_randomize): """ Check that write operations are blocked when IO offset is not aligned """ vol, queue = prepare_cache_and_core(Size.from_MiB(2)) vol = vol.get_front_volume() data = Data(int(Size.from_KiB(1))) if c_int_randomize % 512 != 0: with pytest.raises(Exception): vol.new_io(queue, c_int_randomize, data.size, IoDir.WRITE, 0, 0)
def test_neg_size_unaligned(pyocf_ctx, c_uint16_randomize): """ Check that write operations are blocked when IO size is not aligned """ core = prepare_cache_and_core(Size.from_MiB(2)) data = Data(int(Size.from_B(c_uint16_randomize))) if c_uint16_randomize % 512 != 0: with pytest.raises(Exception, match="Failed to create io!"): core.new_io(core.cache.get_default_queue(), 0, data.size, IoDir.WRITE, 0, 0)
def test_flush_after_mngmt(pyocf_ctx): """ Check whether underlying volumes volatile caches (VC) are flushed after management operation """ block_size = 4096 data = bytes(block_size) cache_device = FlushValVolume(Size.from_MiB(50)) core_device = FlushValVolume(Size.from_MiB(50)) # after start cache VC must be cleared cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WT) assert cache_device.flush_last # adding core must flush VC core = Core.using_device(core_device) cache.add_core(core) assert cache_device.flush_last vol = CoreVolume(core, open=True) queue = cache.get_default_queue() # WT I/O to write data to core and cache VC io_to_exp_obj(vol, queue, block_size * 0, block_size, data, 0, IoDir.WRITE, 0) # WB I/O to produce dirty cachelines in CAS cache.change_cache_mode(CacheMode.WB) io_to_exp_obj(vol, queue, block_size * 1, block_size, data, 0, IoDir.WRITE, 0) # after cache flush VCs are expected to be cleared cache.flush() assert cache_device.flush_last assert core_device.flush_last # I/O to write data to cache device VC io_to_exp_obj(vol, queue, block_size * 0, block_size, data, 0, IoDir.WRITE, 0) # cache save must flush VC cache.save() assert cache_device.flush_last # I/O to write data to cache device VC io_to_exp_obj(vol, queue, block_size * 0, block_size, data, 0, IoDir.WRITE, 0) # cache stop must flush VC cache.stop() assert cache_device.flush_last
def test_attach_different_size(pyocf_ctx, new_cache_size, mode: CacheMode, cls: CacheLineSize): """Start cache and add partition with limited occupancy. Fill partition with data, attach cache with different size and trigger IO. Verify if occupancy thresold is respected with both original and new cache device. """ cache_device = RamVolume(Size.from_MiB(100)) core_device = RamVolume(Size.from_MiB(100)) cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) core = Core.using_device(core_device) cache.add_core(core) vol = CoreVolume(core, open=True) queue = cache.get_default_queue() cache.configure_partition(part_id=1, name="test_part", max_size=50, priority=1) cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER) cache_size = cache.get_stats()["conf"]["size"] block_size = 4096 data = bytes(block_size) for i in range(cache_size.blocks_4k): io_to_exp_obj(vol, queue, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0) part_current_size = CacheLines( cache.get_partition_info(part_id=1)["_curr_size"], cls) assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5 cache.detach_device() new_cache_device = RamVolume(Size.from_MiB(new_cache_size)) cache.attach_device(new_cache_device, force=True) cache_size = cache.get_stats()["conf"]["size"] for i in range(cache_size.blocks_4k): io_to_exp_obj(vol, queue, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0) part_current_size = CacheLines( cache.get_partition_info(part_id=1)["_curr_size"], cls) assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5
def test_secure_erase_simple_io_cleaning(): """ Perform simple IO which will trigger WB cleaning. Track all the data from cleaner (locked) and make sure they are erased and unlocked after use. """ ctx = OcfCtx( OcfLib.getInstance(), b"Security tests ctx", DefaultLogger(LogLevel.WARN), DataCopyTracer, MetadataUpdater, Cleaner, ) ctx.register_volume_type(Volume) cache_device = Volume(S.from_MiB(30)) cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB) core_device = Volume(S.from_MiB(100)) core = Core.using_device(core_device) cache.add_core(core) cmpls = [] for i in range(10000): read_data = Data(S.from_KiB(120)) io = core.new_io() io.set_data(read_data) io.configure( (i * 1259) % int(core_device.size), read_data.size, IoDir.WRITE, 0, 0 ) io.set_queue(cache.get_default_queue()) cmpl = OcfCompletion([("err", c_int)]) io.callback = cmpl.callback cmpls.append(cmpl) io.submit() for c in cmpls: c.wait() stats = cache.get_stats() ctx.exit() assert ( len(DataCopyTracer.needs_erase) == 0 ), "Not all locked Data instances were secure erased!" assert ( len(DataCopyTracer.locked_instances) == 0 ), "Not all locked Data instances were unlocked!" assert (stats["usage"]["clean"]["value"]) > 0, "Cleaner didn't run!"
def test_neg_read_too_long_data(pyocf_ctx, c_uint16_randomize): """ Check if reading data larger than exported object size is properly blocked """ core = prepare_cache_and_core(Size.from_MiB(1)) data = Data(int(Size.from_KiB(c_uint16_randomize))) completion = io_operation(core, data, IoDir.READ) if c_uint16_randomize > 1024: assert completion.results["err"] != 0 else: assert completion.results["err"] == 0
def test_neg_io_class(pyocf_ctx, c_int_randomize): """ Check that IO operations are blocked when IO class number is not in allowed values {0, ..., 32} """ core = prepare_cache_and_core(Size.from_MiB(2)) data = Data(int(Size.from_MiB(1))) completion = io_operation(core, data, randrange(0, 2), io_class=c_int_randomize) if 0 <= c_int_randomize <= 32: assert completion.results["err"] == 0 else: assert completion.results["err"] != 0
def test_neg_io_direction(pyocf_ctx, c_int_randomize): """ Check that IO operations are not executed for unknown IO direction, that is when IO direction value is not in allowed values {0, 1} """ core = prepare_cache_and_core(Size.from_MiB(2)) data = Data(int(Size.from_MiB(1))) completion = io_operation(core, data, c_int_randomize) if c_int_randomize in [0, 1]: assert completion.results["err"] == 0 else: assert completion.results["err"] != 0
def test_neg_write_offset_outside_of_device(pyocf_ctx, c_int_randomize): """ Check that write operations are blocked when IO offset is located outside of device range """ core = prepare_cache_and_core(Size.from_MiB(2)) data = Data(int(Size.from_KiB(1))) completion = io_operation(core, data, IoDir.WRITE, offset=c_int_randomize) if 0 <= c_int_randomize <= int(Size.from_MiB(2)) - int(Size.from_KiB(1)): assert completion.results["err"] == 0 else: assert completion.results["err"] != 0
def test_neg_read_too_far(pyocf_ctx, c_uint16_randomize): """ Check if reading data which would normally fit on exported object is blocked when offset is set so that data is read beyond exported device end """ limited_size = c_uint16_randomize % (int(Size.from_KiB(4)) + 1) core = prepare_cache_and_core(Size.from_MiB(4)) data = Data(int(Size.from_KiB(limited_size))) completion = io_operation(core, data, IoDir.READ, offset=(Size.from_MiB(3))) if limited_size > 1024: assert completion.results["err"] != 0 else: assert completion.results["err"] == 0