def test_surprise_shutdown_stop_cache(pyocf_ctx):
    core_device = RamVolume(S.from_MiB(10))
    error_triggered = True
    error_io_seq_no = 0
    io_offset = mngmt_op_surprise_shutdown_test_io_offset

    while error_triggered:
        # Start cache device without error injection
        error_io = {IoDir.WRITE: error_io_seq_no}
        device = ErrorDevice(
            mngmt_op_surprise_shutdown_test_cache_size, error_seq_no=error_io, armed=False
        )

        # setup cache and insert some data
        cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
        core = Core(device=core_device)
        cache.add_core(core)
        vol = CoreVolume(core, open=True)
        ocf_write(vol, cache.get_default_queue(), 0xAA, io_offset)

        # start error injection
        device.arm()

        try:
            cache.stop()
            status = OcfErrorCode.OCF_OK
        except OcfError as ex:
            status = ex.error_code

        # if error was injected we expect mngmt op error
        error_triggered = device.error_triggered()
        if error_triggered:
            assert status == OcfErrorCode.OCF_ERR_WRITE_CACHE
        else:
            assert status == 0

        if not error_triggered:
            break

        # disable error injection and load the cache
        device.disarm()
        cache = None

        assert core_device.get_bytes()[io_offset] == VOLUME_POISON

        cache = Cache.load_from_device(device, open_cores=False)
        stats = cache.get_stats()
        if stats["conf"]["core_count"] == 1:
            assert stats["usage"]["occupancy"]["value"] == 1
            core = Core(device=core_device)
            cache.add_core(core, try_add=True)
            vol = CoreVolume(core, open=True)
            assert ocf_read(vol, cache.get_default_queue(), io_offset) == 0xAA

        cache.stop()

        # advance error injection point
        error_io_seq_no += 1
def test_surprise_shutdown_cache_reinit(pyocf_ctx):
    core_device = RamVolume(S.from_MiB(10))

    error_io = {IoDir.WRITE: 0}

    io_offset = mngmt_op_surprise_shutdown_test_io_offset

    error_triggered = True
    while error_triggered:
        # Start cache device without error injection
        device = ErrorDevice(
            mngmt_op_surprise_shutdown_test_cache_size, error_seq_no=error_io, armed=False
        )

        # start WB
        cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
        core = Core(device=core_device)
        cache.add_core(core)
        vol = CoreVolume(core, open=True)
        queue = cache.get_default_queue()

        # insert dirty cacheline
        ocf_write(vol, queue, 0xAA, io_offset)

        cache.stop()

        assert core_device.get_bytes()[io_offset] == VOLUME_POISON

        # start error injection
        device.arm()

        # power failure during cache re-initialization
        try:
            # sets force = True by default
            cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
            status = OcfErrorCode.OCF_OK
        except OcfError as ex:
            status = ex.error_code
            cache = None

        error_triggered = device.error_triggered()
        assert error_triggered == (status == OcfErrorCode.OCF_ERR_WRITE_CACHE)

        if cache:
            with pytest.raises(OcfError) as ex:
                cache.stop()
            assert ex.value.error_code == OcfErrorCode.OCF_ERR_WRITE_CACHE

        device.disarm()

        cache = None
        status = OcfErrorCode.OCF_OK
        try:
            cache = Cache.load_from_device(device)
        except OcfError as ex:
            status = ex.error_code

        if not cache:
            assert status == OcfErrorCode.OCF_ERR_NO_METADATA
        else:
            stats = cache.get_stats()
            if stats["conf"]["core_count"] == 0:
                assert stats["usage"]["occupancy"]["value"] == 0
                cache.add_core(core)
                vol = CoreVolume(core, open=True)
                assert ocf_read(vol, cache.get_default_queue(), io_offset) == VOLUME_POISON

            cache.stop()

        error_io[IoDir.WRITE] += 1