Replace util.get_local_ip in favor of components.network.async_get_source_ip() - part 4 (#58669)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Simone Chemelli 2021-11-15 18:18:57 +01:00 committed by GitHub
parent b3ffc1e183
commit 5fc51130ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 83 additions and 125 deletions

View File

@ -124,7 +124,7 @@ class AmbiclimateFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
) )
def _cb_url(self): def _cb_url(self):
return f"{get_url(self.hass)}{AUTH_CALLBACK_PATH}" return f"{get_url(self.hass, prefer_external=True)}{AUTH_CALLBACK_PATH}"
async def _get_authorize_url(self): async def _get_authorize_url(self):
oauth = self._generate_oauth() oauth = self._generate_oauth()

View File

@ -5,7 +5,6 @@ from aiohttp import web
import voluptuous as vol import voluptuous as vol
from homeassistant.components.network import async_get_source_ip from homeassistant.components.network import async_get_source_ip
from homeassistant.components.network.const import PUBLIC_TARGET_IP
from homeassistant.const import ( from homeassistant.const import (
CONF_ENTITIES, CONF_ENTITIES,
CONF_TYPE, CONF_TYPE,
@ -106,7 +105,7 @@ ATTR_EMULATED_HUE_NAME = "emulated_hue_name"
async def async_setup(hass, yaml_config): async def async_setup(hass, yaml_config):
"""Activate the emulated_hue component.""" """Activate the emulated_hue component."""
local_ip = await async_get_source_ip(hass, PUBLIC_TARGET_IP) local_ip = await async_get_source_ip(hass)
config = Config(hass, yaml_config.get(DOMAIN, {}), local_ip) config = Config(hass, yaml_config.get(DOMAIN, {}), local_ip)
await config.async_setup() await config.async_setup()

View File

@ -3,7 +3,6 @@ import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.network import async_get_source_ip from homeassistant.components.network import async_get_source_ip
from homeassistant.components.network.const import PUBLIC_TARGET_IP
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -71,9 +70,7 @@ async def async_setup_entry(hass, config_entry):
name = config[CONF_NAME] name = config[CONF_NAME]
listen_port = config[CONF_LISTEN_PORT] listen_port = config[CONF_LISTEN_PORT]
host_ip = config.get(CONF_HOST_IP) or await async_get_source_ip( host_ip = config.get(CONF_HOST_IP) or await async_get_source_ip(hass)
hass, PUBLIC_TARGET_IP
)
advertise_ip = config.get(CONF_ADVERTISE_IP) advertise_ip = config.get(CONF_ADVERTISE_IP)
advertise_port = config.get(CONF_ADVERTISE_PORT) advertise_port = config.get(CONF_ADVERTISE_PORT)
upnp_bind_multicast = config.get(CONF_UPNP_BIND_MULTICAST) upnp_bind_multicast = config.get(CONF_UPNP_BIND_MULTICAST)

View File

@ -18,6 +18,7 @@ from homeassistant.components.binary_sensor import (
from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
from homeassistant.components.http import HomeAssistantView from homeassistant.components.http import HomeAssistantView
from homeassistant.components.humidifier import DOMAIN as HUMIDIFIER_DOMAIN from homeassistant.components.humidifier import DOMAIN as HUMIDIFIER_DOMAIN
from homeassistant.components.network.const import MDNS_TARGET_IP
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
@ -119,8 +120,6 @@ STATUS_WAIT = 3
PORT_CLEANUP_CHECK_INTERVAL_SECS = 1 PORT_CLEANUP_CHECK_INTERVAL_SECS = 1
MDNS_TARGET_IP = "224.0.0.251"
_HOMEKIT_CONFIG_UPDATE_TIME = ( _HOMEKIT_CONFIG_UPDATE_TIME = (
5 # number of seconds to wait for homekit to see the c# change 5 # number of seconds to wait for homekit to see the c# change
) )

View File

@ -13,6 +13,7 @@ from aiohttp.typedefs import StrOrURL
from aiohttp.web_exceptions import HTTPMovedPermanently, HTTPRedirection from aiohttp.web_exceptions import HTTPMovedPermanently, HTTPRedirection
import voluptuous as vol import voluptuous as vol
from homeassistant.components.network import async_get_source_ip
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, SERVER_PORT from homeassistant.const import EVENT_HOMEASSISTANT_STOP, SERVER_PORT
from homeassistant.core import Event, HomeAssistant from homeassistant.core import Event, HomeAssistant
from homeassistant.helpers import storage from homeassistant.helpers import storage
@ -20,7 +21,6 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
from homeassistant.setup import async_start_setup, async_when_setup_or_start from homeassistant.setup import async_start_setup, async_when_setup_or_start
import homeassistant.util as hass_util
from homeassistant.util import ssl as ssl_util from homeassistant.util import ssl as ssl_util
from .auth import setup_auth from .auth import setup_auth
@ -190,7 +190,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
hass.http = server hass.http = server
local_ip = await hass.async_add_executor_job(hass_util.get_local_ip) local_ip = await async_get_source_ip(hass)
host = local_ip host = local_ip
if server_host is not None: if server_host is not None:

View File

@ -1,7 +1,6 @@
"""Sensor platform for local_ip.""" """Sensor platform for local_ip."""
from homeassistant.components.network import async_get_source_ip from homeassistant.components.network import async_get_source_ip
from homeassistant.components.network.const import PUBLIC_TARGET_IP
from homeassistant.components.sensor import SensorEntity from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME
@ -33,6 +32,4 @@ class IPSensor(SensorEntity):
async def async_update(self) -> None: async def async_update(self) -> None:
"""Fetch new state data for the sensor.""" """Fetch new state data for the sensor."""
self._attr_native_value = await async_get_source_ip( self._attr_native_value = await async_get_source_ip(self.hass)
self.hass, target_ip=PUBLIC_TARGET_IP
)

View File

@ -2,30 +2,28 @@
from __future__ import annotations from __future__ import annotations
from ipaddress import IPv4Address, IPv6Address, ip_interface from ipaddress import IPv4Address, IPv6Address, ip_interface
import logging
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
from . import util from . import util
from .const import DOMAIN, IPV4_BROADCAST_ADDR from .const import IPV4_BROADCAST_ADDR, PUBLIC_TARGET_IP
from .models import Adapter from .models import Adapter
from .network import Network from .network import Network, async_get_network
ZEROCONF_DOMAIN = "zeroconf" # cannot import from zeroconf due to circular dep
_LOGGER = logging.getLogger(__name__)
@bind_hass @bind_hass
async def async_get_adapters(hass: HomeAssistant) -> list[Adapter]: async def async_get_adapters(hass: HomeAssistant) -> list[Adapter]:
"""Get the network adapter configuration.""" """Get the network adapter configuration."""
network: Network = hass.data[DOMAIN] network: Network = await async_get_network(hass)
return network.adapters return network.adapters
@bind_hass @bind_hass
async def async_get_source_ip(hass: HomeAssistant, target_ip: str) -> str: async def async_get_source_ip(
hass: HomeAssistant, target_ip: str = PUBLIC_TARGET_IP
) -> str:
"""Get the source ip for a target ip.""" """Get the source ip for a target ip."""
adapters = await async_get_adapters(hass) adapters = await async_get_adapters(hass)
all_ipv4s = [] all_ipv4s = []
@ -88,20 +86,10 @@ async def async_get_ipv4_broadcast_addresses(hass: HomeAssistant) -> set[IPv4Add
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up network for Home Assistant.""" """Set up network for Home Assistant."""
hass.data[DOMAIN] = network = Network(hass)
await network.async_setup()
if ZEROCONF_DOMAIN in config:
await network.async_migrate_from_zeroconf(config[ZEROCONF_DOMAIN])
network.async_configure()
_LOGGER.debug("Adapters: %s", network.adapters)
# Avoid circular issue: http->network->websocket_api->http # Avoid circular issue: http->network->websocket_api->http
from .websocket import ( # pylint: disable=import-outside-toplevel from .websocket import ( # pylint: disable=import-outside-toplevel
async_register_websocket_commands, async_register_websocket_commands,
) )
async_register_websocket_commands(hass) async_register_websocket_commands(hass)
return True return True

View File

@ -11,6 +11,8 @@ DOMAIN: Final = "network"
STORAGE_KEY: Final = "core.network" STORAGE_KEY: Final = "core.network"
STORAGE_VERSION: Final = 1 STORAGE_VERSION: Final = 1
DATA_NETWORK: Final = "network"
ATTR_ADAPTERS: Final = "adapters" ATTR_ADAPTERS: Final = "adapters"
ATTR_CONFIGURED_ADAPTERS: Final = "configured_adapters" ATTR_CONFIGURED_ADAPTERS: Final = "configured_adapters"
DEFAULT_CONFIGURED_ADAPTERS: list[str] = [] DEFAULT_CONFIGURED_ADAPTERS: list[str] = []

View File

@ -1,23 +1,35 @@
"""Network helper class for the network integration.""" """Network helper class for the network integration."""
from __future__ import annotations from __future__ import annotations
import logging
from typing import Any, cast from typing import Any, cast
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.singleton import singleton
from .const import ( from .const import (
ATTR_CONFIGURED_ADAPTERS, ATTR_CONFIGURED_ADAPTERS,
DATA_NETWORK,
DEFAULT_CONFIGURED_ADAPTERS, DEFAULT_CONFIGURED_ADAPTERS,
STORAGE_KEY, STORAGE_KEY,
STORAGE_VERSION, STORAGE_VERSION,
) )
from .models import Adapter from .models import Adapter
from .util import ( from .util import async_load_adapters, enable_adapters, enable_auto_detected_adapters
adapters_with_exernal_addresses,
async_load_adapters, _LOGGER = logging.getLogger(__name__)
enable_adapters,
enable_auto_detected_adapters,
) @singleton(DATA_NETWORK)
@callback
async def async_get_network(hass: HomeAssistant) -> Network:
"""Get network singleton."""
network = Network(hass)
await network.async_setup()
network.async_configure()
_LOGGER.debug("Adapters: %s", network.adapters)
return network
class Network: class Network:
@ -41,21 +53,6 @@ class Network:
await self.async_load() await self.async_load()
self.adapters = await async_load_adapters() self.adapters = await async_load_adapters()
async def async_migrate_from_zeroconf(self, zc_config: dict[str, Any]) -> None:
"""Migrate configuration from zeroconf."""
if self._data or not zc_config:
return
from homeassistant.components.zeroconf import ( # pylint: disable=import-outside-toplevel
CONF_DEFAULT_INTERFACE,
)
if zc_config.get(CONF_DEFAULT_INTERFACE) is False:
self._data[ATTR_CONFIGURED_ADAPTERS] = adapters_with_exernal_addresses(
self.adapters
)
await self._async_save()
@callback @callback
def async_configure(self) -> None: def async_configure(self) -> None:
"""Configure from storage.""" """Configure from storage."""

View File

@ -57,15 +57,6 @@ def enable_auto_detected_adapters(adapters: list[Adapter]) -> None:
) )
def adapters_with_exernal_addresses(adapters: list[Adapter]) -> list[str]:
"""Enable all interfaces with an external address."""
return [
adapter["name"]
for adapter in adapters
if _adapter_has_external_address(adapter)
]
def _adapter_has_external_address(adapter: Adapter) -> bool: def _adapter_has_external_address(adapter: Adapter) -> bool:
"""Adapter has a non-loopback and non-link-local address.""" """Adapter has a non-loopback and non-link-local address."""
return any( return any(

View File

@ -7,13 +7,8 @@ from homeassistant.components import websocket_api
from homeassistant.components.websocket_api.connection import ActiveConnection from homeassistant.components.websocket_api.connection import ActiveConnection
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from .const import ( from .const import ATTR_ADAPTERS, ATTR_CONFIGURED_ADAPTERS, NETWORK_CONFIG_SCHEMA
ATTR_ADAPTERS, from .network import async_get_network
ATTR_CONFIGURED_ADAPTERS,
DOMAIN,
NETWORK_CONFIG_SCHEMA,
)
from .network import Network
@callback @callback
@ -32,7 +27,7 @@ async def websocket_network_adapters(
msg: dict, msg: dict,
) -> None: ) -> None:
"""Return network preferences.""" """Return network preferences."""
network: Network = hass.data[DOMAIN] network = await async_get_network(hass)
connection.send_result( connection.send_result(
msg["id"], msg["id"],
{ {
@ -56,7 +51,7 @@ async def websocket_network_adapters_configure(
msg: dict, msg: dict,
) -> None: ) -> None:
"""Update network config.""" """Update network config."""
network: Network = hass.data[DOMAIN] network = await async_get_network(hass)
await network.async_reconfig(msg["config"]) await network.async_reconfig(msg["config"])

View File

@ -17,6 +17,7 @@ from zeroconf.asyncio import AsyncServiceInfo
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components import network from homeassistant.components import network
from homeassistant.components.network import async_get_source_ip from homeassistant.components.network import async_get_source_ip
from homeassistant.components.network.const import MDNS_TARGET_IP
from homeassistant.components.network.models import Adapter from homeassistant.components.network.models import Adapter
from homeassistant.const import ( from homeassistant.const import (
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_START,
@ -52,8 +53,6 @@ DEFAULT_IPV6 = True
HOMEKIT_PAIRED_STATUS_FLAG = "sf" HOMEKIT_PAIRED_STATUS_FLAG = "sf"
HOMEKIT_MODEL = "md" HOMEKIT_MODEL = "md"
MDNS_TARGET_IP = "224.0.0.251"
# Property key=value has a max length of 255 # Property key=value has a max length of 255
# so we use 230 to leave space for key= # so we use 230 to leave space for key=
MAX_PROPERTY_VALUE_LEN = 230 MAX_PROPERTY_VALUE_LEN = 230

View File

@ -5,10 +5,9 @@ import asyncio
from collections.abc import Callable, Coroutine, Iterable, KeysView from collections.abc import Callable, Coroutine, Iterable, KeysView
from datetime import datetime, timedelta from datetime import datetime, timedelta
import enum import enum
from functools import lru_cache, wraps from functools import wraps
import random import random
import re import re
import socket
import string import string
import threading import threading
from types import MappingProxyType from types import MappingProxyType
@ -129,26 +128,6 @@ def ensure_unique_string(
return test_string return test_string
# Taken from: http://stackoverflow.com/a/11735897
@lru_cache(maxsize=None)
def get_local_ip() -> str:
"""Try to determine the local IP address of the machine."""
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Use Google Public DNS server to determine own IP
sock.connect(("8.8.8.8", 80))
return sock.getsockname()[0] # type: ignore
except OSError:
try:
return socket.gethostbyname(socket.gethostname())
except socket.gaierror:
return "127.0.0.1"
finally:
sock.close()
# Taken from http://stackoverflow.com/a/23728630 # Taken from http://stackoverflow.com/a/23728630
def get_random_string(length: int = 10) -> str: def get_random_string(length: int = 10) -> str:
"""Return a random string with letters and digits.""" """Return a random string with letters and digits."""

View File

@ -12,6 +12,7 @@ bcrypt==3.1.7
certifi>=2021.5.30 certifi>=2021.5.30
ciso8601==2.2.0 ciso8601==2.2.0
httpx==0.19.0 httpx==0.19.0
ifaddr==0.1.7
jinja2==3.0.3 jinja2==3.0.3
PyJWT==2.1.0 PyJWT==2.1.0
cryptography==35.0.0 cryptography==35.0.0

View File

@ -134,8 +134,8 @@ IGNORE_VIOLATIONS = {
# Demo # Demo
("demo", "manual"), ("demo", "manual"),
("demo", "openalpr_local"), ("demo", "openalpr_local"),
# Migration of settings from zeroconf to network # This would be a circular dep
("network", "zeroconf"), ("http", "network"),
# This should become a helper method that integrations can submit data to # This should become a helper method that integrations can submit data to
("websocket_api", "lovelace"), ("websocket_api", "lovelace"),
("websocket_api", "shopping_list"), ("websocket_api", "shopping_list"),

View File

@ -43,6 +43,7 @@ REQUIRES = [
"certifi>=2021.5.30", "certifi>=2021.5.30",
"ciso8601==2.2.0", "ciso8601==2.2.0",
"httpx==0.19.0", "httpx==0.19.0",
"ifaddr==0.1.7",
"jinja2==3.0.3", "jinja2==3.0.3",
"PyJWT==2.1.0", "PyJWT==2.1.0",
# PyJWT has loose dependency. We want the latest one. # PyJWT has loose dependency. We want the latest one.

View File

@ -179,7 +179,10 @@ async def setup_mock_motioneye_config_entry(
await async_process_ha_core_config( await async_process_ha_core_config(
hass, hass,
{"external_url": "https://example.com"}, {
"internal_url": "https://internal.url",
"external_url": "https://external.url",
},
) )
config_entry = config_entry or create_mock_motioneye_config_entry(hass) config_entry = config_entry or create_mock_motioneye_config_entry(hass)

View File

@ -77,7 +77,7 @@ async def test_setup_camera_without_webhook(hass: HomeAssistant) -> None:
expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_ENABLED] = True expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_ENABLED] = True
expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON
expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_URL] = ( expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_URL] = (
"https://example.com" "https://internal.url"
+ URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID]) + URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID])
+ f"?{WEB_HOOK_MOTION_DETECTED_QUERY_STRING}&device_id={device.id}" + f"?{WEB_HOOK_MOTION_DETECTED_QUERY_STRING}&device_id={device.id}"
) )
@ -85,7 +85,7 @@ async def test_setup_camera_without_webhook(hass: HomeAssistant) -> None:
expected_camera[KEY_WEB_HOOK_STORAGE_ENABLED] = True expected_camera[KEY_WEB_HOOK_STORAGE_ENABLED] = True
expected_camera[KEY_WEB_HOOK_STORAGE_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON expected_camera[KEY_WEB_HOOK_STORAGE_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON
expected_camera[KEY_WEB_HOOK_STORAGE_URL] = ( expected_camera[KEY_WEB_HOOK_STORAGE_URL] = (
"https://example.com" "https://internal.url"
+ URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID]) + URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID])
+ f"?{WEB_HOOK_FILE_STORED_QUERY_STRING}&device_id={device.id}" + f"?{WEB_HOOK_FILE_STORED_QUERY_STRING}&device_id={device.id}"
) )
@ -132,7 +132,7 @@ async def test_setup_camera_with_wrong_webhook(
expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_ENABLED] = True expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_ENABLED] = True
expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON
expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_URL] = ( expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_URL] = (
"https://example.com" "https://internal.url"
+ URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID]) + URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID])
+ f"?{WEB_HOOK_MOTION_DETECTED_QUERY_STRING}&device_id={device.id}" + f"?{WEB_HOOK_MOTION_DETECTED_QUERY_STRING}&device_id={device.id}"
) )
@ -140,7 +140,7 @@ async def test_setup_camera_with_wrong_webhook(
expected_camera[KEY_WEB_HOOK_STORAGE_ENABLED] = True expected_camera[KEY_WEB_HOOK_STORAGE_ENABLED] = True
expected_camera[KEY_WEB_HOOK_STORAGE_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON expected_camera[KEY_WEB_HOOK_STORAGE_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON
expected_camera[KEY_WEB_HOOK_STORAGE_URL] = ( expected_camera[KEY_WEB_HOOK_STORAGE_URL] = (
"https://example.com" "https://internal.url"
+ URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID]) + URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID])
+ f"?{WEB_HOOK_FILE_STORED_QUERY_STRING}&device_id={device.id}" + f"?{WEB_HOOK_FILE_STORED_QUERY_STRING}&device_id={device.id}"
) )
@ -185,7 +185,7 @@ async def test_setup_camera_with_old_webhook(
expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_ENABLED] = True expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_ENABLED] = True
expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON
expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_URL] = ( expected_camera[KEY_WEB_HOOK_NOTIFICATIONS_URL] = (
"https://example.com" "https://internal.url"
+ URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID]) + URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID])
+ f"?{WEB_HOOK_MOTION_DETECTED_QUERY_STRING}&device_id={device.id}" + f"?{WEB_HOOK_MOTION_DETECTED_QUERY_STRING}&device_id={device.id}"
) )
@ -193,7 +193,7 @@ async def test_setup_camera_with_old_webhook(
expected_camera[KEY_WEB_HOOK_STORAGE_ENABLED] = True expected_camera[KEY_WEB_HOOK_STORAGE_ENABLED] = True
expected_camera[KEY_WEB_HOOK_STORAGE_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON expected_camera[KEY_WEB_HOOK_STORAGE_HTTP_METHOD] = KEY_HTTP_METHOD_POST_JSON
expected_camera[KEY_WEB_HOOK_STORAGE_URL] = ( expected_camera[KEY_WEB_HOOK_STORAGE_URL] = (
"https://example.com" "https://internal.url"
+ URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID]) + URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID])
+ f"?{WEB_HOOK_FILE_STORED_QUERY_STRING}&device_id={device.id}" + f"?{WEB_HOOK_FILE_STORED_QUERY_STRING}&device_id={device.id}"
) )
@ -223,7 +223,7 @@ async def test_setup_camera_with_correct_webhook(
KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD KEY_WEB_HOOK_NOTIFICATIONS_HTTP_METHOD
] = KEY_HTTP_METHOD_POST_JSON ] = KEY_HTTP_METHOD_POST_JSON
cameras[KEY_CAMERAS][0][KEY_WEB_HOOK_NOTIFICATIONS_URL] = ( cameras[KEY_CAMERAS][0][KEY_WEB_HOOK_NOTIFICATIONS_URL] = (
"https://example.com" "https://internal.url"
+ URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID]) + URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID])
+ f"?{WEB_HOOK_MOTION_DETECTED_QUERY_STRING}&device_id={device.id}" + f"?{WEB_HOOK_MOTION_DETECTED_QUERY_STRING}&device_id={device.id}"
) )
@ -232,7 +232,7 @@ async def test_setup_camera_with_correct_webhook(
KEY_WEB_HOOK_STORAGE_HTTP_METHOD KEY_WEB_HOOK_STORAGE_HTTP_METHOD
] = KEY_HTTP_METHOD_POST_JSON ] = KEY_HTTP_METHOD_POST_JSON
cameras[KEY_CAMERAS][0][KEY_WEB_HOOK_STORAGE_URL] = ( cameras[KEY_CAMERAS][0][KEY_WEB_HOOK_STORAGE_URL] = (
"https://example.com" "https://internal.url"
+ URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID]) + URL_WEBHOOK_PATH.format(webhook_id=config_entry.data[CONF_WEBHOOK_ID])
+ f"?{WEB_HOOK_FILE_STORED_QUERY_STRING}&device_id={device.id}" + f"?{WEB_HOOK_FILE_STORED_QUERY_STRING}&device_id={device.id}"
) )

View File

@ -0,0 +1,9 @@
"""Tests for the Network Configuration integration."""
import pytest
@pytest.fixture(autouse=True)
def mock_get_source_ip():
"""Override mock of network util's async_get_source_ip."""
return

View File

@ -8,6 +8,7 @@ from homeassistant.components import network
from homeassistant.components.network.const import ( from homeassistant.components.network.const import (
ATTR_ADAPTERS, ATTR_ADAPTERS,
ATTR_CONFIGURED_ADAPTERS, ATTR_CONFIGURED_ADAPTERS,
DOMAIN,
MDNS_TARGET_IP, MDNS_TARGET_IP,
STORAGE_KEY, STORAGE_KEY,
STORAGE_VERSION, STORAGE_VERSION,
@ -59,10 +60,10 @@ async def test_async_detect_interfaces_setting_non_loopback_route(hass, hass_sto
"homeassistant.components.network.util.ifaddr.get_adapters", "homeassistant.components.network.util.ifaddr.get_adapters",
return_value=_generate_mock_adapters(), return_value=_generate_mock_adapters(),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
network_obj = hass.data[network.DOMAIN] network_obj = hass.data[DOMAIN]
assert network_obj.configured_adapters == [] assert network_obj.configured_adapters == []
assert network_obj.adapters == [ assert network_obj.adapters == [
@ -121,10 +122,10 @@ async def test_async_detect_interfaces_setting_loopback_route(hass, hass_storage
"homeassistant.components.network.util.ifaddr.get_adapters", "homeassistant.components.network.util.ifaddr.get_adapters",
return_value=_generate_mock_adapters(), return_value=_generate_mock_adapters(),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
network_obj = hass.data[network.DOMAIN] network_obj = hass.data[DOMAIN]
assert network_obj.configured_adapters == [] assert network_obj.configured_adapters == []
assert network_obj.adapters == [ assert network_obj.adapters == [
{ {
@ -182,10 +183,10 @@ async def test_async_detect_interfaces_setting_empty_route(hass, hass_storage):
"homeassistant.components.network.util.ifaddr.get_adapters", "homeassistant.components.network.util.ifaddr.get_adapters",
return_value=_generate_mock_adapters(), return_value=_generate_mock_adapters(),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
network_obj = hass.data[network.DOMAIN] network_obj = hass.data[DOMAIN]
assert network_obj.configured_adapters == [] assert network_obj.configured_adapters == []
assert network_obj.adapters == [ assert network_obj.adapters == [
{ {
@ -243,10 +244,10 @@ async def test_async_detect_interfaces_setting_exception(hass, hass_storage):
"homeassistant.components.network.util.ifaddr.get_adapters", "homeassistant.components.network.util.ifaddr.get_adapters",
return_value=_generate_mock_adapters(), return_value=_generate_mock_adapters(),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
network_obj = hass.data[network.DOMAIN] network_obj = hass.data[DOMAIN]
assert network_obj.configured_adapters == [] assert network_obj.configured_adapters == []
assert network_obj.adapters == [ assert network_obj.adapters == [
{ {
@ -309,10 +310,10 @@ async def test_interfaces_configured_from_storage(hass, hass_storage):
"homeassistant.components.network.util.ifaddr.get_adapters", "homeassistant.components.network.util.ifaddr.get_adapters",
return_value=_generate_mock_adapters(), return_value=_generate_mock_adapters(),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
network_obj = hass.data[network.DOMAIN] network_obj = hass.data[DOMAIN]
assert network_obj.configured_adapters == ["eth0", "eth1", "vtun0"] assert network_obj.configured_adapters == ["eth0", "eth1", "vtun0"]
assert network_obj.adapters == [ assert network_obj.adapters == [
@ -378,10 +379,10 @@ async def test_interfaces_configured_from_storage_websocket_update(
"homeassistant.components.network.util.ifaddr.get_adapters", "homeassistant.components.network.util.ifaddr.get_adapters",
return_value=_generate_mock_adapters(), return_value=_generate_mock_adapters(),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
network_obj = hass.data[network.DOMAIN] network_obj = hass.data[DOMAIN]
assert network_obj.configured_adapters == ["eth0", "eth1", "vtun0"] assert network_obj.configured_adapters == ["eth0", "eth1", "vtun0"]
ws_client = await hass_ws_client(hass) ws_client = await hass_ws_client(hass)
await ws_client.send_json({"id": 1, "type": "network"}) await ws_client.send_json({"id": 1, "type": "network"})
@ -507,7 +508,7 @@ async def test_async_get_source_ip_matching_interface(hass, hass_storage):
"homeassistant.components.network.util.socket.socket", "homeassistant.components.network.util.socket.socket",
return_value=_mock_socket(["192.168.1.5"]), return_value=_mock_socket(["192.168.1.5"]),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "192.168.1.5" assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "192.168.1.5"
@ -528,7 +529,7 @@ async def test_async_get_source_ip_interface_not_match(hass, hass_storage):
"homeassistant.components.network.util.socket.socket", "homeassistant.components.network.util.socket.socket",
return_value=_mock_socket(["192.168.1.5"]), return_value=_mock_socket(["192.168.1.5"]),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "169.254.3.2" assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "169.254.3.2"
@ -549,7 +550,7 @@ async def test_async_get_source_ip_cannot_determine_target(hass, hass_storage):
"homeassistant.components.network.util.socket.socket", "homeassistant.components.network.util.socket.socket",
return_value=_mock_socket([None]), return_value=_mock_socket([None]),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "192.168.1.5" assert await network.async_get_source_ip(hass, MDNS_TARGET_IP) == "192.168.1.5"
@ -570,7 +571,7 @@ async def test_async_get_ipv4_broadcast_addresses_default(hass, hass_storage):
"homeassistant.components.network.util.ifaddr.get_adapters", "homeassistant.components.network.util.ifaddr.get_adapters",
return_value=_generate_mock_adapters(), return_value=_generate_mock_adapters(),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
assert await network.async_get_ipv4_broadcast_addresses(hass) == { assert await network.async_get_ipv4_broadcast_addresses(hass) == {
@ -593,7 +594,7 @@ async def test_async_get_ipv4_broadcast_addresses_multiple(hass, hass_storage):
"homeassistant.components.network.util.ifaddr.get_adapters", "homeassistant.components.network.util.ifaddr.get_adapters",
return_value=_generate_mock_adapters(), return_value=_generate_mock_adapters(),
): ):
assert await async_setup_component(hass, network.DOMAIN, {network.DOMAIN: {}}) assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
await hass.async_block_till_done() await hass.async_block_till_done()
assert await network.async_get_ipv4_broadcast_addresses(hass) == { assert await network.async_get_ipv4_broadcast_addresses(hass) == {

View File

@ -598,7 +598,7 @@ async def mqtt_mock(hass, mqtt_client_mock, mqtt_config):
return component return component
@pytest.fixture @pytest.fixture(autouse=True)
def mock_get_source_ip(): def mock_get_source_ip():
"""Mock network util's async_get_source_ip.""" """Mock network util's async_get_source_ip."""
with patch( with patch(