Skip to content

Commit a867f82

Browse files
committed
Change show-schedule command to table, add schedule name and derive source
1 parent db068cd commit a867f82

File tree

2 files changed

+66
-13
lines changed

2 files changed

+66
-13
lines changed

orchestrator/cli/scheduler.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,30 @@ def show_schedule() -> None:
6767
6868
in cli underscore is replaced by a dash `show-schedule`
6969
"""
70-
for task in get_all_scheduler_tasks():
71-
typer.echo(f"[{task.id}] Next run: {task.next_run_time} | Trigger: {task.trigger}")
70+
from rich.console import Console
71+
from rich.table import Table
72+
73+
from orchestrator.schedules.service import get_linker_entries_by_schedule_ids
74+
75+
console = Console()
76+
77+
table = Table(title="Scheduled Tasks")
78+
table.add_column("id", no_wrap=True)
79+
table.add_column("name")
80+
table.add_column("source")
81+
table.add_column("next run time")
82+
table.add_column("trigger")
83+
84+
scheduled_tasks = get_all_scheduler_tasks()
85+
_schedule_ids = [task.id for task in scheduled_tasks]
86+
api_managed = {str(i.schedule_id) for i in get_linker_entries_by_schedule_ids(_schedule_ids)}
87+
88+
for task in scheduled_tasks:
89+
source = "API" if task.id in api_managed else "decorator"
90+
run_time = str(task.next_run_time.replace(microsecond=0))
91+
table.add_row(task.id, task.name, source, str(run_time), str(task.trigger))
92+
93+
console.print(table)
7294

7395

7496
@app.command()

test/unit_tests/schedules/test_scheduling.py

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import re
2+
from datetime import datetime
13
from unittest import mock
24

35
from typer.testing import CliRunner
46

57
from orchestrator.cli.scheduler import app
8+
from orchestrator.db.models import WorkflowApschedulerJob
69

710
runner = CliRunner()
811

@@ -15,22 +18,50 @@ def test_run_scheduler(mock_scheduler):
1518
assert result.exit_code == 130
1619

1720

18-
@mock.patch("orchestrator.schedules.scheduler.get_scheduler_store")
19-
def test_show_schedule_command(mock_get_scheduler_store):
21+
def make_mock_job(id_, name, next_run_time_str, trigger):
2022
mock_job = mock.MagicMock()
21-
mock_job.id = "job1"
22-
mock_job.next_run_time = "2025-08-05 12:00:00"
23-
mock_job.trigger = "trigger_info"
23+
mock_job.id = id_
24+
mock_job.name = name
25+
mock_job.next_run_time = datetime.fromisoformat(next_run_time_str)
26+
mock_job.trigger = trigger
27+
return mock_job
28+
29+
30+
def to_ascii_line(line: str):
31+
# Remove unicode from a rich.table outputted line
32+
return line.encode("ascii", "ignore").decode("ascii").strip()
33+
34+
35+
def to_regex(mock_job, *, source):
36+
# Create regex to match mock job in show-schedule output
37+
return re.compile(rf"{mock_job.id}\s+{mock_job.name}\s+{source}\s+.*", flags=re.MULTILINE)
38+
39+
40+
@mock.patch("orchestrator.schedules.service.get_linker_entries_by_schedule_ids")
41+
@mock.patch("orchestrator.schedules.scheduler.get_scheduler_store")
42+
def test_show_schedule_command(mock_get_scheduler_store, mock_get_linker_entries):
43+
# given
44+
mock_job1 = make_mock_job("job1", "My Job 1", "2025-08-05T12:00:00", "trigger_info")
45+
mock_job2 = make_mock_job("6faf2c63-44de-48bc-853d-bb3f57225055", "My Job 2", "2025-08-05T14:00:00", "trigger_info")
2446

2547
mock_scheduler = mock.MagicMock()
26-
mock_scheduler.get_all_jobs.return_value = [mock_job]
48+
mock_scheduler.get_all_jobs.return_value = [mock_job1, mock_job2]
2749
mock_get_scheduler_store.return_value.__enter__.return_value = mock_scheduler
2850

29-
result = runner.invoke(app, ["show-schedule"])
30-
assert result.exit_code == 0
31-
assert "[job1]" in result.output
32-
assert "Next run: 2025-08-05 12:00:00" in result.output
33-
assert "trigger_info" in result.output
51+
mock_linker_entry_job2 = mock.MagicMock(spec=WorkflowApschedulerJob)
52+
mock_linker_entry_job2.schedule_id = mock_job2.id
53+
mock_get_linker_entries.return_value = [mock_linker_entry_job2] # only job 2 is defined in API
54+
55+
regex1 = to_regex(mock_job1, source="decorator")
56+
regex2 = to_regex(mock_job2, source="API")
57+
58+
# when
59+
result = runner.invoke(app, ["show-schedule"], env={"COLUMNS": "300", "LINES": "200"})
60+
output_stripped = "\n".join([to_ascii_line(line) for line in result.output.splitlines()])
61+
62+
# then
63+
assert regex1.findall(output_stripped) != [], f"Regex {regex1} did not match output {output_stripped}"
64+
assert regex2.findall(output_stripped) != [], f"Regex {regex2} did not match output {output_stripped}"
3465

3566

3667
@mock.patch("orchestrator.schedules.scheduler.get_scheduler_store")

0 commit comments

Comments
 (0)