def test_copy_dirty(progress): src = memory.Backend( mode="r", data=create_backing("ABCD"), extents={"dirty": create_dirty_extents("AbCd")}, ) dst_backing = create_backing("0000") dst = memory.Backend("r+", data=dst_backing) io.copy(src, dst, dirty=True, max_workers=1, progress=progress) # Copy dirty extents, skip clean extents. assert dst_backing == create_backing("A0C0")
def test_zero_repr(): op = ops.Zero(memory.Backend("r+"), 4096) rep = repr(op) assert "Zero" in rep assert "offset=0" in rep assert "size=4096" in rep assert "done=0" in rep
def test_close_error(): def close(): raise IOError("backend error") with pytest.raises(IOError): with memory.Backend("r+") as m: m.close = close
def test_write_flush(extra, dirty): size = 4096 dst = memory.Backend("r+", bytearray(b"a" * size)) src = io.BytesIO(b"b" * size) with util.aligned_buffer(4096) as buf: op = ops.Write(dst, src, buf, size, **extra) op.run() assert dst.dirty == dirty
def test_size(): m = memory.Backend("r+", data=bytearray(b"data")) assert m.size() == 4 assert m.tell() == 0 m.zero(5) m.seek(3) assert m.size() == 5 assert m.tell() == 3
def test_read_seek(): src = memory.Backend("r", bytearray(b"0123456789")) src.seek(8) dst = io.BytesIO() with util.aligned_buffer(32) as buf: op = ops.Read(src, dst, buf, 5) op.run() assert dst.getvalue() == b"01234"
def test_copy_dirty_progress(): src = memory.Backend( mode="r", data=create_backing("A0C-"), extents={"dirty": create_zero_extents("A0C-")}, ) dst_backing = create_backing("0000") dst = memory.Backend("r+", data=dst_backing) p = FakeProgress() io.copy(src, dst, dirty=True, max_workers=1, progress=p) # Report at least every extent. assert len(p.updates) >= 4 # Report entire image size. assert sum(p.updates) == len(dst_backing)
def test_zero_after_end(): backing = bytearray(b"x" * 4) m = memory.Backend("r+", data=backing) m.seek(8) m.zero(4) assert m.tell() == 12 assert m.size() == 12 assert backing == b"x" * 4 + b"\0" * 8
def test_close(): m = memory.Backend("r+") m.close() # All operations should fail now with: # ValueError: I/O operation on closed file with pytest.raises(ValueError): m.write("more") with pytest.raises(ValueError): m.readinto(bytearray(10))
def test_write_at_end(): backing = bytearray(b"\0" * 4) m = memory.Backend("r+", data=backing) m.seek(4) m.write(b"x" * 4) assert m.tell() == 8 assert m.size() == 8 assert backing == b"\0" * 4 + b"x" * 4
def test_read_from(): size = 128 src = memory.Backend(data=bytearray(b"x" * size)) dst = memory.ReaderFrom("r+", bytearray(b"y" * size)) buf = bytearray(32) dst.read_from(src, size, buf) assert src.tell() == size assert dst.tell() == size assert src.data() == dst.data()
def test_write_to(): size = 128 src = memory.WriterTo(data=bytearray(b"x" * size)) dst = memory.Backend("r+", data=bytearray(b"y" * size)) buf = bytearray(32) src.write_to(dst, size, buf) assert src.tell() == size assert dst.tell() == size assert src.data() == dst.data()
def test_zero_seek(): dst = memory.Backend("r+", bytearray(b"a" * 10)) dst.seek(8) op = ops.Zero(dst, 5) op.run() dst.seek(0) b = bytearray(11) n = dst.readinto(b) assert n == 10 assert b == b"\0\0\0\0\0aaaaa\0"
def test_propagate_user_error(): class UserError(Exception): pass def close(): raise IOError("backend error") with pytest.raises(UserError): with memory.Backend("r+") as m: m.close = close raise UserError("user error")
def test_open_writeonly(): m = memory.Backend("w") assert not m.readable() assert m.writable() data = b"data" m.write(data) assert m.tell() == len(data) with pytest.raises(IOError): m.readinto(bytearray(10)) m.flush()
def test_write_seek(): dst = memory.Backend("r+", bytearray(b"a" * 10)) dst.seek(8) src = io.BytesIO(b"b" * 5) with util.aligned_buffer(32) as buf: op = ops.Write(dst, src, buf, 5) op.run() dst.seek(0) b = bytearray(11) n = dst.readinto(b) assert n == 10 assert b == b"bbbbbaaaaa\0"
def test_read_from_some(): src = memory.Backend(data=bytearray(b"x" * 128)) dst = memory.ReaderFrom("r+", data=bytearray(b"y" * 128)) buf = bytearray(32) src.seek(32) dst.seek(32) dst.read_from(src, 64, buf) assert src.tell() == 96 assert dst.tell() == 96 assert dst.data() == b"y" * 32 + b"x" * 64 + b"y" * 32
def test_write_inside(): backing = bytearray(b"\0" * 8) m = memory.Backend("r+", data=backing) m.write(b"x" * 4) assert m.tell() == 4 assert m.size() == 8 assert backing == b"x" * 4 + b"\0" * 4 m.write(b"x" * 4) assert m.tell() == 8 assert m.size() == 8 assert backing == b"x" * 8
def test_copy_generic(buffer_size, zero, hole, progress): src_extents = create_zero_extents("B0-") src_backing = create_backing("B0-") dst_backing = create_backing( "AAA" if zero and hole else "AA0" if zero else "A00") src = memory.Backend(mode="r", data=src_backing, extents={"zero": src_extents}) dst = memory.Backend("r+", data=dst_backing) io.copy(src, dst, max_workers=1, buffer_size=buffer_size, zero=zero, hole=hole, progress=progress) assert dst_backing == src_backing
def test_open_readonly(): m = memory.Backend() assert m.readable() assert not m.writable() with pytest.raises(IOError): m.write(b"data") with pytest.raises(IOError): m.zero(4) assert m.tell() == 0 b = bytearray(b"before") assert m.readinto(b) == 0 assert b == b"before"
def test_write_to_some(): size = 128 src = memory.WriterTo(data=bytearray(b"x" * size)) dst = memory.Backend("r+", data=bytearray(b"y" * size)) buf = bytearray(32) src.seek(32) dst.seek(32) src.write_to(dst, 64, buf) assert src.tell() == 96 assert dst.tell() == 96 assert dst.data() == b"y" * 32 + b"x" * 64 + b"y" * 32
def test_user_extents(): extents = { "zero": [ extent.ZeroExtent(0, 32, False, False), extent.ZeroExtent(0, 32, True, False), ], "dirty": [ extent.DirtyExtent(0, 16, True, False), extent.DirtyExtent(0, 48, False, False), ] } data = b"a" * 32 + b"\0" * 32 m = memory.Backend(data=data, extents=extents) assert list(m.extents()) == extents["zero"] assert list(m.extents("zero")) == extents["zero"] assert list(m.extents("dirty")) == extents["dirty"]
def test_open_read_write(): m = memory.Backend("r+") assert m.readable() assert m.writable() assert not m.sparse data = b"data" m.write(data) assert m.tell() == len(data) m.zero(4) size = len(data) + 4 assert m.tell() == size content = data + b"\0" * 4 b = bytearray(size) m.seek(0) assert m.readinto(b) == size assert b == content
def test_dirty(): # backend created clean m = memory.Backend("r+", data=bytearray(b"data")) assert not m.dirty # write ans zero dirty the backend m.write(b"01234") assert m.dirty m.flush() assert not m.dirty m.zero(5) assert m.dirty m.flush() assert not m.dirty # readinto, seek do not affect dirty. b = bytearray(10) m.seek(0) assert not m.dirty m.readinto(b) assert not m.dirty
def test_clone(): backing = bytearray(b"x" * 128) a = memory.Backend(mode="r+", data=backing) b = a.clone() # Backends are indentical on creation. assert a.size() == b.size() assert a.tell() == b.tell() assert a.data() == b.data() # Writng to a modifies the shared backing but does not modify b position. a.write(b"y" * 64) assert a.tell() == 64 assert b.tell() == 0 assert a.dirty assert not b.dirty assert a.data() == b.data() # Writng to b modifies the shared backing but does not modify a position. b.seek(64) b.write(b"y" * 64) assert a.tell() == 64 assert b.tell() == 128 assert b.dirty assert a.data() == b.data() # Extending the backing show in both backends. a.seek(128) a.zero(64) assert a.tell() == 192 assert b.tell() == 128 assert a.size() == b.size() assert a.data() == b.data() # Flusing clears only the flushed backed. a.flush() assert not a.dirty assert b.dirty b.flush() assert not b.dirty
def test_invalid_mode(): with pytest.raises(ValueError): memory.Backend("invalid")
def test_flush_repr(): op = ops.Flush(memory.Backend("r")) rep = repr(op) assert "Flush" in rep assert "done=0" in rep
def test_flush(): dst = memory.Backend("r+") dst.write(b"x") op = ops.Flush(dst) op.run() assert not dst.dirty
def test_zero_flush(extra, dirty): size = 4096 dst = memory.Backend("r+", bytearray(b"a" * size)) op = ops.Zero(dst, size, **extra) op.run() assert dst.dirty == dirty
def test_extents_dirty(): m = memory.Backend(data=bytearray(b"data")) with pytest.raises(errors.UnsupportedOperation): list(m.extents(context="dirty"))