Kaynağa Gözat

recreate/archiver tests: add check_cache tool - lints refcounts

Marian Beermann 8 yıl önce
ebeveyn
işleme
15cefe8dde
1 değiştirilmiş dosya ile 54 ekleme ve 1 silme
  1. 54 1
      src/borg/testsuite/archiver.py

+ 54 - 1
src/borg/testsuite/archiver.py

@@ -29,7 +29,7 @@ from ..archiver import Archiver
 from ..cache import Cache
 from ..cache import Cache
 from ..constants import *  # NOQA
 from ..constants import *  # NOQA
 from ..crypto import bytes_to_long, num_aes_blocks
 from ..crypto import bytes_to_long, num_aes_blocks
-from ..helpers import PatternMatcher, parse_pattern
+from ..helpers import PatternMatcher, parse_pattern, Location
 from ..helpers import Chunk, Manifest
 from ..helpers import Chunk, Manifest
 from ..helpers import EXIT_SUCCESS, EXIT_WARNING, EXIT_ERROR
 from ..helpers import EXIT_SUCCESS, EXIT_WARNING, EXIT_ERROR
 from ..helpers import bin_to_hex
 from ..helpers import bin_to_hex
@@ -260,6 +260,9 @@ class ArchiverTestCaseBase(BaseTestCase):
             archive = Archive(repository, key, manifest, name)
             archive = Archive(repository, key, manifest, name)
         return archive, repository
         return archive, repository
 
 
+    def open_repository(self):
+        return Repository(self.repository_path, exclusive=True)
+
     def create_regular_file(self, name, size=0, contents=None):
     def create_regular_file(self, name, size=0, contents=None):
         filename = os.path.join(self.input_path, name)
         filename = os.path.join(self.input_path, name)
         if not os.path.exists(os.path.dirname(filename)):
         if not os.path.exists(os.path.dirname(filename)):
@@ -1626,6 +1629,40 @@ class ArchiverTestCase(ArchiverTestCaseBase):
             self.cmd('init', self.repository_location, exit_code=1)
             self.cmd('init', self.repository_location, exit_code=1)
         assert not os.path.exists(self.repository_location)
         assert not os.path.exists(self.repository_location)
 
 
+    def check_cache(self):
+        # First run a regular borg check
+        self.cmd('check', self.repository_location)
+        # Then check that the cache on disk matches exactly what's in the repo.
+        with self.open_repository() as repository:
+            manifest, key = Manifest.load(repository)
+            with Cache(repository, key, manifest, sync=False) as cache:
+                original_chunks = cache.chunks
+            cache.destroy(repository)
+            with Cache(repository, key, manifest) as cache:
+                correct_chunks = cache.chunks
+        assert original_chunks is not correct_chunks
+        seen = set()
+        for id, (refcount, size, csize) in correct_chunks.iteritems():
+            o_refcount, o_size, o_csize = original_chunks[id]
+            assert refcount == o_refcount
+            assert size == o_size
+            assert csize == o_csize
+            seen.add(id)
+        for id, (refcount, size, csize) in original_chunks.iteritems():
+            assert id in seen
+
+    def test_check_cache(self):
+        self.cmd('init', self.repository_location)
+        self.cmd('create', self.repository_location + '::test', 'input')
+        with self.open_repository() as repository:
+            manifest, key = Manifest.load(repository)
+            with Cache(repository, key, manifest, sync=False) as cache:
+                cache.begin_txn()
+                cache.chunks.incref(list(cache.chunks.iteritems())[0][0])
+                cache.commit()
+        with pytest.raises(AssertionError):
+            self.check_cache()
+
     def test_recreate_target_rc(self):
     def test_recreate_target_rc(self):
         self.cmd('init', self.repository_location)
         self.cmd('init', self.repository_location)
         output = self.cmd('recreate', self.repository_location, '--target=asdf', exit_code=2)
         output = self.cmd('recreate', self.repository_location, '--target=asdf', exit_code=2)
