From 4c7e10c47f15dfe573be340380d02a66269de90b Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Fri, 3 Mar 2023 15:29:40 +0100 Subject: [PATCH 01/19] Split out reolink tests --- tests/components/reolink/conftest.py | 53 +++++++ tests/components/reolink/test_config_flow.py | 127 ++--------------- tests/components/reolink/test_init.py | 137 +++++++++++++++++++ 3 files changed, 205 insertions(+), 112 deletions(-) create mode 100644 tests/components/reolink/conftest.py create mode 100644 tests/components/reolink/test_init.py diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py new file mode 100644 index 00000000000000..e634df83cad1c8 --- /dev/null +++ b/tests/components/reolink/conftest.py @@ -0,0 +1,53 @@ +"""Test the Reolink config flow.""" +from unittest.mock import AsyncMock, Mock, patch + +import pytest + +TEST_HOST = "1.2.3.4" +TEST_HOST2 = "4.5.6.7" +TEST_USERNAME = "admin" +TEST_USERNAME2 = "username" +TEST_PASSWORD = "password" +TEST_PASSWORD2 = "new_password" +TEST_MAC = "ab:cd:ef:gh:ij:kl" +TEST_PORT = 1234 +TEST_NVR_NAME = "test_reolink_name" +TEST_USE_HTTPS = True + + +def get_mock_info(error=None, user_level="admin", sw_required=False): + """Return a mock gateway info instance.""" + host_mock = Mock() + if error is None: + host_mock.get_host_data = AsyncMock(return_value=None) + else: + host_mock.get_host_data = AsyncMock(side_effect=error) + host_mock.check_new_firmware = AsyncMock(return_value=False) + host_mock.unsubscribe = AsyncMock(return_value=True) + host_mock.logout = AsyncMock(return_value=True) + host_mock.mac_address = TEST_MAC + host_mock.onvif_enabled = True + host_mock.rtmp_enabled = True + host_mock.rtsp_enabled = True + host_mock.nvr_name = TEST_NVR_NAME + host_mock.port = TEST_PORT + host_mock.use_https = TEST_USE_HTTPS + host_mock.is_admin = user_level == "admin" + host_mock.user_level = user_level + host_mock.sw_version_update_required = sw_required + host_mock.timeout = 60 + host_mock.renewtimer = 600 + host_mock.get_states = AsyncMock(return_value=None) + return host_mock + + +@pytest.fixture(name="reolink_connect", autouse=True) +def reolink_connect_fixture(mock_get_source_ip): + """Mock reolink connection and entry setup.""" + with patch( + "homeassistant.components.reolink.host.webhook.async_register", + return_value=True, + ), patch("homeassistant.components.reolink.PLATFORMS", return_value=[]), patch( + "homeassistant.components.reolink.host.Host", return_value=get_mock_info() + ): + yield diff --git a/tests/components/reolink/test_config_flow.py b/tests/components/reolink/test_config_flow.py index a5de5d5acb819f..42bc4792bc8871 100644 --- a/tests/components/reolink/test_config_flow.py +++ b/tests/components/reolink/test_config_flow.py @@ -1,69 +1,32 @@ """Test the Reolink config flow.""" import json -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import patch -import pytest from reolink_aio.exceptions import ApiError, CredentialsInvalidError, ReolinkError from homeassistant import config_entries, data_entry_flow from homeassistant.components import dhcp from homeassistant.components.reolink import const from homeassistant.components.reolink.config_flow import DEFAULT_PROTOCOL -from homeassistant.config import async_process_ha_core_config from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME from homeassistant.core import HomeAssistant -from homeassistant.helpers import issue_registry as ir from homeassistant.helpers.device_registry import format_mac -from tests.common import MockConfigEntry +from .conftest import ( + TEST_HOST, + TEST_HOST2, + TEST_MAC, + TEST_NVR_NAME, + TEST_PASSWORD, + TEST_PASSWORD2, + TEST_PORT, + TEST_USE_HTTPS, + TEST_USERNAME, + TEST_USERNAME2, + get_mock_info, +) -TEST_HOST = "1.2.3.4" -TEST_HOST2 = "4.5.6.7" -TEST_USERNAME = "admin" -TEST_USERNAME2 = "username" -TEST_PASSWORD = "password" -TEST_PASSWORD2 = "new_password" -TEST_MAC = "ab:cd:ef:gh:ij:kl" -TEST_PORT = 1234 -TEST_NVR_NAME = "test_reolink_name" -TEST_USE_HTTPS = True - - -def get_mock_info(error=None, user_level="admin"): - """Return a mock gateway info instance.""" - host_mock = Mock() - if error is None: - host_mock.get_host_data = AsyncMock(return_value=None) - else: - host_mock.get_host_data = AsyncMock(side_effect=error) - host_mock.check_new_firmware = AsyncMock(return_value=False) - host_mock.unsubscribe = AsyncMock(return_value=True) - host_mock.logout = AsyncMock(return_value=True) - host_mock.mac_address = TEST_MAC - host_mock.onvif_enabled = True - host_mock.rtmp_enabled = True - host_mock.rtsp_enabled = True - host_mock.nvr_name = TEST_NVR_NAME - host_mock.port = TEST_PORT - host_mock.use_https = TEST_USE_HTTPS - host_mock.is_admin = user_level == "admin" - host_mock.user_level = user_level - host_mock.timeout = 60 - host_mock.renewtimer = 600 - host_mock.get_states = AsyncMock(return_value=None) - return host_mock - - -@pytest.fixture(name="reolink_connect", autouse=True) -def reolink_connect_fixture(mock_get_source_ip): - """Mock reolink connection and entry setup.""" - with patch( - "homeassistant.components.reolink.host.webhook.async_register", - return_value=True, - ), patch("homeassistant.components.reolink.PLATFORMS", return_value=[]), patch( - "homeassistant.components.reolink.host.Host", return_value=get_mock_info() - ): - yield +from tests.common import MockConfigEntry async def test_config_flow_manual_success(hass: HomeAssistant) -> None: @@ -422,63 +385,3 @@ async def test_dhcp_abort_flow(hass: HomeAssistant) -> None: assert result["type"] is data_entry_flow.FlowResultType.ABORT assert result["reason"] == "already_configured" - - -async def test_http_no_repair_issue(hass: HomeAssistant) -> None: - """Test no repairs issue is raised when http local url is used.""" - config_entry = MockConfigEntry( - domain=const.DOMAIN, - unique_id=format_mac(TEST_MAC), - data={ - CONF_HOST: TEST_HOST, - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_PORT: TEST_PORT, - const.CONF_USE_HTTPS: TEST_USE_HTTPS, - }, - options={ - const.CONF_PROTOCOL: DEFAULT_PROTOCOL, - }, - title=TEST_NVR_NAME, - ) - config_entry.add_to_hass(hass) - - await async_process_ha_core_config( - hass, {"country": "GB", "internal_url": "http://test_homeassistant_address"} - ) - - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - - issue_registry = ir.async_get(hass) - assert len(issue_registry.issues) == 0 - - -async def test_https_repair_issue(hass: HomeAssistant) -> None: - """Test repairs issue is raised when https local url is used.""" - config_entry = MockConfigEntry( - domain=const.DOMAIN, - unique_id=format_mac(TEST_MAC), - data={ - CONF_HOST: TEST_HOST, - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_PORT: TEST_PORT, - const.CONF_USE_HTTPS: TEST_USE_HTTPS, - }, - options={ - const.CONF_PROTOCOL: DEFAULT_PROTOCOL, - }, - title=TEST_NVR_NAME, - ) - config_entry.add_to_hass(hass) - - await async_process_ha_core_config( - hass, {"country": "GB", "internal_url": "https://test_homeassistant_address"} - ) - - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - - issue_registry = ir.async_get(hass) - assert len(issue_registry.issues) == 1 diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py new file mode 100644 index 00000000000000..8628cd56ebe43d --- /dev/null +++ b/tests/components/reolink/test_init.py @@ -0,0 +1,137 @@ +"""Test the Reolink init.""" +from unittest.mock import patch + +from homeassistant.components.reolink import const +from homeassistant.components.reolink.config_flow import DEFAULT_PROTOCOL +from homeassistant.config import async_process_ha_core_config +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME +from homeassistant.core import HomeAssistant +from homeassistant.helpers import issue_registry as ir +from homeassistant.helpers.device_registry import format_mac + +from .conftest import ( + TEST_HOST, + TEST_MAC, + TEST_NVR_NAME, + TEST_PASSWORD, + TEST_PORT, + TEST_USE_HTTPS, + TEST_USERNAME, + get_mock_info, +) + +from tests.common import MockConfigEntry + + +async def test_http_no_repair_issue(hass: HomeAssistant) -> None: + """Test no repairs issue is raised when http local url is used.""" + config_entry = MockConfigEntry( + domain=const.DOMAIN, + unique_id=format_mac(TEST_MAC), + data={ + CONF_HOST: TEST_HOST, + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: TEST_PORT, + const.CONF_USE_HTTPS: TEST_USE_HTTPS, + }, + options={ + const.CONF_PROTOCOL: DEFAULT_PROTOCOL, + }, + title=TEST_NVR_NAME, + ) + config_entry.add_to_hass(hass) + + await async_process_ha_core_config( + hass, {"country": "GB", "internal_url": "http://test_homeassistant_address"} + ) + + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + issue_registry = ir.async_get(hass) + assert (const.DOMAIN, "https_webhook") not in issue_registry.issues + + +async def test_https_repair_issue(hass: HomeAssistant) -> None: + """Test repairs issue is raised when https local url is used.""" + config_entry = MockConfigEntry( + domain=const.DOMAIN, + unique_id=format_mac(TEST_MAC), + data={ + CONF_HOST: TEST_HOST, + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: TEST_PORT, + const.CONF_USE_HTTPS: TEST_USE_HTTPS, + }, + options={ + const.CONF_PROTOCOL: DEFAULT_PROTOCOL, + }, + title=TEST_NVR_NAME, + ) + config_entry.add_to_hass(hass) + + await async_process_ha_core_config( + hass, {"country": "GB", "internal_url": "https://test_homeassistant_address"} + ) + + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + issue_registry = ir.async_get(hass) + assert (const.DOMAIN, "https_webhook") in issue_registry.issues + + +async def test_no_firmware_repair_issue(hass: HomeAssistant) -> None: + """Test no firmware issue is raised when firmware is new enough.""" + config_entry = MockConfigEntry( + domain=const.DOMAIN, + unique_id=format_mac(TEST_MAC), + data={ + CONF_HOST: TEST_HOST, + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: TEST_PORT, + const.CONF_USE_HTTPS: TEST_USE_HTTPS, + }, + options={ + const.CONF_PROTOCOL: DEFAULT_PROTOCOL, + }, + title=TEST_NVR_NAME, + ) + config_entry.add_to_hass(hass) + + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + issue_registry = ir.async_get(hass) + assert (const.DOMAIN, "firmware_update") not in issue_registry.issues + + +async def test_firmware_repair_issue(hass: HomeAssistant) -> None: + """Test firmware issue is raised when too old firmware is used.""" + config_entry = MockConfigEntry( + domain=const.DOMAIN, + unique_id=format_mac(TEST_MAC), + data={ + CONF_HOST: TEST_HOST, + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: TEST_PORT, + const.CONF_USE_HTTPS: TEST_USE_HTTPS, + }, + options={ + const.CONF_PROTOCOL: DEFAULT_PROTOCOL, + }, + title=TEST_NVR_NAME, + ) + config_entry.add_to_hass(hass) + + host_mock = get_mock_info(sw_required=True) + with patch("homeassistant.components.reolink.host.Host", return_value=host_mock): + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + issue_registry = ir.async_get(hass) + assert (const.DOMAIN, "firmware_update") in issue_registry.issues From aaf8d48acab959f4c0c597c82f90bfc7f202e756 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Fri, 3 Mar 2023 17:02:26 +0100 Subject: [PATCH 02/19] Bring __init__ coverage to 100% --- .coveragerc | 1 - tests/components/reolink/conftest.py | 31 ++- tests/components/reolink/test_config_flow.py | 7 +- tests/components/reolink/test_init.py | 188 ++++++++++++------- 4 files changed, 147 insertions(+), 80 deletions(-) diff --git a/.coveragerc b/.coveragerc index ce80bef0a930aa..11a9c99fe09402 100644 --- a/.coveragerc +++ b/.coveragerc @@ -974,7 +974,6 @@ omit = homeassistant/components/rejseplanen/sensor.py homeassistant/components/remember_the_milk/__init__.py homeassistant/components/remote_rpi_gpio/* - homeassistant/components/reolink/__init__.py homeassistant/components/reolink/binary_sensor.py homeassistant/components/reolink/camera.py homeassistant/components/reolink/entity.py diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index e634df83cad1c8..d1ee60aabf8612 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -1,4 +1,5 @@ """Test the Reolink config flow.""" +from collections.abc import Generator from unittest.mock import AsyncMock, Mock, patch import pytest @@ -15,13 +16,14 @@ TEST_USE_HTTPS = True -def get_mock_info(error=None, user_level="admin", sw_required=False): +def get_mock_info(error=None): """Return a mock gateway info instance.""" host_mock = Mock() if error is None: host_mock.get_host_data = AsyncMock(return_value=None) else: host_mock.get_host_data = AsyncMock(side_effect=error) + host_mock.get_states = AsyncMock(return_value=None) host_mock.check_new_firmware = AsyncMock(return_value=False) host_mock.unsubscribe = AsyncMock(return_value=True) host_mock.logout = AsyncMock(return_value=True) @@ -32,22 +34,37 @@ def get_mock_info(error=None, user_level="admin", sw_required=False): host_mock.nvr_name = TEST_NVR_NAME host_mock.port = TEST_PORT host_mock.use_https = TEST_USE_HTTPS - host_mock.is_admin = user_level == "admin" - host_mock.user_level = user_level - host_mock.sw_version_update_required = sw_required + host_mock.is_admin = True + host_mock.user_level = "admin" + host_mock.sw_version_update_required = False host_mock.timeout = 60 host_mock.renewtimer = 600 - host_mock.get_states = AsyncMock(return_value=None) return host_mock -@pytest.fixture(name="reolink_connect", autouse=True) +@pytest.fixture(name="reolink_setup_entry") +def reolink_setup_entry_fixture() -> Generator[AsyncMock, None, None]: + """Override async_setup_entry.""" + with patch( + "homeassistant.components.reolink.async_setup_entry", return_value=True + ) as mock_setup_entry: + yield mock_setup_entry + + +@pytest.fixture(name="reolink_connect") def reolink_connect_fixture(mock_get_source_ip): """Mock reolink connection and entry setup.""" with patch( "homeassistant.components.reolink.host.webhook.async_register", return_value=True, - ), patch("homeassistant.components.reolink.PLATFORMS", return_value=[]), patch( + ), patch( "homeassistant.components.reolink.host.Host", return_value=get_mock_info() ): yield + + +@pytest.fixture(name="reolink_init") +def reolink_init_fixture(mock_get_source_ip): + """Mock reolink connection and entry setup.""" + with patch("homeassistant.components.reolink.PLATFORMS", return_value=[]): + yield diff --git a/tests/components/reolink/test_config_flow.py b/tests/components/reolink/test_config_flow.py index 42bc4792bc8871..fb2f88872c1bad 100644 --- a/tests/components/reolink/test_config_flow.py +++ b/tests/components/reolink/test_config_flow.py @@ -2,6 +2,7 @@ import json from unittest.mock import patch +import pytest from reolink_aio.exceptions import ApiError, CredentialsInvalidError, ReolinkError from homeassistant import config_entries, data_entry_flow @@ -28,6 +29,8 @@ from tests.common import MockConfigEntry +pytestmark = pytest.mark.usefixtures("reolink_setup_entry", "reolink_connect") + async def test_config_flow_manual_success(hass: HomeAssistant) -> None: """Successful flow manually initialized by the user.""" @@ -87,7 +90,9 @@ async def test_config_flow_errors(hass: HomeAssistant) -> None: assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "cannot_connect"} - host_mock = get_mock_info(user_level="guest") + host_mock = get_mock_info() + host_mock.is_admin = False + host_mock.user_level = "guest" with patch("homeassistant.components.reolink.host.Host", return_value=host_mock): result = await hass.config_entries.flow.async_configure( result["flow_id"], diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index 8628cd56ebe43d..c0a586b19148f7 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -1,9 +1,13 @@ """Test the Reolink init.""" -from unittest.mock import patch +from unittest.mock import AsyncMock, Mock, patch + +import pytest +from reolink_aio.exceptions import ReolinkError from homeassistant.components.reolink import const from homeassistant.components.reolink.config_flow import DEFAULT_PROTOCOL from homeassistant.config import async_process_ha_core_config +from homeassistant.config_entries import ConfigEntryState from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME from homeassistant.core import HomeAssistant from homeassistant.helpers import issue_registry as ir @@ -22,9 +26,11 @@ from tests.common import MockConfigEntry +pytestmark = pytest.mark.usefixtures("reolink_connect", "reolink_init") -async def test_http_no_repair_issue(hass: HomeAssistant) -> None: - """Test no repairs issue is raised when http local url is used.""" + +def reolink_mock_config_entry(hass: HomeAssistant) -> MockConfigEntry: + """Add the reolink mock config entry to hass.""" config_entry = MockConfigEntry( domain=const.DOMAIN, unique_id=format_mac(TEST_MAC), @@ -42,96 +48,136 @@ async def test_http_no_repair_issue(hass: HomeAssistant) -> None: ) config_entry.add_to_hass(hass) - await async_process_ha_core_config( - hass, {"country": "GB", "internal_url": "http://test_homeassistant_address"} - ) + return config_entry + + +async def test_ConfigEntryAuthFailed(hass: HomeAssistant) -> None: + """Test a ConfigEntryAuthFailed is raised when credentials are invalid.""" + config_entry = reolink_mock_config_entry(hass) + + mock_info = get_mock_info() + mock_info.is_admin = False + mock_info.user_level = "guest" + with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): + assert await hass.config_entries.async_setup(config_entry.entry_id) is False - assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() - issue_registry = ir.async_get(hass) - assert (const.DOMAIN, "https_webhook") not in issue_registry.issues + assert config_entry.state == ConfigEntryState.SETUP_ERROR + assert not hass.data.get(const.DOMAIN) -async def test_https_repair_issue(hass: HomeAssistant) -> None: - """Test repairs issue is raised when https local url is used.""" - config_entry = MockConfigEntry( - domain=const.DOMAIN, - unique_id=format_mac(TEST_MAC), - data={ - CONF_HOST: TEST_HOST, - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_PORT: TEST_PORT, - const.CONF_USE_HTTPS: TEST_USE_HTTPS, - }, - options={ - const.CONF_PROTOCOL: DEFAULT_PROTOCOL, - }, - title=TEST_NVR_NAME, - ) - config_entry.add_to_hass(hass) +async def test_ConfigEntryNotReady(hass: HomeAssistant) -> None: + """Test a ConfigEntryNotReady is raised when initial connection fails.""" + config_entry = reolink_mock_config_entry(hass) - await async_process_ha_core_config( - hass, {"country": "GB", "internal_url": "https://test_homeassistant_address"} - ) + mock_info = get_mock_info(error=ReolinkError("Test error")) + with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): + assert await hass.config_entries.async_setup(config_entry.entry_id) is False + + await hass.async_block_till_done() + + assert config_entry.state == ConfigEntryState.SETUP_RETRY + assert not hass.data.get(const.DOMAIN) + + +async def test_ConfigEntryNotReady_initial_fetch(hass: HomeAssistant) -> None: + """Test a ConfigEntryNotReady is raised when initial fetch of data fails.""" + config_entry = reolink_mock_config_entry(hass) + + mock_info = get_mock_info() + mock_info.get_states = AsyncMock(side_effect=ReolinkError("Test error")) + with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): + assert await hass.config_entries.async_setup(config_entry.entry_id) is False + + await hass.async_block_till_done() + + assert config_entry.state == ConfigEntryState.SETUP_RETRY + assert not hass.data.get(const.DOMAIN) + + +async def test_firmware_update_not_supported(hass: HomeAssistant) -> None: + """Test successful setup if firmware update is not supported.""" + config_entry = reolink_mock_config_entry(hass) + + mock_info = get_mock_info() + mock_info.supported = Mock(return_value=False) + with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): + assert await hass.config_entries.async_setup(config_entry.entry_id) + + await hass.async_block_till_done() + + assert config_entry.state == ConfigEntryState.LOADED + + +async def test_firmware_update_error(hass: HomeAssistant) -> None: + """Test error during firmware update does not block setup.""" + config_entry = reolink_mock_config_entry(hass) + + mock_info = get_mock_info() + mock_info.check_new_firmware = AsyncMock(side_effect=ReolinkError("Test error")) + with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): + assert await hass.config_entries.async_setup(config_entry.entry_id) + + await hass.async_block_till_done() + + assert config_entry.state == ConfigEntryState.LOADED + + +async def test_unexpected_error(hass: HomeAssistant) -> None: + """Test a unexpected error during initial connection.""" + config_entry = reolink_mock_config_entry(hass) + + mock_info = get_mock_info(error=ValueError("Test error")) + with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): + assert await hass.config_entries.async_setup(config_entry.entry_id) is False + + await hass.async_block_till_done() + + assert config_entry.state == ConfigEntryState.SETUP_ERROR + assert not hass.data.get(const.DOMAIN) + + +async def test_update_listener(hass: HomeAssistant) -> None: + """Test the update listener.""" + config_entry = reolink_mock_config_entry(hass) assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() - issue_registry = ir.async_get(hass) - assert (const.DOMAIN, "https_webhook") in issue_registry.issues + assert config_entry.title == "test_reolink_name" + hass.config_entries.async_update_entry(config_entry, title="New Name") + await hass.async_block_till_done() -async def test_no_firmware_repair_issue(hass: HomeAssistant) -> None: - """Test no firmware issue is raised when firmware is new enough.""" - config_entry = MockConfigEntry( - domain=const.DOMAIN, - unique_id=format_mac(TEST_MAC), - data={ - CONF_HOST: TEST_HOST, - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_PORT: TEST_PORT, - const.CONF_USE_HTTPS: TEST_USE_HTTPS, - }, - options={ - const.CONF_PROTOCOL: DEFAULT_PROTOCOL, - }, - title=TEST_NVR_NAME, + assert config_entry.title == "New Name" + + +async def test_http_no_repair_issue(hass: HomeAssistant) -> None: + """Test no repairs issue is raised when http local url is used.""" + config_entry = reolink_mock_config_entry(hass) + + await async_process_ha_core_config( + hass, {"country": "GB", "internal_url": "http://test_homeassistant_address"} ) - config_entry.add_to_hass(hass) assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() issue_registry = ir.async_get(hass) - assert (const.DOMAIN, "firmware_update") not in issue_registry.issues + assert (const.DOMAIN, "https_webhook") not in issue_registry.issues -async def test_firmware_repair_issue(hass: HomeAssistant) -> None: - """Test firmware issue is raised when too old firmware is used.""" - config_entry = MockConfigEntry( - domain=const.DOMAIN, - unique_id=format_mac(TEST_MAC), - data={ - CONF_HOST: TEST_HOST, - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_PORT: TEST_PORT, - const.CONF_USE_HTTPS: TEST_USE_HTTPS, - }, - options={ - const.CONF_PROTOCOL: DEFAULT_PROTOCOL, - }, - title=TEST_NVR_NAME, +async def test_https_repair_issue(hass: HomeAssistant) -> None: + """Test repairs issue is raised when https local url is used.""" + config_entry = reolink_mock_config_entry(hass) + + await async_process_ha_core_config( + hass, {"country": "GB", "internal_url": "https://test_homeassistant_address"} ) - config_entry.add_to_hass(hass) - host_mock = get_mock_info(sw_required=True) - with patch("homeassistant.components.reolink.host.Host", return_value=host_mock): - assert await hass.config_entries.async_setup(config_entry.entry_id) + assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() issue_registry = ir.async_get(hass) - assert (const.DOMAIN, "firmware_update") in issue_registry.issues + assert (const.DOMAIN, "https_webhook") in issue_registry.issues From 8d6109dd4dd070bb49330da4cf868aa797cba55f Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Fri, 3 Mar 2023 17:14:12 +0100 Subject: [PATCH 03/19] Improve docstrings --- tests/components/reolink/conftest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index d1ee60aabf8612..34ac7c51087026 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -1,4 +1,4 @@ -"""Test the Reolink config flow.""" +"""Setup the Reolink tests.""" from collections.abc import Generator from unittest.mock import AsyncMock, Mock, patch @@ -53,7 +53,7 @@ def reolink_setup_entry_fixture() -> Generator[AsyncMock, None, None]: @pytest.fixture(name="reolink_connect") def reolink_connect_fixture(mock_get_source_ip): - """Mock reolink connection and entry setup.""" + """Mock reolink connection.""" with patch( "homeassistant.components.reolink.host.webhook.async_register", return_value=True, @@ -65,6 +65,6 @@ def reolink_connect_fixture(mock_get_source_ip): @pytest.fixture(name="reolink_init") def reolink_init_fixture(mock_get_source_ip): - """Mock reolink connection and entry setup.""" + """Mock reolink entry setup.""" with patch("homeassistant.components.reolink.PLATFORMS", return_value=[]): yield From 1a594e59dc4b3b289ce6e7b0f2ecd57e237f573d Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Mon, 6 Mar 2023 19:28:32 +0100 Subject: [PATCH 04/19] Use patching and autospec=True for ReolinkHost --- tests/components/reolink/conftest.py | 24 ++++++++++++++++---- tests/components/reolink/test_config_flow.py | 23 +++++++++---------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index 34ac7c51087026..1d2ca883a310f1 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -57,10 +57,26 @@ def reolink_connect_fixture(mock_get_source_ip): with patch( "homeassistant.components.reolink.host.webhook.async_register", return_value=True, - ), patch( - "homeassistant.components.reolink.host.Host", return_value=get_mock_info() - ): - yield + ), patch("homeassistant.components.reolink.host.Host", autospec=True) as host_mock_class: + host_mock = host_mock_class.return_value + host_mock.get_host_data = AsyncMock(return_value=None) + host_mock.get_states = AsyncMock(return_value=None) + host_mock.check_new_firmware = AsyncMock(return_value=False) + host_mock.unsubscribe = AsyncMock(return_value=True) + host_mock.logout = AsyncMock(return_value=True) + host_mock.mac_address = TEST_MAC + host_mock.onvif_enabled = True + host_mock.rtmp_enabled = True + host_mock.rtsp_enabled = True + host_mock.nvr_name = TEST_NVR_NAME + host_mock.port = TEST_PORT + host_mock.use_https = TEST_USE_HTTPS + host_mock.is_admin = True + host_mock.user_level = "admin" + host_mock.sw_version_update_required = False + host_mock.timeout = 60 + host_mock.renewtimer = 600 + yield host_mock @pytest.fixture(name="reolink_init") diff --git a/tests/components/reolink/test_config_flow.py b/tests/components/reolink/test_config_flow.py index fb2f88872c1bad..5753a220afc60f 100644 --- a/tests/components/reolink/test_config_flow.py +++ b/tests/components/reolink/test_config_flow.py @@ -1,6 +1,6 @@ """Test the Reolink config flow.""" import json -from unittest.mock import patch +from unittest.mock import patch, AsyncMock import pytest from reolink_aio.exceptions import ApiError, CredentialsInvalidError, ReolinkError @@ -65,7 +65,7 @@ async def test_config_flow_manual_success(hass: HomeAssistant) -> None: } -async def test_config_flow_errors(hass: HomeAssistant) -> None: +async def test_config_flow_errors(hass: HomeAssistant, reolink_connect) -> None: """Successful flow manually initialized by the user after some errors.""" result = await hass.config_entries.flow.async_init( const.DOMAIN, context={"source": config_entries.SOURCE_USER} @@ -75,16 +75,15 @@ async def test_config_flow_errors(hass: HomeAssistant) -> None: assert result["step_id"] == "user" assert result["errors"] == {} - host_mock = get_mock_info(error=ReolinkError("Test error")) - with patch("homeassistant.components.reolink.host.Host", return_value=host_mock): - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_HOST: TEST_HOST, - }, - ) + #reolink_connect.get_host_data = AsyncMock(side_effect=ReolinkError("Test error")) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_HOST: TEST_HOST, + }, + ) assert result["type"] is data_entry_flow.FlowResultType.FORM assert result["step_id"] == "user" From 1e50301b9fccae87fae3fdbea0fdfc24e052a114 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Mon, 6 Mar 2023 20:13:37 +0100 Subject: [PATCH 05/19] Use fixture --- tests/components/reolink/conftest.py | 26 ------ tests/components/reolink/test_config_flow.py | 93 ++++++++++---------- tests/components/reolink/test_init.py | 57 +++++------- 3 files changed, 65 insertions(+), 111 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index 1d2ca883a310f1..45a9ba2bd2cae0 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -16,32 +16,6 @@ TEST_USE_HTTPS = True -def get_mock_info(error=None): - """Return a mock gateway info instance.""" - host_mock = Mock() - if error is None: - host_mock.get_host_data = AsyncMock(return_value=None) - else: - host_mock.get_host_data = AsyncMock(side_effect=error) - host_mock.get_states = AsyncMock(return_value=None) - host_mock.check_new_firmware = AsyncMock(return_value=False) - host_mock.unsubscribe = AsyncMock(return_value=True) - host_mock.logout = AsyncMock(return_value=True) - host_mock.mac_address = TEST_MAC - host_mock.onvif_enabled = True - host_mock.rtmp_enabled = True - host_mock.rtsp_enabled = True - host_mock.nvr_name = TEST_NVR_NAME - host_mock.port = TEST_PORT - host_mock.use_https = TEST_USE_HTTPS - host_mock.is_admin = True - host_mock.user_level = "admin" - host_mock.sw_version_update_required = False - host_mock.timeout = 60 - host_mock.renewtimer = 600 - return host_mock - - @pytest.fixture(name="reolink_setup_entry") def reolink_setup_entry_fixture() -> Generator[AsyncMock, None, None]: """Override async_setup_entry.""" diff --git a/tests/components/reolink/test_config_flow.py b/tests/components/reolink/test_config_flow.py index 5753a220afc60f..f714ecace64b19 100644 --- a/tests/components/reolink/test_config_flow.py +++ b/tests/components/reolink/test_config_flow.py @@ -1,6 +1,6 @@ """Test the Reolink config flow.""" import json -from unittest.mock import patch, AsyncMock +from unittest.mock import patch, AsyncMock, MagicMock import pytest from reolink_aio.exceptions import ApiError, CredentialsInvalidError, ReolinkError @@ -24,7 +24,6 @@ TEST_USE_HTTPS, TEST_USERNAME, TEST_USERNAME2, - get_mock_info, ) from tests.common import MockConfigEntry @@ -65,7 +64,7 @@ async def test_config_flow_manual_success(hass: HomeAssistant) -> None: } -async def test_config_flow_errors(hass: HomeAssistant, reolink_connect) -> None: +async def test_config_flow_errors(hass: HomeAssistant, reolink_connect: MagicMock) -> None: """Successful flow manually initialized by the user after some errors.""" result = await hass.config_entries.flow.async_init( const.DOMAIN, context={"source": config_entries.SOURCE_USER} @@ -75,7 +74,8 @@ async def test_config_flow_errors(hass: HomeAssistant, reolink_connect) -> None: assert result["step_id"] == "user" assert result["errors"] == {} - #reolink_connect.get_host_data = AsyncMock(side_effect=ReolinkError("Test error")) + reolink_connect.is_admin = False + reolink_connect.user_level = "guest" result = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -87,70 +87,67 @@ async def test_config_flow_errors(hass: HomeAssistant, reolink_connect) -> None: assert result["type"] is data_entry_flow.FlowResultType.FORM assert result["step_id"] == "user" - assert result["errors"] == {CONF_HOST: "cannot_connect"} + assert result["errors"] == {CONF_USERNAME: "not_admin"} - host_mock = get_mock_info() - host_mock.is_admin = False - host_mock.user_level = "guest" - with patch("homeassistant.components.reolink.host.Host", return_value=host_mock): - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_HOST: TEST_HOST, - }, - ) + reolink_connect.is_admin = True + reolink_connect.user_level = "admin" + reolink_connect.get_host_data = AsyncMock(side_effect=ReolinkError("Test error")) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_HOST: TEST_HOST, + }, + ) assert result["type"] is data_entry_flow.FlowResultType.FORM assert result["step_id"] == "user" - assert result["errors"] == {CONF_USERNAME: "not_admin"} + assert result["errors"] == {CONF_HOST: "cannot_connect"} - host_mock = get_mock_info(error=json.JSONDecodeError("test_error", "test", 1)) - with patch("homeassistant.components.reolink.host.Host", return_value=host_mock): - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_HOST: TEST_HOST, - }, - ) + reolink_connect.get_host_data = AsyncMock(side_effect=json.JSONDecodeError("test_error", "test", 1)) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_HOST: TEST_HOST, + }, + ) assert result["type"] is data_entry_flow.FlowResultType.FORM assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "unknown"} - host_mock = get_mock_info(error=CredentialsInvalidError("Test error")) - with patch("homeassistant.components.reolink.host.Host", return_value=host_mock): - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_HOST: TEST_HOST, - }, - ) + reolink_connect.get_host_data = AsyncMock(side_effect=CredentialsInvalidError("Test error")) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_HOST: TEST_HOST, + }, + ) assert result["type"] is data_entry_flow.FlowResultType.FORM assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "invalid_auth"} - host_mock = get_mock_info(error=ApiError("Test error")) - with patch("homeassistant.components.reolink.host.Host", return_value=host_mock): - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_HOST: TEST_HOST, - }, - ) + reolink_connect.get_host_data = AsyncMock(side_effect=ApiError("Test error")) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_HOST: TEST_HOST, + }, + ) assert result["type"] is data_entry_flow.FlowResultType.FORM assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "api_error"} + reolink_connect.get_host_data = AsyncMock(return_value=None) result = await hass.config_entries.flow.async_configure( result["flow_id"], { diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index c0a586b19148f7..18c5a6207a7cad 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -1,5 +1,5 @@ """Test the Reolink init.""" -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import AsyncMock, Mock, patch, MagicMock import pytest from reolink_aio.exceptions import ReolinkError @@ -21,7 +21,6 @@ TEST_PORT, TEST_USE_HTTPS, TEST_USERNAME, - get_mock_info, ) from tests.common import MockConfigEntry @@ -51,87 +50,71 @@ def reolink_mock_config_entry(hass: HomeAssistant) -> MockConfigEntry: return config_entry -async def test_ConfigEntryAuthFailed(hass: HomeAssistant) -> None: +async def test_ConfigEntryAuthFailed(hass: HomeAssistant, reolink_connect: MagicMock) -> None: """Test a ConfigEntryAuthFailed is raised when credentials are invalid.""" config_entry = reolink_mock_config_entry(hass) - mock_info = get_mock_info() - mock_info.is_admin = False - mock_info.user_level = "guest" - with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): - assert await hass.config_entries.async_setup(config_entry.entry_id) is False - + reolink_connect.is_admin = False + reolink_connect.user_level = "guest" + assert await hass.config_entries.async_setup(config_entry.entry_id) is False await hass.async_block_till_done() assert config_entry.state == ConfigEntryState.SETUP_ERROR assert not hass.data.get(const.DOMAIN) -async def test_ConfigEntryNotReady(hass: HomeAssistant) -> None: +async def test_ConfigEntryNotReady(hass: HomeAssistant, reolink_connect: MagicMock) -> None: """Test a ConfigEntryNotReady is raised when initial connection fails.""" config_entry = reolink_mock_config_entry(hass) - mock_info = get_mock_info(error=ReolinkError("Test error")) - with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): - assert await hass.config_entries.async_setup(config_entry.entry_id) is False - + reolink_connect.get_host_data = AsyncMock(side_effect=ReolinkError("Test error")) + assert await hass.config_entries.async_setup(config_entry.entry_id) is False await hass.async_block_till_done() assert config_entry.state == ConfigEntryState.SETUP_RETRY assert not hass.data.get(const.DOMAIN) -async def test_ConfigEntryNotReady_initial_fetch(hass: HomeAssistant) -> None: +async def test_ConfigEntryNotReady_initial_fetch(hass: HomeAssistant, reolink_connect: MagicMock) -> None: """Test a ConfigEntryNotReady is raised when initial fetch of data fails.""" config_entry = reolink_mock_config_entry(hass) - mock_info = get_mock_info() - mock_info.get_states = AsyncMock(side_effect=ReolinkError("Test error")) - with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): - assert await hass.config_entries.async_setup(config_entry.entry_id) is False - + reolink_connect.get_states = AsyncMock(side_effect=ReolinkError("Test error")) + assert await hass.config_entries.async_setup(config_entry.entry_id) is False await hass.async_block_till_done() assert config_entry.state == ConfigEntryState.SETUP_RETRY assert not hass.data.get(const.DOMAIN) -async def test_firmware_update_not_supported(hass: HomeAssistant) -> None: +async def test_firmware_update_not_supported(hass: HomeAssistant, reolink_connect: MagicMock) -> None: """Test successful setup if firmware update is not supported.""" config_entry = reolink_mock_config_entry(hass) - mock_info = get_mock_info() - mock_info.supported = Mock(return_value=False) - with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): - assert await hass.config_entries.async_setup(config_entry.entry_id) - + reolink_connect.supported = Mock(return_value=False) + assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state == ConfigEntryState.LOADED -async def test_firmware_update_error(hass: HomeAssistant) -> None: +async def test_firmware_update_error(hass: HomeAssistant, reolink_connect: MagicMock) -> None: """Test error during firmware update does not block setup.""" config_entry = reolink_mock_config_entry(hass) - mock_info = get_mock_info() - mock_info.check_new_firmware = AsyncMock(side_effect=ReolinkError("Test error")) - with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): - assert await hass.config_entries.async_setup(config_entry.entry_id) - + reolink_connect.check_new_firmware = AsyncMock(side_effect=ReolinkError("Test error")) + assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state == ConfigEntryState.LOADED -async def test_unexpected_error(hass: HomeAssistant) -> None: +async def test_unexpected_error(hass: HomeAssistant, reolink_connect: MagicMock) -> None: """Test a unexpected error during initial connection.""" config_entry = reolink_mock_config_entry(hass) - mock_info = get_mock_info(error=ValueError("Test error")) - with patch("homeassistant.components.reolink.host.Host", return_value=mock_info): - assert await hass.config_entries.async_setup(config_entry.entry_id) is False - + reolink_connect.get_host_data = AsyncMock(side_effect=ValueError("Test error")) + assert await hass.config_entries.async_setup(config_entry.entry_id) is False await hass.async_block_till_done() assert config_entry.state == ConfigEntryState.SETUP_ERROR From 1aa9e68eeaee8e4521e6dc33e3f78b8a8fe83f5d Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Mon, 6 Mar 2023 20:15:25 +0100 Subject: [PATCH 06/19] fix styling --- tests/components/reolink/conftest.py | 6 ++-- tests/components/reolink/test_config_flow.py | 14 ++++++--- tests/components/reolink/test_init.py | 30 ++++++++++++++------ 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index 45a9ba2bd2cae0..bc31481afefb9d 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -1,6 +1,6 @@ """Setup the Reolink tests.""" from collections.abc import Generator -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import AsyncMock, patch import pytest @@ -31,7 +31,9 @@ def reolink_connect_fixture(mock_get_source_ip): with patch( "homeassistant.components.reolink.host.webhook.async_register", return_value=True, - ), patch("homeassistant.components.reolink.host.Host", autospec=True) as host_mock_class: + ), patch( + "homeassistant.components.reolink.host.Host", autospec=True + ) as host_mock_class: host_mock = host_mock_class.return_value host_mock.get_host_data = AsyncMock(return_value=None) host_mock.get_states = AsyncMock(return_value=None) diff --git a/tests/components/reolink/test_config_flow.py b/tests/components/reolink/test_config_flow.py index f714ecace64b19..f7411ea24e135b 100644 --- a/tests/components/reolink/test_config_flow.py +++ b/tests/components/reolink/test_config_flow.py @@ -1,6 +1,6 @@ """Test the Reolink config flow.""" import json -from unittest.mock import patch, AsyncMock, MagicMock +from unittest.mock import AsyncMock, MagicMock import pytest from reolink_aio.exceptions import ApiError, CredentialsInvalidError, ReolinkError @@ -64,7 +64,9 @@ async def test_config_flow_manual_success(hass: HomeAssistant) -> None: } -async def test_config_flow_errors(hass: HomeAssistant, reolink_connect: MagicMock) -> None: +async def test_config_flow_errors( + hass: HomeAssistant, reolink_connect: MagicMock +) -> None: """Successful flow manually initialized by the user after some errors.""" result = await hass.config_entries.flow.async_init( const.DOMAIN, context={"source": config_entries.SOURCE_USER} @@ -105,7 +107,9 @@ async def test_config_flow_errors(hass: HomeAssistant, reolink_connect: MagicMoc assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "cannot_connect"} - reolink_connect.get_host_data = AsyncMock(side_effect=json.JSONDecodeError("test_error", "test", 1)) + reolink_connect.get_host_data = AsyncMock( + side_effect=json.JSONDecodeError("test_error", "test", 1) + ) result = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -119,7 +123,9 @@ async def test_config_flow_errors(hass: HomeAssistant, reolink_connect: MagicMoc assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "unknown"} - reolink_connect.get_host_data = AsyncMock(side_effect=CredentialsInvalidError("Test error")) + reolink_connect.get_host_data = AsyncMock( + side_effect=CredentialsInvalidError("Test error") + ) result = await hass.config_entries.flow.async_configure( result["flow_id"], { diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index 18c5a6207a7cad..255eaefe027c84 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -1,5 +1,5 @@ """Test the Reolink init.""" -from unittest.mock import AsyncMock, Mock, patch, MagicMock +from unittest.mock import AsyncMock, MagicMock, Mock import pytest from reolink_aio.exceptions import ReolinkError @@ -50,7 +50,9 @@ def reolink_mock_config_entry(hass: HomeAssistant) -> MockConfigEntry: return config_entry -async def test_ConfigEntryAuthFailed(hass: HomeAssistant, reolink_connect: MagicMock) -> None: +async def test_ConfigEntryAuthFailed( + hass: HomeAssistant, reolink_connect: MagicMock +) -> None: """Test a ConfigEntryAuthFailed is raised when credentials are invalid.""" config_entry = reolink_mock_config_entry(hass) @@ -63,7 +65,9 @@ async def test_ConfigEntryAuthFailed(hass: HomeAssistant, reolink_connect: Magic assert not hass.data.get(const.DOMAIN) -async def test_ConfigEntryNotReady(hass: HomeAssistant, reolink_connect: MagicMock) -> None: +async def test_ConfigEntryNotReady( + hass: HomeAssistant, reolink_connect: MagicMock +) -> None: """Test a ConfigEntryNotReady is raised when initial connection fails.""" config_entry = reolink_mock_config_entry(hass) @@ -75,7 +79,9 @@ async def test_ConfigEntryNotReady(hass: HomeAssistant, reolink_connect: MagicMo assert not hass.data.get(const.DOMAIN) -async def test_ConfigEntryNotReady_initial_fetch(hass: HomeAssistant, reolink_connect: MagicMock) -> None: +async def test_ConfigEntryNotReady_initial_fetch( + hass: HomeAssistant, reolink_connect: MagicMock +) -> None: """Test a ConfigEntryNotReady is raised when initial fetch of data fails.""" config_entry = reolink_mock_config_entry(hass) @@ -87,7 +93,9 @@ async def test_ConfigEntryNotReady_initial_fetch(hass: HomeAssistant, reolink_co assert not hass.data.get(const.DOMAIN) -async def test_firmware_update_not_supported(hass: HomeAssistant, reolink_connect: MagicMock) -> None: +async def test_firmware_update_not_supported( + hass: HomeAssistant, reolink_connect: MagicMock +) -> None: """Test successful setup if firmware update is not supported.""" config_entry = reolink_mock_config_entry(hass) @@ -98,18 +106,24 @@ async def test_firmware_update_not_supported(hass: HomeAssistant, reolink_connec assert config_entry.state == ConfigEntryState.LOADED -async def test_firmware_update_error(hass: HomeAssistant, reolink_connect: MagicMock) -> None: +async def test_firmware_update_error( + hass: HomeAssistant, reolink_connect: MagicMock +) -> None: """Test error during firmware update does not block setup.""" config_entry = reolink_mock_config_entry(hass) - reolink_connect.check_new_firmware = AsyncMock(side_effect=ReolinkError("Test error")) + reolink_connect.check_new_firmware = AsyncMock( + side_effect=ReolinkError("Test error") + ) assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state == ConfigEntryState.LOADED -async def test_unexpected_error(hass: HomeAssistant, reolink_connect: MagicMock) -> None: +async def test_unexpected_error( + hass: HomeAssistant, reolink_connect: MagicMock +) -> None: """Test a unexpected error during initial connection.""" config_entry = reolink_mock_config_entry(hass) From 495f7edaa67ef70f33e4586b1687bd662d17127f Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Mon, 6 Mar 2023 20:55:01 +0100 Subject: [PATCH 07/19] Parametrize tests --- tests/components/reolink/test_init.py | 126 ++++++++++---------------- 1 file changed, 49 insertions(+), 77 deletions(-) diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index 255eaefe027c84..a5d9eb223c6368 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -1,4 +1,5 @@ """Test the Reolink init.""" +from typing import Any from unittest.mock import AsyncMock, MagicMock, Mock import pytest @@ -50,89 +51,60 @@ def reolink_mock_config_entry(hass: HomeAssistant) -> MockConfigEntry: return config_entry -async def test_ConfigEntryAuthFailed( - hass: HomeAssistant, reolink_connect: MagicMock -) -> None: - """Test a ConfigEntryAuthFailed is raised when credentials are invalid.""" - config_entry = reolink_mock_config_entry(hass) - - reolink_connect.is_admin = False - reolink_connect.user_level = "guest" - assert await hass.config_entries.async_setup(config_entry.entry_id) is False - await hass.async_block_till_done() - - assert config_entry.state == ConfigEntryState.SETUP_ERROR - assert not hass.data.get(const.DOMAIN) - - -async def test_ConfigEntryNotReady( - hass: HomeAssistant, reolink_connect: MagicMock -) -> None: - """Test a ConfigEntryNotReady is raised when initial connection fails.""" - config_entry = reolink_mock_config_entry(hass) - - reolink_connect.get_host_data = AsyncMock(side_effect=ReolinkError("Test error")) - assert await hass.config_entries.async_setup(config_entry.entry_id) is False - await hass.async_block_till_done() - - assert config_entry.state == ConfigEntryState.SETUP_RETRY - assert not hass.data.get(const.DOMAIN) - - -async def test_ConfigEntryNotReady_initial_fetch( - hass: HomeAssistant, reolink_connect: MagicMock -) -> None: - """Test a ConfigEntryNotReady is raised when initial fetch of data fails.""" - config_entry = reolink_mock_config_entry(hass) - - reolink_connect.get_states = AsyncMock(side_effect=ReolinkError("Test error")) - assert await hass.config_entries.async_setup(config_entry.entry_id) is False - await hass.async_block_till_done() - - assert config_entry.state == ConfigEntryState.SETUP_RETRY - assert not hass.data.get(const.DOMAIN) - - -async def test_firmware_update_not_supported( - hass: HomeAssistant, reolink_connect: MagicMock -) -> None: - """Test successful setup if firmware update is not supported.""" - config_entry = reolink_mock_config_entry(hass) - - reolink_connect.supported = Mock(return_value=False) - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - - assert config_entry.state == ConfigEntryState.LOADED - - -async def test_firmware_update_error( - hass: HomeAssistant, reolink_connect: MagicMock +@pytest.mark.parametrize( + ("attr", "value", "expected"), + [ + ( + "is_admin", + False, + ConfigEntryState.SETUP_ERROR, + ), + ( + "get_host_data", + AsyncMock(side_effect=ReolinkError("Test error")), + ConfigEntryState.SETUP_RETRY, + ), + ( + "get_host_data", + AsyncMock(side_effect=ValueError("Test error")), + ConfigEntryState.SETUP_ERROR, + ), + ( + "get_states", + AsyncMock(side_effect=ReolinkError("Test error")), + ConfigEntryState.SETUP_RETRY, + ), + ( + "supported", + Mock(return_value=False), + ConfigEntryState.LOADED, + ), + ( + "check_new_firmware", + AsyncMock(side_effect=ReolinkError("Test error")), + ConfigEntryState.LOADED, + ), + ], +) +async def test_failures_parametrized( + hass: HomeAssistant, + reolink_connect: MagicMock, + attr: str, + value: Any, + expected: ConfigEntryState, ) -> None: - """Test error during firmware update does not block setup.""" + """Test outcomes when changing errors.""" config_entry = reolink_mock_config_entry(hass) - reolink_connect.check_new_firmware = AsyncMock( - side_effect=ReolinkError("Test error") + setattr(reolink_connect, attr, value) + assert await hass.config_entries.async_setup(config_entry.entry_id) is ( + expected == ConfigEntryState.LOADED ) - assert await hass.config_entries.async_setup(config_entry.entry_id) - await hass.async_block_till_done() - - assert config_entry.state == ConfigEntryState.LOADED - - -async def test_unexpected_error( - hass: HomeAssistant, reolink_connect: MagicMock -) -> None: - """Test a unexpected error during initial connection.""" - config_entry = reolink_mock_config_entry(hass) - - reolink_connect.get_host_data = AsyncMock(side_effect=ValueError("Test error")) - assert await hass.config_entries.async_setup(config_entry.entry_id) is False await hass.async_block_till_done() - assert config_entry.state == ConfigEntryState.SETUP_ERROR - assert not hass.data.get(const.DOMAIN) + assert config_entry.state == expected + if expected != ConfigEntryState.LOADED: + assert not hass.data.get(const.DOMAIN) async def test_update_listener(hass: HomeAssistant) -> None: From 22397ab562cbd40975d3d57180133e44ed72cf22 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Mon, 6 Mar 2023 22:31:40 +0100 Subject: [PATCH 08/19] Update tests/components/reolink/conftest.py Co-authored-by: Franck Nijhof --- tests/components/reolink/conftest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index bc31481afefb9d..3b1009a19b1ee3 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -35,11 +35,11 @@ def reolink_connect_fixture(mock_get_source_ip): "homeassistant.components.reolink.host.Host", autospec=True ) as host_mock_class: host_mock = host_mock_class.return_value - host_mock.get_host_data = AsyncMock(return_value=None) - host_mock.get_states = AsyncMock(return_value=None) - host_mock.check_new_firmware = AsyncMock(return_value=False) - host_mock.unsubscribe = AsyncMock(return_value=True) - host_mock.logout = AsyncMock(return_value=True) + host_mock.get_host_data.return_value = None + host_mock.get_states.return_value = None + host_mock.check_new_firmware.return_value = False + host_mock.unsubscribe.return_value = True + host_mock.logout.return_value = True host_mock.mac_address = TEST_MAC host_mock.onvif_enabled = True host_mock.rtmp_enabled = True From f28b378c851abe203b3cd0af83ac2f444bdd05b0 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Mon, 6 Mar 2023 22:33:05 +0100 Subject: [PATCH 09/19] Apply suggestions from code review Co-authored-by: Franck Nijhof --- tests/components/reolink/test_config_flow.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/components/reolink/test_config_flow.py b/tests/components/reolink/test_config_flow.py index f7411ea24e135b..e5ba80dabf6eea 100644 --- a/tests/components/reolink/test_config_flow.py +++ b/tests/components/reolink/test_config_flow.py @@ -93,7 +93,7 @@ async def test_config_flow_errors( reolink_connect.is_admin = True reolink_connect.user_level = "admin" - reolink_connect.get_host_data = AsyncMock(side_effect=ReolinkError("Test error")) + reolink_connect.get_host_data.side_effect = ReolinkError("Test error") result = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -107,8 +107,8 @@ async def test_config_flow_errors( assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "cannot_connect"} - reolink_connect.get_host_data = AsyncMock( - side_effect=json.JSONDecodeError("test_error", "test", 1) + reolink_connect.get_host_data.side_effect = json.JSONDecodeError( + "test_error", "test", 1 ) result = await hass.config_entries.flow.async_configure( result["flow_id"], @@ -123,9 +123,7 @@ async def test_config_flow_errors( assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "unknown"} - reolink_connect.get_host_data = AsyncMock( - side_effect=CredentialsInvalidError("Test error") - ) + reolink_connect.get_host_data.side_effect = CredentialsInvalidError("Test error") result = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -139,7 +137,7 @@ async def test_config_flow_errors( assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "invalid_auth"} - reolink_connect.get_host_data = AsyncMock(side_effect=ApiError("Test error")) + reolink_connect.get_host_data.side_effect = ApiError("Test error") result = await hass.config_entries.flow.async_configure( result["flow_id"], { @@ -153,7 +151,7 @@ async def test_config_flow_errors( assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "api_error"} - reolink_connect.get_host_data = AsyncMock(return_value=None) + reolink_connect.get_host_data.return_value = None result = await hass.config_entries.flow.async_configure( result["flow_id"], { From 856d7b38cbf946b9d5891fb465de1829261882ab Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Mon, 6 Mar 2023 22:39:06 +0100 Subject: [PATCH 10/19] Update test_config_flow.py --- tests/components/reolink/test_config_flow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/reolink/test_config_flow.py b/tests/components/reolink/test_config_flow.py index e5ba80dabf6eea..7d4acb372abbe0 100644 --- a/tests/components/reolink/test_config_flow.py +++ b/tests/components/reolink/test_config_flow.py @@ -1,6 +1,6 @@ """Test the Reolink config flow.""" import json -from unittest.mock import AsyncMock, MagicMock +from unittest.mock import MagicMock import pytest from reolink_aio.exceptions import ApiError, CredentialsInvalidError, ReolinkError @@ -151,7 +151,7 @@ async def test_config_flow_errors( assert result["step_id"] == "user" assert result["errors"] == {CONF_HOST: "api_error"} - reolink_connect.get_host_data.return_value = None + reolink_connect.get_host_data.side_effect = None result = await hass.config_entries.flow.async_configure( result["flow_id"], { From 74060b4efedc5b36cb2800f67695af416e141e1e Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Mon, 6 Mar 2023 22:48:30 +0100 Subject: [PATCH 11/19] convert to fixture --- tests/components/reolink/test_init.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index a5d9eb223c6368..9426dc94919ea8 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -29,7 +29,8 @@ pytestmark = pytest.mark.usefixtures("reolink_connect", "reolink_init") -def reolink_mock_config_entry(hass: HomeAssistant) -> MockConfigEntry: +@pytest.fixture(name="config_entry") +def reolink_config_entry_fixture(hass: HomeAssistant) -> MockConfigEntry: """Add the reolink mock config entry to hass.""" config_entry = MockConfigEntry( domain=const.DOMAIN, @@ -47,7 +48,6 @@ def reolink_mock_config_entry(hass: HomeAssistant) -> MockConfigEntry: title=TEST_NVR_NAME, ) config_entry.add_to_hass(hass) - return config_entry @@ -89,13 +89,12 @@ def reolink_mock_config_entry(hass: HomeAssistant) -> MockConfigEntry: async def test_failures_parametrized( hass: HomeAssistant, reolink_connect: MagicMock, + config_entry: MockConfigEntry, attr: str, value: Any, expected: ConfigEntryState, ) -> None: """Test outcomes when changing errors.""" - config_entry = reolink_mock_config_entry(hass) - setattr(reolink_connect, attr, value) assert await hass.config_entries.async_setup(config_entry.entry_id) is ( expected == ConfigEntryState.LOADED @@ -107,10 +106,10 @@ async def test_failures_parametrized( assert not hass.data.get(const.DOMAIN) -async def test_update_listener(hass: HomeAssistant) -> None: +async def test_update_listener( + hass: HomeAssistant, config_entry: MockConfigEntry +) -> None: """Test the update listener.""" - config_entry = reolink_mock_config_entry(hass) - assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -122,10 +121,10 @@ async def test_update_listener(hass: HomeAssistant) -> None: assert config_entry.title == "New Name" -async def test_http_no_repair_issue(hass: HomeAssistant) -> None: +async def test_http_no_repair_issue( + hass: HomeAssistant, config_entry: MockConfigEntry +) -> None: """Test no repairs issue is raised when http local url is used.""" - config_entry = reolink_mock_config_entry(hass) - await async_process_ha_core_config( hass, {"country": "GB", "internal_url": "http://test_homeassistant_address"} ) @@ -137,10 +136,10 @@ async def test_http_no_repair_issue(hass: HomeAssistant) -> None: assert (const.DOMAIN, "https_webhook") not in issue_registry.issues -async def test_https_repair_issue(hass: HomeAssistant) -> None: +async def test_https_repair_issue( + hass: HomeAssistant, config_entry: MockConfigEntry +) -> None: """Test repairs issue is raised when https local url is used.""" - config_entry = reolink_mock_config_entry(hass) - await async_process_ha_core_config( hass, {"country": "GB", "internal_url": "https://test_homeassistant_address"} ) From 8d3e2d114ad4d07e6df0760804569a986431ccee Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 7 Mar 2023 10:26:43 +0100 Subject: [PATCH 12/19] review comments --- tests/components/reolink/conftest.py | 22 ++++++++++++++++++++++ tests/components/reolink/test_init.py | 24 ------------------------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index 3b1009a19b1ee3..1b4739cf4d164c 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -60,3 +60,25 @@ def reolink_init_fixture(mock_get_source_ip): """Mock reolink entry setup.""" with patch("homeassistant.components.reolink.PLATFORMS", return_value=[]): yield + + +@pytest.fixture(name="config_entry") +def reolink_config_entry_fixture(hass: HomeAssistant) -> MockConfigEntry: + """Add the reolink mock config entry to hass.""" + config_entry = MockConfigEntry( + domain=const.DOMAIN, + unique_id=format_mac(TEST_MAC), + data={ + CONF_HOST: TEST_HOST, + CONF_USERNAME: TEST_USERNAME, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: TEST_PORT, + const.CONF_USE_HTTPS: TEST_USE_HTTPS, + }, + options={ + const.CONF_PROTOCOL: DEFAULT_PROTOCOL, + }, + title=TEST_NVR_NAME, + ) + config_entry.add_to_hass(hass) + return config_entry diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index 9426dc94919ea8..06b669a3982f41 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -29,28 +29,6 @@ pytestmark = pytest.mark.usefixtures("reolink_connect", "reolink_init") -@pytest.fixture(name="config_entry") -def reolink_config_entry_fixture(hass: HomeAssistant) -> MockConfigEntry: - """Add the reolink mock config entry to hass.""" - config_entry = MockConfigEntry( - domain=const.DOMAIN, - unique_id=format_mac(TEST_MAC), - data={ - CONF_HOST: TEST_HOST, - CONF_USERNAME: TEST_USERNAME, - CONF_PASSWORD: TEST_PASSWORD, - CONF_PORT: TEST_PORT, - const.CONF_USE_HTTPS: TEST_USE_HTTPS, - }, - options={ - const.CONF_PROTOCOL: DEFAULT_PROTOCOL, - }, - title=TEST_NVR_NAME, - ) - config_entry.add_to_hass(hass) - return config_entry - - @pytest.mark.parametrize( ("attr", "value", "expected"), [ @@ -102,8 +80,6 @@ async def test_failures_parametrized( await hass.async_block_till_done() assert config_entry.state == expected - if expected != ConfigEntryState.LOADED: - assert not hass.data.get(const.DOMAIN) async def test_update_listener( From 5b3d91e626bb300eee1d42f090eb6bae98ce52f5 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 7 Mar 2023 10:27:44 +0100 Subject: [PATCH 13/19] Update tests/components/reolink/conftest.py Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> --- tests/components/reolink/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index 1b4739cf4d164c..bcef57ffdb4405 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -16,8 +16,8 @@ TEST_USE_HTTPS = True -@pytest.fixture(name="reolink_setup_entry") -def reolink_setup_entry_fixture() -> Generator[AsyncMock, None, None]: +@pytest.fixture +def mock_setup_entry() -> Generator[AsyncMock, None, None]: """Override async_setup_entry.""" with patch( "homeassistant.components.reolink.async_setup_entry", return_value=True From 0f079fe00e514763247f60b623951cf48f272012 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 7 Mar 2023 10:28:26 +0100 Subject: [PATCH 14/19] Update tests/components/reolink/conftest.py Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> --- tests/components/reolink/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index bcef57ffdb4405..624d75f57da01f 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -25,8 +25,8 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]: yield mock_setup_entry -@pytest.fixture(name="reolink_connect") -def reolink_connect_fixture(mock_get_source_ip): +@pytest.fixture +def reolink_connect(mock_get_source_ip: None) -> Generator[MagicMock, None, None]: """Mock reolink connection.""" with patch( "homeassistant.components.reolink.host.webhook.async_register", From e5721e1649e3bc1c1a5b6593c5cf0cb2a865b17f Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 7 Mar 2023 10:28:44 +0100 Subject: [PATCH 15/19] Update tests/components/reolink/conftest.py Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> --- tests/components/reolink/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index 624d75f57da01f..39e60329c6aad1 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -55,8 +55,8 @@ def reolink_connect(mock_get_source_ip: None) -> Generator[MagicMock, None, None yield host_mock -@pytest.fixture(name="reolink_init") -def reolink_init_fixture(mock_get_source_ip): +@pytest.fixture +def reolink_platforms(mock_get_source_ip: None) -> Generator[None, None, None]: """Mock reolink entry setup.""" with patch("homeassistant.components.reolink.PLATFORMS", return_value=[]): yield From 86fbcc1ba53d9c877e1bdc7e761a6c0daea26164 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 7 Mar 2023 10:31:51 +0100 Subject: [PATCH 16/19] fix tests --- tests/components/reolink/conftest.py | 3 +-- tests/components/reolink/test_config_flow.py | 2 +- tests/components/reolink/test_init.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index 39e60329c6aad1..58ccf15fa12586 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -62,8 +62,7 @@ def reolink_platforms(mock_get_source_ip: None) -> Generator[None, None, None]: yield -@pytest.fixture(name="config_entry") -def reolink_config_entry_fixture(hass: HomeAssistant) -> MockConfigEntry: +def config_entry(hass: HomeAssistant) -> MockConfigEntry: """Add the reolink mock config entry to hass.""" config_entry = MockConfigEntry( domain=const.DOMAIN, diff --git a/tests/components/reolink/test_config_flow.py b/tests/components/reolink/test_config_flow.py index 7d4acb372abbe0..b3abb793a9f7a8 100644 --- a/tests/components/reolink/test_config_flow.py +++ b/tests/components/reolink/test_config_flow.py @@ -28,7 +28,7 @@ from tests.common import MockConfigEntry -pytestmark = pytest.mark.usefixtures("reolink_setup_entry", "reolink_connect") +pytestmark = pytest.mark.usefixtures("mock_setup_entry", "reolink_connect") async def test_config_flow_manual_success(hass: HomeAssistant) -> None: diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index 06b669a3982f41..a26471a9120f0d 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -26,7 +26,7 @@ from tests.common import MockConfigEntry -pytestmark = pytest.mark.usefixtures("reolink_connect", "reolink_init") +pytestmark = pytest.mark.usefixtures("reolink_connect", "reolink_platforms") @pytest.mark.parametrize( From 84340291cd6145c59b50c9c2aa29edbad7af6ab4 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 7 Mar 2023 10:37:53 +0100 Subject: [PATCH 17/19] fix imports --- tests/components/reolink/conftest.py | 11 ++++++++++- tests/components/reolink/test_init.py | 13 ------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index 58ccf15fa12586..941a1ca7c8784a 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -1,9 +1,17 @@ """Setup the Reolink tests.""" from collections.abc import Generator -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock, MagicMock, patch import pytest +from homeassistant.components.reolink import const +from homeassistant.components.reolink.config_flow import DEFAULT_PROTOCOL +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME +from homeassistant.core import HomeAssistant +from homeassistant.helpers.device_registry import format_mac + +from tests.common import MockConfigEntry + TEST_HOST = "1.2.3.4" TEST_HOST2 = "4.5.6.7" TEST_USERNAME = "admin" @@ -62,6 +70,7 @@ def reolink_platforms(mock_get_source_ip: None) -> Generator[None, None, None]: yield +@pytest.fixture def config_entry(hass: HomeAssistant) -> MockConfigEntry: """Add the reolink mock config entry to hass.""" config_entry = MockConfigEntry( diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index a26471a9120f0d..fabad27d99f0f1 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -6,23 +6,10 @@ from reolink_aio.exceptions import ReolinkError from homeassistant.components.reolink import const -from homeassistant.components.reolink.config_flow import DEFAULT_PROTOCOL from homeassistant.config import async_process_ha_core_config from homeassistant.config_entries import ConfigEntryState -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_USERNAME from homeassistant.core import HomeAssistant from homeassistant.helpers import issue_registry as ir -from homeassistant.helpers.device_registry import format_mac - -from .conftest import ( - TEST_HOST, - TEST_MAC, - TEST_NVR_NAME, - TEST_PASSWORD, - TEST_PORT, - TEST_USE_HTTPS, - TEST_USERNAME, -) from tests.common import MockConfigEntry From b689a7a2925d39989decf78491b38fe4cd26faa0 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 7 Mar 2023 11:15:39 +0100 Subject: [PATCH 18/19] Update test_init.py --- tests/components/reolink/test_init.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index fabad27d99f0f1..95f37b038b9567 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -69,10 +69,10 @@ async def test_failures_parametrized( assert config_entry.state == expected -async def test_update_listener( +async def test_async_update_entry( hass: HomeAssistant, config_entry: MockConfigEntry ) -> None: - """Test the update listener.""" + """Test the update entry function.""" assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() From 359fcff3416a8b805755b625544afaa27b32929d Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 7 Mar 2023 11:57:50 +0100 Subject: [PATCH 19/19] Check if host is logout on reload --- tests/components/reolink/test_init.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/components/reolink/test_init.py b/tests/components/reolink/test_init.py index 95f37b038b9567..035bfa6e538995 100644 --- a/tests/components/reolink/test_init.py +++ b/tests/components/reolink/test_init.py @@ -69,18 +69,20 @@ async def test_failures_parametrized( assert config_entry.state == expected -async def test_async_update_entry( - hass: HomeAssistant, config_entry: MockConfigEntry +async def test_entry_reloading( + hass: HomeAssistant, config_entry: MockConfigEntry, reolink_connect: MagicMock ) -> None: - """Test the update entry function.""" + """Test the entry is reloaded correctly when settings change.""" assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() + assert reolink_connect.logout.call_count == 0 assert config_entry.title == "test_reolink_name" hass.config_entries.async_update_entry(config_entry, title="New Name") await hass.async_block_till_done() + assert reolink_connect.logout.call_count == 1 assert config_entry.title == "New Name"