Abort ESPHome connection when both name and mac address do not match (#98787)
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
"""ESPHome set up tests."""
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from aioesphomeapi import DeviceInfo
|
||||
|
||||
from homeassistant.components.esphome import DOMAIN
|
||||
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT
|
||||
@@ -10,29 +8,6 @@ from homeassistant.core import HomeAssistant
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_unique_id_updated_to_mac(
|
||||
hass: HomeAssistant, mock_client, mock_zeroconf: None
|
||||
) -> None:
|
||||
"""Test we update config entry unique ID to MAC address."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: "test.local", CONF_PORT: 6053, CONF_PASSWORD: ""},
|
||||
unique_id="mock-config-name",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(
|
||||
mac_address="1122334455aa",
|
||||
)
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.unique_id == "11:22:33:44:55:aa"
|
||||
|
||||
|
||||
async def test_delete_entry(
|
||||
hass: HomeAssistant, mock_client, mock_zeroconf: None
|
||||
) -> None:
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
"""Test ESPHome manager."""
|
||||
from collections.abc import Awaitable, Callable
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from aioesphomeapi import APIClient, EntityInfo, EntityState, UserService
|
||||
from aioesphomeapi import APIClient, DeviceInfo, EntityInfo, EntityState, UserService
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.esphome.const import DOMAIN, STABLE_BLE_VERSION_STR
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components import dhcp
|
||||
from homeassistant.components.esphome.const import (
|
||||
CONF_DEVICE_NAME,
|
||||
DOMAIN,
|
||||
STABLE_BLE_VERSION_STR,
|
||||
)
|
||||
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
|
||||
from .conftest import MockESPHomeDevice
|
||||
@@ -113,3 +122,213 @@ async def test_esphome_device_with_current_bluetooth(
|
||||
)
|
||||
is None
|
||||
)
|
||||
|
||||
|
||||
async def test_unique_id_updated_to_mac(
|
||||
hass: HomeAssistant, mock_client, mock_zeroconf: None
|
||||
) -> None:
|
||||
"""Test we update config entry unique ID to MAC address."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: "test.local", CONF_PORT: 6053, CONF_PASSWORD: ""},
|
||||
unique_id="mock-config-name",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(
|
||||
mac_address="1122334455aa",
|
||||
)
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.unique_id == "11:22:33:44:55:aa"
|
||||
|
||||
|
||||
async def test_unique_id_not_updated_if_name_same_and_already_mac(
|
||||
hass: HomeAssistant, mock_client: APIClient, mock_zeroconf: None
|
||||
) -> None:
|
||||
"""Test we never update the entry unique ID event if the name is the same."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "test.local",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(mac_address="1122334455ab", name="test")
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Mac should never update
|
||||
assert entry.unique_id == "11:22:33:44:55:aa"
|
||||
|
||||
|
||||
async def test_unique_id_updated_if_name_unset_and_already_mac(
|
||||
hass: HomeAssistant, mock_client: APIClient, mock_zeroconf: None
|
||||
) -> None:
|
||||
"""Test we never update config entry unique ID even if the name is unset."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: "test.local", CONF_PORT: 6053, CONF_PASSWORD: ""},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(mac_address="1122334455ab", name="test")
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Mac should never update
|
||||
assert entry.unique_id == "11:22:33:44:55:aa"
|
||||
|
||||
|
||||
async def test_unique_id_not_updated_if_name_different_and_already_mac(
|
||||
hass: HomeAssistant, mock_client: APIClient, mock_zeroconf: None
|
||||
) -> None:
|
||||
"""Test we do not update config entry unique ID if the name is different."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "test.local",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(mac_address="1122334455ab", name="different")
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Mac should not be updated because name is different
|
||||
assert entry.unique_id == "11:22:33:44:55:aa"
|
||||
# Name should not be updated either
|
||||
assert entry.data[CONF_DEVICE_NAME] == "test"
|
||||
|
||||
|
||||
async def test_name_updated_only_if_mac_matches(
|
||||
hass: HomeAssistant, mock_client: APIClient, mock_zeroconf: None
|
||||
) -> None:
|
||||
"""Test we update config entry name only if the mac matches."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "test.local",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "old",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(mac_address="1122334455aa", name="new")
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.unique_id == "11:22:33:44:55:aa"
|
||||
assert entry.data[CONF_DEVICE_NAME] == "new"
|
||||
|
||||
|
||||
async def test_name_updated_only_if_mac_was_unset(
|
||||
hass: HomeAssistant, mock_client: APIClient, mock_zeroconf: None
|
||||
) -> None:
|
||||
"""Test we update config entry name if the old unique id was not a mac."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "test.local",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "old",
|
||||
},
|
||||
unique_id="notamac",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(mac_address="1122334455aa", name="new")
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.unique_id == "11:22:33:44:55:aa"
|
||||
assert entry.data[CONF_DEVICE_NAME] == "new"
|
||||
|
||||
|
||||
async def test_connection_aborted_wrong_device(
|
||||
hass: HomeAssistant,
|
||||
mock_client: APIClient,
|
||||
mock_zeroconf: None,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test we abort the connection if the unique id is a mac and neither name or mac match."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_HOST: "192.168.43.183",
|
||||
CONF_PORT: 6053,
|
||||
CONF_PASSWORD: "",
|
||||
CONF_DEVICE_NAME: "test",
|
||||
},
|
||||
unique_id="11:22:33:44:55:aa",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_client.device_info = AsyncMock(
|
||||
return_value=DeviceInfo(mac_address="1122334455ab", name="different")
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert (
|
||||
"Unexpected device found at 192.168.43.183; expected `test` "
|
||||
"with mac address `11:22:33:44:55:aa`, found `different` "
|
||||
"with mac address `11:22:33:44:55:ab`" in caplog.text
|
||||
)
|
||||
|
||||
caplog.clear()
|
||||
# Make sure discovery triggers a reconnect to the correct device
|
||||
service_info = dhcp.DhcpServiceInfo(
|
||||
ip="192.168.43.184",
|
||||
hostname="test",
|
||||
macaddress="1122334455aa",
|
||||
)
|
||||
new_info = AsyncMock(
|
||||
return_value=DeviceInfo(mac_address="1122334455aa", name="test")
|
||||
)
|
||||
mock_client.device_info = new_info
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"esphome", context={"source": config_entries.SOURCE_DHCP}, data=service_info
|
||||
)
|
||||
|
||||
assert result["type"] == FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert entry.data[CONF_HOST] == "192.168.43.184"
|
||||
await hass.async_block_till_done()
|
||||
assert len(new_info.mock_calls) == 1
|
||||
assert "Unexpected device found at" not in caplog.text
|
||||
|
||||
Reference in New Issue
Block a user