@@ -1634,10 +1671,13 @@ class ArchiverTestCase(ArchiverTestCaseBase):
     def test_recreate_target(self):
     def test_recreate_target(self):
         self.create_test_files()
         self.create_test_files()
         self.cmd('init', self.repository_location)
         self.cmd('init', self.repository_location)
+        self.check_cache()
         archive = self.repository_location + '::test0'
         archive = self.repository_location + '::test0'
         self.cmd('create', archive, 'input')
         self.cmd('create', archive, 'input')
+        self.check_cache()
         original_archive = self.cmd('list', self.repository_location)
         original_archive = self.cmd('list', self.repository_location)
         self.cmd('recreate', archive, 'input/dir2', '-e', 'input/dir2/file3', '--target=new-archive')
         self.cmd('recreate', archive, 'input/dir2', '-e', 'input/dir2/file3', '--target=new-archive')
+        self.check_cache()
         archives = self.cmd('list', self.repository_location)
         archives = self.cmd('list', self.repository_location)
         assert original_archive in archives
         assert original_archive in archives
         assert 'new-archive' in archives
         assert 'new-archive' in archives
@@ -1655,6 +1695,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         archive = self.repository_location + '::test0'
         archive = self.repository_location + '::test0'
         self.cmd('create', archive, 'input')
         self.cmd('create', archive, 'input')
         self.cmd('recreate', archive, 'input/dir2', '-e', 'input/dir2/file3')
         self.cmd('recreate', archive, 'input/dir2', '-e', 'input/dir2/file3')
+        self.check_cache()
         listing = self.cmd('list', '--short', archive)
         listing = self.cmd('list', '--short', archive)
         assert 'file1' not in listing
         assert 'file1' not in listing
         assert 'dir2/file2' in listing
         assert 'dir2/file2' in listing
@@ -1666,6 +1707,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         self._extract_hardlinks_setup()
         self._extract_hardlinks_setup()
         self.cmd('create', self.repository_location + '::test2', 'input')
         self.cmd('create', self.repository_location + '::test2', 'input')
         self.cmd('recreate', self.repository_location + '::test', 'input/dir1')
         self.cmd('recreate', self.repository_location + '::test', 'input/dir1')
+        self.check_cache()
         with changedir('output'):
         with changedir('output'):
             self.cmd('extract', self.repository_location + '::test')
             self.cmd('extract', self.repository_location + '::test')
             assert os.stat('input/dir1/hardlink').st_nlink == 2
             assert os.stat('input/dir1/hardlink').st_nlink == 2
@@ -1689,6 +1731,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         # test1 and test2 do not deduplicate
         # test1 and test2 do not deduplicate
         assert num_chunks == unique_chunks
         assert num_chunks == unique_chunks
         self.cmd('recreate', self.repository_location, '--chunker-params', 'default')
         self.cmd('recreate', self.repository_location, '--chunker-params', 'default')
+        self.check_cache()
         # test1 and test2 do deduplicate after recreate
         # test1 and test2 do deduplicate after recreate
         assert not int(self.cmd('list', self.repository_location + '::test1', 'input/large_file',
         assert not int(self.cmd('list', self.repository_location + '::test1', 'input/large_file',
                                 '--format', '{unique_chunks}'))
                                 '--format', '{unique_chunks}'))
@@ -1702,6 +1745,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         size, csize, sha256_before = file_list.split(' ')
         size, csize, sha256_before = file_list.split(' ')
         assert int(csize) >= int(size)  # >= due to metadata overhead
         assert int(csize) >= int(size)  # >= due to metadata overhead
         self.cmd('recreate', self.repository_location, '-C', 'lz4')
         self.cmd('recreate', self.repository_location, '-C', 'lz4')
+        self.check_cache()
         file_list = self.cmd('list', self.repository_location + '::test', 'input/compressible',
         file_list = self.cmd('list', self.repository_location + '::test', 'input/compressible',
                              '--format', '{size} {csize} {sha256}')
                              '--format', '{size} {csize} {sha256}')
         size, csize, sha256_after = file_list.split(' ')
         size, csize, sha256_after = file_list.split(' ')
