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 c92134b9e3b..00000000000 Binary files a/tests/components/ipp/fixtures/get-printer-attributes-error-0x0503.bin and /dev/null differ 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 e6061adaccd..00000000000 Binary files a/tests/components/ipp/fixtures/get-printer-attributes-success-nodata.bin and /dev/null differ 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 24b903efc5d..00000000000 Binary files a/tests/components/ipp/fixtures/get-printer-attributes.bin and /dev/null differ diff --git a/tests/components/ipp/fixtures/printer.json b/tests/components/ipp/fixtures/printer.json new file mode 100644 index 00000000000..6c3f9cd0545 --- /dev/null +++ b/tests/components/ipp/fixtures/printer.json @@ -0,0 +1,36 @@ +{ + "printer-uuid": "urn:uuid:cfe92100-67c4-11d4-a45f-f8d027761251", + "printer-state": "idle", + "printer-name": "Test Printer", + "printer-location": null, + "printer-make-and-model": "Test HA-1000 Series", + "printer-device-id": "MFG:TEST;CMD:ESCPL2,BDC,D4,D4PX,ESCPR7,END4,GENEP,URF;MDL:HA-1000 Series;CLS:PRINTER;DES:TEST HA-1000 Series;CID:EpsonRGB;FID:FXN,DPA,WFA,ETN,AFN,DAN,WRA;RID:20;DDS:022500;ELG:1000;SN:555534593035345555;URF:CP1,PQ4-5,OB9,OFU0,RS360,SRGB24,W8,DM3,IS1-7-6,V1.4,MT1-3-7-8-10-11-12;", + "printer-uri-supported": [ + "ipps://192.168.1.31:631/ipp/print", + "ipp://192.168.1.31:631/ipp/print" + ], + "uri-authentication-supported": ["none", "none"], + "uri-security-supported": ["tls", "none"], + "printer-info": "Test HA-1000 Series", + "printer-up-time": 30, + "printer-firmware-string-version": "20.23.06HA", + "printer-more-info": "http://192.168.1.31:80/PRESENTATION/BONJOUR", + "marker-names": [ + "Black ink", + "Photo black ink", + "Cyan ink", + "Yellow ink", + "Magenta ink" + ], + "marker-types": [ + "ink-cartridge", + "ink-cartridge", + "ink-cartridge", + "ink-cartridge", + "ink-cartridge" + ], + "marker-colors": ["#000000", "#000000", "#00FFFF", "#FFFF00", "#FF00FF"], + "marker-levels": [58, 98, 91, 95, 73], + "marker-low-levels": [10, 10, 10, 10, 10], + "marker-high-levels": [100, 100, 100, 100, 100] +} diff --git a/tests/components/ipp/test_config_flow.py b/tests/components/ipp/test_config_flow.py index 214488d49a0..69a2bb9287a 100644 --- a/tests/components/ipp/test_config_flow.py +++ b/tests/components/ipp/test_config_flow.py @@ -1,6 +1,15 @@ """Tests for the IPP config flow.""" import dataclasses -from unittest.mock import patch +from unittest.mock import MagicMock + +from pyipp import ( + IPPConnectionError, + IPPConnectionUpgradeRequired, + IPPError, + IPPParseError, + IPPVersionNotSupportedError, +) +import pytest from homeassistant.components.ipp.const import CONF_BASE_PATH, DOMAIN from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF @@ -12,11 +21,11 @@ from . import ( MOCK_USER_INPUT, MOCK_ZEROCONF_IPP_SERVICE_INFO, MOCK_ZEROCONF_IPPS_SERVICE_INFO, - init_integration, - mock_connection, ) -from tests.test_util.aiohttp import AiohttpClientMocker +from tests.common import MockConfigEntry + +pytestmark = pytest.mark.usefixtures("mock_setup_entry") async def test_show_user_form(hass: HomeAssistant) -> 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"