From 604a01d3539b0bab1b57c15c1386b15e8fc7ce4e Mon Sep 17 00:00:00 2001 From: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Date: Thu, 5 Nov 2026 15:41:47 -0500 Subject: [PATCH] fix: map log destination errors --- tools/droiddeckctl | 5 ++++- tools/tests/test_droiddeckctl.py | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tools/droiddeckctl b/tools/droiddeckctl index 02fe7020c..65fb274ce 100755 --- a/tools/droiddeckctl +++ b/tools/droiddeckctl @@ -425,7 +425,10 @@ def start_session(adb: str, serial: str, request: dict) -> dict: def unpack_logs(archive: Path, destination: Path, session_id: str) -> None: """Unpack a Share logs zip so the session's own files sit at the top of destination.""" destination = destination.resolve() - destination.mkdir(parents=True, exist_ok=True) + try: + destination.mkdir(parents=True, exist_ok=True) + except OSError as exc: + raise ControlError(f"Could not unpack the session logs: {exc}", "LOG_PULL_FAILED") from exc manifest = destination / ".droiddeckctl-managed-logs.json" try: previous = json.loads(manifest.read_text(encoding="utf-8")) diff --git a/tools/tests/test_droiddeckctl.py b/tools/tests/test_droiddeckctl.py index 531bcd891..731e3aa38 100644 --- a/tools/tests/test_droiddeckctl.py +++ b/tools/tests/test_droiddeckctl.py @@ -610,6 +610,23 @@ class DroiddeckctlTest(FakeAdbTest): self.assertFalse((destination / "steam/console.log").exists()) self.assertEqual("keep me", (destination / "notes.txt").read_text()) + def test_logs_map_destination_creation_failure_to_pull_error(self): + destination = (self.dir / "artifacts").resolve() + archive = self.dir / "logs.zip" + real_mkdir = Path.mkdir + + def fail_destination(path, *args, **kwargs): + if path == destination: + raise PermissionError("injected destination failure") + return real_mkdir(path, *args, **kwargs) + + with unittest.mock.patch.object(Path, "mkdir", new=fail_destination): + with self.assertRaises(ctl.ControlError) as raised: + ctl.unpack_logs(archive, destination, "s1") + + self.assertEqual("LOG_PULL_FAILED", raised.exception.code) + self.assertIn("injected destination failure", str(raised.exception)) + def test_logs_do_not_follow_a_stale_managed_symlink(self): if os.name == "nt": self.skipTest("symlink creation is unavailable on this Windows host")