@@ -1714,6 +1758,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         self.cmd('create', self.repository_location + '::test', 'input')
         self.cmd('create', self.repository_location + '::test', 'input')
         archives_before = self.cmd('list', self.repository_location + '::test')
         archives_before = self.cmd('list', self.repository_location + '::test')
         self.cmd('recreate', self.repository_location, '-n', '-e', 'input/compressible')
         self.cmd('recreate', self.repository_location, '-n', '-e', 'input/compressible')
+        self.check_cache()
         archives_after = self.cmd('list', self.repository_location + '::test')
         archives_after = self.cmd('list', self.repository_location + '::test')
         assert archives_after == archives_before
         assert archives_after == archives_before
 
 
@@ -1723,6 +1768,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         self.cmd('create', self.repository_location + '::test', 'input')
         self.cmd('create', self.repository_location + '::test', 'input')
         info_before = self.cmd('info', self.repository_location + '::test')
         info_before = self.cmd('info', self.repository_location + '::test')
         self.cmd('recreate', self.repository_location, '--chunker-params', 'default')
         self.cmd('recreate', self.repository_location, '--chunker-params', 'default')
+        self.check_cache()
         info_after = self.cmd('info', self.repository_location + '::test')
         info_after = self.cmd('info', self.repository_location + '::test')
         assert info_before == info_after  # includes archive ID
         assert info_before == info_after  # includes archive ID
 
 
@@ -1743,18 +1789,22 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         self.cmd('create', self.repository_location + '::test', 'input')
         self.cmd('create', self.repository_location + '::test', 'input')
 
 
         output = self.cmd('recreate', '--list', '--info', self.repository_location + '::test', '-e', 'input/file2')
         output = self.cmd('recreate', '--list', '--info', self.repository_location + '::test', '-e', 'input/file2')
+        self.check_cache()
         self.assert_in("input/file1", output)
         self.assert_in("input/file1", output)
         self.assert_in("x input/file2", output)
         self.assert_in("x input/file2", output)
 
 
         output = self.cmd('recreate', '--list', self.repository_location + '::test', '-e', 'input/file3')
         output = self.cmd('recreate', '--list', self.repository_location + '::test', '-e', 'input/file3')
+        self.check_cache()
         self.assert_in("input/file1", output)
         self.assert_in("input/file1", output)
         self.assert_in("x input/file3", output)
         self.assert_in("x input/file3", output)
 
 
         output = self.cmd('recreate', self.repository_location + '::test', '-e', 'input/file4')
         output = self.cmd('recreate', self.repository_location + '::test', '-e', 'input/file4')
+        self.check_cache()
         self.assert_not_in("input/file1", output)
         self.assert_not_in("input/file1", output)
         self.assert_not_in("x input/file4", output)
         self.assert_not_in("x input/file4", output)
 
 
         output = self.cmd('recreate', '--info', self.repository_location + '::test', '-e', 'input/file5')
         output = self.cmd('recreate', '--info', self.repository_location + '::test', '-e', 'input/file5')
+        self.check_cache()
         self.assert_not_in("input/file1", output)
         self.assert_not_in("input/file1", output)
         self.assert_not_in("x input/file5", output)
         self.assert_not_in("x input/file5", output)
 
 
@@ -2095,6 +2145,9 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase):
 class RemoteArchiverTestCase(ArchiverTestCase):
 class RemoteArchiverTestCase(ArchiverTestCase):
     prefix = '__testsuite__:'
     prefix = '__testsuite__:'
 
 
+    def open_repository(self):
+        return RemoteRepository(Location(self.repository_location))
+
     def test_remote_repo_restrict_to_path(self):
     def test_remote_repo_restrict_to_path(self):
         # restricted to repo directory itself:
         # restricted to repo directory itself:
         with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', self.repository_path]):
         with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', self.repository_path]):