diff --git a/tests/components/airly/__init__.py b/tests/components/airly/__init__.py index 29828bddc17..87e549b9298 100644 --- a/tests/components/airly/__init__.py +++ b/tests/components/airly/__init__.py @@ -1,32 +1,33 @@ """Tests for Airly.""" -import json - from homeassistant.components.airly.const import DOMAIN -from tests.async_mock import patch from tests.common import MockConfigEntry, load_fixture +API_KEY_VALIDATION_URL = ( + "https://airapi.airly.eu/v2/measurements/point?lat=52.241310&lng=20.991010" +) +API_POINT_URL = ( + "https://airapi.airly.eu/v2/measurements/point?lat=123.000000&lng=456.000000" +) -async def init_integration(hass, forecast=False) -> MockConfigEntry: + +async def init_integration(hass, aioclient_mock) -> MockConfigEntry: """Set up the Airly integration in Home Assistant.""" entry = MockConfigEntry( domain=DOMAIN, title="Home", - unique_id="55.55-122.12", + unique_id="123-456", data={ "api_key": "foo", - "latitude": 55.55, - "longitude": 122.12, + "latitude": 123, + "longitude": 456, "name": "Home", }, ) - with patch( - "airly._private._RequestsHandler.get", - return_value=json.loads(load_fixture("airly_valid_station.json")), - ): - entry.add_to_hass(hass) - await hass.config_entries.async_setup(entry.entry_id) - await hass.async_block_till_done() + aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_valid_station.json")) + entry.add_to_hass(hass) + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() return entry diff --git a/tests/components/airly/test_air_quality.py b/tests/components/airly/test_air_quality.py index fca2761f2f3..24a98cbf155 100644 --- a/tests/components/airly/test_air_quality.py +++ b/tests/components/airly/test_air_quality.py @@ -1,6 +1,5 @@ """Test air_quality of Airly integration.""" from datetime import timedelta -import json from airly.exceptions import AirlyError @@ -21,19 +20,21 @@ from homeassistant.const import ( ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + HTTP_INTERNAL_SERVER_ERROR, STATE_UNAVAILABLE, ) from homeassistant.setup import async_setup_component from homeassistant.util.dt import utcnow -from tests.async_mock import patch +from . import API_POINT_URL + from tests.common import async_fire_time_changed, load_fixture from tests.components.airly import init_integration -async def test_air_quality(hass): +async def test_air_quality(hass, aioclient_mock): """Test states of the air_quality.""" - await init_integration(hass) + await init_integration(hass, aioclient_mock) registry = await hass.helpers.entity_registry.async_get_registry() state = hass.states.get("air_quality.home") @@ -58,56 +59,55 @@ async def test_air_quality(hass): entry = registry.async_get("air_quality.home") assert entry - assert entry.unique_id == "55.55-122.12" + assert entry.unique_id == "123-456" -async def test_availability(hass): +async def test_availability(hass, aioclient_mock): """Ensure that we mark the entities unavailable correctly when service causes an error.""" - await init_integration(hass) + await init_integration(hass, aioclient_mock) state = hass.states.get("air_quality.home") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "14" + aioclient_mock.clear_requests() + aioclient_mock.get( + API_POINT_URL, exc=AirlyError(HTTP_INTERNAL_SERVER_ERROR, "Unexpected error") + ) future = utcnow() + timedelta(minutes=60) - with patch( - "airly._private._RequestsHandler.get", - side_effect=AirlyError(500, "Unexpected error"), - ): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - state = hass.states.get("air_quality.home") - assert state - assert state.state == STATE_UNAVAILABLE + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + state = hass.states.get("air_quality.home") + assert state + assert state.state == STATE_UNAVAILABLE + + aioclient_mock.clear_requests() + aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_valid_station.json")) future = utcnow() + timedelta(minutes=120) - with patch( - "airly._private._RequestsHandler.get", - return_value=json.loads(load_fixture("airly_valid_station.json")), - ): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() - state = hass.states.get("air_quality.home") - assert state - assert state.state != STATE_UNAVAILABLE - assert state.state == "14" + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + state = hass.states.get("air_quality.home") + assert state + assert state.state != STATE_UNAVAILABLE + assert state.state == "14" -async def test_manual_update_entity(hass): +async def test_manual_update_entity(hass, aioclient_mock): """Test manual update entity via service homeasasistant/update_entity.""" - await init_integration(hass) + await init_integration(hass, aioclient_mock) + call_count = aioclient_mock.call_count await async_setup_component(hass, "homeassistant", {}) - with patch( - "homeassistant.components.airly.AirlyDataUpdateCoordinator._async_update_data" - ) as mock_update: - await hass.services.async_call( - "homeassistant", - "update_entity", - {ATTR_ENTITY_ID: ["air_quality.home"]}, - blocking=True, - ) - assert mock_update.call_count == 1 + await hass.services.async_call( + "homeassistant", + "update_entity", + {ATTR_ENTITY_ID: ["air_quality.home"]}, + blocking=True, + ) + + assert aioclient_mock.call_count == call_count + 1 diff --git a/tests/components/airly/test_config_flow.py b/tests/components/airly/test_config_flow.py index d7d45bbd7e3..e5ae80022b8 100644 --- a/tests/components/airly/test_config_flow.py +++ b/tests/components/airly/test_config_flow.py @@ -1,6 +1,4 @@ """Define tests for the Airly config flow.""" -import json - from airly.exceptions import AirlyError from homeassistant import data_entry_flow @@ -11,14 +9,15 @@ from homeassistant.const import ( CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, - HTTP_FORBIDDEN, + HTTP_UNAUTHORIZED, ) -from tests.async_mock import patch -from tests.common import MockConfigEntry, load_fixture +from . import API_KEY_VALIDATION_URL, API_POINT_URL + +from tests.common import MockConfigEntry, load_fixture, patch CONFIG = { - CONF_NAME: "abcd", + CONF_NAME: "Home", CONF_API_KEY: "foo", CONF_LATITUDE: 123, CONF_LONGITUDE: 456, @@ -35,69 +34,63 @@ async def test_show_form(hass): assert result["step_id"] == SOURCE_USER -async def test_invalid_api_key(hass): +async def test_invalid_api_key(hass, aioclient_mock): """Test that errors are shown when API key is invalid.""" - with patch( - "airly._private._RequestsHandler.get", - side_effect=AirlyError( - HTTP_FORBIDDEN, {"message": "Invalid authentication credentials"} + aioclient_mock.get( + API_KEY_VALIDATION_URL, + exc=AirlyError( + HTTP_UNAUTHORIZED, {"message": "Invalid authentication credentials"} ), - ): + ) - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER}, data=CONFIG - ) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=CONFIG + ) - assert result["errors"] == {"base": "invalid_api_key"} + assert result["errors"] == {"base": "invalid_api_key"} -async def test_invalid_location(hass): +async def test_invalid_location(hass, aioclient_mock): """Test that errors are shown when location is invalid.""" - with patch( - "airly._private._RequestsHandler.get", - return_value=json.loads(load_fixture("airly_no_station.json")), - ): + aioclient_mock.get( + API_KEY_VALIDATION_URL, text=load_fixture("airly_valid_station.json") + ) + aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_no_station.json")) - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER}, data=CONFIG - ) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=CONFIG + ) - assert result["errors"] == {"base": "wrong_location"} + assert result["errors"] == {"base": "wrong_location"} -async def test_duplicate_error(hass): +async def test_duplicate_error(hass, aioclient_mock): """Test that errors are shown when duplicates are added.""" + aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_valid_station.json")) + MockConfigEntry(domain=DOMAIN, unique_id="123-456", data=CONFIG).add_to_hass(hass) - with patch( - "airly._private._RequestsHandler.get", - return_value=json.loads(load_fixture("airly_valid_station.json")), - ): - MockConfigEntry(domain=DOMAIN, unique_id="123-456", data=CONFIG).add_to_hass( - hass - ) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=CONFIG + ) - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER}, data=CONFIG - ) - - assert result["type"] == "abort" - assert result["reason"] == "already_configured" + assert result["type"] == "abort" + assert result["reason"] == "already_configured" -async def test_create_entry(hass): +async def test_create_entry(hass, aioclient_mock): """Test that the user step works.""" + aioclient_mock.get( + API_KEY_VALIDATION_URL, text=load_fixture("airly_valid_station.json") + ) + aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_valid_station.json")) - with patch( - "airly._private._RequestsHandler.get", - return_value=json.loads(load_fixture("airly_valid_station.json")), - ): - + with patch("homeassistant.components.airly.async_setup_entry", return_value=True): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, data=CONFIG ) - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result["title"] == CONFIG[CONF_NAME] - assert result["data"][CONF_LATITUDE] == CONFIG[CONF_LATITUDE] - assert result["data"][CONF_LONGITUDE] == CONFIG[CONF_LONGITUDE] - assert result["data"][CONF_API_KEY] == CONFIG[CONF_API_KEY] + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result["title"] == CONFIG[CONF_NAME] + assert result["data"][CONF_LATITUDE] == CONFIG[CONF_LATITUDE] + assert result["data"][CONF_LONGITUDE] == CONFIG[CONF_LONGITUDE] + assert result["data"][CONF_API_KEY] == CONFIG[CONF_API_KEY] diff --git a/tests/components/airly/test_init.py b/tests/components/airly/test_init.py index 28f2aca4fbb..cb0ccf268f7 100644 --- a/tests/components/airly/test_init.py +++ b/tests/components/airly/test_init.py @@ -1,6 +1,5 @@ """Test init of Airly integration.""" from datetime import timedelta -import json from homeassistant.components.airly.const import DOMAIN from homeassistant.config_entries import ( @@ -10,14 +9,15 @@ from homeassistant.config_entries import ( ) from homeassistant.const import STATE_UNAVAILABLE -from tests.async_mock import patch +from . import API_POINT_URL + from tests.common import MockConfigEntry, load_fixture from tests.components.airly import init_integration -async def test_async_setup_entry(hass): +async def test_async_setup_entry(hass, aioclient_mock): """Test a successful setup entry.""" - await init_integration(hass) + await init_integration(hass, aioclient_mock) state = hass.states.get("air_quality.home") assert state is not None @@ -25,75 +25,69 @@ async def test_async_setup_entry(hass): assert state.state == "14" -async def test_config_not_ready(hass): +async def test_config_not_ready(hass, aioclient_mock): """Test for setup failure if connection to Airly is missing.""" entry = MockConfigEntry( domain=DOMAIN, title="Home", - unique_id="55.55-122.12", + unique_id="123-456", data={ "api_key": "foo", - "latitude": 55.55, - "longitude": 122.12, + "latitude": 123, + "longitude": 456, "name": "Home", }, ) - with patch("airly._private._RequestsHandler.get", side_effect=ConnectionError()): - entry.add_to_hass(hass) - await hass.config_entries.async_setup(entry.entry_id) - assert entry.state == ENTRY_STATE_SETUP_RETRY + aioclient_mock.get(API_POINT_URL, exc=ConnectionError()) + entry.add_to_hass(hass) + await hass.config_entries.async_setup(entry.entry_id) + assert entry.state == ENTRY_STATE_SETUP_RETRY -async def test_config_without_unique_id(hass): +async def test_config_without_unique_id(hass, aioclient_mock): """Test for setup entry without unique_id.""" entry = MockConfigEntry( domain=DOMAIN, title="Home", data={ "api_key": "foo", - "latitude": 55.55, - "longitude": 122.12, + "latitude": 123, + "longitude": 456, "name": "Home", }, ) - with patch( - "airly._private._RequestsHandler.get", - return_value=json.loads(load_fixture("airly_valid_station.json")), - ): - entry.add_to_hass(hass) - await hass.config_entries.async_setup(entry.entry_id) - assert entry.state == ENTRY_STATE_LOADED - assert entry.unique_id == "55.55-122.12" + aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_valid_station.json")) + entry.add_to_hass(hass) + await hass.config_entries.async_setup(entry.entry_id) + assert entry.state == ENTRY_STATE_LOADED + assert entry.unique_id == "123-456" -async def test_config_with_turned_off_station(hass): +async def test_config_with_turned_off_station(hass, aioclient_mock): """Test for setup entry for a turned off measuring station.""" entry = MockConfigEntry( domain=DOMAIN, title="Home", - unique_id="55.55-122.12", + unique_id="123-456", data={ "api_key": "foo", - "latitude": 55.55, - "longitude": 122.12, + "latitude": 123, + "longitude": 456, "name": "Home", }, ) - with patch( - "airly._private._RequestsHandler.get", - return_value=json.loads(load_fixture("airly_no_station.json")), - ): - entry.add_to_hass(hass) - await hass.config_entries.async_setup(entry.entry_id) - assert entry.state == ENTRY_STATE_SETUP_RETRY + aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_no_station.json")) + entry.add_to_hass(hass) + await hass.config_entries.async_setup(entry.entry_id) + assert entry.state == ENTRY_STATE_SETUP_RETRY -async def test_update_interval(hass): +async def test_update_interval(hass, aioclient_mock): """Test correct update interval when the number of configured instances changes.""" - entry = await init_integration(hass) + entry = await init_integration(hass, aioclient_mock) assert len(hass.config_entries.async_entries(DOMAIN)) == 1 assert entry.state == ENTRY_STATE_LOADED @@ -112,13 +106,13 @@ async def test_update_interval(hass): }, ) - with patch( - "airly._private._RequestsHandler.get", - return_value=json.loads(load_fixture("airly_valid_station.json")), - ): - entry.add_to_hass(hass) - await hass.config_entries.async_setup(entry.entry_id) - await hass.async_block_till_done() + aioclient_mock.get( + "https://airapi.airly.eu/v2/measurements/point?lat=66.660000&lng=111.110000", + text=load_fixture("airly_valid_station.json"), + ) + entry.add_to_hass(hass) + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() assert len(hass.config_entries.async_entries(DOMAIN)) == 2 assert entry.state == ENTRY_STATE_LOADED @@ -126,9 +120,9 @@ async def test_update_interval(hass): assert instance.update_interval == timedelta(minutes=30) -async def test_unload_entry(hass): +async def test_unload_entry(hass, aioclient_mock): """Test successful unload of entry.""" - entry = await init_integration(hass) + entry = await init_integration(hass, aioclient_mock) assert len(hass.config_entries.async_entries(DOMAIN)) == 1 assert entry.state == ENTRY_STATE_LOADED diff --git a/tests/components/airly/test_sensor.py b/tests/components/airly/test_sensor.py index 45b98d7c27c..abc53294bbc 100644 --- a/tests/components/airly/test_sensor.py +++ b/tests/components/airly/test_sensor.py @@ -1,6 +1,5 @@ """Test sensor of Airly integration.""" from datetime import timedelta -import json from homeassistant.components.airly.sensor import ATTRIBUTION from homeassistant.const import ( @@ -21,14 +20,15 @@ from homeassistant.const import ( from homeassistant.setup import async_setup_component from homeassistant.util.dt import utcnow -from tests.async_mock import patch +from . import API_POINT_URL + from tests.common import async_fire_time_changed, load_fixture from tests.components.airly import init_integration -async def test_sensor(hass): +async def test_sensor(hass, aioclient_mock): """Test states of the sensor.""" - await init_integration(hass) + await init_integration(hass, aioclient_mock) registry = await hass.helpers.entity_registry.async_get_registry() state = hass.states.get("sensor.home_humidity") @@ -40,7 +40,7 @@ async def test_sensor(hass): entry = registry.async_get("sensor.home_humidity") assert entry - assert entry.unique_id == "55.55-122.12-humidity" + assert entry.unique_id == "123-456-humidity" state = hass.states.get("sensor.home_pm1") assert state @@ -54,7 +54,7 @@ async def test_sensor(hass): entry = registry.async_get("sensor.home_pm1") assert entry - assert entry.unique_id == "55.55-122.12-pm1" + assert entry.unique_id == "123-456-pm1" state = hass.states.get("sensor.home_pressure") assert state @@ -65,7 +65,7 @@ async def test_sensor(hass): entry = registry.async_get("sensor.home_pressure") assert entry - assert entry.unique_id == "55.55-122.12-pressure" + assert entry.unique_id == "123-456-pressure" state = hass.states.get("sensor.home_temperature") assert state @@ -76,53 +76,51 @@ async def test_sensor(hass): entry = registry.async_get("sensor.home_temperature") assert entry - assert entry.unique_id == "55.55-122.12-temperature" + assert entry.unique_id == "123-456-temperature" -async def test_availability(hass): +async def test_availability(hass, aioclient_mock): """Ensure that we mark the entities unavailable correctly when service is offline.""" - await init_integration(hass) + await init_integration(hass, aioclient_mock) state = hass.states.get("sensor.home_humidity") assert state assert state.state != STATE_UNAVAILABLE assert state.state == "92.8" + aioclient_mock.clear_requests() + aioclient_mock.get(API_POINT_URL, exc=ConnectionError()) future = utcnow() + timedelta(minutes=60) - with patch("airly._private._RequestsHandler.get", side_effect=ConnectionError()): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() + async_fire_time_changed(hass, future) + await hass.async_block_till_done() - state = hass.states.get("sensor.home_humidity") - assert state - assert state.state == STATE_UNAVAILABLE + state = hass.states.get("sensor.home_humidity") + assert state + assert state.state == STATE_UNAVAILABLE + aioclient_mock.clear_requests() + aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_valid_station.json")) future = utcnow() + timedelta(minutes=120) - with patch( - "airly._private._RequestsHandler.get", - return_value=json.loads(load_fixture("airly_valid_station.json")), - ): - async_fire_time_changed(hass, future) - await hass.async_block_till_done() + async_fire_time_changed(hass, future) + await hass.async_block_till_done() - state = hass.states.get("sensor.home_humidity") - assert state - assert state.state != STATE_UNAVAILABLE - assert state.state == "92.8" + state = hass.states.get("sensor.home_humidity") + assert state + assert state.state != STATE_UNAVAILABLE + assert state.state == "92.8" -async def test_manual_update_entity(hass): +async def test_manual_update_entity(hass, aioclient_mock): """Test manual update entity via service homeasasistant/update_entity.""" - await init_integration(hass) + await init_integration(hass, aioclient_mock) + call_count = aioclient_mock.call_count await async_setup_component(hass, "homeassistant", {}) - with patch( - "homeassistant.components.airly.AirlyDataUpdateCoordinator._async_update_data" - ) as mock_update: - await hass.services.async_call( - "homeassistant", - "update_entity", - {ATTR_ENTITY_ID: ["sensor.home_humidity"]}, - blocking=True, - ) - assert mock_update.call_count == 1 + await hass.services.async_call( + "homeassistant", + "update_entity", + {ATTR_ENTITY_ID: ["sensor.home_humidity"]}, + blocking=True, + ) + + assert aioclient_mock.call_count == call_count + 1