From c6f95de4923d799029c108315f31485fd8a94d58 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 23 Jul 2024 18:12:11 +0200 Subject: [PATCH] improve borg check --repair healing tests, see #8302 test the healing more thoroughly: - preservation of correct chunks list in .chunks_healthy - check that .chunks_healthy is removed after healing - check that doing another borg check --repair run does not find something to heal, again. also did a datatype consistency fix for item.chunks_healthy list members: they are now post processed in the same way as item.chunks, so they have type ChunkListEntry rather than simple tuple. --- src/borg/archive.py | 2 ++ src/borg/testsuite/archiver/check_cmd.py | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/borg/archive.py b/src/borg/archive.py index eda4ec4c6..fe19b4b6b 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -282,6 +282,8 @@ def unpack_many(self, ids, *, filter=None, preload=False): item = Item(internal_dict=_item) if "chunks" in item: item.chunks = [ChunkListEntry(*e) for e in item.chunks] + if "chunks_healthy" in item: + item.chunks_healthy = [ChunkListEntry(*e) for e in item.chunks_healthy] if filter and not filter(item): continue if preload and "chunks" in item: diff --git a/src/borg/testsuite/archiver/check_cmd.py b/src/borg/testsuite/archiver/check_cmd.py index 16b768073..87fd10ab3 100644 --- a/src/borg/testsuite/archiver/check_cmd.py +++ b/src/borg/testsuite/archiver/check_cmd.py @@ -115,14 +115,20 @@ def test_missing_file_chunk(archivers, request): output = cmd(archiver, "list", "archive1", "--format={health}#{path}{NL}", exit_code=0) assert "broken#" in output - # check that the file in the old archives has now a different chunk list without the killed chunk + # check that the file in the old archives has now a different chunk list without the killed chunk. + # also check that the correct original chunks list is preserved in item.chunks_healthy. for archive_name in ("archive1", "archive2"): archive, repository = open_archive(archiver.repository_path, archive_name) with repository: for item in archive.iter_items(): if item.path.endswith(src_file): - assert valid_chunks != item.chunks + assert len(valid_chunks) == len(item.chunks) assert killed_chunk not in item.chunks + assert valid_chunks != item.chunks + assert "chunks_healthy" in item + assert len(valid_chunks) == len(item.chunks_healthy) + assert killed_chunk in item.chunks_healthy + assert valid_chunks == item.chunks_healthy break else: pytest.fail("should not happen") # convert 'fail' @@ -136,13 +142,15 @@ def test_missing_file_chunk(archivers, request): assert "Healed previously missing file chunk" in output assert f"{src_file}: Completely healed previously damaged file!" in output - # check that the file in the old archives has the correct chunks again + # check that the file in the old archives has the correct chunks again. + # also check that chunks_healthy list is removed as it is not needed any more. for archive_name in ("archive1", "archive2"): archive, repository = open_archive(archiver.repository_path, archive_name) with repository: for item in archive.iter_items(): if item.path.endswith(src_file): assert valid_chunks == item.chunks + assert "chunks_healthy" not in item break else: pytest.fail("should not happen") @@ -151,6 +159,11 @@ def test_missing_file_chunk(archivers, request): output = cmd(archiver, "list", "archive1", "--format={health}#{path}{NL}", exit_code=0) assert "broken#" not in output + # check should be fine now (and not show it has healed anything). + output = cmd(archiver, "check", "-v", "--repair", exit_code=0) + assert "Healed previously missing file chunk" not in output + assert "testsuite/archiver.py: Completely healed previously damaged file!" not in output + def test_missing_archive_item_chunk(archivers, request): archiver = request.getfixturevalue(archivers)