From 7390e3a997f1fbdfbd84de8c7b7fa5dba4031ed8 Mon Sep 17 00:00:00 2001 From: Chris Talkington Date: Sun, 9 Jul 2023 17:37:32 -0500 Subject: [PATCH] Refactor IPP tests (#94097) refactor ipp tests --- tests/components/ipp/__init__.py | 112 +------------- tests/components/ipp/conftest.py | 99 ++++++++++++ .../get-printer-attributes-error-0x0503.bin | Bin 75 -> 0 bytes .../get-printer-attributes-success-nodata.bin | Bin 72 -> 0 bytes .../ipp/fixtures/get-printer-attributes.bin | Bin 9143 -> 0 bytes tests/components/ipp/fixtures/printer.json | 36 +++++ tests/components/ipp/test_config_flow.py | 145 ++++++++++-------- tests/components/ipp/test_init.py | 54 ++++--- tests/components/ipp/test_sensor.py | 86 +++++------ 9 files changed, 290 insertions(+), 242 deletions(-) create mode 100644 tests/components/ipp/conftest.py delete mode 100644 tests/components/ipp/fixtures/get-printer-attributes-error-0x0503.bin delete mode 100644 tests/components/ipp/fixtures/get-printer-attributes-success-nodata.bin delete mode 100644 tests/components/ipp/fixtures/get-printer-attributes.bin create mode 100644 tests/components/ipp/fixtures/printer.json diff --git a/tests/components/ipp/__init__.py b/tests/components/ipp/__init__.py index feda6554210..f66630b2a69 100644 --- a/tests/components/ipp/__init__.py +++ b/tests/components/ipp/__init__.py @@ -1,20 +1,8 @@ """Tests for the IPP integration.""" -import aiohttp -from pyipp import IPPConnectionUpgradeRequired, IPPError from homeassistant.components import zeroconf -from homeassistant.components.ipp.const import CONF_BASE_PATH, DOMAIN -from homeassistant.const import ( - CONF_HOST, - CONF_PORT, - CONF_SSL, - CONF_UUID, - CONF_VERIFY_SSL, -) -from homeassistant.core import HomeAssistant - -from tests.common import MockConfigEntry, get_fixture_path -from tests.test_util.aiohttp import AiohttpClientMocker +from homeassistant.components.ipp.const import CONF_BASE_PATH +from homeassistant.const import CONF_HOST, CONF_PORT, CONF_SSL, CONF_VERIFY_SSL ATTR_HOSTNAME = "hostname" ATTR_PROPERTIES = "properties" @@ -59,99 +47,3 @@ MOCK_ZEROCONF_IPPS_SERVICE_INFO = zeroconf.ZeroconfServiceInfo( port=ZEROCONF_PORT, properties={"rp": ZEROCONF_RP}, ) - - -def load_fixture_binary(filename): - """Load a binary fixture.""" - return get_fixture_path(filename, "ipp").read_bytes() - - -def mock_connection( - aioclient_mock: AiohttpClientMocker, - host: str = HOST, - port: int = PORT, - ssl: bool = False, - base_path: str = BASE_PATH, - conn_error: bool = False, - conn_upgrade_error: bool = False, - ipp_error: bool = False, - no_unique_id: bool = False, - parse_error: bool = False, - version_not_supported: bool = False, -): - """Mock the IPP connection.""" - scheme = "https" if ssl else "http" - ipp_url = f"{scheme}://{host}:{port}" - - if ipp_error: - aioclient_mock.post(f"{ipp_url}{base_path}", exc=IPPError) - return - - if conn_error: - aioclient_mock.post(f"{ipp_url}{base_path}", exc=aiohttp.ClientError) - return - - if conn_upgrade_error: - aioclient_mock.post(f"{ipp_url}{base_path}", exc=IPPConnectionUpgradeRequired) - return - - fixture = "get-printer-attributes.bin" - if no_unique_id: - fixture = "get-printer-attributes-success-nodata.bin" - elif version_not_supported: - fixture = "get-printer-attributes-error-0x0503.bin" - - if parse_error: - content = "BAD" - else: - content = load_fixture_binary(fixture) - - aioclient_mock.post( - f"{ipp_url}{base_path}", - content=content, - headers={"Content-Type": "application/ipp"}, - ) - - -async def init_integration( - hass: HomeAssistant, - aioclient_mock: AiohttpClientMocker, - skip_setup: bool = False, - host: str = HOST, - port: int = PORT, - ssl: bool = False, - base_path: str = BASE_PATH, - uuid: str = "cfe92100-67c4-11d4-a45f-f8d027761251", - unique_id: str = "cfe92100-67c4-11d4-a45f-f8d027761251", - conn_error: bool = False, -) -> MockConfigEntry: - """Set up the IPP integration in Home Assistant.""" - entry = MockConfigEntry( - domain=DOMAIN, - unique_id=unique_id, - data={ - CONF_HOST: host, - CONF_PORT: port, - CONF_SSL: ssl, - CONF_VERIFY_SSL: True, - CONF_BASE_PATH: base_path, - CONF_UUID: uuid, - }, - ) - - entry.add_to_hass(hass) - - mock_connection( - aioclient_mock, - host=host, - port=port, - ssl=ssl, - base_path=base_path, - conn_error=conn_error, - ) - - if not skip_setup: - await hass.config_entries.async_setup(entry.entry_id) - await hass.async_block_till_done() - - return entry diff --git a/tests/components/ipp/conftest.py b/tests/components/ipp/conftest.py new file mode 100644 index 00000000000..de3f1e0e73c --- /dev/null +++ b/tests/components/ipp/conftest.py @@ -0,0 +1,99 @@ +"""Fixtures for IPP integration tests.""" +from collections.abc import Generator +import json +from unittest.mock import AsyncMock, MagicMock, patch + +from pyipp import Printer +import pytest + +from homeassistant.components.ipp.const import CONF_BASE_PATH, DOMAIN +from homeassistant.const import ( + CONF_HOST, + CONF_PORT, + CONF_SSL, + CONF_UUID, + CONF_VERIFY_SSL, +) +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry, load_fixture + + +@pytest.fixture +def mock_config_entry() -> MockConfigEntry: + """Return the default mocked config entry.""" + return MockConfigEntry( + title="IPP Printer", + domain=DOMAIN, + data={ + CONF_HOST: "192.168.1.31", + CONF_PORT: 631, + CONF_SSL: False, + CONF_VERIFY_SSL: True, + CONF_BASE_PATH: "/ipp/print", + CONF_UUID: "cfe92100-67c4-11d4-a45f-f8d027761251", + }, + unique_id="cfe92100-67c4-11d4-a45f-f8d027761251", + ) + + +@pytest.fixture +def mock_setup_entry() -> Generator[AsyncMock, None, None]: + """Mock setting up a config entry.""" + with patch( + "homeassistant.components.ipp.async_setup_entry", return_value=True + ) as mock_setup_entry: + yield mock_setup_entry + + +@pytest.fixture +async def mock_printer( + request: pytest.FixtureRequest, +) -> Printer: + """Return the mocked printer.""" + fixture: str = "ipp/printer.json" + if hasattr(request, "param") and request.param: + fixture = request.param + + return Printer.from_dict(json.loads(load_fixture(fixture))) + + +@pytest.fixture +def mock_ipp_config_flow( + mock_printer: Printer, +) -> Generator[None, MagicMock, None]: + """Return a mocked IPP client.""" + + with patch( + "homeassistant.components.ipp.config_flow.IPP", autospec=True + ) as ipp_mock: + client = ipp_mock.return_value + client.printer.return_value = mock_printer + yield client + + +@pytest.fixture +def mock_ipp( + request: pytest.FixtureRequest, mock_printer: Printer +) -> Generator[None, MagicMock, None]: + """Return a mocked IPP client.""" + + with patch( + "homeassistant.components.ipp.coordinator.IPP", autospec=True + ) as ipp_mock: + client = ipp_mock.return_value + client.printer.return_value = mock_printer + yield client + + +@pytest.fixture +async def init_integration( + hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_ipp: MagicMock +) -> MockConfigEntry: + """Set up the IPP 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/ipp/fixtures/get-printer-attributes-error-0x0503.bin b/tests/components/ipp/fixtures/get-printer-attributes-error-0x0503.bin deleted file mode 100644 index c92134b9e3bc72859ffd410f8235e36622c2d57f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75 zcmZQ%WMyVxk7is_i diff --git a/tests/components/ipp/fixtures/get-printer-attributes-success-nodata.bin b/tests/components/ipp/fixtures/get-printer-attributes-success-nodata.bin deleted file mode 100644 index e6061adaccdef6f4705bba31c5166ee7b9cefe5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72 zcmZQ#00PFkS&Z%sLWw0MMVU#ZC8@=_$r*`7#i=C>tfeJsx)vS`(nxZ7i6x~)i8;DC QiFxUziRq~fOsRRy0Q|TXqyPW_ diff --git a/tests/components/ipp/fixtures/get-printer-attributes.bin b/tests/components/ipp/fixtures/get-printer-attributes.bin deleted file mode 100644 index 24b903efc5d6fda33b8693ecb2238244d439313a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9143 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 None: @@ -31,11 +40,10 @@ async def test_show_user_form(hass: HomeAssistant) -> None: async def test_show_zeroconf_form( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test that the zeroconf confirmation form is served.""" - mock_connection(aioclient_mock) - discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( DOMAIN, @@ -49,10 +57,11 @@ async def test_show_zeroconf_form( async def test_connection_error( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we show user form on IPP connection error.""" - mock_connection(aioclient_mock, conn_error=True) + mock_ipp_config_flow.printer.side_effect = IPPConnectionError user_input = MOCK_USER_INPUT.copy() result = await hass.config_entries.flow.async_init( @@ -67,10 +76,11 @@ async def test_connection_error( async def test_zeroconf_connection_error( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort zeroconf flow on IPP connection error.""" - mock_connection(aioclient_mock, conn_error=True) + mock_ipp_config_flow.printer.side_effect = IPPConnectionError discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( @@ -84,10 +94,11 @@ async def test_zeroconf_connection_error( async def test_zeroconf_confirm_connection_error( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort zeroconf flow on IPP connection error.""" - mock_connection(aioclient_mock, conn_error=True) + mock_ipp_config_flow.printer.side_effect = IPPConnectionError discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( @@ -99,10 +110,11 @@ async def test_zeroconf_confirm_connection_error( async def test_user_connection_upgrade_required( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we show the user form if connection upgrade required by server.""" - mock_connection(aioclient_mock, conn_upgrade_error=True) + mock_ipp_config_flow.printer.side_effect = IPPConnectionUpgradeRequired user_input = MOCK_USER_INPUT.copy() result = await hass.config_entries.flow.async_init( @@ -117,10 +129,11 @@ async def test_user_connection_upgrade_required( async def test_zeroconf_connection_upgrade_required( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort zeroconf flow on IPP connection error.""" - mock_connection(aioclient_mock, conn_upgrade_error=True) + mock_ipp_config_flow.printer.side_effect = IPPConnectionUpgradeRequired discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( @@ -134,10 +147,11 @@ async def test_zeroconf_connection_upgrade_required( async def test_user_parse_error( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort user flow on IPP parse error.""" - mock_connection(aioclient_mock, parse_error=True) + mock_ipp_config_flow.printer.side_effect = IPPParseError user_input = MOCK_USER_INPUT.copy() result = await hass.config_entries.flow.async_init( @@ -151,10 +165,11 @@ async def test_user_parse_error( async def test_zeroconf_parse_error( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort zeroconf flow on IPP parse error.""" - mock_connection(aioclient_mock, parse_error=True) + mock_ipp_config_flow.printer.side_effect = IPPParseError discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( @@ -168,10 +183,11 @@ async def test_zeroconf_parse_error( async def test_user_ipp_error( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort the user flow on IPP error.""" - mock_connection(aioclient_mock, ipp_error=True) + mock_ipp_config_flow.printer.side_effect = IPPError user_input = MOCK_USER_INPUT.copy() result = await hass.config_entries.flow.async_init( @@ -185,10 +201,11 @@ async def test_user_ipp_error( async def test_zeroconf_ipp_error( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort zeroconf flow on IPP error.""" - mock_connection(aioclient_mock, ipp_error=True) + mock_ipp_config_flow.printer.side_effect = IPPError discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( @@ -202,10 +219,11 @@ async def test_zeroconf_ipp_error( async def test_user_ipp_version_error( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort user flow on IPP version not supported error.""" - mock_connection(aioclient_mock, version_not_supported=True) + mock_ipp_config_flow.printer.side_effect = IPPVersionNotSupportedError user_input = {**MOCK_USER_INPUT} result = await hass.config_entries.flow.async_init( @@ -219,10 +237,11 @@ async def test_user_ipp_version_error( async def test_zeroconf_ipp_version_error( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort zeroconf flow on IPP version not supported error.""" - mock_connection(aioclient_mock, version_not_supported=True) + mock_ipp_config_flow.printer.side_effect = IPPVersionNotSupportedError discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( @@ -236,10 +255,12 @@ async def test_zeroconf_ipp_version_error( async def test_user_device_exists_abort( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort user flow if printer already configured.""" - await init_integration(hass, aioclient_mock, skip_setup=True) + mock_config_entry.add_to_hass(hass) user_input = MOCK_USER_INPUT.copy() result = await hass.config_entries.flow.async_init( @@ -253,10 +274,12 @@ async def test_user_device_exists_abort( async def test_zeroconf_device_exists_abort( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort zeroconf flow if printer already configured.""" - await init_integration(hass, aioclient_mock, skip_setup=True) + mock_config_entry.add_to_hass(hass) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( @@ -270,10 +293,12 @@ async def test_zeroconf_device_exists_abort( async def test_zeroconf_with_uuid_device_exists_abort( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_ipp_config_flow: MagicMock, ) -> None: """Test we abort zeroconf flow if printer already configured.""" - await init_integration(hass, aioclient_mock, skip_setup=True) + mock_config_entry.add_to_hass(hass) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) discovery_info.properties = { @@ -292,10 +317,12 @@ async def test_zeroconf_with_uuid_device_exists_abort( async def test_zeroconf_empty_unique_id( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test zeroconf flow if printer lacks (empty) unique identification.""" - mock_connection(aioclient_mock, no_unique_id=True) + printer = mock_ipp_config_flow.printer.return_value + printer.unique_id = None discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) discovery_info.properties = { @@ -312,10 +339,12 @@ async def test_zeroconf_empty_unique_id( async def test_zeroconf_no_unique_id( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test zeroconf flow if printer lacks unique identification.""" - mock_connection(aioclient_mock, no_unique_id=True) + printer = mock_ipp_config_flow.printer.return_value + printer.unique_id = None discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( @@ -328,11 +357,10 @@ async def test_zeroconf_no_unique_id( async def test_full_user_flow_implementation( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test the full manual user flow from start to finish.""" - mock_connection(aioclient_mock) - result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, @@ -341,11 +369,10 @@ async def test_full_user_flow_implementation( assert result["step_id"] == "user" assert result["type"] == FlowResultType.FORM - with patch("homeassistant.components.ipp.async_setup_entry", return_value=True): - result = await hass.config_entries.flow.async_configure( - result["flow_id"], - user_input={CONF_HOST: "192.168.1.31", CONF_BASE_PATH: "/ipp/print"}, - ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_HOST: "192.168.1.31", CONF_BASE_PATH: "/ipp/print"}, + ) assert result["type"] == FlowResultType.CREATE_ENTRY assert result["title"] == "192.168.1.31" @@ -359,11 +386,10 @@ async def test_full_user_flow_implementation( async def test_full_zeroconf_flow_implementation( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test the full manual user flow from start to finish.""" - mock_connection(aioclient_mock) - discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) result = await hass.config_entries.flow.async_init( DOMAIN, @@ -374,10 +400,9 @@ async def test_full_zeroconf_flow_implementation( assert result["step_id"] == "zeroconf_confirm" assert result["type"] == FlowResultType.FORM - with patch("homeassistant.components.ipp.async_setup_entry", return_value=True): - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input={} - ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input={} + ) assert result["type"] == FlowResultType.CREATE_ENTRY assert result["title"] == "EPSON XP-6000 Series" @@ -393,11 +418,10 @@ async def test_full_zeroconf_flow_implementation( async def test_full_zeroconf_tls_flow_implementation( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_ipp_config_flow: MagicMock, ) -> None: """Test the full manual user flow from start to finish.""" - mock_connection(aioclient_mock, ssl=True) - discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPPS_SERVICE_INFO) result = await hass.config_entries.flow.async_init( DOMAIN, @@ -409,10 +433,9 @@ async def test_full_zeroconf_tls_flow_implementation( assert result["type"] == FlowResultType.FORM assert result["description_placeholders"] == {CONF_NAME: "EPSON XP-6000 Series"} - with patch("homeassistant.components.ipp.async_setup_entry", return_value=True): - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input={} - ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input={} + ) assert result["type"] == FlowResultType.CREATE_ENTRY assert result["title"] == "EPSON XP-6000 Series" diff --git a/tests/components/ipp/test_init.py b/tests/components/ipp/test_init.py index 32060b4df86..f502c30068c 100644 --- a/tests/components/ipp/test_init.py +++ b/tests/components/ipp/test_init.py @@ -1,33 +1,45 @@ """Tests for the IPP integration.""" +from unittest.mock import AsyncMock, MagicMock, patch + +from pyipp import IPPConnectionError + from homeassistant.components.ipp.const import DOMAIN from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant -from . import init_integration - -from tests.test_util.aiohttp import AiohttpClientMocker +from tests.common import MockConfigEntry +@patch( + "homeassistant.components.ipp.coordinator.IPP._request", + side_effect=IPPConnectionError, +) async def test_config_entry_not_ready( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + mock_request: MagicMock, hass: HomeAssistant, mock_config_entry: MockConfigEntry ) -> None: """Test the IPP configuration entry not ready.""" - entry = await init_integration(hass, aioclient_mock, conn_error=True) - assert entry.state is ConfigEntryState.SETUP_RETRY - - -async def test_unload_config_entry( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker -) -> None: - """Test the IPP configuration entry unloading.""" - entry = await init_integration(hass, aioclient_mock) - - assert hass.data[DOMAIN] - assert entry.entry_id in hass.data[DOMAIN] - assert entry.state is ConfigEntryState.LOADED - - await hass.config_entries.async_unload(entry.entry_id) + 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 entry.entry_id not in hass.data[DOMAIN] - assert entry.state is ConfigEntryState.NOT_LOADED + assert mock_request.call_count == 1 + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY + + +async def test_load_unload_config_entry( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_ipp: AsyncMock, +) -> None: + """Test the IPP 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.entry_id in hass.data[DOMAIN] + 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 mock_config_entry.entry_id not in hass.data[DOMAIN] + assert mock_config_entry.state is ConfigEntryState.NOT_LOADED diff --git a/tests/components/ipp/test_sensor.py b/tests/components/ipp/test_sensor.py index f8dd94ffc72..ebebd18bc72 100644 --- a/tests/components/ipp/test_sensor.py +++ b/tests/components/ipp/test_sensor.py @@ -1,119 +1,105 @@ """Tests for the IPP sensor platform.""" -from datetime import datetime -from unittest.mock import patch +from unittest.mock import AsyncMock -from homeassistant.components.ipp.const import DOMAIN -from homeassistant.components.sensor import ( - ATTR_OPTIONS as SENSOR_ATTR_OPTIONS, - DOMAIN as SENSOR_DOMAIN, -) +import pytest + +from homeassistant.components.sensor import ATTR_OPTIONS from homeassistant.const import ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, PERCENTAGE from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er -from homeassistant.util import dt as dt_util -from . import init_integration, mock_connection - -from tests.test_util.aiohttp import AiohttpClientMocker +from tests.common import MockConfigEntry +@pytest.mark.freeze_time("2019-11-11 09:10:32+00:00") +@pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_sensors( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + init_integration: MockConfigEntry, ) -> None: """Test the creation and values of the IPP sensors.""" - mock_connection(aioclient_mock) - - entry = await init_integration(hass, aioclient_mock, skip_setup=True) - registry = er.async_get(hass) - - # Pre-create registry entries for disabled by default sensors - registry.async_get_or_create( - SENSOR_DOMAIN, - DOMAIN, - "cfe92100-67c4-11d4-a45f-f8d027761251_uptime", - suggested_object_id="epson_xp_6000_series_uptime", - disabled_by=None, - ) - - test_time = datetime(2019, 11, 11, 9, 10, 32, tzinfo=dt_util.UTC) - with patch("homeassistant.components.ipp.sensor.utcnow", return_value=test_time): - await hass.config_entries.async_setup(entry.entry_id) - await hass.async_block_till_done() - - state = hass.states.get("sensor.epson_xp_6000_series") + state = hass.states.get("sensor.test_ha_1000_series") assert state assert state.attributes.get(ATTR_ICON) == "mdi:printer" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None - assert state.attributes.get(SENSOR_ATTR_OPTIONS) == ["idle", "printing", "stopped"] + assert state.attributes.get(ATTR_OPTIONS) == ["idle", "printing", "stopped"] - entry = registry.async_get("sensor.epson_xp_6000_series") + entry = entity_registry.async_get("sensor.test_ha_1000_series") assert entry assert entry.translation_key == "printer" - state = hass.states.get("sensor.epson_xp_6000_series_black_ink") + state = hass.states.get("sensor.test_ha_1000_series_black_ink") assert state assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.state == "58" - state = hass.states.get("sensor.epson_xp_6000_series_photo_black_ink") + state = hass.states.get("sensor.test_ha_1000_series_photo_black_ink") assert state assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.state == "98" - state = hass.states.get("sensor.epson_xp_6000_series_cyan_ink") + state = hass.states.get("sensor.test_ha_1000_series_cyan_ink") assert state assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.state == "91" - state = hass.states.get("sensor.epson_xp_6000_series_yellow_ink") + state = hass.states.get("sensor.test_ha_1000_series_yellow_ink") assert state assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.state == "95" - state = hass.states.get("sensor.epson_xp_6000_series_magenta_ink") + state = hass.states.get("sensor.test_ha_1000_series_magenta_ink") assert state assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.state == "73" - state = hass.states.get("sensor.epson_xp_6000_series_uptime") + state = hass.states.get("sensor.test_ha_1000_series_uptime") assert state assert state.attributes.get(ATTR_ICON) == "mdi:clock-outline" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None - assert state.state == "2019-10-26T15:37:00+00:00" + assert state.state == "2019-11-11T09:10:02+00:00" - entry = registry.async_get("sensor.epson_xp_6000_series_uptime") + entry = entity_registry.async_get("sensor.test_ha_1000_series_uptime") assert entry assert entry.unique_id == "cfe92100-67c4-11d4-a45f-f8d027761251_uptime" async def test_disabled_by_default_sensors( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + init_integration: MockConfigEntry, ) -> None: """Test the disabled by default IPP sensors.""" - await init_integration(hass, aioclient_mock) registry = er.async_get(hass) - state = hass.states.get("sensor.epson_xp_6000_series_uptime") + state = hass.states.get("sensor.test_ha_1000_series_uptime") assert state is None - entry = registry.async_get("sensor.epson_xp_6000_series_uptime") + entry = registry.async_get("sensor.test_ha_1000_series_uptime") assert entry assert entry.disabled assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION async def test_missing_entry_unique_id( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_ipp: AsyncMock, ) -> None: """Test the unique_id of IPP sensor when printer is missing identifiers.""" - entry = await init_integration(hass, aioclient_mock, uuid=None, unique_id=None) + 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() + registry = er.async_get(hass) - entity = registry.async_get("sensor.epson_xp_6000_series") + entity = registry.async_get("sensor.test_ha_1000_series") assert entity - assert entity.unique_id == f"{entry.entry_id}_printer" + assert entity.unique_id == f"{mock_config_entry.entry_id}_printer"