mirror of
https://github.com/borgbackup/borg.git
synced 2025-02-23 14:41:43 +00:00
fix local repo / upgrader tests
This commit is contained in:
parent
d3d51e12ea
commit
1e739fd52d
4 changed files with 45 additions and 24 deletions
|
@ -134,7 +134,7 @@ def do_init(self, args, repository):
|
||||||
pass
|
pass
|
||||||
return self.exit_code
|
return self.exit_code
|
||||||
|
|
||||||
@with_repository(exclusive='repair', manifest=False)
|
@with_repository(exclusive=True, manifest=False)
|
||||||
def do_check(self, args, repository):
|
def do_check(self, args, repository):
|
||||||
"""Check repository consistency"""
|
"""Check repository consistency"""
|
||||||
if args.repair:
|
if args.repair:
|
||||||
|
@ -174,7 +174,7 @@ def do_migrate_to_repokey(self, args, repository):
|
||||||
key_new.change_passphrase() # option to change key protection passphrase, save
|
key_new.change_passphrase() # option to change key protection passphrase, save
|
||||||
return EXIT_SUCCESS
|
return EXIT_SUCCESS
|
||||||
|
|
||||||
@with_repository(fake='dry_run')
|
@with_repository(fake='dry_run', exclusive=True)
|
||||||
def do_create(self, args, repository, manifest=None, key=None):
|
def do_create(self, args, repository, manifest=None, key=None):
|
||||||
"""Create new archive"""
|
"""Create new archive"""
|
||||||
matcher = PatternMatcher(fallback=True)
|
matcher = PatternMatcher(fallback=True)
|
||||||
|
@ -595,7 +595,7 @@ def do_info(self, args, repository, manifest, key, archive, cache):
|
||||||
print(str(cache))
|
print(str(cache))
|
||||||
return self.exit_code
|
return self.exit_code
|
||||||
|
|
||||||
@with_repository()
|
@with_repository(exclusive=True)
|
||||||
def do_prune(self, args, repository, manifest, key):
|
def do_prune(self, args, repository, manifest, key):
|
||||||
"""Prune repository archives according to specified rules"""
|
"""Prune repository archives according to specified rules"""
|
||||||
if not any((args.hourly, args.daily,
|
if not any((args.hourly, args.daily,
|
||||||
|
@ -722,7 +722,7 @@ def do_debug_get_obj(self, args, repository):
|
||||||
print("object %s fetched." % hex_id)
|
print("object %s fetched." % hex_id)
|
||||||
return EXIT_SUCCESS
|
return EXIT_SUCCESS
|
||||||
|
|
||||||
@with_repository(manifest=False)
|
@with_repository(manifest=False, exclusive=True)
|
||||||
def do_debug_put_obj(self, args, repository):
|
def do_debug_put_obj(self, args, repository):
|
||||||
"""put file(s) contents into the repository"""
|
"""put file(s) contents into the repository"""
|
||||||
for path in args.paths:
|
for path in args.paths:
|
||||||
|
@ -734,7 +734,7 @@ def do_debug_put_obj(self, args, repository):
|
||||||
repository.commit()
|
repository.commit()
|
||||||
return EXIT_SUCCESS
|
return EXIT_SUCCESS
|
||||||
|
|
||||||
@with_repository(manifest=False)
|
@with_repository(manifest=False, exclusive=True)
|
||||||
def do_debug_delete_obj(self, args, repository):
|
def do_debug_delete_obj(self, args, repository):
|
||||||
"""delete the objects with the given IDs from the repo"""
|
"""delete the objects with the given IDs from the repo"""
|
||||||
modified = False
|
modified = False
|
||||||
|
|
|
@ -236,7 +236,7 @@ def create_src_archive(self, name):
|
||||||
self.cmd('create', self.repository_location + '::' + name, src_dir)
|
self.cmd('create', self.repository_location + '::' + name, src_dir)
|
||||||
|
|
||||||
def open_archive(self, name):
|
def open_archive(self, name):
|
||||||
repository = Repository(self.repository_path)
|
repository = Repository(self.repository_path, exclusive=True)
|
||||||
with repository:
|
with repository:
|
||||||
manifest, key = Manifest.load(repository)
|
manifest, key = Manifest.load(repository)
|
||||||
archive = Archive(repository, key, manifest, name)
|
archive = Archive(repository, key, manifest, name)
|
||||||
|
@ -1288,7 +1288,7 @@ def test_missing_manifest(self):
|
||||||
|
|
||||||
def test_extra_chunks(self):
|
def test_extra_chunks(self):
|
||||||
self.cmd('check', self.repository_location, exit_code=0)
|
self.cmd('check', self.repository_location, exit_code=0)
|
||||||
with Repository(self.repository_location) as repository:
|
with Repository(self.repository_location, exclusive=True) as repository:
|
||||||
repository.put(b'01234567890123456789012345678901', b'xxxx')
|
repository.put(b'01234567890123456789012345678901', b'xxxx')
|
||||||
repository.commit()
|
repository.commit()
|
||||||
self.cmd('check', self.repository_location, exit_code=1)
|
self.cmd('check', self.repository_location, exit_code=1)
|
||||||
|
|
|
@ -12,11 +12,17 @@
|
||||||
from . import BaseTestCase
|
from . import BaseTestCase
|
||||||
|
|
||||||
|
|
||||||
|
UNSPECIFIED = object() # for default values where we can't use None
|
||||||
|
|
||||||
|
|
||||||
class RepositoryTestCaseBase(BaseTestCase):
|
class RepositoryTestCaseBase(BaseTestCase):
|
||||||
key_size = 32
|
key_size = 32
|
||||||
|
exclusive = True
|
||||||
|
|
||||||
def open(self, create=False):
|
def open(self, create=False, exclusive=UNSPECIFIED):
|
||||||
return Repository(os.path.join(self.tmppath, 'repository'), create=create)
|
if exclusive is UNSPECIFIED:
|
||||||
|
exclusive = self.exclusive
|
||||||
|
return Repository(os.path.join(self.tmppath, 'repository'), exclusive=exclusive, create=create)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.tmppath = tempfile.mkdtemp()
|
self.tmppath = tempfile.mkdtemp()
|
||||||
|
@ -27,10 +33,10 @@ def tearDown(self):
|
||||||
self.repository.close()
|
self.repository.close()
|
||||||
shutil.rmtree(self.tmppath)
|
shutil.rmtree(self.tmppath)
|
||||||
|
|
||||||
def reopen(self):
|
def reopen(self, exclusive=UNSPECIFIED):
|
||||||
if self.repository:
|
if self.repository:
|
||||||
self.repository.close()
|
self.repository.close()
|
||||||
self.repository = self.open()
|
self.repository = self.open(exclusive=exclusive)
|
||||||
|
|
||||||
|
|
||||||
class RepositoryTestCase(RepositoryTestCaseBase):
|
class RepositoryTestCase(RepositoryTestCaseBase):
|
||||||
|
@ -156,17 +162,6 @@ def test_crash_before_compact_segments(self):
|
||||||
self.assert_equal(len(self.repository), 3)
|
self.assert_equal(len(self.repository), 3)
|
||||||
self.assert_equal(self.repository.check(), True)
|
self.assert_equal(self.repository.check(), True)
|
||||||
|
|
||||||
def test_replay_of_readonly_repository(self):
|
|
||||||
self.add_keys()
|
|
||||||
for name in os.listdir(self.repository.path):
|
|
||||||
if name.startswith('index.'):
|
|
||||||
os.unlink(os.path.join(self.repository.path, name))
|
|
||||||
with patch.object(UpgradableLock, 'upgrade', side_effect=LockFailed) as upgrade:
|
|
||||||
self.reopen()
|
|
||||||
with self.repository:
|
|
||||||
self.assert_raises(LockFailed, lambda: len(self.repository))
|
|
||||||
upgrade.assert_called_once_with()
|
|
||||||
|
|
||||||
def test_crash_before_write_index(self):
|
def test_crash_before_write_index(self):
|
||||||
self.add_keys()
|
self.add_keys()
|
||||||
self.repository.write_index = None
|
self.repository.write_index = None
|
||||||
|
@ -179,6 +174,32 @@ def test_crash_before_write_index(self):
|
||||||
self.assert_equal(len(self.repository), 3)
|
self.assert_equal(len(self.repository), 3)
|
||||||
self.assert_equal(self.repository.check(), True)
|
self.assert_equal(self.repository.check(), True)
|
||||||
|
|
||||||
|
def test_replay_lock_upgrade_old(self):
|
||||||
|
self.add_keys()
|
||||||
|
for name in os.listdir(self.repository.path):
|
||||||
|
if name.startswith('index.'):
|
||||||
|
os.unlink(os.path.join(self.repository.path, name))
|
||||||
|
with patch.object(Lock, 'upgrade', side_effect=LockFailed) as upgrade:
|
||||||
|
self.reopen(exclusive=None) # simulate old client that always does lock upgrades
|
||||||
|
with self.repository:
|
||||||
|
# the repo is only locked by a shared read lock, but to replay segments,
|
||||||
|
# we need an exclusive write lock - check if the lock gets upgraded.
|
||||||
|
self.assert_raises(LockFailed, lambda: len(self.repository))
|
||||||
|
upgrade.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_replay_lock_upgrade(self):
|
||||||
|
self.add_keys()
|
||||||
|
for name in os.listdir(self.repository.path):
|
||||||
|
if name.startswith('index.'):
|
||||||
|
os.unlink(os.path.join(self.repository.path, name))
|
||||||
|
with patch.object(Lock, 'upgrade', side_effect=LockFailed) as upgrade:
|
||||||
|
self.reopen(exclusive=False) # current client usually does not do lock upgrade, except for replay
|
||||||
|
with self.repository:
|
||||||
|
# the repo is only locked by a shared read lock, but to replay segments,
|
||||||
|
# we need an exclusive write lock - check if the lock gets upgraded.
|
||||||
|
self.assert_raises(LockFailed, lambda: len(self.repository))
|
||||||
|
upgrade.assert_called_once_with()
|
||||||
|
|
||||||
def test_crash_before_deleting_compacted_segments(self):
|
def test_crash_before_deleting_compacted_segments(self):
|
||||||
self.add_keys()
|
self.add_keys()
|
||||||
self.repository.io.delete_segment = None
|
self.repository.io.delete_segment = None
|
||||||
|
@ -202,7 +223,7 @@ def test_ignores_commit_tag_in_data(self):
|
||||||
|
|
||||||
class RepositoryAppendOnlyTestCase(RepositoryTestCaseBase):
|
class RepositoryAppendOnlyTestCase(RepositoryTestCaseBase):
|
||||||
def open(self, create=False):
|
def open(self, create=False):
|
||||||
return Repository(os.path.join(self.tmppath, 'repository'), create=create, append_only=True)
|
return Repository(os.path.join(self.tmppath, 'repository'), exclusive=True, create=create, append_only=True)
|
||||||
|
|
||||||
def test_destroy_append_only(self):
|
def test_destroy_append_only(self):
|
||||||
# Can't destroy append only repo (via the API)
|
# Can't destroy append only repo (via the API)
|
||||||
|
|
|
@ -23,7 +23,7 @@ def repo_valid(path):
|
||||||
:param path: the path to the repository
|
:param path: the path to the repository
|
||||||
:returns: if borg can check the repository
|
:returns: if borg can check the repository
|
||||||
"""
|
"""
|
||||||
with Repository(str(path), create=False) as repository:
|
with Repository(str(path), exclusive=True, create=False) as repository:
|
||||||
# can't check raises() because check() handles the error
|
# can't check raises() because check() handles the error
|
||||||
return repository.check()
|
return repository.check()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue