Add additional data source to dhcp (#48430)
This commit is contained in:
parent
23c7c4c977
commit
2ff94c8ed9
6 changed files with 235 additions and 60 deletions
|
@ -1,4 +1,5 @@
|
|||
"""Test the DHCP discovery integration."""
|
||||
import datetime
|
||||
import threading
|
||||
from unittest.mock import patch
|
||||
|
||||
|
@ -21,8 +22,9 @@ from homeassistant.const import (
|
|||
STATE_NOT_HOME,
|
||||
)
|
||||
from homeassistant.setup import async_setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import mock_coro
|
||||
from tests.common import async_fire_time_changed
|
||||
|
||||
# connect b8:b7:f1:6d:b5:33 192.168.210.56
|
||||
RAW_DHCP_REQUEST = (
|
||||
|
@ -59,9 +61,7 @@ async def test_dhcp_match_hostname_and_macaddress(hass):
|
|||
|
||||
packet = Ether(RAW_DHCP_REQUEST)
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
# Ensure no change is ignored
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
@ -84,9 +84,7 @@ async def test_dhcp_match_hostname(hass):
|
|||
|
||||
packet = Ether(RAW_DHCP_REQUEST)
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
||||
assert len(mock_init.mock_calls) == 1
|
||||
|
@ -107,9 +105,7 @@ async def test_dhcp_match_macaddress(hass):
|
|||
|
||||
packet = Ether(RAW_DHCP_REQUEST)
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
||||
assert len(mock_init.mock_calls) == 1
|
||||
|
@ -130,9 +126,7 @@ async def test_dhcp_nomatch(hass):
|
|||
|
||||
packet = Ether(RAW_DHCP_REQUEST)
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
||||
assert len(mock_init.mock_calls) == 0
|
||||
|
@ -146,9 +140,7 @@ async def test_dhcp_nomatch_hostname(hass):
|
|||
|
||||
packet = Ether(RAW_DHCP_REQUEST)
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
||||
assert len(mock_init.mock_calls) == 0
|
||||
|
@ -162,9 +154,7 @@ async def test_dhcp_nomatch_non_dhcp_packet(hass):
|
|||
|
||||
packet = Ether(b"")
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
||||
assert len(mock_init.mock_calls) == 0
|
||||
|
@ -187,9 +177,7 @@ async def test_dhcp_nomatch_non_dhcp_request_packet(hass):
|
|||
("hostname", b"connect"),
|
||||
]
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
||||
assert len(mock_init.mock_calls) == 0
|
||||
|
@ -212,9 +200,7 @@ async def test_dhcp_invalid_hostname(hass):
|
|||
("hostname", "connect"),
|
||||
]
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
||||
assert len(mock_init.mock_calls) == 0
|
||||
|
@ -237,9 +223,7 @@ async def test_dhcp_missing_hostname(hass):
|
|||
("hostname", None),
|
||||
]
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
||||
assert len(mock_init.mock_calls) == 0
|
||||
|
@ -262,9 +246,7 @@ async def test_dhcp_invalid_option(hass):
|
|||
("hostname"),
|
||||
]
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
dhcp_watcher.handle_dhcp_packet(packet)
|
||||
|
||||
assert len(mock_init.mock_calls) == 0
|
||||
|
@ -282,8 +264,8 @@ async def test_setup_and_stop(hass):
|
|||
|
||||
with patch("homeassistant.components.dhcp.AsyncSniffer.start") as start_call, patch(
|
||||
"homeassistant.components.dhcp._verify_l2socket_setup",
|
||||
), patch(
|
||||
"homeassistant.components.dhcp.compile_filter",
|
||||
), patch("homeassistant.components.dhcp.compile_filter",), patch(
|
||||
"homeassistant.components.dhcp.DiscoverHosts.async_discover"
|
||||
):
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -309,7 +291,7 @@ async def test_setup_fails_as_root(hass, caplog):
|
|||
with patch("os.geteuid", return_value=0), patch(
|
||||
"homeassistant.components.dhcp._verify_l2socket_setup",
|
||||
side_effect=Scapy_Exception,
|
||||
):
|
||||
), patch("homeassistant.components.dhcp.DiscoverHosts.async_discover"):
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -332,7 +314,7 @@ async def test_setup_fails_non_root(hass, caplog):
|
|||
with patch("os.geteuid", return_value=10), patch(
|
||||
"homeassistant.components.dhcp._verify_l2socket_setup",
|
||||
side_effect=Scapy_Exception,
|
||||
):
|
||||
), patch("homeassistant.components.dhcp.DiscoverHosts.async_discover"):
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
||||
|
@ -356,7 +338,9 @@ async def test_setup_fails_with_broken_libpcap(hass, caplog):
|
|||
side_effect=ImportError,
|
||||
) as compile_filter, patch(
|
||||
"homeassistant.components.dhcp.AsyncSniffer",
|
||||
) as async_sniffer:
|
||||
) as async_sniffer, patch(
|
||||
"homeassistant.components.dhcp.DiscoverHosts.async_discover"
|
||||
):
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
|
||||
|
@ -383,9 +367,7 @@ async def test_device_tracker_hostname_and_macaddress_exists_before_start(hass):
|
|||
},
|
||||
)
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
device_tracker_watcher = dhcp.DeviceTrackerWatcher(
|
||||
hass,
|
||||
{},
|
||||
|
@ -409,9 +391,7 @@ async def test_device_tracker_hostname_and_macaddress_exists_before_start(hass):
|
|||
async def test_device_tracker_hostname_and_macaddress_after_start(hass):
|
||||
"""Test matching based on hostname and macaddress after start."""
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
device_tracker_watcher = dhcp.DeviceTrackerWatcher(
|
||||
hass,
|
||||
{},
|
||||
|
@ -446,9 +426,7 @@ async def test_device_tracker_hostname_and_macaddress_after_start(hass):
|
|||
async def test_device_tracker_hostname_and_macaddress_after_start_not_home(hass):
|
||||
"""Test matching based on hostname and macaddress after start but not home."""
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
device_tracker_watcher = dhcp.DeviceTrackerWatcher(
|
||||
hass,
|
||||
{},
|
||||
|
@ -476,9 +454,7 @@ async def test_device_tracker_hostname_and_macaddress_after_start_not_home(hass)
|
|||
async def test_device_tracker_hostname_and_macaddress_after_start_not_router(hass):
|
||||
"""Test matching based on hostname and macaddress after start but not router."""
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
device_tracker_watcher = dhcp.DeviceTrackerWatcher(
|
||||
hass,
|
||||
{},
|
||||
|
@ -508,9 +484,7 @@ async def test_device_tracker_hostname_and_macaddress_after_start_hostname_missi
|
|||
):
|
||||
"""Test matching based on hostname and macaddress after start but missing hostname."""
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
device_tracker_watcher = dhcp.DeviceTrackerWatcher(
|
||||
hass,
|
||||
{},
|
||||
|
@ -547,9 +521,7 @@ async def test_device_tracker_ignore_self_assigned_ips_before_start(hass):
|
|||
},
|
||||
)
|
||||
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=mock_coro()
|
||||
) as mock_init:
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init:
|
||||
device_tracker_watcher = dhcp.DeviceTrackerWatcher(
|
||||
hass,
|
||||
{},
|
||||
|
@ -561,3 +533,136 @@ async def test_device_tracker_ignore_self_assigned_ips_before_start(hass):
|
|||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_init.mock_calls) == 0
|
||||
|
||||
|
||||
async def test_aiodiscover_finds_new_hosts(hass):
|
||||
"""Test aiodiscover finds new host."""
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init, patch(
|
||||
"homeassistant.components.dhcp.DiscoverHosts.async_discover",
|
||||
return_value=[
|
||||
{
|
||||
dhcp.DISCOVERY_IP_ADDRESS: "192.168.210.56",
|
||||
dhcp.DISCOVERY_HOSTNAME: "connect",
|
||||
dhcp.DISCOVERY_MAC_ADDRESS: "b8b7f16db533",
|
||||
}
|
||||
],
|
||||
):
|
||||
device_tracker_watcher = dhcp.NetworkWatcher(
|
||||
hass,
|
||||
{},
|
||||
[{"domain": "mock-domain", "hostname": "connect", "macaddress": "B8B7F1*"}],
|
||||
)
|
||||
await device_tracker_watcher.async_start()
|
||||
await hass.async_block_till_done()
|
||||
await device_tracker_watcher.async_stop()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_init.mock_calls) == 1
|
||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||
assert mock_init.mock_calls[0][2]["context"] == {"source": "dhcp"}
|
||||
assert mock_init.mock_calls[0][2]["data"] == {
|
||||
dhcp.IP_ADDRESS: "192.168.210.56",
|
||||
dhcp.HOSTNAME: "connect",
|
||||
dhcp.MAC_ADDRESS: "b8b7f16db533",
|
||||
}
|
||||
|
||||
|
||||
async def test_aiodiscover_does_not_call_again_on_shorter_hostname(hass):
|
||||
"""Verify longer hostnames generate a new flow but shorter ones do not.
|
||||
|
||||
Some routers will truncate hostnames so we want to accept
|
||||
additional discovery where the hostname is longer and then
|
||||
reject shorter ones.
|
||||
"""
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init, patch(
|
||||
"homeassistant.components.dhcp.DiscoverHosts.async_discover",
|
||||
return_value=[
|
||||
{
|
||||
dhcp.DISCOVERY_IP_ADDRESS: "192.168.210.56",
|
||||
dhcp.DISCOVERY_HOSTNAME: "irobot-abc",
|
||||
dhcp.DISCOVERY_MAC_ADDRESS: "b8b7f16db533",
|
||||
},
|
||||
{
|
||||
dhcp.DISCOVERY_IP_ADDRESS: "192.168.210.56",
|
||||
dhcp.DISCOVERY_HOSTNAME: "irobot-abcdef",
|
||||
dhcp.DISCOVERY_MAC_ADDRESS: "b8b7f16db533",
|
||||
},
|
||||
{
|
||||
dhcp.DISCOVERY_IP_ADDRESS: "192.168.210.56",
|
||||
dhcp.DISCOVERY_HOSTNAME: "irobot-abc",
|
||||
dhcp.DISCOVERY_MAC_ADDRESS: "b8b7f16db533",
|
||||
},
|
||||
],
|
||||
):
|
||||
device_tracker_watcher = dhcp.NetworkWatcher(
|
||||
hass,
|
||||
{},
|
||||
[
|
||||
{
|
||||
"domain": "mock-domain",
|
||||
"hostname": "irobot-*",
|
||||
"macaddress": "B8B7F1*",
|
||||
}
|
||||
],
|
||||
)
|
||||
await device_tracker_watcher.async_start()
|
||||
await hass.async_block_till_done()
|
||||
await device_tracker_watcher.async_stop()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_init.mock_calls) == 2
|
||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||
assert mock_init.mock_calls[0][2]["context"] == {"source": "dhcp"}
|
||||
assert mock_init.mock_calls[0][2]["data"] == {
|
||||
dhcp.IP_ADDRESS: "192.168.210.56",
|
||||
dhcp.HOSTNAME: "irobot-abc",
|
||||
dhcp.MAC_ADDRESS: "b8b7f16db533",
|
||||
}
|
||||
assert mock_init.mock_calls[1][1][0] == "mock-domain"
|
||||
assert mock_init.mock_calls[1][2]["context"] == {"source": "dhcp"}
|
||||
assert mock_init.mock_calls[1][2]["data"] == {
|
||||
dhcp.IP_ADDRESS: "192.168.210.56",
|
||||
dhcp.HOSTNAME: "irobot-abcdef",
|
||||
dhcp.MAC_ADDRESS: "b8b7f16db533",
|
||||
}
|
||||
|
||||
|
||||
async def test_aiodiscover_finds_new_hosts_after_interval(hass):
|
||||
"""Test aiodiscover finds new host after interval."""
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init, patch(
|
||||
"homeassistant.components.dhcp.DiscoverHosts.async_discover",
|
||||
return_value=[],
|
||||
):
|
||||
device_tracker_watcher = dhcp.NetworkWatcher(
|
||||
hass,
|
||||
{},
|
||||
[{"domain": "mock-domain", "hostname": "connect", "macaddress": "B8B7F1*"}],
|
||||
)
|
||||
await device_tracker_watcher.async_start()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_init.mock_calls) == 0
|
||||
|
||||
with patch.object(hass.config_entries.flow, "async_init") as mock_init, patch(
|
||||
"homeassistant.components.dhcp.DiscoverHosts.async_discover",
|
||||
return_value=[
|
||||
{
|
||||
dhcp.DISCOVERY_IP_ADDRESS: "192.168.210.56",
|
||||
dhcp.DISCOVERY_HOSTNAME: "connect",
|
||||
dhcp.DISCOVERY_MAC_ADDRESS: "b8b7f16db533",
|
||||
}
|
||||
],
|
||||
):
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + datetime.timedelta(minutes=65))
|
||||
await hass.async_block_till_done()
|
||||
await device_tracker_watcher.async_stop()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_init.mock_calls) == 1
|
||||
assert mock_init.mock_calls[0][1][0] == "mock-domain"
|
||||
assert mock_init.mock_calls[0][2]["context"] == {"source": "dhcp"}
|
||||
assert mock_init.mock_calls[0][2]["data"] == {
|
||||
dhcp.IP_ADDRESS: "192.168.210.56",
|
||||
dhcp.HOSTNAME: "connect",
|
||||
dhcp.MAC_ADDRESS: "b8b7f16db533",
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue