diff --git a/src/bakrest/backup.py b/src/bakrest/backup.py index 9e3d594..11e591d 100644 --- a/src/bakrest/backup.py +++ b/src/bakrest/backup.py @@ -186,7 +186,7 @@ def _run_robocopy( command = _build_robocopy_command(config, event, destination_root) logger.info("Running robocopy command: %s", _redact_command(command)) try: - completed = subprocess.run(command, capture_output=True, text=True, check=False) + completed = _run_command(command) except OSError as exc: message = f"Errore avvio robocopy: {exc}" logger.exception(message) @@ -223,7 +223,7 @@ def _run_rsync(config: AppConfig, events: list[ChangeEvent], logger: logging.Log command = _build_rsync_command(config, events) files_from_path = _extract_files_from_path(command) logger.info("Running rsync command: %s", _redact_command(command)) - completed = subprocess.run(command, capture_output=True, text=True, check=False) + completed = _run_command(command) except OSError as exc: message = f"Errore avvio rsync: {exc}" logger.exception(message) @@ -340,3 +340,14 @@ def _source_arg(path: Path) -> str: def _redact_command(command: list[str]) -> str: return " ".join(command) + + +def _run_command(command: list[str]) -> subprocess.CompletedProcess[str]: + return subprocess.run( + command, + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + check=False, + ) diff --git a/tests/test_backup.py b/tests/test_backup.py index c61e762..faf6518 100644 --- a/tests/test_backup.py +++ b/tests/test_backup.py @@ -7,6 +7,7 @@ from bakrest.backup import ( _build_robocopy_command, _build_rsync_command, _robocopy_destination_dir, + _run_command, _run_robocopy, _split_existing_files, ) @@ -146,7 +147,7 @@ def test_robocopy_marks_each_file_copied_after_all_destinations( pending_counts_after_commands: list[int] = [] - def fake_run(command, capture_output, text, check): + def fake_run(command, **kwargs): pending_counts_after_commands.append(registry.pending_count()) return subprocess.CompletedProcess(command, 0, stdout="", stderr="") @@ -172,3 +173,19 @@ class _NullLogger: def exception(self, *args, **kwargs) -> None: pass + + +def test_run_command_uses_lossy_utf8_decoding(monkeypatch) -> None: + calls = {} + + def fake_run(*args, **kwargs): + calls.update(kwargs) + return subprocess.CompletedProcess(args[0], 0, stdout="", stderr="") + + monkeypatch.setattr("bakrest.backup.subprocess.run", fake_run) + + _run_command(["robocopy"]) + + assert calls["encoding"] == "utf-8" + assert calls["errors"] == "replace" + assert calls["text"] is True