Files
pkgmgr/tests/integration/test_mirror_commands.py
Kevin Veen-Birkenbach b4e0594901 style: modernise typing and clean up lint findings
Repository-wide mechanical cleanup so `ruff check src tests` has a chance
of passing; no behavioural changes.

- Add `from __future__ import annotations` where PEP 604 unions are used.
  This has to come first: pyproject declares requires-python >= 3.9, where
  `X | None` is not evaluable at runtime unless annotations are stringified.
- Replace typing.List/Dict/Tuple/Set with the builtin generics and
  Optional[X] with X | None, then drop the imports that became unused.
  The four actions/*/__init__.py files needed this by hand because ruff
  leaves unused imports in __init__.py alone (possible re-exports).
- Strip shebangs from 72 importable modules. None of them are executable
  or invoked directly; the entry points are console_scripts and runpy.
- Flatten nested `with` blocks, collapse needless-bool returns, and apply
  the remaining mechanical ruff fixes (PIE810, FLY002, PERF102, FURB192,
  RUF059, I001).
- Pass check=False explicitly to the four subprocess.run() calls that
  inspect returncode themselves. That is the existing default.

Two rewrites are visible to mocks, so their tests move with them:
subprocess.run(stdout=PIPE, stderr=PIPE) became capture_output=True, and
open(path, "r", ...) lost the redundant mode.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:47:13 +02:00

199 lines
7.6 KiB
Python

"""
CLI integration tests for `pkgmgr mirror`.
These tests validate:
- CLI argument parsing
- command dispatch
- command orchestration
All side effects (git, network, remote provisioning, filesystem writes)
are patched to keep tests deterministic and CI-safe.
"""
from __future__ import annotations
import importlib
import io
import os
import runpy
import sys
import unittest
from contextlib import ExitStack, redirect_stderr, redirect_stdout
from unittest.mock import MagicMock, PropertyMock, patch
class TestIntegrationMirrorCommands(unittest.TestCase):
"""Integration tests for `pkgmgr mirror` commands."""
def _run_pkgmgr(
self, args: list[str], extra_env: dict[str, str] | None = None
) -> str:
"""Execute pkgmgr with the given arguments and return captured output."""
original_argv = list(sys.argv)
original_env = dict(os.environ)
buffer = io.StringIO()
cmd_repr = "pkgmgr " + " ".join(args)
# Shared dummy context used by multiple mirror commands
dummy_ctx = MagicMock()
dummy_ctx.identifier = "dummy-repo"
dummy_ctx.repo_dir = "/tmp/dummy-repo"
dummy_ctx.config_mirrors = {"origin": "git@github.com:alice/repo.git"}
dummy_ctx.file_mirrors = {"backup": "ssh://git@git.example:2201/alice/repo.git"}
type(dummy_ctx).resolved_mirrors = PropertyMock(
return_value={
"origin": "git@github.com:alice/repo.git",
"backup": "ssh://git@git.example:2201/alice/repo.git",
}
)
# Helper: patch with create=True so missing symbols don't explode.
# IMPORTANT: patch() does not auto-import submodules when resolving dotted names.
def _p(target: str, **kwargs):
module_name = target.rsplit(".", 1)[0]
try:
importlib.import_module(module_name)
except ModuleNotFoundError:
# Best-effort: allow patch(create=True) even if a symbol moved.
pass
return patch(target, create=True, **kwargs)
# Fake result for remote provisioning (preview-safe)
def _fake_ensure_remote_repo(spec, provider_hint=None, options=None):
# Safety: E2E should only ever call this in preview mode
if options is not None and getattr(options, "preview", False) is not True:
raise AssertionError(
f"{cmd_repr} attempted ensure_remote_repo without preview=True in E2E."
)
r = MagicMock()
r.status = "preview"
r.message = "Preview mode (E2E patched): no remote provisioning performed."
r.url = None
return r
try:
sys.argv = ["pkgmgr"] + list(args)
if extra_env:
os.environ.update(extra_env)
with ExitStack() as stack:
# build_context is imported directly in these modules:
stack.enter_context(
_p(
"pkgmgr.actions.mirror.list_cmd.build_context",
return_value=dummy_ctx,
)
)
stack.enter_context(
_p(
"pkgmgr.actions.mirror.diff_cmd.build_context",
return_value=dummy_ctx,
)
)
stack.enter_context(
_p(
"pkgmgr.actions.mirror.merge_cmd.build_context",
return_value=dummy_ctx,
)
)
stack.enter_context(
_p(
"pkgmgr.actions.mirror.setup_cmd.build_context",
return_value=dummy_ctx,
)
)
stack.enter_context(
_p(
"pkgmgr.actions.mirror.remote_provision.build_context",
return_value=dummy_ctx,
)
)
# Deterministic remote probing (refactor: probe_remote_reachable_detail)
# Patch where it is USED (setup_cmd imported it directly).
stack.enter_context(
_p(
"pkgmgr.actions.mirror.setup_cmd.probe_remote_reachable_detail",
return_value=(True, ""),
)
)
# setup_cmd imports ensure_origin_remote directly:
stack.enter_context(
_p(
"pkgmgr.actions.mirror.setup_cmd.ensure_origin_remote",
return_value=None,
)
)
# Extra safety: if any code calls git_remote.ensure_origin_remote directly
stack.enter_context(
_p(
"pkgmgr.actions.mirror.git_remote.ensure_origin_remote",
return_value=None,
)
)
# remote provisioning: remote_provision imports ensure_remote_repo directly from core:
stack.enter_context(
_p(
"pkgmgr.actions.mirror.remote_provision.ensure_remote_repo",
side_effect=_fake_ensure_remote_repo,
)
)
with redirect_stdout(buffer), redirect_stderr(buffer):
try:
runpy.run_module("pkgmgr", run_name="__main__")
except SystemExit as exc:
code = exc.code if isinstance(exc.code, int) else None
if code not in (0, None):
raise AssertionError(
f"{cmd_repr!r} failed with exit code {exc.code!r}.\n\nOutput:\n{buffer.getvalue()}"
)
return buffer.getvalue()
finally:
sys.argv = original_argv
os.environ.clear()
os.environ.update(original_env)
def test_mirror_help(self) -> None:
output = self._run_pkgmgr(["mirror", "--help"])
self.assertIn("usage:", output.lower())
self.assertIn("mirror", output.lower())
def test_mirror_list_preview_all(self) -> None:
output = self._run_pkgmgr(["mirror", "list", "--preview", "--all"])
self.assertTrue(output.strip(), "Expected output from mirror list")
def test_mirror_diff_preview_all(self) -> None:
output = self._run_pkgmgr(["mirror", "diff", "--preview", "--all"])
self.assertTrue(output.strip(), "Expected output from mirror diff")
def test_mirror_merge_config_to_file_preview_all(self) -> None:
output = self._run_pkgmgr(
["mirror", "merge", "config", "file", "--preview", "--all"]
)
self.assertTrue(
output.strip(), "Expected output from mirror merge (config -> file)"
)
def test_mirror_setup_preview_all(self) -> None:
output = self._run_pkgmgr(["mirror", "setup", "--preview", "--all"])
self.assertTrue(output.strip(), "Expected output from mirror setup")
def test_mirror_check_preview_all(self) -> None:
output = self._run_pkgmgr(["mirror", "check", "--preview", "--all"])
self.assertTrue(output.strip(), "Expected output from mirror check")
def test_mirror_provision_preview_all(self) -> None:
output = self._run_pkgmgr(["mirror", "provision", "--preview", "--all"])
self.assertTrue(
output.strip(), "Expected output from mirror provision (preview)"
)
if __name__ == "__main__":
unittest.main()