Source code for tests.test_doctor

# Copyright Kevin Deldycke <[email protected]> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""Checks for the `doctor` operation and its dedicated contract.

Health comes from the diagnostic command's exit code alone, the report merges
`<stdout>` and `<stderr>`, and the diagnosis never inflates the end-of-run
error tally. The argv assertions monkeypatch the binary-resolution seams on the
pooled manager singletons, so they run identically on any host.
"""

from __future__ import annotations

from pathlib import Path

import pytest

from meta_package_manager.capabilities import Operations, implements
from meta_package_manager.execution import CLIError
from meta_package_manager.pool import pool

from .fake_manager import FakeManager
from .test_sudo import only_escalator


[docs] @pytest.mark.parametrize( ("manager_id", "token"), ( ("apt", "check"), ("brew", "doctor"), ("cask", "doctor"), ("composer", "diagnose"), ("dnf", "check"), ("flatpak", "--dry-run"), ("gem", "check"), ("mise", "doctor"), ("npm", "doctor"), ("pacman", "--check"), ("pip", "check"), ("pkg", "--checksums"), ("scoop", "checkup"), ("xbps", "--all"), ), ) def test_doctor_cli_argv(monkeypatch, manager_id, token): """Each manager's diagnostic invocation carries its native verb.""" manager = pool[manager_id] monkeypatch.setattr( manager, "cli_path", Path("/fake/bin") / manager.cli_names[0], raising=False ) monkeypatch.setattr(manager, "which", lambda name: Path("/fake/bin") / name) monkeypatch.setattr( manager, "sibling_cli", lambda name, **kwargs: Path("/fake/bin") / name ) tokens = tuple(str(arg) for arg in manager.doctor_cli()) assert token in tokens
[docs] @pytest.mark.parametrize( "manager_id", ("apt", "brew", "cask", "dnf", "macports", "pacman", "pip", "tlmgr", "xbps"), ) def test_doctor_supported(manager_id): assert implements(pool[manager_id], Operations.doctor) is True
[docs] @pytest.mark.parametrize("manager_id", ("cargo", "cave", "mas", "snap", "uv")) def test_doctor_unsupported(manager_id): assert implements(pool[manager_id], Operations.doctor) is False
# Base orchestrator contract, driven through a stubbed run(). def _doctor_with_stubbed_run(monkeypatch, *, code, stdout, stderr, completed=True): """Run `doctor()` on a manager whose `run` mimics one executor outcome. Reproduces `run()`'s observable surface: sets `_last_run` on completion (or leaves it `None` for a spawn that never finished), applies the failure gate's default tolerance (a non-zero exit only accumulates a `CLIError` when `<stderr>` is non-empty), and returns `<stdout>`. """ manager = pool["mise"] monkeypatch.setattr(manager, "doctor_cli", lambda: ("doctor",)) monkeypatch.setattr(manager, "cli_errors", []) def fake_run(*args, **kwargs): manager._last_run = (code, stdout, stderr) if completed else None if completed and code and stderr: manager.cli_errors.append(CLIError(code, stdout, stderr)) elif not completed: manager.cli_errors.append(CLIError(None, "", "Timed out.")) return stdout monkeypatch.setattr(manager, "run", fake_run) return manager
[docs] @pytest.mark.parametrize( ("code", "stdout", "stderr", "verdict"), ( # A healthy run merges both streams into the report. pytest.param( 0, "All good.", "Note: chatter.", (True, "All good.\nNote: chatter."), id="healthy-merges-streams", ), # A non-zero exit with a silent `<stderr>`, the shape of `pip check`, passes # the failure gate but still reads as unhealthy: the exit code is the # verdict. pytest.param( 1, "conflicting dependencies found", "", (False, "conflicting dependencies found"), id="unhealthy-from-stdout-only-exit", ), # The unhealthy exit is the diagnosis, not a plumbing error: the `CLIError` # of the gate is reclaimed, so the end-of-run summary is not inflated. pytest.param( 1, "", "Warning: broken linkage.", (False, "Warning: broken linkage."), id="reclaims-failure-gate-entry", ), ), ) def test_doctor_verdict(monkeypatch, code, stdout, stderr, verdict): """The exit code decides the health, and no run leaves a `CLIError` behind.""" manager = _doctor_with_stubbed_run( monkeypatch, code=code, stdout=stdout, stderr=stderr ) assert manager.doctor() == verdict assert manager.cli_errors == []
[docs] def test_doctor_incomplete_run_stays_an_error(monkeypatch): """A spawn that never completed is a plumbing error. Like a timeout or an interrupt: unhealthy, and its `CLIError` stays in the tally. """ manager = _doctor_with_stubbed_run( monkeypatch, code=0, stdout="", stderr="", completed=False ) assert manager.doctor() == (False, "") assert len(manager.cli_errors) == 1
[docs] def test_base_doctor_not_implemented(): """A manager without a diagnostic verb propagates `NotImplementedError`.""" with pytest.raises(NotImplementedError): pool["uv"].doctor()
# CLI plumbing, driven through deterministic fakes. @pytest.fixture(autouse=True) def _no_host_escalator(): """Keep the escalation report of `mpm doctor` off the real host's escalator. Pretends the host carries none, so the report spends no probe. """ with only_escalator(None): yield
[docs] class HealthyDoctorFakeManager(FakeManager): """Fake manager whose diagnosis succeeds with a report."""
[docs] def doctor_cli(self) -> tuple[str, ...]: return ("doctor",)
[docs] def doctor(self) -> tuple[bool, str]: return True, "Your system is ready."
[docs] class SickDoctorFakeManager(HealthyDoctorFakeManager): """Fake manager whose diagnosis reports problems."""
[docs] def doctor(self) -> tuple[bool, str]: return False, "Broken linkage found."
[docs] class SilentDoctorFakeManager(HealthyDoctorFakeManager): """Fake manager whose diagnosis succeeds silently (the apt-get check shape)."""
[docs] def doctor(self) -> tuple[bool, str]: return True, ""
[docs] def test_doctor_healthy_relays_report(invoke, patch_pool_with): fake = patch_pool_with(HealthyDoctorFakeManager()) result = invoke("doctor") assert result.exit_code == 0 assert f"{fake.id}:" in result.stdout assert "Your system is ready." in result.stdout
[docs] def test_doctor_opens_on_the_escalation_report(invoke, patch_pool_with): """The escalation report comes first, and never changes the exit code.""" patch_pool_with(HealthyDoctorFakeManager()) result = invoke("doctor") assert result.exit_code == 0 assert result.stdout.startswith("Privilege escalation:\nEscalator: none found")
[docs] def test_doctor_without_diagnostic_verb_still_reports(invoke, monkeypatch): """Selected managers that all lack a diagnostic verb are no selection error. The escalation report is the whole diagnosis, as on SliTaz with `tazpkg`. """ fake = FakeManager() assert not implements(fake, Operations.doctor) def select(*args, implements_operation=None, **kwargs): if implements_operation is None or implements(fake, implements_operation): yield fake monkeypatch.setattr(pool, "_select_managers", select) result = invoke("doctor") assert result.exit_code == 0 assert result.stdout.startswith("Privilege escalation:") assert "None of the selected managers has a diagnostic verb." in result.stderr
[docs] def test_doctor_with_no_manager_selected_fails_after_reporting(invoke, monkeypatch): """No manager selected at all stays the usual error. It comes once the escalation report is out. """ monkeypatch.setattr(pool, "_select_managers", lambda *args, **kwargs: iter(())) result = invoke("doctor") assert result.exit_code == 2 assert result.stdout.startswith("Privilege escalation:") assert "No manager selected." in result.stderr
[docs] def test_doctor_unhealthy_exits_nonzero(invoke, patch_pool_with): fake = patch_pool_with(SickDoctorFakeManager()) result = invoke("doctor") assert result.exit_code == 1 assert "Broken linkage found." in result.stdout assert f"1 manager reported problems ({fake.id})." in result.stderr
[docs] @pytest.mark.parametrize("flag", ("--zero-exit", "-0")) def test_doctor_zero_exit_opt_out(invoke, patch_pool_with, flag): """-0/--zero-exit keeps the exit code at 0. The critical summary stays as the durable record. """ fake = patch_pool_with(SickDoctorFakeManager()) result = invoke(flag, "doctor") assert result.exit_code == 0 assert f"1 manager reported problems ({fake.id})." in result.stderr
[docs] def test_doctor_silent_healthy_prints_no_section(invoke, patch_pool_with): """A healthy manager with an empty report gets no stdout section. The trail already says everything. """ fake = patch_pool_with(SilentDoctorFakeManager()) result = invoke("doctor") assert result.exit_code == 0 assert f"{fake.id}:" not in result.stdout