From 4c4f8be0b99b682b335c5528656867167ee5d343 Mon Sep 17 00:00:00 2001 From: Xuezhao Lan Date: Sun, 31 May 2026 03:34:09 -0700 Subject: [PATCH] test(cron): cover CLI helpers --- tests/hermes_cli/test_cron.py | 139 ++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/tests/hermes_cli/test_cron.py b/tests/hermes_cli/test_cron.py index aa4f6b116f14..5be2e6d1c551 100644 --- a/tests/hermes_cli/test_cron.py +++ b/tests/hermes_cli/test_cron.py @@ -1,10 +1,12 @@ """Tests for hermes_cli.cron command handling.""" from argparse import Namespace +from types import SimpleNamespace import pytest from cron.jobs import create_job, get_job, list_jobs +from hermes_cli import cron as cron_cli from hermes_cli.cron import cron_command @@ -57,6 +59,11 @@ def test_edit_can_replace_and_clear_skills(self, tmp_cron_dir, capsys): skills=["maps", "blogwatcher"], profile="default", clear_skills=False, + add_skills=None, + remove_skills=None, + script=None, + workdir=None, + no_agent=None, ) ) updated = get_job(job["id"]) @@ -79,6 +86,11 @@ def test_edit_can_replace_and_clear_skills(self, tmp_cron_dir, capsys): skills=None, profile="", clear_skills=True, + add_skills=None, + remove_skills=None, + script=None, + workdir=None, + no_agent=None, ) ) cleared = get_job(job["id"]) @@ -101,6 +113,9 @@ def test_create_with_multiple_skills(self, tmp_cron_dir, capsys): skill=None, skills=["blogwatcher", "maps"], profile="default", + script=None, + workdir=None, + no_agent=False, ) ) out = capsys.readouterr().out @@ -127,3 +142,127 @@ def test_list_does_not_crash_when_repeat_is_null(self, tmp_cron_dir, capsys): out = capsys.readouterr().out assert "Repeat: ∞" in out + + +def test_cron_list_warns_when_gateway_not_running(monkeypatch, capsys): + monkeypatch.setattr( + "cron.jobs.list_jobs", + lambda include_disabled=False: [ + { + "id": "job-1", + "name": "Nightly docs", + "schedule_display": "every day", + "state": "scheduled", + "enabled": True, + "next_run_at": "2026-06-01T00:00:00Z", + "deliver": ["local"], + } + ], + ) + monkeypatch.setattr("hermes_cli.gateway.find_gateway_pids", lambda: []) + + cron_cli.cron_list() + + out = capsys.readouterr().out + assert "Gateway is not running" in out + assert "Nightly docs" in out + + + +def test_cron_status_reports_running_gateway(monkeypatch, capsys): + monkeypatch.setattr("hermes_cli.gateway.find_gateway_pids", lambda: [1234, 5678]) + monkeypatch.setattr( + "cron.jobs.list_jobs", + lambda include_disabled=False: [ + {"next_run_at": "2026-06-01T00:00:00Z"}, + {"next_run_at": "2026-05-31T12:00:00Z"}, + ], + ) + + cron_cli.cron_status() + + out = capsys.readouterr().out + assert "Gateway is running" in out + assert "1234, 5678" in out + assert "2 active job(s)" in out + assert "2026-05-31T12:00:00Z" in out + + + +def test_cron_tick_invokes_scheduler_tick_with_verbose(monkeypatch): + calls = [] + monkeypatch.setattr("cron.scheduler.tick", lambda verbose=False: calls.append(verbose)) + + cron_cli.cron_tick() + + assert calls == [True] + + + +def test_cron_create_success_prints_job_details(monkeypatch, capsys): + monkeypatch.setattr( + cron_cli, + "_cron_api", + lambda **kwargs: { + "success": True, + "job_id": "job-1", + "name": "Nightly docs", + "schedule": "every day", + "skills": ["docs"], + "next_run_at": "2026-06-01T00:00:00Z", + "job": { + "script": "scripts/build_docs.py", + "no_agent": True, + "workdir": "/tmp/repo", + "profile": "docs-profile", + }, + }, + ) + + args = SimpleNamespace( + schedule="every day", + prompt="refresh docs", + name="Nightly docs", + deliver=None, + repeat=None, + skill="docs", + skills=None, + script="scripts/build_docs.py", + workdir="/tmp/repo", + profile="docs-profile", + no_agent=True, + ) + + rc = cron_cli.cron_create(args) + + out = capsys.readouterr().out + assert rc == 0 + assert "Created job: job-1" in out + assert "Skills: docs" in out + assert "Mode: no-agent" in out + assert "Profile: docs-profile" in out + + + +def test_cron_create_failure_returns_nonzero(monkeypatch, capsys): + monkeypatch.setattr(cron_cli, "_cron_api", lambda **kwargs: {"success": False, "error": "boom"}) + + args = SimpleNamespace( + schedule="every day", + prompt="refresh docs", + name=None, + deliver=None, + repeat=None, + skill=None, + skills=None, + script=None, + workdir=None, + profile=None, + no_agent=False, + ) + + rc = cron_cli.cron_create(args) + + out = capsys.readouterr().out + assert rc == 1 + assert "Failed to create job: boom" in out