79 lines
2.8 KiB
Python
79 lines
2.8 KiB
Python
"""Tests for the recurring worker-tier jobs (scheduler.py): job registration,
|
|
cadence from env, idempotent start/stop, and that each job calls the right
|
|
underlying function. No real hours-long wait — inspects APScheduler's own job
|
|
registry rather than letting anything actually fire."""
|
|
import datetime
|
|
|
|
import pytest
|
|
|
|
from notifications import scheduler
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _clean_scheduler():
|
|
"""Every test starts from "not running" and leaves nothing behind, even on
|
|
failure — scheduler._scheduler is module-global state shared across tests."""
|
|
scheduler.stop()
|
|
yield
|
|
scheduler.stop()
|
|
|
|
|
|
def test_start_registers_both_jobs_with_configured_intervals(monkeypatch):
|
|
monkeypatch.setattr(scheduler, "WARM_CITIES_INTERVAL_HOURS", 24)
|
|
monkeypatch.setattr(scheduler, "INDEXNOW_INTERVAL_HOURS", 6)
|
|
scheduler.start()
|
|
jobs = {j.id: j for j in scheduler._scheduler.get_jobs()}
|
|
assert set(jobs) == {"warm_cities", "indexnow"}
|
|
assert jobs["warm_cities"].trigger.interval == datetime.timedelta(hours=24)
|
|
assert jobs["indexnow"].trigger.interval == datetime.timedelta(hours=6)
|
|
assert jobs["warm_cities"].func is scheduler._warm_cities_job
|
|
assert jobs["indexnow"].func is scheduler._indexnow_job
|
|
|
|
|
|
def test_start_does_not_run_a_job_immediately():
|
|
"""warm_cities already runs at deploy time; an immediate duplicate run on
|
|
every worker boot/restart would just be wasted work — the first scheduled
|
|
run must be one interval away, not "now"."""
|
|
scheduler.start()
|
|
now = datetime.datetime.now(datetime.timezone.utc)
|
|
for job in scheduler._scheduler.get_jobs():
|
|
assert job.next_run_time > now
|
|
|
|
|
|
def test_start_is_idempotent(monkeypatch):
|
|
scheduler.start()
|
|
first = scheduler._scheduler
|
|
calls = []
|
|
monkeypatch.setattr(scheduler.BackgroundScheduler, "__init__",
|
|
lambda self, **kw: calls.append(1) or None)
|
|
scheduler.start()
|
|
assert scheduler._scheduler is first
|
|
assert calls == [] # a second BackgroundScheduler was never constructed
|
|
|
|
|
|
def test_stop_shuts_down_and_clears_state():
|
|
scheduler.start()
|
|
assert scheduler._scheduler is not None
|
|
scheduler.stop()
|
|
assert scheduler._scheduler is None
|
|
|
|
|
|
def test_stop_without_start_is_a_safe_no_op():
|
|
scheduler.stop() # must not raise
|
|
assert scheduler._scheduler is None
|
|
|
|
|
|
def test_warm_cities_job_calls_warm_cities_main(monkeypatch):
|
|
import warm_cities
|
|
calls = []
|
|
monkeypatch.setattr(warm_cities, "main", lambda: calls.append(1))
|
|
scheduler._warm_cities_job()
|
|
assert calls == [1]
|
|
|
|
|
|
def test_indexnow_job_calls_submit_if_changed(monkeypatch):
|
|
import indexnow
|
|
calls = []
|
|
monkeypatch.setattr(indexnow, "submit_if_changed", lambda: calls.append(1))
|
|
scheduler._indexnow_job()
|
|
assert calls == [1]
|