Ctrl K
ComunidadGuías…

tests/test_cli_polish.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""CLI ergonomics (audit 2026-07-12).

Three rough edges a daily user hit every time: `job --version` errored, a bare
`job` printed a usage error instead of help, and `job list` dumped the broker's
entire job history with no cap and no indication anything was withheld.
"""

from __future__ import annotations

from datetime import UTC, datetime

from typer.testing import CliRunner

import job_cli.cli as cli_mod
from jobd import __version__


class _Resp:
    def __init__(self, data, headers=None):
        self._data = data
        self.headers = headers or {}

    def raise_for_status(self):
        pass

    def json(self):
        return self._data


def _fake_client(jobs, total, capture):
    recent = datetime.now(UTC).isoformat()
    workers = [{"host": "desktop", "last_heartbeat": recent, "state": "online"}]

    class FakeClient:
        def __enter__(self):
            return self

        def __exit__(self, *a):
            pass

        def get(self, path, params=None):
            if path == "/workers":
                return _Resp(workers)
            capture["params"] = params or {}
            limit = (params or {}).get("limit")
            page = jobs[:limit] if limit else jobs
            return _Resp(page, {"X-Total-Count": str(total)})

    return FakeClient


def _jobs(n):
    return [
        {"id": i, "state": "completed", "project": "project-a", "cmd": ["echo", str(i)]}
        for i in range(n, 0, -1)
    ]


def test_version_flag_reports_the_version():
    r = CliRunner().invoke(cli_mod.app, ["--version"])
    assert r.exit_code == 0
    assert __version__ in r.stdout


def test_bare_job_shows_the_full_help():
    """Bare `job` used to print a terse usage error with no command list. It now
    prints the full help. (Exit code stays 2 — Click's convention for "no command
    given" — so scripts can still detect it; the fix is that the user now sees
    what the commands ARE.)"""
    r = CliRunner().invoke(cli_mod.app, [])
    assert "Usage:" in r.stdout
    assert "submit" in r.stdout  # the command list is what was missing
    assert "list" in r.stdout


def test_help_documents_jobd_url():
    """JOBD_URL is the single most important setting and appeared nowhere."""
    r = CliRunner().invoke(cli_mod.app, ["--help"])
    assert r.exit_code == 0
    assert "JOBD_URL" in r.stdout


def test_list_caps_by_default_and_says_what_it_withheld(monkeypatch):
    capture: dict = {}
    monkeypatch.setattr(cli_mod, "_client", lambda: _fake_client(_jobs(200), 200, capture)())
    r = CliRunner().invoke(cli_mod.app, ["list"])
    assert r.exit_code == 0
    assert capture["params"]["limit"] == cli_mod._LIST_DEFAULT_LIMIT
    # Never truncate silently.
    assert "showing 50 of 200" in r.stdout
    assert "--all" in r.stdout


def test_list_all_removes_the_cap(monkeypatch):
    capture: dict = {}
    monkeypatch.setattr(cli_mod, "_client", lambda: _fake_client(_jobs(200), 200, capture)())
    r = CliRunner().invoke(cli_mod.app, ["list", "--all"])
    assert r.exit_code == 0
    assert "limit" not in capture["params"]
    assert "showing" not in r.stdout  # nothing withheld -> no footer


def test_list_explicit_limit_is_honoured(monkeypatch):
    capture: dict = {}
    monkeypatch.setattr(cli_mod, "_client", lambda: _fake_client(_jobs(200), 200, capture)())
    r = CliRunner().invoke(cli_mod.app, ["list", "--limit", "5"])
    assert r.exit_code == 0
    assert capture["params"]["limit"] == 5
    assert "showing 5 of 200" in r.stdout


def test_array_listing_is_not_silently_truncated(monkeypatch):
    """A truncated array misrepresents its shape, so --array shows all members."""
    capture: dict = {}
    monkeypatch.setattr(cli_mod, "_client", lambda: _fake_client(_jobs(80), 80, capture)())
    r = CliRunner().invoke(cli_mod.app, ["list", "--array", "A7"])
    assert r.exit_code == 0
    assert "limit" not in capture["params"]