| from __future__ import annotations |
|
|
| from types import SimpleNamespace |
| from unittest.mock import patch |
|
|
| import pytest |
|
|
| from jarvis.runtime_entrypoint import ( |
| maybe_run_backup_or_restore, |
| run_jarvis_event_loop, |
| ) |
|
|
|
|
| def test_maybe_run_backup_or_restore_returns_false_when_no_maintenance_args() -> None: |
| args = SimpleNamespace(backup=None, restore=None, force=False) |
| ran = maybe_run_backup_or_restore( |
| args, |
| config_class=lambda: object(), |
| create_backup_bundle_fn=lambda config, path: {}, |
| restore_backup_bundle_fn=lambda config, path, overwrite=False: {}, |
| ) |
| assert ran is False |
|
|
|
|
| def test_maybe_run_backup_or_restore_backup_prints_result(capsys) -> None: |
| args = SimpleNamespace(backup="/tmp/backup.zip", restore=None, force=False) |
| ran = maybe_run_backup_or_restore( |
| args, |
| config_class=lambda: object(), |
| create_backup_bundle_fn=lambda config, path: {"ok": True, "path": path}, |
| restore_backup_bundle_fn=lambda config, path, overwrite=False: {}, |
| ) |
| captured = capsys.readouterr() |
| assert ran is True |
| assert '"ok": true' in captured.out.lower() |
| assert "/tmp/backup.zip" in captured.out |
|
|
|
|
| def test_maybe_run_backup_or_restore_failure_raises_system_exit(capsys) -> None: |
| args = SimpleNamespace(backup="/tmp/backup.zip", restore=None, force=False) |
|
|
| with pytest.raises(SystemExit) as exc_info: |
| maybe_run_backup_or_restore( |
| args, |
| config_class=lambda: object(), |
| create_backup_bundle_fn=lambda config, path: (_ for _ in ()).throw(RuntimeError("boom")), |
| restore_backup_bundle_fn=lambda config, path, overwrite=False: {}, |
| ) |
|
|
| captured = capsys.readouterr() |
| assert exc_info.value.code == 1 |
| assert '"ok": false' in captured.out.lower() |
| assert "boom" in captured.out |
|
|
|
|
| def test_run_jarvis_event_loop_bootstraps_and_cleans_up() -> None: |
| class _FakeTask: |
| def __init__(self) -> None: |
| self.cancelled = False |
|
|
| def cancel(self) -> None: |
| self.cancelled = True |
|
|
| class _FakeLoop: |
| def __init__(self) -> None: |
| self.calls: list[object] = [] |
| self.task = _FakeTask() |
| self.closed = False |
|
|
| def create_task(self, coro): |
| self.calls.append(("create_task", coro)) |
| return self.task |
|
|
| def run_until_complete(self, awaitable): |
| self.calls.append(("run_until_complete", awaitable)) |
| return None |
|
|
| def shutdown_asyncgens(self): |
| return "shutdown_asyncgens" |
|
|
| def shutdown_default_executor(self): |
| return "shutdown_default_executor" |
|
|
| def close(self): |
| self.closed = True |
|
|
| fake_loop = _FakeLoop() |
| jarvis = SimpleNamespace(run=lambda: "run-coro") |
| signal_calls: list[tuple[object, object]] = [] |
|
|
| with patch("jarvis.runtime_entrypoint.asyncio.new_event_loop", return_value=fake_loop), \ |
| patch("jarvis.runtime_entrypoint.asyncio.set_event_loop") as set_event_loop, \ |
| patch("jarvis.runtime_entrypoint.signal.signal", side_effect=lambda sig, handler: signal_calls.append((sig, handler))): |
| run_jarvis_event_loop(jarvis) |
|
|
| set_event_loop.assert_called_once_with(fake_loop) |
| assert fake_loop.closed is True |
| assert any(call[0] == "create_task" for call in fake_loop.calls) |
| assert len(signal_calls) >= 1 |
|
|