Files
auto-archiver/deploy/tests/test_gsheet_poller.py
2026-03-12 11:47:20 +00:00

125 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Tests for deploy/gsheet_poller.py background Google Sheets polling."""
import os
from unittest.mock import patch, MagicMock
from deploy.gsheet_poller import start_poller, _poll_once
# ── start_poller ──────────────────────────────────────────────────────
class TestStartPoller:
def test_disabled_when_no_gsheet_url(self):
"""No thread should be started when GSHEET_URL is empty."""
with (
patch.dict(os.environ, {"GSHEET_URL": ""}, clear=False),
patch("deploy.gsheet_poller.threading.Thread") as mock_thread,
):
start_poller()
mock_thread.assert_not_called()
def test_disabled_when_gsheet_url_absent(self):
env = {k: v for k, v in os.environ.items() if k != "GSHEET_URL"}
with patch.dict(os.environ, env, clear=True), patch("deploy.gsheet_poller.threading.Thread") as mock_thread:
start_poller()
mock_thread.assert_not_called()
def test_starts_thread_when_gsheet_url_set(self):
with (
patch.dict(os.environ, {"GSHEET_URL": "https://example.com/sheet"}, clear=False),
patch("deploy.gsheet_poller.threading.Thread") as mock_thread,
):
mock_instance = MagicMock()
mock_thread.return_value = mock_instance
start_poller()
mock_thread.assert_called_once()
assert mock_thread.call_args.kwargs["daemon"] is True
assert mock_thread.call_args.kwargs["name"] == "gsheet-poller"
mock_instance.start.assert_called_once()
def test_default_interval_300(self):
env = {"GSHEET_URL": "https://example.com/sheet"}
# Remove POLL_INTERVAL if present
clean_env = {k: v for k, v in os.environ.items() if k != "POLL_INTERVAL"}
clean_env.update(env)
with (
patch.dict(os.environ, clean_env, clear=True),
patch("deploy.gsheet_poller.threading.Thread") as mock_thread,
):
mock_thread.return_value = MagicMock()
start_poller()
# interval should be passed as arg to _poll_loop
args = mock_thread.call_args.kwargs.get("args") or mock_thread.call_args[1].get("args")
assert args == (300,)
def test_custom_interval(self):
with (
patch.dict(os.environ, {"GSHEET_URL": "x", "POLL_INTERVAL": "600"}, clear=False),
patch("deploy.gsheet_poller.threading.Thread") as mock_thread,
):
mock_thread.return_value = MagicMock()
start_poller()
args = mock_thread.call_args.kwargs.get("args") or mock_thread.call_args[1].get("args")
assert args == (600,)
def test_interval_minimum_enforced(self):
"""Intervals below 60 should be clamped to 60."""
with (
patch.dict(os.environ, {"GSHEET_URL": "x", "POLL_INTERVAL": "10"}, clear=False),
patch("deploy.gsheet_poller.threading.Thread") as mock_thread,
):
mock_thread.return_value = MagicMock()
start_poller()
args = mock_thread.call_args.kwargs.get("args") or mock_thread.call_args[1].get("args")
assert args == (60,)
# ── _poll_once ────────────────────────────────────────────────────────
class TestPollOnce:
def test_calls_subprocess_with_config(self):
with patch("deploy.gsheet_poller.subprocess.run") as mock_run:
mock_run.return_value = MagicMock(returncode=0, stderr="")
_poll_once()
mock_run.assert_called_once()
cmd = mock_run.call_args[0][0]
assert "auto_archiver" in " ".join(cmd)
assert "--config" in cmd
def test_handles_nonzero_exit(self):
"""Should not raise on non-zero exit, just log a warning."""
with patch("deploy.gsheet_poller.subprocess.run") as mock_run:
mock_run.return_value = MagicMock(returncode=1, stderr="some error")
_poll_once() # should not raise
def test_handles_timeout(self):
"""Should not raise on timeout, just log."""
import subprocess
with patch("deploy.gsheet_poller.subprocess.run") as mock_run:
mock_run.side_effect = subprocess.TimeoutExpired(cmd="test", timeout=600)
_poll_once() # should not raise
def test_handles_exception(self):
"""Should not raise on arbitrary exceptions."""
with patch("deploy.gsheet_poller.subprocess.run") as mock_run:
mock_run.side_effect = OSError("broken")
_poll_once() # should not raise
def test_uses_correct_config_path(self):
with patch("deploy.gsheet_poller.subprocess.run") as mock_run:
mock_run.return_value = MagicMock(returncode=0, stderr="")
_poll_once()
cmd = mock_run.call_args[0][0]
config_idx = cmd.index("--config")
assert cmd[config_idx + 1] == "/app/secrets/orchestration.yaml"
def test_timeout_set(self):
with patch("deploy.gsheet_poller.subprocess.run") as mock_run:
mock_run.return_value = MagicMock(returncode=0, stderr="")
_poll_once()
assert mock_run.call_args[1]["timeout"] == 600