pyocf: Update tests after the API changes

Signed-off-by: Robert Baldyga <robert.baldyga@huawei.com>
Signed-off-by: Michal Mielewczyk <michal.mielewczyk@huawei.com>
This commit is contained in:
Robert Baldyga 2023-10-13 21:52:47 +02:00 committed by Michal Mielewczyk
parent c5741df0ed
commit be0ad8fe20
3 changed files with 129 additions and 103 deletions

View File

@ -88,19 +88,13 @@ class VolumeOps(Structure):
class VolumeProperties(Structure):
_fields_ = [
("_name", c_char_p),
("_io_priv_size", c_uint32),
("_volume_priv_size", c_uint32),
("_caps", VolumeCaps),
("_io_ops", IoOps),
("_deinit", c_char_p),
("_ops_", VolumeOps),
]
class VolumeIoPriv(Structure):
_fields_ = [("_data", c_void_p), ("_offset", c_uint64)]
VOLUME_POISON = 0x13
@ -243,11 +237,9 @@ class Volume:
Volume._props_[cls] = VolumeProperties(
_name=str(cls.__name__).encode("ascii"),
_io_priv_size=sizeof(VolumeIoPriv),
_volume_priv_size=0,
_caps=VolumeCaps(_atomic_writes=0),
_ops_=cls.get_ops(),
_io_ops=cls.get_io_ops(),
_deinit=0,
)
return Volume._props_[cls]
@ -267,22 +259,6 @@ class Volume:
def get_by_uuid(cls, uuid):
return cls._uuid_[uuid]
@staticmethod
@IoOps.SET_DATA
def _io_set_data(io, data, offset):
io_priv = cast(OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv))
data = Data.get_instance(data)
io_priv.contents._offset = offset
io_priv.contents._data = data.handle
return 0
@staticmethod
@IoOps.GET_DATA
def _io_get_data(io):
io_priv = cast(OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv))
return io_priv.contents._data
def __init__(self, uuid=None):
if uuid:
if uuid in type(self)._uuid_:
@ -499,8 +475,7 @@ class RamVolume(Volume):
return
try:
io_priv = cast(OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv))
offset = io_priv.contents._offset
offset = OcfLib.getInstance().ocf_io_get_offset(io)
if io.contents._dir == IoDir.WRITE:
src_ptr = cast(OcfLib.getInstance().ocf_io_get_data(io), c_void_p)
@ -512,7 +487,6 @@ class RamVolume(Volume):
src = self.data_ptr + io.contents._addr
memmove(dst, src, io.contents._bytes)
io_priv.contents._offset += io.contents._bytes
io.contents._end(io, 0)
except: # noqa E722
@ -597,7 +571,6 @@ class ErrorDevice(Volume):
def should_forward_io(self, rw, addr):
if not self.armed:
return True
direction = IoDir(rw)
seq_no_match = (
self.error_seq_no[direction] >= 0
@ -633,7 +606,7 @@ class ErrorDevice(Volume):
else:
self.complete_submit_with_error(io)
def complete_forward_with_error(self, token, rw):
def complete_forward_with_error(self, token, rw=IoDir.WRITE):
self.error = True
direction = IoDir(rw)
self.stats["errors"][direction] += 1
@ -646,16 +619,16 @@ class ErrorDevice(Volume):
self.complete_forward_with_error(token, rw)
def do_forward_flush(self, token):
if self.data_only or self.should_forward_io(0, 0):
if self.data_only or self.should_forward_io(IoDir.WRITE, 0):
self.vol.do_forward_flush(token)
else:
self.complete_forward_with_error(token, rw)
self.complete_forward_with_error(token)
def do_forward_discard(self, token, addr, nbytes):
if self.data_only or self.should_forward_io(0, addr):
if self.data_only or self.should_forward_io(IoDir.WRITE, addr):
self.vol.do_forward_discard(token, addr, nbytes)
else:
self.complete_forward_with_error(token, rw)
self.complete_forward_with_error(token)
def arm(self):
self.armed = True
@ -812,7 +785,7 @@ class TraceDevice(Volume):
lib = OcfLib.getInstance()
lib.ocf_io_get_priv.restype = POINTER(VolumeIoPriv)
lib.ocf_io_get_offset.restype = c_uint32
lib.ocf_io_get_volume.argtypes = [c_void_p]
lib.ocf_io_get_volume.restype = c_void_p
lib.ocf_io_get_data.argtypes = [c_void_p]

View File

@ -4,10 +4,7 @@
# SPDX-License-Identifier: BSD-3-Clause
#
from ctypes import c_int, memmove, cast, c_void_p
from enum import IntEnum
from itertools import product
import random
from ctypes import memmove, cast, c_void_p, c_uint64
import pytest
@ -18,6 +15,7 @@ from pyocf.types.volume_core import CoreVolume
from pyocf.types.data import Data
from pyocf.types.io import IoDir, Sync
from pyocf.utils import Size
from pyocf.ocf import OcfLib
def __io(io, data):
@ -48,19 +46,19 @@ class FlagsValVolume(RamVolume):
self.fail = False
super().__init__(size)
def set_check(self, check):
self.check = check
def submit_io(self, io):
if self.check:
flags = io.contents._flags
if flags != self.flags:
def set_check(self):
self.check = True
self.fail = True
super().submit_io(io)
def do_forward_io(self, token, rw, addr, nbytes, offset):
if self.check:
flags = lib.ocf_forward_get_flags(token)
if flags == self.flags:
self.fail = False
super().do_forward_io(token, rw, addr, nbytes, offset)
@pytest.mark.parametrize("cache_mode", CacheMode)
def test_io_flags(pyocf_ctx, cache_mode):
def test_io_flags(pyocf_ctx):
"""
Verify that I/O flags provided at the top volume interface
are propagated down to bottom volumes for all associated
@ -74,44 +72,54 @@ def test_io_flags(pyocf_ctx, cache_mode):
pyocf_ctx.register_volume_type(FlagsValVolume)
cache_device = FlagsValVolume(Size.from_MiB(50), flags)
cache_device = FlagsValVolume(Size.from_MiB(50), 0)
core_device = FlagsValVolume(Size.from_MiB(50), flags)
cache = Cache.start_on_device(cache_device, cache_mode=cache_mode)
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
core = Core.using_device(core_device)
cache.add_core(core)
vol = CoreVolume(core)
cache_device.set_check(True)
core_device.set_check(True)
def set_check():
cache_device.set_check()
core_device.set_check()
# write miss
set_check()
io_to_exp_obj(vol, block_size * 0, block_size, data, 0, IoDir.WRITE, flags)
assert not cache_device.fail
assert not core_device.fail
# read miss
set_check()
io_to_exp_obj(vol, block_size * 1, block_size, data, 0, IoDir.READ, flags)
assert not cache_device.fail
assert not core_device.fail
# "dirty" read hit
set_check()
io_to_exp_obj(vol, block_size * 0, block_size, data, 0, IoDir.READ, flags)
assert not cache_device.fail
assert not core_device.fail
# "clean" read hit
set_check()
io_to_exp_obj(vol, block_size * 1, block_size, data, 0, IoDir.READ, flags)
assert not cache_device.fail
assert not core_device.fail
cache.change_cache_mode(CacheMode.WT)
# "dirty" write hit
set_check()
io_to_exp_obj(vol, block_size * 0, block_size, data, 0, IoDir.WRITE, flags)
assert not cache_device.fail
assert not core_device.fail
# "clean" write hit
set_check()
io_to_exp_obj(vol, block_size * 1, block_size, data, 0, IoDir.WRITE, flags)
assert not cache_device.fail
assert not core_device.fail
lib = OcfLib.getInstance()
lib.ocf_forward_get_flags.argtypes = [c_uint64]
lib.ocf_forward_get_flags.restype = c_uint64

View File

@ -12,7 +12,7 @@ from threading import Event
from collections import namedtuple
from pyocf.ocf import OcfLib
from pyocf.types.volume import RamVolume, ErrorDevice, TraceDevice, IoFlags, VolumeIoPriv
from pyocf.types.volume import RamVolume, ErrorDevice, TraceDevice, IoFlags
from pyocf.types.cvolume import CVolume
from pyocf.types.data import Data
from pyocf.types.io import IoDir
@ -287,19 +287,25 @@ def test_io_propagation_basic(pyocf_ctx):
ret = cvol_submit_data_io(cvol, addr, io_size)
assert ret == 0
ret = cvol_submit_flush_io(cvol, addr, io_size, IoFlags.FLUSH)
ret = cvol_submit_flush_io(cvol, addr, io_size)
assert ret == 0
ret = cvol_submit_discard_io(cvol, addr, io_size)
assert ret == 0
for io_type in TraceDevice.IoType:
ios = io_trace[vol][io_type]
ios = io_trace[vol][TraceDevice.IoType.Data]
assert len(ios) == 1
io = ios[0]
assert io.dir == IoDir.WRITE
assert io.addr == addr.B - int(vol_begin[i])
assert io.bytes == io_size.B
assert ios[0].dir == IoDir.WRITE
assert ios[0].addr == addr.B - int(vol_begin[i])
assert ios[0].bytes == io_size.B
ios = io_trace[vol][TraceDevice.IoType.Flush]
assert len(ios) == i + 1
ios = io_trace[vol][TraceDevice.IoType.Discard]
assert len(ios) == 1
assert ios[0].addr == addr.B - int(vol_begin[i])
assert ios[0].bytes == io_size.B
cvol.close()
cvol.destroy()
@ -355,27 +361,36 @@ def test_io_propagation_cross_boundary(pyocf_ctx):
ret = cvol_submit_data_io(cvol, addr, io_size)
assert ret == 0
ret = cvol_submit_flush_io(cvol, addr, io_size, IoFlags.FLUSH)
ret = cvol_submit_flush_io(cvol, addr, io_size)
assert ret == 0
ret = cvol_submit_discard_io(cvol, addr, io_size)
assert ret == 0
for io_type in TraceDevice.IoType:
ios1 = io_trace[vols[i]][io_type]
ios2 = io_trace[vols[i + 1]][io_type]
ios1 = io_trace[vols[i]][TraceDevice.IoType.Data]
ios2 = io_trace[vols[i + 1]][TraceDevice.IoType.Data]
assert len(ios1) == 1
io = ios1[0]
assert io.dir == IoDir.WRITE
assert io.addr == int(vols[i].vol.size - (io_size / 2))
assert io.bytes == io_size.B / 2
assert ios1[0].dir == IoDir.WRITE
assert ios1[0].addr == int(vols[i].vol.size - (io_size / 2))
assert ios1[0].bytes == io_size.B / 2
assert len(ios2) == 1
io = ios2[0]
assert io.dir == IoDir.WRITE
assert io.addr == 0
assert io.bytes == io_size.B / 2
assert ios2[0].dir == IoDir.WRITE
assert ios2[0].addr == 0
assert ios2[0].bytes == io_size.B / 2
ios1 = io_trace[vols[i]][TraceDevice.IoType.Flush]
ios2 = io_trace[vols[i + 1]][TraceDevice.IoType.Flush]
assert len(ios1) == 1
assert len(ios2) == 1
ios1 = io_trace[vols[i]][TraceDevice.IoType.Discard]
ios2 = io_trace[vols[i + 1]][TraceDevice.IoType.Discard]
assert len(ios1) == 1
assert ios1[0].addr == int(vols[i].vol.size - (io_size / 2))
assert ios1[0].bytes == io_size.B / 2
assert len(ios2) == 1
assert ios2[0].addr == 0
assert ios2[0].bytes == io_size.B / 2
cvol.close()
cvol.destroy()
@ -483,25 +498,51 @@ def test_io_propagation_multiple_subvolumes(pyocf_ctx, rand_seed):
ret = cvol_submit_data_io(cvol, addr, size)
assert ret == 0
ret = cvol_submit_flush_io(cvol, addr, size, IoFlags.FLUSH)
ret = cvol_submit_flush_io(cvol, addr, size)
assert ret == 0
ret = cvol_submit_discard_io(cvol, addr, size)
assert ret == 0
for vol in middle:
for io in io_trace[vol].values():
assert len(io) == 1
assert io[0].addr == 0
assert io[0].bytes == int(vol.vol.size)
ios = io_trace[vol][TraceDevice.IoType.Data]
assert len(ios) == 1
assert ios[0].addr == 0
assert ios[0].bytes == int(vol.vol.size)
for io in io_trace[first].values():
assert io[0].addr == int(start_offset)
assert io[0].bytes == int(vol_size - start_offset)
ios = io_trace[first][TraceDevice.IoType.Data]
assert len(ios) == 1
assert ios[0].addr == int(start_offset)
assert ios[0].bytes == int(vol_size - start_offset)
for io in io_trace[last].values():
assert io[0].addr == 0
assert io[0].bytes == int(end_offset)
ios = io_trace[last][TraceDevice.IoType.Data]
assert len(ios) == 1
assert ios[0].addr == 0
assert ios[0].bytes == int(end_offset)
ios = io_trace[vol][TraceDevice.IoType.Flush]
assert len(ios) == 1
ios = io_trace[first][TraceDevice.IoType.Flush]
assert len(ios) == 1
ios = io_trace[last][TraceDevice.IoType.Flush]
assert len(ios) == 1
ios = io_trace[vol][TraceDevice.IoType.Discard]
assert len(ios) == 1
assert ios[0].addr == 0
assert ios[0].bytes == int(vol.vol.size)
ios = io_trace[first][TraceDevice.IoType.Discard]
assert len(ios) == 1
assert ios[0].addr == int(start_offset)
assert ios[0].bytes == int(vol_size - start_offset)
ios = io_trace[last][TraceDevice.IoType.Discard]
assert len(ios) == 1
assert ios[0].addr == 0
assert ios[0].bytes == int(end_offset)
cvol.close()
cvol.destroy()
@ -538,16 +579,16 @@ def test_io_completion(pyocf_ctx, rand_seed):
self.pending_ios = []
self.io_submitted = Event()
def do_submit_io(self, io):
self.pending_ios.append(("io", io))
def do_forward_io(self, token, rw, addr, nbytes, offset):
self.pending_ios.append(("io", token, rw, addr, nbytes, offset))
self.io_submitted.set()
def do_submit_flush(self, flush):
self.pending_ios.append(("flush", flush))
def do_forward_flush(self, token):
self.pending_ios.append(("flush", token))
self.io_submitted.set()
def do_submit_discard(self, discard):
self.pending_ios.append(("discard", discard))
def do_forward_discard(self, token, addr, nbytes):
self.pending_ios.append(("discard", token, addr, nbytes))
self.io_submitted.set()
def wait_submitted(self):
@ -558,13 +599,13 @@ def test_io_completion(pyocf_ctx, rand_seed):
if not self.pending_ios:
return False
io_type, io = self.pending_ios.pop()
io_type, token, *params = self.pending_ios.pop()
if io_type == "io":
super().do_submit_io(io)
super().do_forward_io(token, *params)
elif io_type == "flush":
super().do_submit_flush(io)
super().do_forward_flush(token)
elif io_type == "discard":
super().do_submit_discard(io)
super().do_forward_discard(token, *params)
else:
assert False
@ -586,14 +627,18 @@ def test_io_completion(pyocf_ctx, rand_seed):
addr = vol_size / 2
size = (subvol_count - 1) * vol_size
for op, flags in [("submit", 0), ("submit_flush", IoFlags.FLUSH), ("submit_discard", 0)]:
for op, cnt in [
("submit", subvol_count),
("submit_flush", len(vols)),
("submit_discard", subvol_count)
]:
io = cvol.new_io(
queue=None,
addr=addr,
length=size,
direction=IoDir.WRITE,
io_class=0,
flags=flags,
flags=0,
)
completion = OcfCompletion([("err", c_int)])
io.callback = completion.callback
@ -604,7 +649,7 @@ def test_io_completion(pyocf_ctx, rand_seed):
submit_fn = getattr(io, op)
submit_fn()
pending_vols = vols[:subvol_count]
pending_vols = vols[:cnt]
for v in pending_vols:
v.wait_submitted()
@ -674,7 +719,7 @@ def test_io_error(pyocf_ctx, rand_seed):
assert ret == -OcfErrorCode.OCF_ERR_IO
# verify flush properly propagated
ret = cvol_submit_flush_io(cvol, addr, size, IoFlags.FLUSH)
ret = cvol_submit_flush_io(cvol, addr, size)
assert ret == -OcfErrorCode.OCF_ERR_IO
# verdiscard discard properly propagated