test_systemd_backup_paths.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. """Reinstalling must not silently take away a writable path (#2544).
  2. ``ProtectSystem=strict`` means the unit's ``ReadWritePaths`` is the *complete*
  3. list of places Bambuddy can write. An operator who backs up to a NAS adds their
  4. share to it by hand — and both installers overwrite the unit file wholesale, so
  5. that line used to vanish on the next install. The backups then failed with EROFS
  6. every night, which looks like a NAS permission problem and is not one.
  7. So the installers keep the operator's extra paths, and the unit says why they
  8. matter.
  9. """
  10. from __future__ import annotations
  11. from pathlib import Path
  12. import pytest
  13. REPO = Path(__file__).resolve().parents[3]
  14. INSTALLERS = ["install/install.sh", "spoolbuddy/install/install.sh"]
  15. def _read(rel: str) -> str:
  16. path = REPO / rel
  17. assert path.is_file(), f"launcher moved or was removed: {rel}"
  18. return path.read_text()
  19. class TestUnitTemplate:
  20. def test_readwritepaths_still_grants_the_three_app_dirs(self):
  21. unit = _read("deploy/bambuddy.service")
  22. line = next(line for line in unit.splitlines() if line.startswith("ReadWritePaths="))
  23. assert "DATA_DIR" in line and "LOG_DIR" in line and "INSTALL_PATH" in line
  24. def test_unit_explains_how_to_add_a_backup_share(self):
  25. """Whoever reads this unit next has to be able to work out why their NAS
  26. is read-only for the service but not for their shell.
  27. """
  28. unit = _read("deploy/bambuddy.service")
  29. assert "systemctl edit" in unit, "the unit should show how to add a writable path via a drop-in"
  30. class TestInstallersPreserveCustomPaths:
  31. @pytest.mark.parametrize("installer", INSTALLERS)
  32. def test_generated_unit_appends_the_carried_over_paths(self, installer):
  33. script = _read(installer)
  34. line = next(line for line in script.splitlines() if line.startswith("ReadWritePaths="))
  35. assert "$extra_rw" in line, (
  36. f"{installer} writes ReadWritePaths without $extra_rw, so a NAS share the operator "
  37. "added to the unit is dropped on reinstall:\n" + line
  38. )
  39. @pytest.mark.parametrize("installer", INSTALLERS)
  40. def test_existing_unit_is_read_for_custom_paths_and_backed_up(self, installer):
  41. script = _read(installer)
  42. assert "ReadWritePaths=" in script and "extra_rw+=" in script, (
  43. f"{installer} no longer carries the previous unit's ReadWritePaths forward"
  44. )
  45. assert ".bak-" in script, f"{installer} overwrites the unit without backing it up first"