mirror of
https://github.com/kevinveenbirkenbach/docker-volume-backup.git
synced 2026-08-20 21:22:54 +00:00
A finished generation cannot show whether a volume held a database, nor whether a dump was produced for it: under --only-sql a failed dump falls back to a file copy, and the resulting files/ tree looks like any other copy. The run knows both and threw the knowledge away as a printed warning, leaving every reader to guess from file names. Each generation now carries a manifest.json stating its layout and, per volume, database / dumped / engine. baudolo.generation is the single place those names are spelled; restore/paths.py, backup/db.py and backup/volume.py stop repeating them. It is deliberately import-free so a consumer can read the manifest with nothing but json, on hosts where this package is not installed. BREAKING CHANGE: BackupException is renamed BackupError. The rename is atomic across the ten modules that define or import it, three of which also carry the manifest change, so it lands in this commit rather than a separate one that could not import. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
45 lines
1.5 KiB
Python
45 lines
1.5 KiB
Python
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from baudolo.backup import docker as docker_mod
|
|
from baudolo.backup.shell import BackupError
|
|
|
|
|
|
class TestImageId(unittest.TestCase):
|
|
def test_the_id_is_returned_without_surrounding_whitespace(self) -> None:
|
|
with patch.object(
|
|
docker_mod, "execute_shell_command", return_value=["sha256:abc \n"]
|
|
):
|
|
self.assertEqual(docker_mod.image_id("c1"), "sha256:abc")
|
|
|
|
|
|
class TestHasTool(unittest.TestCase):
|
|
def test_a_tool_that_runs_is_present(self) -> None:
|
|
with patch.object(docker_mod, "execute_shell_command", return_value=[]):
|
|
self.assertTrue(docker_mod.has_tool("c1", "pg_dumpall"))
|
|
|
|
def test_a_tool_that_exits_non_zero_is_absent(self) -> None:
|
|
with patch.object(
|
|
docker_mod, "execute_shell_command", side_effect=BackupError("127")
|
|
):
|
|
self.assertFalse(docker_mod.has_tool("c1", "mariadb-dump"))
|
|
|
|
def test_the_probe_needs_no_shell_in_the_image(self) -> None:
|
|
"""A distroless database ships no shell; `sh -c` would deny every tool."""
|
|
captured = []
|
|
|
|
def _capture(cmd):
|
|
captured.append(cmd)
|
|
return []
|
|
|
|
with patch.object(docker_mod, "execute_shell_command", side_effect=_capture):
|
|
docker_mod.has_tool("c1", "pg_dumpall")
|
|
|
|
self.assertEqual(
|
|
captured, [["docker", "exec", "c1", "pg_dumpall", "--version"]]
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|