Files
dotfiles/tests/test_heater_serve.py
Claude b3199dfc31 Add comprehensive test suite achieving 99% code coverage
Added 35 test files with 502 tests covering all Python modules including
API routes, ORM models, splendor game logic/TUI, heater controller,
weather service, NixOS installer, ZFS dataset management, and utilities.
Coverage improved from 11% to 99% (2540/2564 statements covered).

https://claude.ai/code/session_01SVzgLDUS1Cdc4eh1ijETTh
2026-03-09 03:55:38 +00:00

104 lines
3.8 KiB
Python

"""Tests for heater/main.py serve function and lifespan."""
from __future__ import annotations
import sys
from unittest.mock import MagicMock, patch
import pytest
from click.exceptions import Exit
from python.heater.models import DeviceConfig
def test_serve_missing_params() -> None:
"""Test serve raises when device params are missing."""
mock_tinytuya = MagicMock()
with patch.dict(sys.modules, {"tinytuya": mock_tinytuya}):
if "python.heater.controller" in sys.modules:
del sys.modules["python.heater.controller"]
if "python.heater.main" in sys.modules:
del sys.modules["python.heater.main"]
from python.heater.main import serve
with pytest.raises(Exit):
serve(host="localhost", port=8124, log_level="INFO")
def test_serve_with_params() -> None:
"""Test serve starts uvicorn when params provided."""
mock_tinytuya = MagicMock()
with patch.dict(sys.modules, {"tinytuya": mock_tinytuya}):
if "python.heater.controller" in sys.modules:
del sys.modules["python.heater.controller"]
if "python.heater.main" in sys.modules:
del sys.modules["python.heater.main"]
from python.heater.main import serve
with patch("python.heater.main.uvicorn.run") as mock_run:
serve(
host="localhost",
port=8124,
log_level="INFO",
device_id="abc",
device_ip="10.0.0.1",
local_key="key123",
)
mock_run.assert_called_once()
def test_heater_off_route_failure() -> None:
"""Test /off route raises HTTPException on failure."""
mock_tinytuya = MagicMock()
mock_device = MagicMock()
mock_device.set_value.side_effect = ConnectionError("fail")
mock_tinytuya.Device.return_value = mock_device
with patch.dict(sys.modules, {"tinytuya": mock_tinytuya}):
if "python.heater.controller" in sys.modules:
del sys.modules["python.heater.controller"]
if "python.heater.main" in sys.modules:
del sys.modules["python.heater.main"]
from python.heater.main import create_app
from python.heater.controller import HeaterController
from fastapi import HTTPException
config = DeviceConfig(device_id="abc", ip="10.0.0.1", local_key="key")
app = create_app(config)
app.state.controller = HeaterController(config)
for route in app.routes:
if hasattr(route, "path") and route.path == "/off":
with pytest.raises(HTTPException):
route.endpoint()
break
def test_heater_toggle_route_failure() -> None:
"""Test /toggle route raises HTTPException on failure."""
mock_tinytuya = MagicMock()
mock_device = MagicMock()
# toggle calls status() first then set_value - make set_value fail
mock_device.status.return_value = {"dps": {"1": True}}
mock_device.set_value.side_effect = ConnectionError("fail")
mock_tinytuya.Device.return_value = mock_device
with patch.dict(sys.modules, {"tinytuya": mock_tinytuya}):
if "python.heater.controller" in sys.modules:
del sys.modules["python.heater.controller"]
if "python.heater.main" in sys.modules:
del sys.modules["python.heater.main"]
from python.heater.main import create_app
from python.heater.controller import HeaterController
from fastapi import HTTPException
config = DeviceConfig(device_id="abc", ip="10.0.0.1", local_key="key")
app = create_app(config)
app.state.controller = HeaterController(config)
for route in app.routes:
if hasattr(route, "path") and route.path == "/toggle":
with pytest.raises(HTTPException):
route.endpoint()
break