From 42bca0f94a393ed841f03f7d60d99d2881851b47 Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Sun, 6 Aug 2023 19:39:24 +0200 Subject: [PATCH] Complete test coverage for OpenSky (#97863) * Use mockobject for OpenSky testing * Complete test coverage for OpenSky * Complete test coverage for OpenSky * Use method patching --- .coveragerc | 1 - tests/components/opensky/conftest.py | 23 +++- tests/components/opensky/fixtures/states.json | 105 ++++++++++++++++ .../components/opensky/fixtures/states_1.json | 45 +++++++ .../opensky/snapshots/test_sensor.ambr | 42 +++++++ tests/components/opensky/test_sensor.py | 113 ++++++++++++++++-- 6 files changed, 317 insertions(+), 12 deletions(-) create mode 100644 tests/components/opensky/fixtures/states.json create mode 100644 tests/components/opensky/fixtures/states_1.json create mode 100644 tests/components/opensky/snapshots/test_sensor.ambr diff --git a/.coveragerc b/.coveragerc index 7e0c71ec9fb..d895b1adf0a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -863,7 +863,6 @@ omit = homeassistant/components/openhome/const.py homeassistant/components/openhome/media_player.py homeassistant/components/opensensemap/air_quality.py - homeassistant/components/opensky/sensor.py homeassistant/components/opentherm_gw/__init__.py homeassistant/components/opentherm_gw/binary_sensor.py homeassistant/components/opentherm_gw/climate.py diff --git a/tests/components/opensky/conftest.py b/tests/components/opensky/conftest.py index 63e514d0d8f..7cf3074a2a3 100644 --- a/tests/components/opensky/conftest.py +++ b/tests/components/opensky/conftest.py @@ -1,5 +1,6 @@ """Configure tests for the OpenSky integration.""" from collections.abc import Awaitable, Callable +import json from unittest.mock import patch import pytest @@ -10,7 +11,7 @@ from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component -from tests.common import MockConfigEntry +from tests.common import MockConfigEntry, load_fixture ComponentSetup = Callable[[MockConfigEntry], Awaitable[None]] @@ -32,6 +33,23 @@ def mock_config_entry() -> MockConfigEntry: ) +@pytest.fixture(name="config_entry_altitude") +def mock_config_entry_altitude() -> MockConfigEntry: + """Create Opensky entry with altitude in Home Assistant.""" + return MockConfigEntry( + domain=DOMAIN, + title="OpenSky", + data={ + CONF_LATITUDE: 0.0, + CONF_LONGITUDE: 0.0, + }, + options={ + CONF_RADIUS: 10.0, + CONF_ALTITUDE: 12500.0, + }, + ) + + @pytest.fixture(name="setup_integration") async def mock_setup_integration( hass: HomeAssistant, @@ -40,9 +58,10 @@ async def mock_setup_integration( async def func(mock_config_entry: MockConfigEntry) -> None: mock_config_entry.add_to_hass(hass) + json_fixture = load_fixture("opensky/states.json") with patch( "python_opensky.OpenSky.get_states", - return_value=StatesResponse(states=[], time=0), + return_value=StatesResponse.parse_obj(json.loads(json_fixture)), ): assert await async_setup_component(hass, DOMAIN, {}) await hass.async_block_till_done() diff --git a/tests/components/opensky/fixtures/states.json b/tests/components/opensky/fixtures/states.json new file mode 100644 index 00000000000..7fee53157c8 --- /dev/null +++ b/tests/components/opensky/fixtures/states.json @@ -0,0 +1,105 @@ +{ + "time": 1691244533, + "states": [ + { + "icao24": "3c6708", + "callsign": "DLH459 ", + "origin_country": "Germany", + "time_position": 1691244522, + "last_contact": 1691244522, + "longitude": 5.4445, + "latitude": 52.2991, + "baro_altitude": 12496.8, + "on_ground": false, + "velocity": 259.73, + "true_track": 134.84, + "vertical_rate": 0, + "sensors": null, + "geo_altitude": 12710.16, + "squawk": "1151", + "spi": false, + "position_source": 0, + "category": 6 + }, + { + "icao24": "3c6708", + "callsign": " ", + "origin_country": "Germany", + "time_position": 1691244522, + "last_contact": 1691244522, + "longitude": 5.4445, + "latitude": 52.2991, + "baro_altitude": 12496.8, + "on_ground": false, + "velocity": 259.73, + "true_track": 134.84, + "vertical_rate": 0, + "sensors": null, + "geo_altitude": 12710.16, + "squawk": "1151", + "spi": false, + "position_source": 0, + "category": 6 + }, + { + "icao24": "4846df", + "callsign": "", + "origin_country": "Kingdom of the Netherlands", + "time_position": 1691244404, + "last_contact": 1691244404, + "longitude": 4.7441, + "latitude": 52.3076, + "baro_altitude": null, + "on_ground": true, + "velocity": 8.75, + "true_track": 272.81, + "vertical_rate": null, + "sensors": null, + "geo_altitude": null, + "squawk": null, + "spi": false, + "position_source": 0, + "category": 17 + }, + { + "icao24": "4846df", + "callsign": "DLH420 ", + "origin_country": "Kingdom of the Netherlands", + "time_position": 1691244404, + "last_contact": 1691244404, + "longitude": 4.7441, + "latitude": 52.3076, + "baro_altitude": null, + "on_ground": true, + "velocity": 8.75, + "true_track": 272.81, + "vertical_rate": null, + "sensors": null, + "geo_altitude": null, + "squawk": null, + "spi": false, + "position_source": 0, + "category": 17 + }, + { + "icao24": "3e3d01", + "callsign": "ECA2HL ", + "origin_country": "Germany", + "time_position": 1691244533, + "last_contact": 1691244533, + "longitude": 5.5217, + "latitude": 52.4561, + "baro_altitude": 12500.8, + "on_ground": false, + "velocity": 201.9, + "true_track": 82.39, + "vertical_rate": 0, + "sensors": null, + "geo_altitude": 12733.02, + "squawk": "1071", + "spi": false, + "position_source": 0, + "category": 1 + } + ] +} diff --git a/tests/components/opensky/fixtures/states_1.json b/tests/components/opensky/fixtures/states_1.json new file mode 100644 index 00000000000..bd76428627e --- /dev/null +++ b/tests/components/opensky/fixtures/states_1.json @@ -0,0 +1,45 @@ +{ + "time": 1691244533, + "states": [ + { + "icao24": "4846df", + "callsign": "", + "origin_country": "Kingdom of the Netherlands", + "time_position": 1691244404, + "last_contact": 1691244404, + "longitude": 4.7441, + "latitude": 52.3076, + "baro_altitude": null, + "on_ground": true, + "velocity": 8.75, + "true_track": 272.81, + "vertical_rate": null, + "sensors": null, + "geo_altitude": null, + "squawk": null, + "spi": false, + "position_source": 0, + "category": 17 + }, + { + "icao24": "3e3d01", + "callsign": "ECA2HL ", + "origin_country": "Germany", + "time_position": 1691244533, + "last_contact": 1691244533, + "longitude": 5.5217, + "latitude": 52.4561, + "baro_altitude": 12500.8, + "on_ground": false, + "velocity": 201.9, + "true_track": 82.39, + "vertical_rate": 0, + "sensors": null, + "geo_altitude": 12733.02, + "squawk": "1071", + "spi": false, + "position_source": 0, + "category": 1 + } + ] +} diff --git a/tests/components/opensky/snapshots/test_sensor.ambr b/tests/components/opensky/snapshots/test_sensor.ambr new file mode 100644 index 00000000000..1bd85d23400 --- /dev/null +++ b/tests/components/opensky/snapshots/test_sensor.ambr @@ -0,0 +1,42 @@ +# serializer version: 1 +# name: test_sensor + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Information provided by the OpenSky Network (https://opensky-network.org)', + 'friendly_name': 'OpenSky', + 'icon': 'mdi:airplane', + 'unit_of_measurement': 'flights', + }), + 'context': , + 'entity_id': 'sensor.opensky', + 'last_changed': , + 'last_updated': , + 'state': '2', + }) +# --- +# name: test_sensor_altitude + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'attribution': 'Information provided by the OpenSky Network (https://opensky-network.org)', + 'friendly_name': 'OpenSky', + 'icon': 'mdi:airplane', + 'unit_of_measurement': 'flights', + }), + 'context': , + 'entity_id': 'sensor.opensky', + 'last_changed': , + 'last_updated': , + 'state': '1', + }) +# --- +# name: test_sensor_updating + list([ + , + ]) +# --- +# name: test_sensor_updating.1 + list([ + , + , + ]) +# --- diff --git a/tests/components/opensky/test_sensor.py b/tests/components/opensky/test_sensor.py index 1768efebc78..eb17721929c 100644 --- a/tests/components/opensky/test_sensor.py +++ b/tests/components/opensky/test_sensor.py @@ -1,20 +1,115 @@ """OpenSky sensor tests.""" -from homeassistant.components.opensky.const import DOMAIN +from datetime import timedelta +import json +from unittest.mock import patch + +from python_opensky import StatesResponse +from syrupy import SnapshotAssertion + +from homeassistant.components.opensky.const import ( + DOMAIN, + EVENT_OPENSKY_ENTRY, + EVENT_OPENSKY_EXIT, +) from homeassistant.config_entries import ConfigEntryState from homeassistant.const import CONF_PLATFORM, CONF_RADIUS, Platform -from homeassistant.core import HomeAssistant +from homeassistant.core import Event, HomeAssistant from homeassistant.helpers import issue_registry as ir from homeassistant.setup import async_setup_component +from homeassistant.util import dt as dt_util + +from .conftest import ComponentSetup + +from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture LEGACY_CONFIG = {Platform.SENSOR: [{CONF_PLATFORM: DOMAIN, CONF_RADIUS: 10.0}]} async def test_legacy_migration(hass: HomeAssistant) -> None: """Test migration from yaml to config flow.""" - assert await async_setup_component(hass, Platform.SENSOR, LEGACY_CONFIG) - await hass.async_block_till_done() - entries = hass.config_entries.async_entries(DOMAIN) - assert len(entries) == 1 - assert entries[0].state is ConfigEntryState.LOADED - issue_registry = ir.async_get(hass) - assert len(issue_registry.issues) == 1 + json_fixture = load_fixture("opensky/states.json") + with patch( + "python_opensky.OpenSky.get_states", + return_value=StatesResponse.parse_obj(json.loads(json_fixture)), + ): + assert await async_setup_component(hass, Platform.SENSOR, LEGACY_CONFIG) + await hass.async_block_till_done() + entries = hass.config_entries.async_entries(DOMAIN) + assert len(entries) == 1 + assert entries[0].state is ConfigEntryState.LOADED + issue_registry = ir.async_get(hass) + assert len(issue_registry.issues) == 1 + + +async def test_sensor( + hass: HomeAssistant, + config_entry: MockConfigEntry, + setup_integration: ComponentSetup, + snapshot: SnapshotAssertion, +): + """Test setup sensor.""" + await setup_integration(config_entry) + + state = hass.states.get("sensor.opensky") + assert state == snapshot + events = [] + + async def event_listener(event: Event) -> None: + events.append(event) + + hass.bus.async_listen(EVENT_OPENSKY_ENTRY, event_listener) + hass.bus.async_listen(EVENT_OPENSKY_EXIT, event_listener) + assert events == [] + + +async def test_sensor_altitude( + hass: HomeAssistant, + config_entry_altitude: MockConfigEntry, + setup_integration: ComponentSetup, + snapshot: SnapshotAssertion, +): + """Test setup sensor with a set altitude.""" + await setup_integration(config_entry_altitude) + + state = hass.states.get("sensor.opensky") + assert state == snapshot + + +async def test_sensor_updating( + hass: HomeAssistant, + config_entry: MockConfigEntry, + setup_integration: ComponentSetup, + snapshot: SnapshotAssertion, +): + """Test updating sensor.""" + await setup_integration(config_entry) + + def get_states_response_fixture(fixture: str) -> StatesResponse: + json_fixture = load_fixture(fixture) + return StatesResponse.parse_obj(json.loads(json_fixture)) + + events = [] + + async def event_listener(event: Event) -> None: + events.append(event) + + hass.bus.async_listen(EVENT_OPENSKY_ENTRY, event_listener) + hass.bus.async_listen(EVENT_OPENSKY_EXIT, event_listener) + + async def skip_time_and_check_events() -> None: + future = dt_util.utcnow() + timedelta(minutes=15) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + assert events == snapshot + + with patch( + "python_opensky.OpenSky.get_states", + return_value=get_states_response_fixture("opensky/states_1.json"), + ): + await skip_time_and_check_events() + with patch( + "python_opensky.OpenSky.get_states", + return_value=get_states_response_fixture("opensky/states.json"), + ): + await skip_time_and_check_events()