"""Scheduled nightly agent install.""" from __future__ import annotations from datetime import datetime, timezone from unittest.mock import AsyncMock, patch import pytest from server.application.services import agent_install_schedule as sched from server.background.schedule_runner import _cron_match def test_cron_matches_beijing_2340(): # 2026-06-17 23:40 Beijing = 2026-06-17 15:40 UTC at = datetime(2026, 6, 17, 15, 40, tzinfo=timezone.utc) assert _cron_match("40 23 * * *", at) is True def test_cron_not_match_2340_at_other_minute(): at = datetime(2026, 6, 17, 15, 41, tzinfo=timezone.utc) assert _cron_match("40 23 * * *", at) is False @pytest.mark.asyncio async def test_run_scheduled_skips_without_servers(monkeypatch): monkeypatch.setattr(sched.settings, "AGENT_INSTALL_SCHEDULE_ENABLED", "true") monkeypatch.setattr(sched.settings, "API_BASE_URL", "https://api.example.com") monkeypatch.setattr(sched, "list_no_agent_server_ids", AsyncMock(return_value=[])) monkeypatch.setattr(sched, "_already_ran_today", AsyncMock(return_value=False)) monkeypatch.setattr(sched, "_install_agent_batch_running", AsyncMock(return_value=False)) mark = AsyncMock() monkeypatch.setattr(sched, "_mark_ran_today", mark) result = await sched.run_scheduled_agent_install() assert result["action"] == "skipped" assert result["reason"] == "no_servers_without_agent" mark.assert_awaited_once() @pytest.mark.asyncio async def test_run_scheduled_starts_install_batch(monkeypatch): monkeypatch.setattr(sched.settings, "AGENT_INSTALL_SCHEDULE_ENABLED", "true") monkeypatch.setattr(sched.settings, "API_BASE_URL", "https://api.example.com") monkeypatch.setattr(sched, "list_no_agent_server_ids", AsyncMock(return_value=[10, 11])) monkeypatch.setattr(sched, "_already_ran_today", AsyncMock(return_value=False)) monkeypatch.setattr(sched, "_install_agent_batch_running", AsyncMock(return_value=False)) monkeypatch.setattr(sched, "_mark_ran_today", AsyncMock()) start = AsyncMock(return_value={"job_id": 42, "label": "批量安装 Agent(定时)"}) monkeypatch.setattr( "server.application.services.server_batch_service.start_batch_job", start, ) result = await sched.run_scheduled_agent_install() assert result["action"] == "started" assert result["job_id"] == 42 start.assert_awaited_once_with( op="install-agent", server_ids=[10, 11], operator="system", params={"scheduled": True, "cron": "40 23 * * *"}, ) @pytest.mark.asyncio async def test_run_scheduled_skips_without_api_base_url(monkeypatch): monkeypatch.setattr(sched.settings, "AGENT_INSTALL_SCHEDULE_ENABLED", "true") monkeypatch.setattr(sched.settings, "API_BASE_URL", "") monkeypatch.setattr(sched, "_already_ran_today", AsyncMock(return_value=False)) result = await sched.run_scheduled_agent_install() assert result == {"action": "skipped", "reason": "api_base_url_unconfigured"}