Skip to content

Commit ba7f770

Browse files
agentgonzoSteve
authored andcommitted
aurora watch tests
1 parent be6b51a commit ba7f770

File tree

4 files changed

+374
-0
lines changed

4 files changed

+374
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""The tests for the AuroraWatch UK integration."""
2+
3+
from homeassistant.core import HomeAssistant
4+
5+
from tests.common import MockConfigEntry
6+
7+
8+
async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
9+
"""Fixture for setting up the component."""
10+
config_entry.add_to_hass(hass)
11+
12+
await hass.config_entries.async_setup(config_entry.entry_id)
13+
await hass.async_block_till_done()
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""Common fixtures for the AuroraWatch UK tests."""
2+
3+
from collections.abc import Generator
4+
from unittest.mock import AsyncMock, patch
5+
6+
import pytest
7+
8+
from homeassistant.components.aurorawatch.const import DOMAIN
9+
10+
from tests.common import MockConfigEntry
11+
12+
# Sample XML responses for testing
13+
MOCK_STATUS_XML = """<?xml version="1.0" encoding="UTF-8"?>
14+
<current_status api_version="0.2">
15+
<updated>
16+
<datetime>2024-01-15T12:00:00Z</datetime>
17+
</updated>
18+
<site_status status_id="green" project_id="awn" site_id="lancaster" site_url="http://aurorawatch.lancs.ac.uk">
19+
<status_description>No significant activity</status_description>
20+
</site_status>
21+
</current_status>
22+
"""
23+
24+
MOCK_ACTIVITY_XML = """<?xml version="1.0" encoding="UTF-8"?>
25+
<activity_data api_version="0.2">
26+
<activity>
27+
<datetime>2024-01-15T11:00:00Z</datetime>
28+
<value>45.2</value>
29+
</activity>
30+
<activity>
31+
<datetime>2024-01-15T12:00:00Z</datetime>
32+
<value>52.7</value>
33+
</activity>
34+
</activity_data>
35+
"""
36+
37+
MOCK_INVALID_STATUS_XML = """<?xml version="1.0" encoding="UTF-8"?>
38+
<invalid_status>
39+
<missing_required_fields />
40+
</invalid_status>
41+
"""
42+
43+
MOCK_MALFORMED_XML = """<?xml version="1.0" encoding="UTF-8"?>
44+
<unclosed_tag>
45+
"""
46+
47+
48+
@pytest.fixture
49+
def mock_setup_entry() -> Generator[AsyncMock]:
50+
"""Override async_setup_entry."""
51+
with patch(
52+
"homeassistant.components.aurorawatch.async_setup_entry",
53+
return_value=True,
54+
) as mock_setup_entry:
55+
yield mock_setup_entry
56+
57+
58+
@pytest.fixture
59+
def mock_aiohttp_session() -> Generator[AsyncMock]:
60+
"""Mock aiohttp session."""
61+
with patch(
62+
"homeassistant.components.aurorawatch.coordinator.async_get_clientsession"
63+
) as mock_session_factory:
64+
mock_session = AsyncMock()
65+
mock_session_factory.return_value = mock_session
66+
67+
# Create mock responses
68+
mock_status_response = AsyncMock()
69+
mock_status_response.text = AsyncMock(return_value=MOCK_STATUS_XML)
70+
mock_status_response.raise_for_status = AsyncMock()
71+
72+
mock_activity_response = AsyncMock()
73+
mock_activity_response.text = AsyncMock(return_value=MOCK_ACTIVITY_XML)
74+
mock_activity_response.raise_for_status = AsyncMock()
75+
76+
# Mock session.get to return different responses based on URL
77+
async def mock_get(url):
78+
if "current-status.xml" in url:
79+
return mock_status_response
80+
if "sum-activity.xml" in url:
81+
return mock_activity_response
82+
return AsyncMock()
83+
84+
mock_session.get = mock_get
85+
86+
yield mock_session
87+
88+
89+
@pytest.fixture
90+
def mock_config_entry() -> MockConfigEntry:
91+
"""Mock a config entry."""
92+
return MockConfigEntry(
93+
domain=DOMAIN,
94+
title="AuroraWatch UK",
95+
data={},
96+
unique_id=DOMAIN,
97+
)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""Test the AuroraWatch UK config flow."""
2+
3+
from unittest.mock import AsyncMock
4+
5+
import pytest
6+
7+
from homeassistant.components.aurorawatch.const import DOMAIN
8+
from homeassistant.config_entries import SOURCE_USER
9+
from homeassistant.core import HomeAssistant
10+
from homeassistant.data_entry_flow import FlowResultType
11+
12+
from tests.common import MockConfigEntry
13+
14+
15+
async def test_full_flow(
16+
hass: HomeAssistant,
17+
mock_setup_entry: AsyncMock,
18+
mock_aiohttp_session: AsyncMock,
19+
) -> None:
20+
"""Test full config flow."""
21+
result = await hass.config_entries.flow.async_init(
22+
DOMAIN, context={"source": SOURCE_USER}
23+
)
24+
assert result["type"] is FlowResultType.FORM
25+
assert result["errors"] == {}
26+
assert result["step_id"] == "user"
27+
28+
result = await hass.config_entries.flow.async_configure(
29+
result["flow_id"],
30+
user_input={},
31+
)
32+
await hass.async_block_till_done()
33+
34+
assert result["type"] is FlowResultType.CREATE_ENTRY
35+
assert result["title"] == "AuroraWatch UK"
36+
assert result["data"] == {}
37+
assert len(mock_setup_entry.mock_calls) == 1
38+
39+
40+
async def test_flow_already_configured(
41+
hass: HomeAssistant,
42+
mock_aiohttp_session: AsyncMock,
43+
) -> None:
44+
"""Test config flow aborts if already configured."""
45+
mock_entry = MockConfigEntry(
46+
domain=DOMAIN,
47+
title="AuroraWatch UK",
48+
data={},
49+
unique_id=DOMAIN,
50+
)
51+
mock_entry.add_to_hass(hass)
52+
53+
result = await hass.config_entries.flow.async_init(
54+
DOMAIN, context={"source": SOURCE_USER}
55+
)
56+
57+
assert result["type"] is FlowResultType.ABORT
58+
assert result["reason"] == "already_configured"
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
"""Test the AuroraWatch UK sensor platform."""
2+
3+
from unittest.mock import AsyncMock
4+
5+
from aiohttp import ClientError
6+
import pytest
7+
8+
from homeassistant.components.aurorawatch.const import (
9+
ATTR_API_VERSION,
10+
ATTR_LAST_UPDATED,
11+
ATTR_PROJECT_ID,
12+
ATTR_SITE_ID,
13+
ATTR_SITE_URL,
14+
DOMAIN,
15+
)
16+
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
17+
from homeassistant.const import STATE_UNAVAILABLE
18+
from homeassistant.core import HomeAssistant
19+
from homeassistant.helpers import entity_registry as er
20+
21+
from . import setup_integration
22+
23+
from tests.common import MockConfigEntry
24+
25+
26+
async def test_sensor_setup(
27+
hass: HomeAssistant,
28+
mock_aiohttp_session: AsyncMock,
29+
mock_config_entry: MockConfigEntry,
30+
) -> None:
31+
"""Test sensor setup."""
32+
await setup_integration(hass, mock_config_entry)
33+
34+
entity_registry = er.async_get(hass)
35+
36+
# Check that both sensors are created
37+
status_sensor = entity_registry.async_get("sensor.aurorawatch_uk_aurora_status")
38+
assert status_sensor
39+
assert status_sensor.unique_id == "aurorawatch_aurora_status"
40+
assert status_sensor.translation_key == "aurora_status"
41+
42+
activity_sensor = entity_registry.async_get(
43+
"sensor.aurorawatch_uk_geomagnetic_activity"
44+
)
45+
assert activity_sensor
46+
assert activity_sensor.unique_id == "aurorawatch_geomagnetic_activity"
47+
assert activity_sensor.translation_key == "geomagnetic_activity"
48+
49+
50+
async def test_sensor_states(
51+
hass: HomeAssistant,
52+
mock_aiohttp_session: AsyncMock,
53+
mock_config_entry: MockConfigEntry,
54+
) -> None:
55+
"""Test sensor states."""
56+
await setup_integration(hass, mock_config_entry)
57+
58+
# Check status sensor state
59+
status_state = hass.states.get("sensor.aurorawatch_uk_aurora_status")
60+
assert status_state
61+
assert status_state.state == "green"
62+
63+
# Check activity sensor state
64+
activity_state = hass.states.get("sensor.aurorawatch_uk_geomagnetic_activity")
65+
assert activity_state
66+
assert activity_state.state == "52.7"
67+
assert activity_state.attributes.get("unit_of_measurement") == "nT"
68+
assert activity_state.attributes.get("state_class") == "measurement"
69+
70+
71+
async def test_sensor_attributes(
72+
hass: HomeAssistant,
73+
mock_aiohttp_session: AsyncMock,
74+
mock_config_entry: MockConfigEntry,
75+
) -> None:
76+
"""Test sensor attributes."""
77+
await setup_integration(hass, mock_config_entry)
78+
79+
# Check status sensor attributes
80+
status_state = hass.states.get("sensor.aurorawatch_uk_aurora_status")
81+
assert status_state
82+
assert status_state.attributes.get(ATTR_LAST_UPDATED) == "2024-01-15T12:00:00Z"
83+
assert status_state.attributes.get(ATTR_PROJECT_ID) == "awn"
84+
assert status_state.attributes.get(ATTR_SITE_ID) == "lancaster"
85+
assert (
86+
status_state.attributes.get(ATTR_SITE_URL) == "http://aurorawatch.lancs.ac.uk"
87+
)
88+
assert status_state.attributes.get(ATTR_API_VERSION) == "0.2"
89+
assert (
90+
status_state.attributes.get("attribution") == "Data provided by AuroraWatch UK"
91+
)
92+
93+
94+
async def test_sensor_update_failure_network_error(
95+
hass: HomeAssistant,
96+
mock_config_entry: MockConfigEntry,
97+
) -> None:
98+
"""Test sensor update with network error."""
99+
from unittest.mock import patch
100+
101+
with patch(
102+
"homeassistant.components.aurorawatch.coordinator.async_get_clientsession"
103+
) as mock_session_factory:
104+
mock_session = AsyncMock()
105+
mock_session_factory.return_value = mock_session
106+
107+
# Mock network error
108+
mock_session.get.side_effect = ClientError("Connection failed")
109+
110+
mock_config_entry.add_to_hass(hass)
111+
await hass.config_entries.async_setup(mock_config_entry.entry_id)
112+
await hass.async_block_till_done()
113+
114+
# Sensors should be unavailable
115+
status_state = hass.states.get("sensor.aurorawatch_uk_aurora_status")
116+
assert status_state
117+
assert status_state.state == STATE_UNAVAILABLE
118+
119+
activity_state = hass.states.get("sensor.aurorawatch_uk_geomagnetic_activity")
120+
assert activity_state
121+
assert activity_state.state == STATE_UNAVAILABLE
122+
123+
124+
async def test_sensor_update_failure_invalid_xml(
125+
hass: HomeAssistant,
126+
mock_config_entry: MockConfigEntry,
127+
) -> None:
128+
"""Test sensor update with invalid XML."""
129+
from unittest.mock import patch
130+
131+
from tests.components.aurorawatch.conftest import MOCK_MALFORMED_XML
132+
133+
with patch(
134+
"homeassistant.components.aurorawatch.coordinator.async_get_clientsession"
135+
) as mock_session_factory:
136+
mock_session = AsyncMock()
137+
mock_session_factory.return_value = mock_session
138+
139+
# Mock malformed XML response
140+
mock_response = AsyncMock()
141+
mock_response.text = AsyncMock(return_value=MOCK_MALFORMED_XML)
142+
mock_response.raise_for_status = AsyncMock()
143+
mock_session.get.return_value = mock_response
144+
145+
mock_config_entry.add_to_hass(hass)
146+
await hass.config_entries.async_setup(mock_config_entry.entry_id)
147+
await hass.async_block_till_done()
148+
149+
# Sensors should be unavailable due to parsing error
150+
status_state = hass.states.get("sensor.aurorawatch_uk_aurora_status")
151+
assert status_state
152+
assert status_state.state == STATE_UNAVAILABLE
153+
154+
155+
async def test_sensor_update_failure_missing_fields(
156+
hass: HomeAssistant,
157+
mock_config_entry: MockConfigEntry,
158+
) -> None:
159+
"""Test sensor update with missing required fields."""
160+
from unittest.mock import patch
161+
162+
from tests.components.aurorawatch.conftest import MOCK_INVALID_STATUS_XML
163+
164+
with patch(
165+
"homeassistant.components.aurorawatch.coordinator.async_get_clientsession"
166+
) as mock_session_factory:
167+
mock_session = AsyncMock()
168+
mock_session_factory.return_value = mock_session
169+
170+
# Mock invalid XML response (missing required fields)
171+
mock_response = AsyncMock()
172+
mock_response.text = AsyncMock(return_value=MOCK_INVALID_STATUS_XML)
173+
mock_response.raise_for_status = AsyncMock()
174+
mock_session.get.return_value = mock_response
175+
176+
mock_config_entry.add_to_hass(hass)
177+
await hass.config_entries.async_setup(mock_config_entry.entry_id)
178+
await hass.async_block_till_done()
179+
180+
# Sensors should be unavailable due to missing fields
181+
status_state = hass.states.get("sensor.aurorawatch_uk_aurora_status")
182+
assert status_state
183+
assert status_state.state == STATE_UNAVAILABLE
184+
185+
186+
async def test_sensor_device_info(
187+
hass: HomeAssistant,
188+
mock_aiohttp_session: AsyncMock,
189+
mock_config_entry: MockConfigEntry,
190+
) -> None:
191+
"""Test sensor device info."""
192+
await setup_integration(hass, mock_config_entry)
193+
194+
entity_registry = er.async_get(hass)
195+
status_sensor = entity_registry.async_get("sensor.aurorawatch_uk_aurora_status")
196+
assert status_sensor
197+
assert status_sensor.device_id
198+
199+
from homeassistant.helpers import device_registry as dr
200+
201+
device_registry = dr.async_get(hass)
202+
device = device_registry.async_get(status_sensor.device_id)
203+
assert device
204+
assert device.manufacturer == "Lancaster University"
205+
assert device.model == "AuroraWatch UK"
206+
assert device.name == "AuroraWatch UK"

0 commit comments

Comments
 (0)