Refactor Airly tests (#44315)

This commit is contained in:
Maciej Bieniek 2020-12-17 16:44:46 +01:00 committed by GitHub
parent 7c63119ad2
commit 94e1f8e631
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 171 additions and 185 deletions

View file

@ -1,32 +1,33 @@
"""Tests for Airly.""" """Tests for Airly."""
import json
from homeassistant.components.airly.const import DOMAIN from homeassistant.components.airly.const import DOMAIN
from tests.async_mock import patch
from tests.common import MockConfigEntry, load_fixture 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.""" """Set up the Airly integration in Home Assistant."""
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
title="Home", title="Home",
unique_id="55.55-122.12", unique_id="123-456",
data={ data={
"api_key": "foo", "api_key": "foo",
"latitude": 55.55, "latitude": 123,
"longitude": 122.12, "longitude": 456,
"name": "Home", "name": "Home",
}, },
) )
with patch( aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_valid_station.json"))
"airly._private._RequestsHandler.get", entry.add_to_hass(hass)
return_value=json.loads(load_fixture("airly_valid_station.json")), await hass.config_entries.async_setup(entry.entry_id)
): await hass.async_block_till_done()
entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
return entry return entry

View file

@ -1,6 +1,5 @@
"""Test air_quality of Airly integration.""" """Test air_quality of Airly integration."""
from datetime import timedelta from datetime import timedelta
import json
from airly.exceptions import AirlyError from airly.exceptions import AirlyError
@ -21,19 +20,21 @@ from homeassistant.const import (
ATTR_ICON, ATTR_ICON,
ATTR_UNIT_OF_MEASUREMENT, ATTR_UNIT_OF_MEASUREMENT,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
HTTP_INTERNAL_SERVER_ERROR,
STATE_UNAVAILABLE, STATE_UNAVAILABLE,
) )
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util.dt import utcnow 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.common import async_fire_time_changed, load_fixture
from tests.components.airly import init_integration 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.""" """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() registry = await hass.helpers.entity_registry.async_get_registry()
state = hass.states.get("air_quality.home") state = hass.states.get("air_quality.home")
@ -58,56 +59,55 @@ async def test_air_quality(hass):
entry = registry.async_get("air_quality.home") entry = registry.async_get("air_quality.home")
assert entry 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.""" """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") state = hass.states.get("air_quality.home")
assert state assert state
assert state.state != STATE_UNAVAILABLE assert state.state != STATE_UNAVAILABLE
assert state.state == "14" 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) 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") async_fire_time_changed(hass, future)
assert state await hass.async_block_till_done()
assert state.state == STATE_UNAVAILABLE
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) 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") async_fire_time_changed(hass, future)
assert state await hass.async_block_till_done()
assert state.state != STATE_UNAVAILABLE
assert state.state == "14" 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.""" """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", {}) await async_setup_component(hass, "homeassistant", {})
with patch( await hass.services.async_call(
"homeassistant.components.airly.AirlyDataUpdateCoordinator._async_update_data" "homeassistant",
) as mock_update: "update_entity",
await hass.services.async_call( {ATTR_ENTITY_ID: ["air_quality.home"]},
"homeassistant", blocking=True,
"update_entity", )
{ATTR_ENTITY_ID: ["air_quality.home"]},
blocking=True, assert aioclient_mock.call_count == call_count + 1
)
assert mock_update.call_count == 1

View file

@ -1,6 +1,4 @@
"""Define tests for the Airly config flow.""" """Define tests for the Airly config flow."""
import json
from airly.exceptions import AirlyError from airly.exceptions import AirlyError
from homeassistant import data_entry_flow from homeassistant import data_entry_flow
@ -11,14 +9,15 @@ from homeassistant.const import (
CONF_LATITUDE, CONF_LATITUDE,
CONF_LONGITUDE, CONF_LONGITUDE,
CONF_NAME, CONF_NAME,
HTTP_FORBIDDEN, HTTP_UNAUTHORIZED,
) )
from tests.async_mock import patch from . import API_KEY_VALIDATION_URL, API_POINT_URL
from tests.common import MockConfigEntry, load_fixture
from tests.common import MockConfigEntry, load_fixture, patch
CONFIG = { CONFIG = {
CONF_NAME: "abcd", CONF_NAME: "Home",
CONF_API_KEY: "foo", CONF_API_KEY: "foo",
CONF_LATITUDE: 123, CONF_LATITUDE: 123,
CONF_LONGITUDE: 456, CONF_LONGITUDE: 456,
@ -35,69 +34,63 @@ async def test_show_form(hass):
assert result["step_id"] == SOURCE_USER 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.""" """Test that errors are shown when API key is invalid."""
with patch( aioclient_mock.get(
"airly._private._RequestsHandler.get", API_KEY_VALIDATION_URL,
side_effect=AirlyError( exc=AirlyError(
HTTP_FORBIDDEN, {"message": "Invalid authentication credentials"} HTTP_UNAUTHORIZED, {"message": "Invalid authentication credentials"}
), ),
): )
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG 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.""" """Test that errors are shown when location is invalid."""
with patch( aioclient_mock.get(
"airly._private._RequestsHandler.get", API_KEY_VALIDATION_URL, text=load_fixture("airly_valid_station.json")
return_value=json.loads(load_fixture("airly_no_station.json")), )
): aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_no_station.json"))
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG 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.""" """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( result = await hass.config_entries.flow.async_init(
"airly._private._RequestsHandler.get", DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
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( assert result["type"] == "abort"
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG 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.""" """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( with patch("homeassistant.components.airly.async_setup_entry", return_value=True):
"airly._private._RequestsHandler.get",
return_value=json.loads(load_fixture("airly_valid_station.json")),
):
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == CONFIG[CONF_NAME] assert result["title"] == CONFIG[CONF_NAME]
assert result["data"][CONF_LATITUDE] == CONFIG[CONF_LATITUDE] assert result["data"][CONF_LATITUDE] == CONFIG[CONF_LATITUDE]
assert result["data"][CONF_LONGITUDE] == CONFIG[CONF_LONGITUDE] assert result["data"][CONF_LONGITUDE] == CONFIG[CONF_LONGITUDE]
assert result["data"][CONF_API_KEY] == CONFIG[CONF_API_KEY] assert result["data"][CONF_API_KEY] == CONFIG[CONF_API_KEY]

View file

@ -1,6 +1,5 @@
"""Test init of Airly integration.""" """Test init of Airly integration."""
from datetime import timedelta from datetime import timedelta
import json
from homeassistant.components.airly.const import DOMAIN from homeassistant.components.airly.const import DOMAIN
from homeassistant.config_entries import ( from homeassistant.config_entries import (
@ -10,14 +9,15 @@ from homeassistant.config_entries import (
) )
from homeassistant.const import STATE_UNAVAILABLE 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.common import MockConfigEntry, load_fixture
from tests.components.airly import init_integration 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.""" """Test a successful setup entry."""
await init_integration(hass) await init_integration(hass, aioclient_mock)
state = hass.states.get("air_quality.home") state = hass.states.get("air_quality.home")
assert state is not None assert state is not None
@ -25,75 +25,69 @@ async def test_async_setup_entry(hass):
assert state.state == "14" 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.""" """Test for setup failure if connection to Airly is missing."""
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
title="Home", title="Home",
unique_id="55.55-122.12", unique_id="123-456",
data={ data={
"api_key": "foo", "api_key": "foo",
"latitude": 55.55, "latitude": 123,
"longitude": 122.12, "longitude": 456,
"name": "Home", "name": "Home",
}, },
) )
with patch("airly._private._RequestsHandler.get", side_effect=ConnectionError()): aioclient_mock.get(API_POINT_URL, exc=ConnectionError())
entry.add_to_hass(hass) entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
assert entry.state == ENTRY_STATE_SETUP_RETRY 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.""" """Test for setup entry without unique_id."""
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
title="Home", title="Home",
data={ data={
"api_key": "foo", "api_key": "foo",
"latitude": 55.55, "latitude": 123,
"longitude": 122.12, "longitude": 456,
"name": "Home", "name": "Home",
}, },
) )
with patch( aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_valid_station.json"))
"airly._private._RequestsHandler.get", entry.add_to_hass(hass)
return_value=json.loads(load_fixture("airly_valid_station.json")), await hass.config_entries.async_setup(entry.entry_id)
): assert entry.state == ENTRY_STATE_LOADED
entry.add_to_hass(hass) assert entry.unique_id == "123-456"
await hass.config_entries.async_setup(entry.entry_id)
assert entry.state == ENTRY_STATE_LOADED
assert entry.unique_id == "55.55-122.12"
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.""" """Test for setup entry for a turned off measuring station."""
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
title="Home", title="Home",
unique_id="55.55-122.12", unique_id="123-456",
data={ data={
"api_key": "foo", "api_key": "foo",
"latitude": 55.55, "latitude": 123,
"longitude": 122.12, "longitude": 456,
"name": "Home", "name": "Home",
}, },
) )
with patch( aioclient_mock.get(API_POINT_URL, text=load_fixture("airly_no_station.json"))
"airly._private._RequestsHandler.get", entry.add_to_hass(hass)
return_value=json.loads(load_fixture("airly_no_station.json")), await hass.config_entries.async_setup(entry.entry_id)
): assert entry.state == ENTRY_STATE_SETUP_RETRY
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.""" """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 len(hass.config_entries.async_entries(DOMAIN)) == 1
assert entry.state == ENTRY_STATE_LOADED assert entry.state == ENTRY_STATE_LOADED
@ -112,13 +106,13 @@ async def test_update_interval(hass):
}, },
) )
with patch( aioclient_mock.get(
"airly._private._RequestsHandler.get", "https://airapi.airly.eu/v2/measurements/point?lat=66.660000&lng=111.110000",
return_value=json.loads(load_fixture("airly_valid_station.json")), text=load_fixture("airly_valid_station.json"),
): )
entry.add_to_hass(hass) entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.config_entries.async_entries(DOMAIN)) == 2 assert len(hass.config_entries.async_entries(DOMAIN)) == 2
assert entry.state == ENTRY_STATE_LOADED assert entry.state == ENTRY_STATE_LOADED
@ -126,9 +120,9 @@ async def test_update_interval(hass):
assert instance.update_interval == timedelta(minutes=30) 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.""" """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 len(hass.config_entries.async_entries(DOMAIN)) == 1
assert entry.state == ENTRY_STATE_LOADED assert entry.state == ENTRY_STATE_LOADED

View file

@ -1,6 +1,5 @@
"""Test sensor of Airly integration.""" """Test sensor of Airly integration."""
from datetime import timedelta from datetime import timedelta
import json
from homeassistant.components.airly.sensor import ATTRIBUTION from homeassistant.components.airly.sensor import ATTRIBUTION
from homeassistant.const import ( from homeassistant.const import (
@ -21,14 +20,15 @@ from homeassistant.const import (
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util.dt import utcnow 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.common import async_fire_time_changed, load_fixture
from tests.components.airly import init_integration from tests.components.airly import init_integration
async def test_sensor(hass): async def test_sensor(hass, aioclient_mock):
"""Test states of the sensor.""" """Test states of the sensor."""
await init_integration(hass) await init_integration(hass, aioclient_mock)
registry = await hass.helpers.entity_registry.async_get_registry() registry = await hass.helpers.entity_registry.async_get_registry()
state = hass.states.get("sensor.home_humidity") state = hass.states.get("sensor.home_humidity")
@ -40,7 +40,7 @@ async def test_sensor(hass):
entry = registry.async_get("sensor.home_humidity") entry = registry.async_get("sensor.home_humidity")
assert entry 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") state = hass.states.get("sensor.home_pm1")
assert state assert state
@ -54,7 +54,7 @@ async def test_sensor(hass):
entry = registry.async_get("sensor.home_pm1") entry = registry.async_get("sensor.home_pm1")
assert entry 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") state = hass.states.get("sensor.home_pressure")
assert state assert state
@ -65,7 +65,7 @@ async def test_sensor(hass):
entry = registry.async_get("sensor.home_pressure") entry = registry.async_get("sensor.home_pressure")
assert entry 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") state = hass.states.get("sensor.home_temperature")
assert state assert state
@ -76,53 +76,51 @@ async def test_sensor(hass):
entry = registry.async_get("sensor.home_temperature") entry = registry.async_get("sensor.home_temperature")
assert entry 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.""" """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") state = hass.states.get("sensor.home_humidity")
assert state assert state
assert state.state != STATE_UNAVAILABLE assert state.state != STATE_UNAVAILABLE
assert state.state == "92.8" assert state.state == "92.8"
aioclient_mock.clear_requests()
aioclient_mock.get(API_POINT_URL, exc=ConnectionError())
future = utcnow() + timedelta(minutes=60) future = utcnow() + timedelta(minutes=60)
with patch("airly._private._RequestsHandler.get", side_effect=ConnectionError()): async_fire_time_changed(hass, future)
async_fire_time_changed(hass, future) await hass.async_block_till_done()
await hass.async_block_till_done()
state = hass.states.get("sensor.home_humidity") state = hass.states.get("sensor.home_humidity")
assert state assert state
assert state.state == STATE_UNAVAILABLE 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) future = utcnow() + timedelta(minutes=120)
with patch( async_fire_time_changed(hass, future)
"airly._private._RequestsHandler.get", await hass.async_block_till_done()
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("sensor.home_humidity") state = hass.states.get("sensor.home_humidity")
assert state assert state
assert state.state != STATE_UNAVAILABLE assert state.state != STATE_UNAVAILABLE
assert state.state == "92.8" 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.""" """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", {}) await async_setup_component(hass, "homeassistant", {})
with patch( await hass.services.async_call(
"homeassistant.components.airly.AirlyDataUpdateCoordinator._async_update_data" "homeassistant",
) as mock_update: "update_entity",
await hass.services.async_call( {ATTR_ENTITY_ID: ["sensor.home_humidity"]},
"homeassistant", blocking=True,
"update_entity", )
{ATTR_ENTITY_ID: ["sensor.home_humidity"]},
blocking=True, assert aioclient_mock.call_count == call_count + 1
)
assert mock_update.call_count == 1