mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
110 lines
3.8 KiB
Python
110 lines
3.8 KiB
Python
from typing import Any
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
import requests
|
|
|
|
from infrastructure.solar.google_solar_api_client import (
|
|
BuildingInsightsNotFoundError,
|
|
GoogleSolarApiClient,
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Slice 1: Successful response returns parsed JSON
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_get_building_insights_returns_parsed_json() -> None:
|
|
# Arrange
|
|
client = GoogleSolarApiClient(api_key="test-key")
|
|
payload: dict[str, Any] = {"solarPotential": {"maxArrayPanelsCount": 20}}
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = payload
|
|
|
|
with patch("requests.get", return_value=mock_response) as mock_get:
|
|
mock_response.raise_for_status.return_value = None
|
|
|
|
# Act
|
|
result = client.get_building_insights(longitude=-0.1278, latitude=51.5074)
|
|
|
|
# Assert
|
|
assert result == payload
|
|
mock_get.assert_called_once()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Slice 2: Transient HTTP errors trigger retries
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_get_building_insights_retries_on_transient_error() -> None:
|
|
# Arrange
|
|
client = GoogleSolarApiClient(api_key="test-key")
|
|
payload: dict[str, Any] = {"solarPotential": {"maxArrayPanelsCount": 20}}
|
|
|
|
transient_error = requests.exceptions.ConnectionError("timeout")
|
|
transient_error.response = None # type: ignore[attr-defined]
|
|
|
|
success_response = MagicMock()
|
|
success_response.json.return_value = payload
|
|
success_response.raise_for_status.return_value = None
|
|
|
|
with patch("requests.get", side_effect=[transient_error, success_response]) as mock_get:
|
|
with patch("time.sleep"):
|
|
# Act
|
|
result = client.get_building_insights(longitude=-0.1278, latitude=51.5074)
|
|
|
|
# Assert
|
|
assert result == payload
|
|
assert mock_get.call_count == 2
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Slice 3: 404 + entity-not-found raises BuildingInsightsNotFoundError
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_get_building_insights_raises_on_entity_not_found() -> None:
|
|
# Arrange
|
|
client = GoogleSolarApiClient(api_key="test-key")
|
|
|
|
not_found_response = MagicMock()
|
|
not_found_response.status_code = 404
|
|
not_found_response.json.return_value = {
|
|
"error": {"message": GoogleSolarApiClient.ENTITY_NOT_FOUND_ERROR}
|
|
}
|
|
|
|
http_error = requests.exceptions.HTTPError("404")
|
|
http_error.response = not_found_response
|
|
|
|
with patch("requests.get") as mock_get:
|
|
mock_get.return_value.raise_for_status.side_effect = http_error
|
|
mock_get.return_value.response = not_found_response
|
|
|
|
# Act / Assert
|
|
with pytest.raises(BuildingInsightsNotFoundError):
|
|
client.get_building_insights(longitude=-0.1278, latitude=51.5074)
|
|
|
|
assert mock_get.call_count == 1
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Slice 4: Retry exhaustion propagates the exception to the caller
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_get_building_insights_propagates_exception_after_retry_exhaustion() -> None:
|
|
# Arrange
|
|
client = GoogleSolarApiClient(api_key="test-key")
|
|
|
|
error = requests.exceptions.ConnectionError("persistent failure")
|
|
error.response = None # type: ignore[attr-defined]
|
|
|
|
with patch("requests.get", side_effect=error) as mock_get:
|
|
with patch("time.sleep"):
|
|
# Act / Assert
|
|
with pytest.raises(requests.exceptions.ConnectionError):
|
|
client.get_building_insights(longitude=-0.1278, latitude=51.5074)
|
|
|
|
assert mock_get.call_count == GoogleSolarApiClient.MAX_RETRIES
|