From 6ef7539a31c59c2d86ecac365814152cd2f4beb7 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Thu, 23 Dec 2021 07:25:26 +0100 Subject: [PATCH] Add base integration tests to Luftdaten (#62594) --- .coveragerc | 1 - .../components/luftdaten/__init__.py | 2 +- tests/components/luftdaten/conftest.py | 58 +++++++++++++- .../components/luftdaten/test_config_flow.py | 80 +++++++++---------- tests/components/luftdaten/test_init.py | 75 +++++++++++++++++ 5 files changed, 170 insertions(+), 46 deletions(-) create mode 100644 tests/components/luftdaten/test_init.py diff --git a/.coveragerc b/.coveragerc index 26f05a7816a..d5876b62b61 100644 --- a/.coveragerc +++ b/.coveragerc @@ -607,7 +607,6 @@ omit = homeassistant/components/lookin/climate.py homeassistant/components/lookin/media_player.py homeassistant/components/luci/device_tracker.py - homeassistant/components/luftdaten/__init__.py homeassistant/components/luftdaten/sensor.py homeassistant/components/lupusec/* homeassistant/components/lutron/* diff --git a/homeassistant/components/luftdaten/__init__.py b/homeassistant/components/luftdaten/__init__.py index 33ddcf67a1e..8725c25bf8e 100644 --- a/homeassistant/components/luftdaten/__init__.py +++ b/homeassistant/components/luftdaten/__init__.py @@ -28,7 +28,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # For backwards compat, set unique ID if entry.unique_id is None: hass.config_entries.async_update_entry( - entry, unique_id=entry.data[CONF_SENSOR_ID] + entry, unique_id=str(entry.data[CONF_SENSOR_ID]) ) luftdaten = Luftdaten(entry.data[CONF_SENSOR_ID]) diff --git a/tests/components/luftdaten/conftest.py b/tests/components/luftdaten/conftest.py index 28cade2c34d..14d8991e41c 100644 --- a/tests/components/luftdaten/conftest.py +++ b/tests/components/luftdaten/conftest.py @@ -2,12 +2,13 @@ from __future__ import annotations from collections.abc import Generator -from unittest.mock import patch +from unittest.mock import MagicMock, patch import pytest -from homeassistant.components.luftdaten import DOMAIN -from homeassistant.components.luftdaten.const import CONF_SENSOR_ID +from homeassistant.components.luftdaten.const import CONF_SENSOR_ID, DOMAIN +from homeassistant.const import CONF_SHOW_ON_MAP +from homeassistant.core import HomeAssistant from tests.common import MockConfigEntry @@ -18,7 +19,7 @@ def mock_config_entry() -> MockConfigEntry: return MockConfigEntry( title="12345", domain=DOMAIN, - data={CONF_SENSOR_ID: 123456}, + data={CONF_SENSOR_ID: 12345, CONF_SHOW_ON_MAP: True}, unique_id="12345", ) @@ -30,3 +31,52 @@ def mock_setup_entry() -> Generator[None, None, None]: "homeassistant.components.luftdaten.async_setup_entry", return_value=True ): yield + + +@pytest.fixture +def mock_luftdaten_config_flow() -> Generator[None, MagicMock, None]: + """Return a mocked Luftdaten client.""" + with patch( + "homeassistant.components.luftdaten.config_flow.Luftdaten", autospec=True + ) as luftdaten_mock: + luftdaten = luftdaten_mock.return_value + luftdaten.validate_sensor.return_value = True + yield luftdaten + + +@pytest.fixture +def mock_luftdaten() -> Generator[None, MagicMock, None]: + """Return a mocked Luftdaten client.""" + with patch( + "homeassistant.components.luftdaten.Luftdaten", autospec=True + ) as luftdaten_mock: + luftdaten = luftdaten_mock.return_value + luftdaten.sensor_id = 12345 + luftdaten.meta = { + "altitude": 123.456, + "latitude": 56.789, + "longitude": 12.345, + "sensor_id": 12345, + } + luftdaten.values = { + "humidity": 34.70, + "P1": 8.5, + "P2": 4.07, + "pressure_at_sea_level": 103102.13, + "pressure": 98545.00, + "temperature": 22.30, + } + yield luftdaten + + +@pytest.fixture +async def init_integration( + hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_luftdaten: MagicMock +) -> MockConfigEntry: + """Set up the Luftdaten integration for testing.""" + mock_config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + return mock_config_entry diff --git a/tests/components/luftdaten/test_config_flow.py b/tests/components/luftdaten/test_config_flow.py index 21589381066..595d4397200 100644 --- a/tests/components/luftdaten/test_config_flow.py +++ b/tests/components/luftdaten/test_config_flow.py @@ -1,5 +1,5 @@ """Define tests for the Luftdaten config flow.""" -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock from luftdaten.exceptions import LuftdatenConnectionError @@ -40,7 +40,9 @@ async def test_duplicate_error( assert result2.get("reason") == "already_configured" -async def test_communication_error(hass: HomeAssistant) -> None: +async def test_communication_error( + hass: HomeAssistant, mock_luftdaten_config_flow: MagicMock +) -> None: """Test that no sensor is added while unable to communicate with API.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER} @@ -50,23 +52,22 @@ async def test_communication_error(hass: HomeAssistant) -> None: assert result.get("step_id") == SOURCE_USER assert "flow_id" in result - with patch("luftdaten.Luftdaten.get_data", side_effect=LuftdatenConnectionError): - result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], - user_input={CONF_SENSOR_ID: 12345}, - ) + mock_luftdaten_config_flow.get_data.side_effect = LuftdatenConnectionError + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_SENSOR_ID: 12345}, + ) assert result2.get("type") == RESULT_TYPE_FORM assert result2.get("step_id") == SOURCE_USER assert result2.get("errors") == {CONF_SENSOR_ID: "cannot_connect"} + assert "flow_id" in result2 - with patch("luftdaten.Luftdaten.get_data"), patch( - "luftdaten.Luftdaten.validate_sensor", return_value=True - ): - result3 = await hass.config_entries.flow.async_configure( - result2["flow_id"], - user_input={CONF_SENSOR_ID: 12345}, - ) + mock_luftdaten_config_flow.get_data.side_effect = None + result3 = await hass.config_entries.flow.async_configure( + result2["flow_id"], + user_input={CONF_SENSOR_ID: 12345}, + ) assert result3.get("type") == RESULT_TYPE_CREATE_ENTRY assert result3.get("title") == "12345" @@ -76,7 +77,9 @@ async def test_communication_error(hass: HomeAssistant) -> None: } -async def test_invalid_sensor(hass: HomeAssistant) -> None: +async def test_invalid_sensor( + hass: HomeAssistant, mock_luftdaten_config_flow: MagicMock +) -> None: """Test that an invalid sensor throws an error.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER} @@ -86,26 +89,22 @@ async def test_invalid_sensor(hass: HomeAssistant) -> None: assert result.get("step_id") == SOURCE_USER assert "flow_id" in result - with patch("luftdaten.Luftdaten.get_data", return_value=False), patch( - "luftdaten.Luftdaten.validate_sensor", return_value=False - ): - result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], - user_input={CONF_SENSOR_ID: 12345}, - ) + mock_luftdaten_config_flow.validate_sensor.return_value = False + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_SENSOR_ID: 11111}, + ) assert result2.get("type") == RESULT_TYPE_FORM assert result2.get("step_id") == SOURCE_USER assert result2.get("errors") == {CONF_SENSOR_ID: "invalid_sensor"} assert "flow_id" in result2 - with patch("luftdaten.Luftdaten.get_data"), patch( - "luftdaten.Luftdaten.validate_sensor", return_value=True - ): - result3 = await hass.config_entries.flow.async_configure( - result2["flow_id"], - user_input={CONF_SENSOR_ID: 12345}, - ) + mock_luftdaten_config_flow.validate_sensor.return_value = True + result3 = await hass.config_entries.flow.async_configure( + result2["flow_id"], + user_input={CONF_SENSOR_ID: 12345}, + ) assert result3.get("type") == RESULT_TYPE_CREATE_ENTRY assert result3.get("title") == "12345" @@ -115,7 +114,11 @@ async def test_invalid_sensor(hass: HomeAssistant) -> None: } -async def test_step_user(hass: HomeAssistant, mock_setup_entry: MagicMock) -> None: +async def test_step_user( + hass: HomeAssistant, + mock_setup_entry: MagicMock, + mock_luftdaten_config_flow: MagicMock, +) -> None: """Test that the user step works.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER} @@ -125,16 +128,13 @@ async def test_step_user(hass: HomeAssistant, mock_setup_entry: MagicMock) -> No assert result.get("step_id") == SOURCE_USER assert "flow_id" in result - with patch("luftdaten.Luftdaten.get_data", return_value=True), patch( - "luftdaten.Luftdaten.validate_sensor", return_value=True - ): - result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], - user_input={ - CONF_SENSOR_ID: 12345, - CONF_SHOW_ON_MAP: True, - }, - ) + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_SENSOR_ID: 12345, + CONF_SHOW_ON_MAP: True, + }, + ) assert result2.get("type") == RESULT_TYPE_CREATE_ENTRY assert result2.get("title") == "12345" diff --git a/tests/components/luftdaten/test_init.py b/tests/components/luftdaten/test_init.py new file mode 100644 index 00000000000..83902b19cd7 --- /dev/null +++ b/tests/components/luftdaten/test_init.py @@ -0,0 +1,75 @@ +"""Tests for the Luftdaten integration.""" +from unittest.mock import AsyncMock, MagicMock, patch + +from luftdaten.exceptions import LuftdatenError + +from homeassistant.components.luftdaten.const import DOMAIN +from homeassistant.config_entries import ConfigEntryState +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry + + +async def test_load_unload_config_entry( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_luftdaten: AsyncMock, +) -> None: + """Test the Luftdaten configuration entry loading/unloading.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.state is ConfigEntryState.LOADED + + await hass.config_entries.async_unload(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert not hass.data.get(DOMAIN) + assert mock_config_entry.state is ConfigEntryState.NOT_LOADED + + +@patch( + "homeassistant.components.luftdaten.Luftdaten.get_data", + side_effect=LuftdatenError, +) +async def test_config_entry_not_ready( + mock_get_data: MagicMock, + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, +) -> None: + """Test the Luftdaten configuration entry not ready.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_get_data.call_count == 1 + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY + + +async def test_config_entry_not_ready_no_data( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_luftdaten: MagicMock, +) -> None: + """Test the Luftdaten configuration entry not ready.""" + mock_luftdaten.values = {} + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + mock_luftdaten.get_data.assert_called() + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY + + +async def test_setting_unique_id( + hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_luftdaten: MagicMock +) -> None: + """Test we set unique ID if not set yet.""" + mock_config_entry.unique_id = None + mock_config_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.unique_id == "12345"