repository: add complementary index corruption test

This commit is contained in:
Marian Beermann 2017-06-02 16:22:02 +02:00
parent 2e067a7ae8
commit 54e023c75a
2 changed files with 36 additions and 6 deletions

View File

@ -490,6 +490,8 @@ class Repository:
b'storage_quota_use': self.storage_quota_use, b'storage_quota_use': self.storage_quota_use,
} }
integrity = { integrity = {
# Integrity version started at 2, the current hints version.
# Thus, integrity version == hints version, for now.
b'version': 2, b'version': 2,
} }
transaction_id = self.io.get_segments_transaction_id() transaction_id = self.io.get_segments_transaction_id()

View File

@ -503,11 +503,6 @@ class RepositoryAuxiliaryCorruptionTestCase(RepositoryTestCaseBase):
self.repository.commit() self.repository.commit()
self.repository.close() self.repository.close()
def corrupt(self, file):
with open(file, 'r+b') as fd:
fd.seek(-1, io.SEEK_END)
fd.write(b'1')
def do_commit(self): def do_commit(self):
with self.repository: with self.repository:
self.repository.put(H(0), b'fox') self.repository.put(H(0), b'fox')
@ -544,12 +539,42 @@ class RepositoryAuxiliaryCorruptionTestCase(RepositoryTestCaseBase):
with self.repository: with self.repository:
assert len(self.repository) == 1 assert len(self.repository) == 1
def _corrupt_index(self):
# HashIndex is able to detect incorrect headers and file lengths,
# but on its own it can't tell if the data is correct.
index_path = os.path.join(self.repository.path, 'index.1')
with open(index_path, 'r+b') as fd:
index_data = fd.read()
# Flip one bit in a key stored in the index
corrupted_key = (int.from_bytes(H(0), 'little') ^ 1).to_bytes(32, 'little')
corrupted_index_data = index_data.replace(H(0), corrupted_key)
assert corrupted_index_data != index_data
assert len(corrupted_index_data) == len(index_data)
fd.seek(0)
fd.write(corrupted_index_data)
def test_index_corrupted(self): def test_index_corrupted(self):
self.corrupt(os.path.join(self.repository.path, 'index.1')) # HashIndex is able to detect incorrect headers and file lengths,
# but on its own it can't tell if the data itself is correct.
self._corrupt_index()
with self.repository: with self.repository:
# Data corruption is detected due to mismatching checksums
# and fixed by rebuilding the index.
assert len(self.repository) == 1 assert len(self.repository) == 1
assert self.repository.get(H(0)) == b'foo' assert self.repository.get(H(0)) == b'foo'
def test_index_corrupted_without_integrity(self):
self._corrupt_index()
integrity_path = os.path.join(self.repository.path, 'integrity.1')
os.unlink(integrity_path)
with self.repository:
# Since the corrupted key is not noticed, the repository still thinks
# it contains one key...
assert len(self.repository) == 1
with pytest.raises(Repository.ObjectNotFound):
# ... but the real, uncorrupted key is not found in the corrupted index.
self.repository.get(H(0))
def test_unreadable_index(self): def test_unreadable_index(self):
index = os.path.join(self.repository.path, 'index.1') index = os.path.join(self.repository.path, 'index.1')
os.unlink(index) os.unlink(index)
@ -558,13 +583,16 @@ class RepositoryAuxiliaryCorruptionTestCase(RepositoryTestCaseBase):
self.do_commit() self.do_commit()
def test_unknown_integrity_version(self): def test_unknown_integrity_version(self):
# For now an unknown integrity data version is ignored and not an error.
integrity_path = os.path.join(self.repository.path, 'integrity.1') integrity_path = os.path.join(self.repository.path, 'integrity.1')
with open(integrity_path, 'r+b') as fd: with open(integrity_path, 'r+b') as fd:
msgpack.pack({ msgpack.pack({
# Borg only understands version 2
b'version': 4.7, b'version': 4.7,
}, fd) }, fd)
fd.truncate() fd.truncate()
with self.repository: with self.repository:
# No issues accessing the repository
assert len(self.repository) == 1 assert len(self.repository) == 1
assert self.repository.get(H(0)) == b'foo' assert self.repository.get(H(0)) == b'foo'