Refactor IPP tests (#94097)

refactor ipp tests
This commit is contained in:
Chris Talkington 2023-07-09 17:37:32 -05:00 committed by GitHub
parent ac594e6bce
commit 7390e3a997
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 290 additions and 242 deletions

View file

@ -1,20 +1,8 @@
"""Tests for the IPP integration.""" """Tests for the IPP integration."""
import aiohttp
from pyipp import IPPConnectionUpgradeRequired, IPPError
from homeassistant.components import zeroconf from homeassistant.components import zeroconf
from homeassistant.components.ipp.const import CONF_BASE_PATH, DOMAIN from homeassistant.components.ipp.const import CONF_BASE_PATH
from homeassistant.const import ( from homeassistant.const import CONF_HOST, CONF_PORT, CONF_SSL, CONF_VERIFY_SSL
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
ATTR_HOSTNAME = "hostname" ATTR_HOSTNAME = "hostname"
ATTR_PROPERTIES = "properties" ATTR_PROPERTIES = "properties"
@ -59,99 +47,3 @@ MOCK_ZEROCONF_IPPS_SERVICE_INFO = zeroconf.ZeroconfServiceInfo(
port=ZEROCONF_PORT, port=ZEROCONF_PORT,
properties={"rp": ZEROCONF_RP}, 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

View file

@ -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

View file

@ -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]
}

View file

@ -1,6 +1,15 @@
"""Tests for the IPP config flow.""" """Tests for the IPP config flow."""
import dataclasses 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.components.ipp.const import CONF_BASE_PATH, DOMAIN
from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF
@ -12,11 +21,11 @@ from . import (
MOCK_USER_INPUT, MOCK_USER_INPUT,
MOCK_ZEROCONF_IPP_SERVICE_INFO, MOCK_ZEROCONF_IPP_SERVICE_INFO,
MOCK_ZEROCONF_IPPS_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: 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( async def test_show_zeroconf_form(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test that the zeroconf confirmation form is served.""" """Test that the zeroconf confirmation form is served."""
mock_connection(aioclient_mock)
discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
@ -49,10 +57,11 @@ async def test_show_zeroconf_form(
async def test_connection_error( async def test_connection_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we show user form on IPP connection error.""" """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() user_input = MOCK_USER_INPUT.copy()
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -67,10 +76,11 @@ async def test_connection_error(
async def test_zeroconf_connection_error( async def test_zeroconf_connection_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort zeroconf flow on IPP connection error.""" """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) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( 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( async def test_zeroconf_confirm_connection_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort zeroconf flow on IPP connection error.""" """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) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( 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( async def test_user_connection_upgrade_required(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we show the user form if connection upgrade required by server.""" """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() user_input = MOCK_USER_INPUT.copy()
result = await hass.config_entries.flow.async_init( 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( async def test_zeroconf_connection_upgrade_required(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort zeroconf flow on IPP connection error.""" """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) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( 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( async def test_user_parse_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort user flow on IPP parse error.""" """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() user_input = MOCK_USER_INPUT.copy()
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -151,10 +165,11 @@ async def test_user_parse_error(
async def test_zeroconf_parse_error( async def test_zeroconf_parse_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort zeroconf flow on IPP parse error.""" """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) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -168,10 +183,11 @@ async def test_zeroconf_parse_error(
async def test_user_ipp_error( async def test_user_ipp_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort the user flow on IPP error.""" """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() user_input = MOCK_USER_INPUT.copy()
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -185,10 +201,11 @@ async def test_user_ipp_error(
async def test_zeroconf_ipp_error( async def test_zeroconf_ipp_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort zeroconf flow on IPP error.""" """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) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( 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( async def test_user_ipp_version_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort user flow on IPP version not supported error.""" """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} user_input = {**MOCK_USER_INPUT}
result = await hass.config_entries.flow.async_init( 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( async def test_zeroconf_ipp_version_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort zeroconf flow on IPP version not supported error.""" """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) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( 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( async def test_user_device_exists_abort(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort user flow if printer already configured.""" """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() user_input = MOCK_USER_INPUT.copy()
result = await hass.config_entries.flow.async_init( 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( async def test_zeroconf_device_exists_abort(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test we abort zeroconf flow if printer already configured.""" """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 = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( 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( 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: ) -> None:
"""Test we abort zeroconf flow if printer already configured.""" """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 = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
discovery_info.properties = { discovery_info.properties = {
@ -292,10 +317,12 @@ async def test_zeroconf_with_uuid_device_exists_abort(
async def test_zeroconf_empty_unique_id( async def test_zeroconf_empty_unique_id(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test zeroconf flow if printer lacks (empty) unique identification.""" """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 = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
discovery_info.properties = { discovery_info.properties = {
@ -312,10 +339,12 @@ async def test_zeroconf_empty_unique_id(
async def test_zeroconf_no_unique_id( async def test_zeroconf_no_unique_id(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test zeroconf flow if printer lacks unique identification.""" """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) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( 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( async def test_full_user_flow_implementation(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test the full manual user flow from start to finish.""" """Test the full manual user flow from start to finish."""
mock_connection(aioclient_mock)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={"source": SOURCE_USER}, context={"source": SOURCE_USER},
@ -341,11 +369,10 @@ async def test_full_user_flow_implementation(
assert result["step_id"] == "user" assert result["step_id"] == "user"
assert result["type"] == FlowResultType.FORM 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 = await hass.config_entries.flow.async_configure( result["flow_id"],
result["flow_id"], user_input={CONF_HOST: "192.168.1.31", CONF_BASE_PATH: "/ipp/print"},
user_input={CONF_HOST: "192.168.1.31", CONF_BASE_PATH: "/ipp/print"}, )
)
assert result["type"] == FlowResultType.CREATE_ENTRY assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "192.168.1.31" 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( async def test_full_zeroconf_flow_implementation(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test the full manual user flow from start to finish.""" """Test the full manual user flow from start to finish."""
mock_connection(aioclient_mock)
discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPP_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
@ -374,10 +400,9 @@ async def test_full_zeroconf_flow_implementation(
assert result["step_id"] == "zeroconf_confirm" assert result["step_id"] == "zeroconf_confirm"
assert result["type"] == FlowResultType.FORM 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 = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={}
result["flow_id"], user_input={} )
)
assert result["type"] == FlowResultType.CREATE_ENTRY assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "EPSON XP-6000 Series" 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( async def test_full_zeroconf_tls_flow_implementation(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_ipp_config_flow: MagicMock,
) -> None: ) -> None:
"""Test the full manual user flow from start to finish.""" """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) discovery_info = dataclasses.replace(MOCK_ZEROCONF_IPPS_SERVICE_INFO)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
@ -409,10 +433,9 @@ async def test_full_zeroconf_tls_flow_implementation(
assert result["type"] == FlowResultType.FORM assert result["type"] == FlowResultType.FORM
assert result["description_placeholders"] == {CONF_NAME: "EPSON XP-6000 Series"} 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 = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={}
result["flow_id"], user_input={} )
)
assert result["type"] == FlowResultType.CREATE_ENTRY assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == "EPSON XP-6000 Series" assert result["title"] == "EPSON XP-6000 Series"

View file

@ -1,33 +1,45 @@
"""Tests for the IPP integration.""" """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.components.ipp.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from . import init_integration from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
@patch(
"homeassistant.components.ipp.coordinator.IPP._request",
side_effect=IPPConnectionError,
)
async def test_config_entry_not_ready( async def test_config_entry_not_ready(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker mock_request: MagicMock, hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None: ) -> None:
"""Test the IPP configuration entry not ready.""" """Test the IPP configuration entry not ready."""
entry = await init_integration(hass, aioclient_mock, conn_error=True) mock_config_entry.add_to_hass(hass)
assert entry.state is ConfigEntryState.SETUP_RETRY await hass.config_entries.async_setup(mock_config_entry.entry_id)
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)
await hass.async_block_till_done() await hass.async_block_till_done()
assert entry.entry_id not in hass.data[DOMAIN] assert mock_request.call_count == 1
assert entry.state is ConfigEntryState.NOT_LOADED 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

View file

@ -1,119 +1,105 @@
"""Tests for the IPP sensor platform.""" """Tests for the IPP sensor platform."""
from datetime import datetime from unittest.mock import AsyncMock
from unittest.mock import patch
from homeassistant.components.ipp.const import DOMAIN import pytest
from homeassistant.components.sensor import (
ATTR_OPTIONS as SENSOR_ATTR_OPTIONS, from homeassistant.components.sensor import ATTR_OPTIONS
DOMAIN as SENSOR_DOMAIN,
)
from homeassistant.const import ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, PERCENTAGE from homeassistant.const import ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, PERCENTAGE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from . import init_integration, mock_connection from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
@pytest.mark.freeze_time("2019-11-11 09:10:32+00:00")
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_sensors( async def test_sensors(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
entity_registry: er.EntityRegistry,
init_integration: MockConfigEntry,
) -> None: ) -> None:
"""Test the creation and values of the IPP sensors.""" """Test the creation and values of the IPP sensors."""
mock_connection(aioclient_mock) state = hass.states.get("sensor.test_ha_1000_series")
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")
assert state assert state
assert state.attributes.get(ATTR_ICON) == "mdi:printer" assert state.attributes.get(ATTR_ICON) == "mdi:printer"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None 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
assert entry.translation_key == "printer" 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
assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_ICON) == "mdi:water"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE
assert state.state == "58" 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
assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_ICON) == "mdi:water"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE
assert state.state == "98" 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
assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_ICON) == "mdi:water"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE
assert state.state == "91" 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
assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_ICON) == "mdi:water"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE
assert state.state == "95" 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
assert state.attributes.get(ATTR_ICON) == "mdi:water" assert state.attributes.get(ATTR_ICON) == "mdi:water"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is PERCENTAGE
assert state.state == "73" 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
assert state.attributes.get(ATTR_ICON) == "mdi:clock-outline" assert state.attributes.get(ATTR_ICON) == "mdi:clock-outline"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None 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
assert entry.unique_id == "cfe92100-67c4-11d4-a45f-f8d027761251_uptime" assert entry.unique_id == "cfe92100-67c4-11d4-a45f-f8d027761251_uptime"
async def test_disabled_by_default_sensors( async def test_disabled_by_default_sensors(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
) -> None: ) -> None:
"""Test the disabled by default IPP sensors.""" """Test the disabled by default IPP sensors."""
await init_integration(hass, aioclient_mock)
registry = er.async_get(hass) 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 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
assert entry.disabled assert entry.disabled
assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION
async def test_missing_entry_unique_id( async def test_missing_entry_unique_id(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_ipp: AsyncMock,
) -> None: ) -> None:
"""Test the unique_id of IPP sensor when printer is missing identifiers.""" """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) 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
assert entity.unique_id == f"{entry.entry_id}_printer" assert entity.unique_id == f"{mock_config_entry.entry_id}_printer"