Refactor tests for Brother integration (#117377)

* Refactor tests - step 1

* Remove fixture

* Refactor test_init

* Refactor test_diagnostics

* Refactor test_config_flow

* Increase test coverage

* Cleaning

* Cleaning

* Check config entry state in test_async_setup_entry

* Simplify patching

* Use AsyncMock when patching

---------

Co-authored-by: Maciej Bieniek <478555+bieniu@users.noreply.github.com>
This commit is contained in:
Maciej Bieniek 2024-05-19 20:41:47 +02:00 committed by GitHub
parent d2008ffdd7
commit 826f6c6f7e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 332 additions and 418 deletions

View file

@ -1,37 +1,15 @@
"""Tests for Brother Printer integration.""" """Tests for Brother Printer integration."""
import json
from unittest.mock import patch
from homeassistant.components.brother.const import DOMAIN
from homeassistant.const import CONF_HOST, CONF_TYPE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture from tests.common import MockConfigEntry
async def init_integration( async def init_integration(
hass: HomeAssistant, skip_setup: bool = False hass: HomeAssistant, entry: MockConfigEntry
) -> MockConfigEntry: ) -> MockConfigEntry:
"""Set up the Brother integration in Home Assistant.""" """Set up the Brother integration in Home Assistant."""
entry = MockConfigEntry(
domain=DOMAIN,
title="HL-L2340DW 0123456789",
unique_id="0123456789",
data={CONF_HOST: "localhost", CONF_TYPE: "laser"},
)
entry.add_to_hass(hass) entry.add_to_hass(hass)
if not skip_setup: await hass.config_entries.async_setup(entry.entry_id)
with ( await hass.async_block_till_done()
patch("brother.Brother.initialize"),
patch(
"brother.Brother._get_data",
return_value=json.loads(load_fixture("printer_data.json", "brother")),
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
return entry

View file

@ -1,10 +1,81 @@
"""Test fixtures for brother.""" """Test fixtures for brother."""
from collections.abc import Generator from collections.abc import Generator
from datetime import UTC, datetime
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from brother import BrotherSensors
import pytest import pytest
from homeassistant.components.brother.const import DOMAIN
from homeassistant.const import CONF_HOST, CONF_TYPE
from tests.common import MockConfigEntry
BROTHER_DATA = BrotherSensors(
belt_unit_remaining_life=97,
belt_unit_remaining_pages=48436,
black_counter=None,
black_drum_counter=1611,
black_drum_remaining_life=92,
black_drum_remaining_pages=16389,
black_ink_remaining=None,
black_ink_status=None,
black_ink=None,
black_toner_remaining=75,
black_toner_status=1,
black_toner=80,
bw_counter=709,
color_counter=902,
cyan_counter=None,
cyan_drum_counter=1611,
cyan_drum_remaining_life=92,
cyan_drum_remaining_pages=16389,
cyan_ink_remaining=None,
cyan_ink_status=None,
cyan_ink=None,
cyan_toner_remaining=10,
cyan_toner_status=1,
cyan_toner=10,
drum_counter=986,
drum_remaining_life=92,
drum_remaining_pages=11014,
drum_status=1,
duplex_unit_pages_counter=538,
fuser_remaining_life=97,
fuser_unit_remaining_pages=None,
image_counter=None,
laser_remaining_life=None,
laser_unit_remaining_pages=48389,
magenta_counter=None,
magenta_drum_counter=1611,
magenta_drum_remaining_life=92,
magenta_drum_remaining_pages=16389,
magenta_ink_remaining=None,
magenta_ink_status=None,
magenta_ink=None,
magenta_toner_remaining=8,
magenta_toner_status=2,
magenta_toner=10,
page_counter=986,
pf_kit_1_remaining_life=98,
pf_kit_1_remaining_pages=48741,
pf_kit_mp_remaining_life=None,
pf_kit_mp_remaining_pages=None,
status="waiting",
uptime=datetime(2024, 3, 3, 15, 4, 24, tzinfo=UTC),
yellow_counter=None,
yellow_drum_counter=1611,
yellow_drum_remaining_life=92,
yellow_drum_remaining_pages=16389,
yellow_ink_remaining=None,
yellow_ink_status=None,
yellow_ink=None,
yellow_toner_remaining=2,
yellow_toner_status=2,
yellow_toner=10,
)
@pytest.fixture @pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock, None, None]: def mock_setup_entry() -> Generator[AsyncMock, None, None]:
@ -13,3 +84,34 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"homeassistant.components.brother.async_setup_entry", return_value=True "homeassistant.components.brother.async_setup_entry", return_value=True
) as mock_setup_entry: ) as mock_setup_entry:
yield mock_setup_entry yield mock_setup_entry
@pytest.fixture
def mock_brother_client() -> Generator[AsyncMock, None, None]:
"""Mock Brother client."""
with (
patch("homeassistant.components.brother.Brother", autospec=True) as mock_client,
patch(
"homeassistant.components.brother.config_flow.Brother",
new=mock_client,
),
):
client = mock_client.create.return_value
client.async_update.return_value = BROTHER_DATA
client.serial = "0123456789"
client.mac = "AA:BB:CC:DD:EE:FF"
client.model = "HL-L2340DW"
client.firmware = "1.2.3"
yield client
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Mock a config entry."""
return MockConfigEntry(
domain=DOMAIN,
title="HL-L2340DW 0123456789",
unique_id="0123456789",
data={CONF_HOST: "localhost", CONF_TYPE: "laser"},
)

View file

@ -1,77 +0,0 @@
{
"1.3.6.1.2.1.1.3.0": "413613515",
"1.3.6.1.2.1.43.10.2.1.4.1.1": "986",
"1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.10.0": [
"000104000003da",
"010104000002c5",
"02010400000386",
"0601040000021a",
"0701040000012d",
"080104000000ed"
],
"1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.17.0": "1.17",
"1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.8.0": [
"110104000003da",
"31010400000001",
"32010400000001",
"33010400000002",
"34010400000002",
"35010400000001",
"410104000023f0",
"54010400000001",
"55010400000001",
"63010400000001",
"68010400000001",
"690104000025e4",
"6a0104000025e4",
"6d010400002648",
"6f010400001d4c",
"700104000003e8",
"71010400000320",
"720104000000c8",
"7301040000064b",
"7401040000064b",
"7501040000064b",
"76010400000001",
"77010400000001",
"78010400000001",
"790104000023f0",
"7a0104000023f0",
"7b0104000023f0",
"7e01040000064b",
"800104000023f0",
"81010400000050",
"8201040000000a",
"8301040000000a",
"8401040000000a",
"8601040000000a"
],
"1.3.6.1.4.1.2435.2.3.9.1.1.7.0": "MFG:Brother;CMD:PJL,HBP,URF;MDL:HL-L2340DW series;CLS:PRINTER;CID:Brother Laser Type1;URF:W8,CP1,IS4-1,MT1-3-4-5-8,OB10,PQ4,RS300-600,V1.3,DM1;",
"1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.11.0": [
"7301040000bd05",
"7701040000be65",
"82010400002b06",
"8801040000bd34",
"a4010400004005",
"a5010400004005",
"a6010400004005",
"a7010400004005"
],
"1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.21.0": [
"00002302000025",
"00020016010200",
"00210200022202",
"020000a1040000"
],
"1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.20.0": [
"00a40100a50100",
"0100a301008801",
"01017301007701",
"870100a10100a2",
"a60100a70100a0"
],
"1.3.6.1.4.1.2435.2.3.9.4.2.1.5.5.1.0": "0123456789",
"1.3.6.1.4.1.2435.2.3.9.4.2.1.5.4.5.2.0": "WAITING ",
"1.3.6.1.2.1.43.7.1.1.4.1.1": "2004",
"1.3.6.1.2.1.2.2.1.6.1": "aa:bb:cc:dd:ee:ff"
}

View file

@ -52,7 +52,7 @@
'pf_kit_mp_remaining_life': None, 'pf_kit_mp_remaining_life': None,
'pf_kit_mp_remaining_pages': None, 'pf_kit_mp_remaining_pages': None,
'status': 'waiting', 'status': 'waiting',
'uptime': '2019-09-24T12:14:56+00:00', 'uptime': '2024-03-03T15:04:24+00:00',
'yellow_counter': None, 'yellow_counter': None,
'yellow_drum_counter': 1611, 'yellow_drum_counter': 1611,
'yellow_drum_remaining_life': 92, 'yellow_drum_remaining_life': 92,
@ -64,7 +64,7 @@
'yellow_toner_remaining': 2, 'yellow_toner_remaining': 2,
'yellow_toner_status': 2, 'yellow_toner_status': 2,
}), }),
'firmware': '1.17', 'firmware': '1.2.3',
'info': dict({ 'info': dict({
'host': 'localhost', 'host': 'localhost',
'type': 'laser', 'type': 'laser',

View file

@ -1,8 +1,7 @@
"""Define tests for the Brother Printer config flow.""" """Define tests for the Brother Printer config flow."""
from ipaddress import ip_address from ipaddress import ip_address
import json from unittest.mock import AsyncMock, patch
from unittest.mock import patch
from brother import SnmpError, UnsupportedModelError from brother import SnmpError, UnsupportedModelError
import pytest import pytest
@ -14,7 +13,9 @@ from homeassistant.const import CONF_HOST, CONF_TYPE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry, load_fixture from . import init_integration
from tests.common import MockConfigEntry
CONFIG = {CONF_HOST: "127.0.0.1", CONF_TYPE: "laser"} CONFIG = {CONF_HOST: "127.0.0.1", CONF_TYPE: "laser"}
@ -31,65 +32,21 @@ async def test_show_form(hass: HomeAssistant) -> None:
assert result["step_id"] == "user" assert result["step_id"] == "user"
async def test_create_entry_with_hostname(hass: HomeAssistant) -> None: @pytest.mark.parametrize("host", ["example.local", "127.0.0.1", "2001:db8::1428:57ab"])
"""Test that the user step works with printer hostname.""" async def test_create_entry(
with ( hass: HomeAssistant, host: str, mock_brother_client: AsyncMock
patch("brother.Brother.initialize"), ) -> None:
patch( """Test that the user step works with printer hostname/IPv4/IPv6."""
"brother.Brother._get_data", result = await hass.config_entries.flow.async_init(
return_value=json.loads(load_fixture("printer_data.json", "brother")), DOMAIN,
), context={"source": SOURCE_USER},
): data={CONF_HOST: host, CONF_TYPE: "laser"},
result = await hass.config_entries.flow.async_init( )
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_HOST: "example.local", CONF_TYPE: "laser"},
)
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "HL-L2340DW 0123456789" assert result["title"] == "HL-L2340DW 0123456789"
assert result["data"][CONF_HOST] == "example.local" assert result["data"][CONF_HOST] == host
assert result["data"][CONF_TYPE] == "laser" assert result["data"][CONF_TYPE] == "laser"
async def test_create_entry_with_ipv4_address(hass: HomeAssistant) -> None:
"""Test that the user step works with printer IPv4 address."""
with (
patch("brother.Brother.initialize"),
patch(
"brother.Brother._get_data",
return_value=json.loads(load_fixture("printer_data.json", "brother")),
),
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "HL-L2340DW 0123456789"
assert result["data"][CONF_HOST] == "127.0.0.1"
assert result["data"][CONF_TYPE] == "laser"
async def test_create_entry_with_ipv6_address(hass: HomeAssistant) -> None:
"""Test that the user step works with printer IPv6 address."""
with (
patch("brother.Brother.initialize"),
patch(
"brother.Brother._get_data",
return_value=json.loads(load_fixture("printer_data.json", "brother")),
),
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_HOST: "2001:db8::1428:57ab", CONF_TYPE: "laser"},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "HL-L2340DW 0123456789"
assert result["data"][CONF_HOST] == "2001:db8::1428:57ab"
assert result["data"][CONF_TYPE] == "laser"
async def test_invalid_hostname(hass: HomeAssistant) -> None: async def test_invalid_hostname(hass: HomeAssistant) -> None:
@ -103,97 +60,87 @@ async def test_invalid_hostname(hass: HomeAssistant) -> None:
assert result["errors"] == {CONF_HOST: "wrong_host"} assert result["errors"] == {CONF_HOST: "wrong_host"}
@pytest.mark.parametrize("exc", [ConnectionError, TimeoutError]) @pytest.mark.parametrize(
async def test_connection_error(hass: HomeAssistant, exc: Exception) -> None: ("exc", "base_error"),
[
(ConnectionError, "cannot_connect"),
(TimeoutError, "cannot_connect"),
(SnmpError("SNMP error"), "snmp_error"),
],
)
async def test_errors(
hass: HomeAssistant, exc: Exception, base_error: str, mock_brother_client: AsyncMock
) -> None:
"""Test connection to host error.""" """Test connection to host error."""
with ( mock_brother_client.async_update.side_effect = exc
patch("brother.Brother.initialize"),
patch("brother.Brother._get_data", side_effect=exc),
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["errors"] == {"base": "cannot_connect"} result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["errors"] == {"base": base_error}
async def test_snmp_error(hass: HomeAssistant) -> None:
"""Test SNMP error."""
with (
patch("brother.Brother.initialize"),
patch("brother.Brother._get_data", side_effect=SnmpError("error")),
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["errors"] == {"base": "snmp_error"}
async def test_unsupported_model_error(hass: HomeAssistant) -> None: async def test_unsupported_model_error(hass: HomeAssistant) -> None:
"""Test unsupported printer model error.""" """Test unsupported printer model error."""
with ( with patch(
patch("brother.Brother.initialize"), "homeassistant.components.brother.Brother.create",
patch("brother.Brother._get_data", side_effect=UnsupportedModelError("error")), new=AsyncMock(side_effect=UnsupportedModelError("error")),
): ):
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
) )
assert result["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "unsupported_model" assert result["reason"] == "unsupported_model"
async def test_device_exists_abort(hass: HomeAssistant) -> None: async def test_device_exists_abort(
hass: HomeAssistant,
mock_brother_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test we abort config flow if Brother printer already configured.""" """Test we abort config flow if Brother printer already configured."""
with ( await init_integration(hass, mock_config_entry)
patch("brother.Brother.initialize"),
patch(
"brother.Brother._get_data",
return_value=json.loads(load_fixture("printer_data.json", "brother")),
),
):
MockConfigEntry(domain=DOMAIN, unique_id="0123456789", data=CONFIG).add_to_hass(
hass
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["type"] is FlowResultType.ABORT result = await hass.config_entries.flow.async_init(
assert result["reason"] == "already_configured" DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
@pytest.mark.parametrize("exc", [ConnectionError, TimeoutError, SnmpError("error")]) @pytest.mark.parametrize("exc", [ConnectionError, TimeoutError, SnmpError("error")])
async def test_zeroconf_exception(hass: HomeAssistant, exc: Exception) -> None: async def test_zeroconf_exception(
hass: HomeAssistant, exc: Exception, mock_brother_client: AsyncMock
) -> None:
"""Test we abort zeroconf flow on exception.""" """Test we abort zeroconf flow on exception."""
with ( mock_brother_client.async_update.side_effect = exc
patch("brother.Brother.initialize"),
patch("brother.Brother._get_data", side_effect=exc),
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_ZEROCONF},
data=zeroconf.ZeroconfServiceInfo(
ip_address=ip_address("127.0.0.1"),
ip_addresses=[ip_address("127.0.0.1")],
hostname="example.local.",
name="Brother Printer",
port=None,
properties={},
type="mock_type",
),
)
assert result["type"] is FlowResultType.ABORT result = await hass.config_entries.flow.async_init(
assert result["reason"] == "cannot_connect" DOMAIN,
context={"source": SOURCE_ZEROCONF},
data=zeroconf.ZeroconfServiceInfo(
ip_address=ip_address("127.0.0.1"),
ip_addresses=[ip_address("127.0.0.1")],
hostname="example.local.",
name="Brother Printer",
port=None,
properties={},
type="mock_type",
),
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "cannot_connect"
async def test_zeroconf_unsupported_model(hass: HomeAssistant) -> None: async def test_zeroconf_unsupported_model(hass: HomeAssistant) -> None:
"""Test unsupported printer model error.""" """Test unsupported printer model error."""
with ( with patch(
patch("brother.Brother.initialize"), "homeassistant.components.brother.Brother.create",
patch("brother.Brother._get_data") as mock_get_data, new=AsyncMock(side_effect=UnsupportedModelError("error")),
): ):
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
@ -209,46 +156,37 @@ async def test_zeroconf_unsupported_model(hass: HomeAssistant) -> None:
), ),
) )
assert result["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "unsupported_model" assert result["reason"] == "unsupported_model"
assert len(mock_get_data.mock_calls) == 0
async def test_zeroconf_device_exists_abort(hass: HomeAssistant) -> None: async def test_zeroconf_device_exists_abort(
hass: HomeAssistant,
mock_brother_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test we abort zeroconf flow if Brother printer already configured.""" """Test we abort zeroconf flow if Brother printer already configured."""
with ( await init_integration(hass, mock_config_entry)
patch("brother.Brother.initialize"),
patch( result = await hass.config_entries.flow.async_init(
"brother.Brother._get_data", DOMAIN,
return_value=json.loads(load_fixture("printer_data.json", "brother")), context={"source": SOURCE_ZEROCONF},
data=zeroconf.ZeroconfServiceInfo(
ip_address=ip_address("127.0.0.1"),
ip_addresses=[ip_address("127.0.0.1")],
hostname="example.local.",
name="Brother Printer",
port=None,
properties={},
type="mock_type",
), ),
): )
entry = MockConfigEntry(
domain=DOMAIN,
unique_id="0123456789",
data={CONF_HOST: "example.local", CONF_TYPE: "laser"},
)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init( assert result["type"] is FlowResultType.ABORT
DOMAIN, assert result["reason"] == "already_configured"
context={"source": SOURCE_ZEROCONF},
data=zeroconf.ZeroconfServiceInfo(
ip_address=ip_address("127.0.0.1"),
ip_addresses=[ip_address("127.0.0.1")],
hostname="example.local.",
name="Brother Printer",
port=None,
properties={},
type="mock_type",
),
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
# Test config entry got updated with latest IP # Test config entry got updated with latest IP
assert entry.data["host"] == "127.0.0.1" assert mock_config_entry.data[CONF_HOST] == "127.0.0.1"
async def test_zeroconf_no_probe_existing_device(hass: HomeAssistant) -> None: async def test_zeroconf_no_probe_existing_device(hass: HomeAssistant) -> None:
@ -256,8 +194,8 @@ async def test_zeroconf_no_probe_existing_device(hass: HomeAssistant) -> None:
entry = MockConfigEntry(domain=DOMAIN, unique_id="0123456789", data=CONFIG) entry = MockConfigEntry(domain=DOMAIN, unique_id="0123456789", data=CONFIG)
entry.add_to_hass(hass) entry.add_to_hass(hass)
with ( with (
patch("brother.Brother.initialize"), patch("homeassistant.components.brother.Brother.initialize"),
patch("brother.Brother._get_data") as mock_get_data, patch("homeassistant.components.brother.Brother._get_data") as mock_get_data,
): ):
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
@ -279,39 +217,34 @@ async def test_zeroconf_no_probe_existing_device(hass: HomeAssistant) -> None:
assert len(mock_get_data.mock_calls) == 0 assert len(mock_get_data.mock_calls) == 0
async def test_zeroconf_confirm_create_entry(hass: HomeAssistant) -> None: async def test_zeroconf_confirm_create_entry(
hass: HomeAssistant, mock_brother_client: AsyncMock
) -> None:
"""Test zeroconf confirmation and create config entry.""" """Test zeroconf confirmation and create config entry."""
with ( result = await hass.config_entries.flow.async_init(
patch("brother.Brother.initialize"), DOMAIN,
patch( context={"source": SOURCE_ZEROCONF},
"brother.Brother._get_data", data=zeroconf.ZeroconfServiceInfo(
return_value=json.loads(load_fixture("printer_data.json", "brother")), ip_address=ip_address("127.0.0.1"),
ip_addresses=[ip_address("127.0.0.1")],
hostname="example.local.",
name="Brother Printer",
port=None,
properties={},
type="mock_type",
), ),
): )
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_ZEROCONF},
data=zeroconf.ZeroconfServiceInfo(
ip_address=ip_address("127.0.0.1"),
ip_addresses=[ip_address("127.0.0.1")],
hostname="example.local.",
name="Brother Printer",
port=None,
properties={},
type="mock_type",
),
)
assert result["step_id"] == "zeroconf_confirm" assert result["step_id"] == "zeroconf_confirm"
assert result["description_placeholders"]["model"] == "HL-L2340DW" assert result["description_placeholders"]["model"] == "HL-L2340DW"
assert result["description_placeholders"]["serial_number"] == "0123456789" assert result["description_placeholders"]["serial_number"] == "0123456789"
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_TYPE: "laser"} result["flow_id"], user_input={CONF_TYPE: "laser"}
) )
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "HL-L2340DW 0123456789" assert result["title"] == "HL-L2340DW 0123456789"
assert result["data"][CONF_HOST] == "127.0.0.1" assert result["data"][CONF_HOST] == "127.0.0.1"
assert result["data"][CONF_TYPE] == "laser" assert result["data"][CONF_TYPE] == "laser"

View file

@ -1,17 +1,14 @@
"""Test Brother diagnostics.""" """Test Brother diagnostics."""
from datetime import datetime from unittest.mock import AsyncMock
import json
from unittest.mock import Mock, patch
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.util.dt import UTC
from . import init_integration from . import init_integration
from tests.common import load_fixture from tests.common import MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
@ -19,23 +16,15 @@ from tests.typing import ClientSessionGenerator
async def test_entry_diagnostics( async def test_entry_diagnostics(
hass: HomeAssistant, hass: HomeAssistant,
hass_client: ClientSessionGenerator, hass_client: ClientSessionGenerator,
mock_brother_client: AsyncMock,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
entry = await init_integration(hass, skip_setup=True) await init_integration(hass, mock_config_entry)
test_time = datetime(2019, 11, 11, 9, 10, 32, tzinfo=UTC) result = await get_diagnostics_for_config_entry(
with ( hass, hass_client, mock_config_entry
patch("brother.Brother.initialize"), )
patch("brother.datetime", now=Mock(return_value=test_time)),
patch(
"brother.Brother._get_data",
return_value=json.loads(load_fixture("printer_data.json", "brother")),
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
result = await get_diagnostics_for_config_entry(hass, hass_client, entry)
assert result == snapshot assert result == snapshot

View file

@ -1,13 +1,13 @@
"""Test init of Brother integration.""" """Test init of Brother integration."""
from unittest.mock import patch from unittest.mock import AsyncMock, patch
from brother import SnmpError from brother import SnmpError
import pytest import pytest
from homeassistant.components.brother.const import DOMAIN from homeassistant.components.brother.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_HOST, CONF_TYPE, STATE_UNAVAILABLE from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from . import init_integration from . import init_integration
@ -15,61 +15,76 @@ from . import init_integration
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
async def test_async_setup_entry(hass: HomeAssistant) -> None: async def test_async_setup_entry(
hass: HomeAssistant,
mock_brother_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test a successful setup entry.""" """Test a successful setup entry."""
await init_integration(hass) await init_integration(hass, mock_config_entry)
state = hass.states.get("sensor.hl_l2340dw_status") assert mock_config_entry.state is ConfigEntryState.LOADED
assert state is not None
assert state.state != STATE_UNAVAILABLE
assert state.state == "waiting"
async def test_config_not_ready(hass: HomeAssistant) -> None: async def test_config_not_ready(
hass: HomeAssistant,
mock_brother_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test for setup failure if connection to broker is missing.""" """Test for setup failure if connection to broker is missing."""
entry = MockConfigEntry( mock_brother_client.async_update.side_effect = ConnectionError
domain=DOMAIN,
title="HL-L2340DW 0123456789",
unique_id="0123456789",
data={CONF_HOST: "localhost", CONF_TYPE: "laser"},
)
with ( await init_integration(hass, mock_config_entry)
patch("brother.Brother.initialize"),
patch("brother.Brother._get_data", side_effect=ConnectionError()), assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
):
entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id)
assert entry.state is ConfigEntryState.SETUP_RETRY
@pytest.mark.parametrize("exc", [(SnmpError("SNMP Error")), (ConnectionError)]) @pytest.mark.parametrize("exc", [(SnmpError("SNMP Error")), (ConnectionError)])
async def test_error_on_init(hass: HomeAssistant, exc: Exception) -> None: async def test_error_on_init(
hass: HomeAssistant, exc: Exception, mock_config_entry: MockConfigEntry
) -> None:
"""Test for error on init.""" """Test for error on init."""
entry = MockConfigEntry( with patch(
domain=DOMAIN, "homeassistant.components.brother.Brother.create",
title="HL-L2340DW 0123456789", new=AsyncMock(side_effect=exc),
unique_id="0123456789", ):
data={CONF_HOST: "localhost", CONF_TYPE: "laser"}, await init_integration(hass, mock_config_entry)
)
with patch("brother.Brother.initialize", side_effect=exc): assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id)
assert entry.state is ConfigEntryState.SETUP_RETRY
async def test_unload_entry(hass: HomeAssistant) -> None: async def test_unload_entry(
hass: HomeAssistant,
mock_brother_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test successful unload of entry.""" """Test successful unload of entry."""
entry = await init_integration(hass) await init_integration(hass, mock_config_entry)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1 assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert entry.state is ConfigEntryState.LOADED assert mock_config_entry.state is ConfigEntryState.LOADED
with patch("homeassistant.components.brother.lcd.unconfigure") as mock_unconfigure: with patch("homeassistant.components.brother.lcd.unconfigure") as mock_unconfigure:
assert await hass.config_entries.async_unload(entry.entry_id) assert await hass.config_entries.async_unload(mock_config_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
assert mock_unconfigure.called assert mock_unconfigure.called
assert entry.state is ConfigEntryState.NOT_LOADED assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
assert not hass.data.get(DOMAIN) assert not hass.data.get(DOMAIN)
async def test_unconfigure_snmp_engine_on_ha_stop(
hass: HomeAssistant,
mock_brother_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test that the SNMP engine is unconfigured when HA stops."""
await init_integration(hass, mock_config_entry)
with patch(
"homeassistant.components.brother.utils.lcd.unconfigure"
) as mock_unconfigure:
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
await hass.async_block_till_done()
assert mock_unconfigure.called

View file

@ -1,23 +1,19 @@
"""Test sensor of Brother integration.""" """Test sensor of Brother integration."""
from datetime import timedelta from unittest.mock import AsyncMock, patch
import json
from unittest.mock import patch
from freezegun.api import FrozenDateTimeFactory from freezegun.api import FrozenDateTimeFactory
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from homeassistant.components.brother.const import DOMAIN from homeassistant.components.brother.const import DOMAIN, UPDATE_INTERVAL
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, Platform from homeassistant.const import STATE_UNAVAILABLE, Platform
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.setup import async_setup_component
from homeassistant.util.dt import utcnow
from . import init_integration from . import init_integration
from tests.common import async_fire_time_changed, load_fixture, snapshot_platform from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
async def test_sensors( async def test_sensors(
@ -25,78 +21,56 @@ async def test_sensors(
entity_registry: er.EntityRegistry, entity_registry: er.EntityRegistry,
entity_registry_enabled_by_default: None, entity_registry_enabled_by_default: None,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
freezer: FrozenDateTimeFactory, mock_brother_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None: ) -> None:
"""Test states of the sensors.""" """Test states of the sensors."""
hass.config.set_time_zone("UTC")
freezer.move_to("2024-04-20 12:00:00+00:00")
with patch("homeassistant.components.brother.PLATFORMS", [Platform.SENSOR]): with patch("homeassistant.components.brother.PLATFORMS", [Platform.SENSOR]):
entry = await init_integration(hass) await init_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, entry.entry_id) await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
async def test_availability(hass: HomeAssistant) -> None: async def test_availability(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
mock_brother_client: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Ensure that we mark the entities unavailable correctly when device is offline.""" """Ensure that we mark the entities unavailable correctly when device is offline."""
await init_integration(hass) entity_id = "sensor.hl_l2340dw_status"
await init_integration(hass, mock_config_entry)
state = hass.states.get("sensor.hl_l2340dw_status") state = hass.states.get(entity_id)
assert state assert state
assert state.state != STATE_UNAVAILABLE assert state.state != STATE_UNAVAILABLE
assert state.state == "waiting" assert state.state == "waiting"
future = utcnow() + timedelta(minutes=5) mock_brother_client.async_update.side_effect = ConnectionError
with ( freezer.tick(UPDATE_INTERVAL)
patch("brother.Brother.initialize"), async_fire_time_changed(hass)
patch("brother.Brother._get_data", side_effect=ConnectionError()), await hass.async_block_till_done()
):
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
state = hass.states.get("sensor.hl_l2340dw_status") state = hass.states.get(entity_id)
assert state assert state
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE
future = utcnow() + timedelta(minutes=10) mock_brother_client.async_update.side_effect = None
with ( freezer.tick(UPDATE_INTERVAL)
patch("brother.Brother.initialize"), async_fire_time_changed(hass)
patch( await hass.async_block_till_done()
"brother.Brother._get_data",
return_value=json.loads(load_fixture("printer_data.json", "brother")),
),
):
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
state = hass.states.get("sensor.hl_l2340dw_status") state = hass.states.get(entity_id)
assert state assert state
assert state.state != STATE_UNAVAILABLE assert state.state != STATE_UNAVAILABLE
assert state.state == "waiting" assert state.state == "waiting"
async def test_manual_update_entity(hass: HomeAssistant) -> None:
"""Test manual update entity via service homeassistant/update_entity."""
await init_integration(hass)
data = json.loads(load_fixture("printer_data.json", "brother"))
await async_setup_component(hass, "homeassistant", {})
with patch(
"homeassistant.components.brother.Brother.async_update", return_value=data
) as mock_update:
await hass.services.async_call(
"homeassistant",
"update_entity",
{ATTR_ENTITY_ID: ["sensor.hl_l2340dw_status"]},
blocking=True,
)
assert len(mock_update.mock_calls) == 1
async def test_unique_id_migration( async def test_unique_id_migration(
hass: HomeAssistant, entity_registry: er.EntityRegistry hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_config_entry: MockConfigEntry,
mock_brother_client: AsyncMock,
) -> None: ) -> None:
"""Test states of the unique_id migration.""" """Test states of the unique_id migration."""
@ -108,7 +82,7 @@ async def test_unique_id_migration(
disabled_by=None, disabled_by=None,
) )
await init_integration(hass) await init_integration(hass, mock_config_entry)
entry = entity_registry.async_get("sensor.hl_l2340dw_b_w_counter") entry = entity_registry.async_get("sensor.hl_l2340dw_b_w_counter")
assert entry assert entry