From 60f37b587bdeac9caf47bce276d368c0758b7382 Mon Sep 17 00:00:00 2001 From: Shinsuke Sugaya Date: Sat, 28 Mar 2026 21:33:16 +0900 Subject: [PATCH] feat(scheduler): display jobLogId from scheduler start API response Support the new jobLogId field added in codelibs/fess#3103. When a scheduler is started and job logging is enabled, the API now returns a pre-generated job log ID. Display it in text output so users can track job execution. JSON/YAML output already includes it via raw response dump. Backward compatible with older Fess versions. --- src/fessctl/commands/scheduler.py | 6 +- tests/unit/test_client.py | 2 +- tests/unit/test_scheduler_start.py | 89 ++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 tests/unit/test_scheduler_start.py diff --git a/src/fessctl/commands/scheduler.py b/src/fessctl/commands/scheduler.py index 855644b..e1087e6 100644 --- a/src/fessctl/commands/scheduler.py +++ b/src/fessctl/commands/scheduler.py @@ -278,7 +278,11 @@ def start_scheduler( typer.echo(yaml.dump(result)) else: if status == 0: - typer.echo(format_result_markdown(True, f"Scheduler '{scheduler_id}' started successfully.", "Scheduler", "start", scheduler_id)) + job_log_id = result.get("response", {}).get("jobLogId") + message = f"Scheduler '{scheduler_id}' started successfully." + if job_log_id: + message += f" Job Log ID: {job_log_id}" + typer.echo(format_result_markdown(True, message, "Scheduler", "start", scheduler_id)) else: message: str = result.get("response", {}).get("message", "") typer.echo(format_result_markdown(False, f"Failed to start Scheduler. {message} Status code: {status}", "Scheduler", "start")) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 57c9690..038092a 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -452,7 +452,7 @@ class TestSchedulerAPIs: def test_start_scheduler(self, mock_put, client): """Test starting a scheduler.""" mock_response = Mock() - mock_response.json.return_value = {"response": {"status": 0}} + mock_response.json.return_value = {"response": {"status": 0, "jobLogId": "abc123def456"}} mock_put.return_value = mock_response client.start_scheduler("scheduler-123") diff --git a/tests/unit/test_scheduler_start.py b/tests/unit/test_scheduler_start.py new file mode 100644 index 0000000..9674062 --- /dev/null +++ b/tests/unit/test_scheduler_start.py @@ -0,0 +1,89 @@ +""" +Unit tests for scheduler start command jobLogId support. +""" +import json +from unittest.mock import Mock, patch + +import pytest +from typer.testing import CliRunner + +from fessctl.commands.scheduler import scheduler_app + + +@pytest.fixture +def runner(): + return CliRunner() + + +class TestSchedulerStartJobLogId: + """Tests for jobLogId in scheduler start response.""" + + @patch("fessctl.commands.scheduler.FessAPIClient") + def test_start_with_job_log_id_text_output(self, mock_client_class, runner): + """Test that jobLogId is displayed in text output when present.""" + mock_client = Mock() + mock_client.start_scheduler.return_value = { + "response": {"status": 0, "jobLogId": "abc123def456"} + } + mock_client_class.return_value = mock_client + + result = runner.invoke(scheduler_app, ["start", "sched-001"]) + assert result.exit_code == 0 + assert "started successfully" in result.stdout + assert "Job Log ID: abc123def456" in result.stdout + + @patch("fessctl.commands.scheduler.FessAPIClient") + def test_start_without_job_log_id_text_output(self, mock_client_class, runner): + """Test backward compatibility: no jobLogId field (old Fess).""" + mock_client = Mock() + mock_client.start_scheduler.return_value = { + "response": {"status": 0} + } + mock_client_class.return_value = mock_client + + result = runner.invoke(scheduler_app, ["start", "sched-001"]) + assert result.exit_code == 0 + assert "started successfully" in result.stdout + assert "Job Log ID" not in result.stdout + + @patch("fessctl.commands.scheduler.FessAPIClient") + def test_start_with_null_job_log_id_text_output(self, mock_client_class, runner): + """Test that null jobLogId (logging disabled) does not show ID.""" + mock_client = Mock() + mock_client.start_scheduler.return_value = { + "response": {"status": 0, "jobLogId": None} + } + mock_client_class.return_value = mock_client + + result = runner.invoke(scheduler_app, ["start", "sched-001"]) + assert result.exit_code == 0 + assert "started successfully" in result.stdout + assert "Job Log ID" not in result.stdout + + @patch("fessctl.commands.scheduler.FessAPIClient") + def test_start_with_job_log_id_json_output(self, mock_client_class, runner): + """Test that jobLogId appears in JSON output.""" + mock_client = Mock() + mock_client.start_scheduler.return_value = { + "response": {"status": 0, "jobLogId": "abc123def456"} + } + mock_client_class.return_value = mock_client + + result = runner.invoke(scheduler_app, ["start", "sched-001", "--output", "json"]) + assert result.exit_code == 0 + data = json.loads(result.stdout) + assert data["response"]["jobLogId"] == "abc123def456" + + @patch("fessctl.commands.scheduler.FessAPIClient") + def test_start_failure_text_output(self, mock_client_class, runner): + """Test that failure response does not show jobLogId.""" + mock_client = Mock() + mock_client.start_scheduler.return_value = { + "response": {"status": 1, "message": "Job is not available"} + } + mock_client_class.return_value = mock_client + + result = runner.invoke(scheduler_app, ["start", "sched-001"]) + assert result.exit_code != 0 + assert "Failed to start Scheduler" in result.stdout + assert "Job Log ID" not in result.stdout