def test_leases_bad_record(self, tmp_vol, fake_sanlock): vol = xlease.LeasesVolume(tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size) # Index three leases. with utils.closing(vol): vol.add("lease1") vol.add("lease2") vol.add("lease3") # Corrupt index record of second lease on storage. with io.open(tmp_vol.path, "r+b") as f: index_record_offset = xlease.RECORD_BASE + 1 * xlease.RECORD_SIZE f.seek(tmp_vol.alignment + index_record_offset) f.write(b"!" * xlease.RECORD_SIZE) # Reload the index to memory from storage. vol = xlease.LeasesVolume(tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size) with utils.closing(vol): # Dumping leases from index skips the second bad index record # and gets to the last record. assert set(vol.leases()) == {"lease1", "lease3"}
def test_bad_mtime(self, tmp_vol): vol = xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size) with utils.closing(vol): with io.open(vol.path, "r+b") as f: f.seek(xlease.INDEX_BASE + 59) f.write(b"not a number") with pytest.raises(xlease.InvalidIndex): xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size).close()
def test_bad_lockspace(self, tmp_vol): vol = xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size) with utils.closing(vol): with io.open(vol.path, "r+b") as f: f.seek(sc.ALIGNMENT_1M + 10) f.write(b"\xf0") with pytest.raises(xlease.InvalidIndex): xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size).close()
def test_truncated_index(self, tmp_vol): vol = xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size) with utils.closing(vol): # Truncate index, reading it should fail. with io.open(vol.path, "r+b") as f: f.truncate( xlease.INDEX_BASE + xlease.INDEX_SIZE - tmp_vol.block_size) with pytest.raises(xlease.InvalidIndex): xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size).close()
def test_add_write_failure(self, tmp_vol): base = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(base): file = FailingWriter(base.path) with utils.closing(file): vol = xlease.LeasesVolume(file) with utils.closing(vol): lease_id = make_uuid() with pytest.raises(WriteError): vol.add(lease_id) # Must succeed becuase writng to storage failed assert lease_id not in vol.leases()
def test_unsupported_version(self, tmp_vol): vol = xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size) with utils.closing(vol): md = xlease.IndexMetadata(2, "lockspace") with io.open(vol.path, "r+b") as f: f.seek(xlease.INDEX_BASE) f.write(md.bytes()) with pytest.raises(xlease.InvalidIndex): xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size).close()
def test_remove_write_failure(self, tmp_vol): record = xlease.Record(make_uuid(), 0, updating=True) tmp_vol.write_records((42, record)) base = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(base): file = FailingWriter(base.path) with utils.closing(file): vol = xlease.LeasesVolume(file) with utils.closing(vol): with pytest.raises(WriteError): vol.remove(record.resource) # Must succeed becuase writng to storage failed assert record.resource in vol.leases()
def test_updating(self, tmp_vol): vol = xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size) with utils.closing(vol): md = xlease.IndexMetadata(xlease.INDEX_VERSION, "lockspace", updating=True) with io.open(vol.path, "r+b") as f: f.seek(sc.ALIGNMENT_1M) f.write(md.bytes()) with pytest.raises(xlease.InvalidIndex): xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size).close()
def test_rebuild_empty(self, tmp_vol, fake_sanlock): # Add underlying sanlock resources. for i in [3, 4, 6]: resource = "%04d" % i offset = xlease.lease_offset(i, tmp_vol.alignment) fake_sanlock.write_resource( tmp_vol.lockspace.encode("utf-8"), resource.encode("utf-8"), [(tmp_vol.path, offset)], align=tmp_vol.alignment, sector=tmp_vol.block_size) # Check that the index is empty before rebuilding. vol = xlease.LeasesVolume( tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size) with utils.closing(vol): assert vol.leases() == {} # Rebuild the index from storage. xlease.rebuild_index( tmp_vol.lockspace, tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size) # After rebuilding the index it should contain all the underlying # resources. expected = { "0003": { "offset": xlease.lease_offset(3, tmp_vol.alignment), "updating": False, }, "0004": { "offset": xlease.lease_offset(4, tmp_vol.alignment), "updating": False, }, "0006": { "offset": xlease.lease_offset(6, tmp_vol.alignment), "updating": False, }, } vol = xlease.LeasesVolume( tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size) with utils.closing(vol): assert vol.leases() == expected
def test_remove_sanlock_failure(self, tmp_vol, fake_sanlock): vol = xlease.LeasesVolume( tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size) with utils.closing(vol): lease_id = make_uuid() vol.add(lease_id) # Make sanlock fail to remove a resource (currnently removing a # resouce by writing invalid lockspace and resoruce name). fake_sanlock.errors["write_resource"] = \ fake_sanlock.SanlockException with pytest.raises(fake_sanlock.SanlockException): vol.remove(lease_id) # We should have an updating lease record lease = vol.leases()[lease_id] assert lease["updating"] # There lease should still be on storage res = fake_sanlock.read_resource( vol.path, lease["offset"], align=tmp_vol.alignment, sector=tmp_vol.block_size) assert res["lockspace"] == vol.lockspace.encode("utf-8") assert res["resource"] == lease_id.encode("utf-8")
def test_add_first_free_slot(self, tmp_vol, fake_sanlock): vol = xlease.LeasesVolume( tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size) with utils.closing(vol): uuids = [make_uuid() for i in range(4)] for uuid in uuids[:3]: vol.add(uuid) vol.remove(uuids[1]) vol.add(uuids[3]) leases = vol.leases() # The first lease in the first slot offset = xlease.lease_offset(0, tmp_vol.alignment) assert leases[uuids[0]]["offset"] == offset # The forth lease was added in the second slot after the second # lease was removed. offset = xlease.lease_offset(1, tmp_vol.alignment) assert leases[uuids[3]]["offset"] == offset # The third lease in the third slot offset = xlease.lease_offset(2, tmp_vol.alignment) assert leases[uuids[2]]["offset"] == offset
def test_bad_magic(self, tmp_vol): tmp_vol.zero_storage() with pytest.raises(xlease.InvalidIndex): xlease.LeasesVolume( tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size).close()
def test_empty(self, tmp_vol): vol = xlease.LeasesVolume( tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size) with utils.closing(vol): assert vol.leases() == {}
def test_time_add(self, tmp_vol, fake_sanlock): setup = """ import os from testlib import make_uuid from vdsm import utils from vdsm.storage import xlease path = "%s" lockspace = os.path.basename(os.path.dirname(path)) def bench(): lease_id = make_uuid() file = xlease.DirectFile(path) with utils.closing(file): vol = xlease.LeasesVolume(file) with utils.closing(vol, log="test"): vol.add(lease_id) """ vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): count = 100 elapsed = timeit.timeit("bench()", setup=setup % vol.path, number=count) # Note: this does not include the time to create the real sanlock # resource. print("%d adds in %.6f seconds (%.6f seconds per add)" % (count, elapsed, elapsed / count))
def test_time_lookup(self, tmp_vol): setup = """ import os from testlib import make_uuid from vdsm import utils from vdsm.storage import exception as se from vdsm.storage import xlease path = "%s" lockspace = os.path.basename(os.path.dirname(path)) lease_id = make_uuid() def bench(): file = xlease.DirectFile(path) with utils.closing(file): vol = xlease.LeasesVolume(file) with utils.closing(vol, log="test"): try: vol.lookup(lease_id) except se.NoSuchLease: pass """ vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): count = 100 elapsed = timeit.timeit("bench()", setup=setup % vol.path, number=count) print("%d lookups in %.6f seconds (%.6f seconds per lookup)" % (count, elapsed, elapsed / count))
def test_bad_lockspace(self, tmp_vol): vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): with io.open(vol.path, "r+b") as f: f.seek(xlease.INDEX_BASE + 10) f.write(b"\xf0") self.check_invalid_index(vol.path)
def test_lookup_exists(self, tmp_vol, fake_sanlock): vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): lease_id = make_uuid() add_info = vol.add(lease_id) lookup_info = vol.lookup(lease_id) assert add_info == lookup_info
def test_bad_mtime(self, tmp_vol): vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): with io.open(vol.path, "r+b") as f: f.seek(xlease.INDEX_BASE + 59) f.write(b"not a number") self.check_invalid_index(vol.path)
def test_remove_missing(self, tmp_vol): vol = xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size) with utils.closing(vol): lease_id = make_uuid() with pytest.raises(se.NoSuchLease): vol.remove(lease_id)
def test_rebuild_empty(self, fake_sanlock): with make_volume() as vol: # Add underlying sanlock resources for i in [3, 4, 6]: resource = "%04d" % i offset = xlease.USER_RESOURCE_BASE + xlease.SLOT_SIZE * i fake_sanlock.write_resource(vol.lockspace, resource, [(vol.path, offset)]) # The index is empty assert vol.leases() == {} # After rebuilding the index it should contain all the underlying # resources. file = xlease.DirectFile(vol.path) with utils.closing(file): xlease.rebuild_index(vol.lockspace, file) expected = { "0003": { "offset": xlease.USER_RESOURCE_BASE + xlease.SLOT_SIZE * 3, "updating": False, }, "0004": { "offset": xlease.USER_RESOURCE_BASE + xlease.SLOT_SIZE * 4, "updating": False, }, "0006": { "offset": xlease.USER_RESOURCE_BASE + xlease.SLOT_SIZE * 6, "updating": False, }, } file = xlease.DirectFile(vol.path) with utils.closing(file): vol = xlease.LeasesVolume(file) with utils.closing(vol): assert vol.leases() == expected
def test_magic_big_endian(self, tmp_vol): vol = xlease.LeasesVolume( tmp_vol.backend, block_size=tmp_vol.block_size) with utils.closing(vol): with io.open(vol.path, "rb") as f: f.seek(xlease.INDEX_BASE) assert f.read(4) == b"\x12\x15\x20\x16"
def test_lookup_missing(self, tmp_vol): vol = xlease.LeasesVolume(tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size) with utils.closing(vol): with pytest.raises(se.NoSuchLease): vol.lookup(make_uuid())
def test_create_read_failure(self, tmp_vol): file = FailingReader(tmp_vol.path) with utils.closing(file): with pytest.raises(ReadError): xlease.LeasesVolume(file, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size)
def test_truncated_index(self, tmp_vol): vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): # Truncate index, reading it should fail. with io.open(vol.path, "r+b") as f: f.truncate( xlease.INDEX_BASE + xlease.INDEX_SIZE - xlease.BLOCK_SIZE) self.check_invalid_index(vol.path)
def test_unsupported_version(self, tmp_vol): vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): md = xlease.IndexMetadata(2, "lockspace") with io.open(vol.path, "r+b") as f: f.seek(xlease.INDEX_BASE) f.write(md.bytes()) self.check_invalid_index(vol.path)
def test_metadata(self, tmp_vol, monkeypatch): monkeypatch.setattr("time.time", lambda: 123456789) tmp_vol.format_index() vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): lockspace = os.path.basename(os.path.dirname(vol.path)) assert vol.version == 1 assert vol.lockspace == lockspace assert vol.mtime == 123456789
def test_updating(self, tmp_vol): vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): md = xlease.IndexMetadata(xlease.INDEX_VERSION, "lockspace", updating=True) with io.open(vol.path, "r+b") as f: f.seek(xlease.INDEX_BASE) f.write(md.bytes()) self.check_invalid_index(vol.path)
def test_lookup_updating(self, tmp_vol): record = xlease.Record(make_uuid(), 0, updating=True) tmp_vol.write_records((42, record)) vol = xlease.LeasesVolume(tmp_vol.backend) with utils.closing(vol): leases = vol.leases() assert leases[record.resource]["updating"] with pytest.raises(xlease.LeaseUpdating): vol.lookup(record.resource)
def test_bad_mtime(self, tmp_vol): with io.open(tmp_vol.path, "r+b") as f: f.seek(tmp_vol.alignment + 59) f.write(b"not a number") with pytest.raises(xlease.InvalidIndex): xlease.LeasesVolume(tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size).close()
def test_unsupported_version(self, tmp_vol): md = xlease.IndexMetadata(2, "lockspace") with io.open(tmp_vol.path, "r+b") as f: f.seek(tmp_vol.alignment) f.write(md.bytes()) with pytest.raises(xlease.InvalidIndex): xlease.LeasesVolume(tmp_vol.backend, alignment=tmp_vol.alignment, block_size=tmp_vol.block_size).close()