Add init test to Freebox (#46998)

* Add init test to Freebox

* Review : more readable conftest

* Expect 2 blank lines between defs

* Review : Not I/O in the event loop

* Fix test_setup test

* remove useless const

* Review : mock setup methods

* Add service test

* Add import test
This commit is contained in:
Quentame 2021-03-02 13:37:33 +01:00 committed by GitHub
parent ab53b49d3f
commit 6b9abfc2c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 585 additions and 64 deletions

View File

@ -314,7 +314,6 @@ omit =
homeassistant/components/foscam/camera.py homeassistant/components/foscam/camera.py
homeassistant/components/foursquare/* homeassistant/components/foursquare/*
homeassistant/components/free_mobile/notify.py homeassistant/components/free_mobile/notify.py
homeassistant/components/freebox/__init__.py
homeassistant/components/freebox/device_tracker.py homeassistant/components/freebox/device_tracker.py
homeassistant/components/freebox/router.py homeassistant/components/freebox/router.py
homeassistant/components/freebox/sensor.py homeassistant/components/freebox/sensor.py

View File

@ -9,7 +9,7 @@ from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.typing import HomeAssistantType
from .const import DOMAIN, PLATFORMS from .const import DOMAIN, PLATFORMS, SERVICE_REBOOT
from .router import FreeboxRouter from .router import FreeboxRouter
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -55,7 +55,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
"""Handle reboot service call.""" """Handle reboot service call."""
await router.reboot() await router.reboot()
hass.services.async_register(DOMAIN, "reboot", async_reboot) hass.services.async_register(DOMAIN, SERVICE_REBOOT, async_reboot)
async def async_close_connection(event): async def async_close_connection(event):
"""Close Freebox connection on HA Stop.""" """Close Freebox connection on HA Stop."""
@ -79,5 +79,6 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry):
if unload_ok: if unload_ok:
router = hass.data[DOMAIN].pop(entry.unique_id) router = hass.data[DOMAIN].pop(entry.unique_id)
await router.close() await router.close()
hass.services.async_remove(DOMAIN, SERVICE_REBOOT)
return unload_ok return unload_ok

View File

@ -8,6 +8,7 @@ from homeassistant.const import (
) )
DOMAIN = "freebox" DOMAIN = "freebox"
SERVICE_REBOOT = "reboot"
APP_DESC = { APP_DESC = {
"app_id": "hass", "app_id": "hass",

View File

@ -1,6 +1,7 @@
"""Represent the Freebox router and its devices and sensors.""" """Represent the Freebox router and its devices and sensors."""
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging import logging
import os
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
@ -31,6 +32,18 @@ _LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = timedelta(seconds=30) SCAN_INTERVAL = timedelta(seconds=30)
async def get_api(hass: HomeAssistantType, host: str) -> Freepybox:
"""Get the Freebox API."""
freebox_path = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY).path
if not os.path.exists(freebox_path):
await hass.async_add_executor_job(os.makedirs, freebox_path)
token_file = Path(f"{freebox_path}/{slugify(host)}.conf")
return Freepybox(APP_DESC, token_file, API_VERSION)
class FreeboxRouter: class FreeboxRouter:
"""Representation of a Freebox router.""" """Representation of a Freebox router."""
@ -188,13 +201,3 @@ class FreeboxRouter:
def wifi(self) -> Wifi: def wifi(self) -> Wifi:
"""Return the wifi.""" """Return the wifi."""
return self._api.wifi return self._api.wifi
async def get_api(hass: HomeAssistantType, host: str) -> Freepybox:
"""Get the Freebox API."""
freebox_path = Path(hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY).path)
freebox_path.mkdir(exist_ok=True)
token_file = Path(f"{freebox_path}/{slugify(host)}.conf")
return Freepybox(APP_DESC, token_file, API_VERSION)

View File

@ -1,11 +1,41 @@
"""Test helpers for Freebox.""" """Test helpers for Freebox."""
from unittest.mock import patch from unittest.mock import AsyncMock, patch
import pytest import pytest
from .const import (
DATA_CALL_GET_CALLS_LOG,
DATA_CONNECTION_GET_STATUS,
DATA_LAN_GET_HOSTS_LIST,
DATA_STORAGE_GET_DISKS,
DATA_SYSTEM_GET_CONFIG,
WIFI_GET_GLOBAL_CONFIG,
)
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def mock_path(): def mock_path():
"""Mock path lib.""" """Mock path lib."""
with patch("homeassistant.components.freebox.router.Path"): with patch("homeassistant.components.freebox.router.Path"):
yield yield
@pytest.fixture(name="router")
def mock_router():
"""Mock a successful connection."""
with patch("homeassistant.components.freebox.router.Freepybox") as service_mock:
instance = service_mock.return_value
instance.open = AsyncMock()
instance.system.get_config = AsyncMock(return_value=DATA_SYSTEM_GET_CONFIG)
# sensor
instance.call.get_calls_log = AsyncMock(return_value=DATA_CALL_GET_CALLS_LOG)
instance.storage.get_disks = AsyncMock(return_value=DATA_STORAGE_GET_DISKS)
instance.connection.get_status = AsyncMock(
return_value=DATA_CONNECTION_GET_STATUS
)
# switch
instance.wifi.get_global_config = AsyncMock(return_value=WIFI_GET_GLOBAL_CONFIG)
# device_tracker
instance.lan.get_hosts_list = AsyncMock(return_value=DATA_LAN_GET_HOSTS_LIST)
instance.close = AsyncMock()
yield service_mock

View File

@ -0,0 +1,376 @@
"""Test constants."""
MOCK_HOST = "myrouter.freeboxos.fr"
MOCK_PORT = 1234
# router
DATA_SYSTEM_GET_CONFIG = {
"mac": "68:A3:78:00:00:00",
"model_info": {
"has_ext_telephony": True,
"has_speakers_jack": True,
"wifi_type": "2d4_5g",
"pretty_name": "Freebox Server (r2)",
"customer_hdd_slots": 0,
"name": "fbxgw-r2/full",
"has_speakers": True,
"internal_hdd_size": 250,
"has_femtocell_exp": True,
"has_internal_hdd": True,
"has_dect": True,
},
"fans": [{"id": "fan0_speed", "name": "Ventilateur 1", "value": 2130}],
"sensors": [
{"id": "temp_hdd", "name": "Disque dur", "value": 40},
{"id": "temp_sw", "name": "Température Switch", "value": 50},
{"id": "temp_cpum", "name": "Température CPU M", "value": 60},
{"id": "temp_cpub", "name": "Température CPU B", "value": 56},
],
"board_name": "fbxgw2r",
"disk_status": "active",
"uptime": "156 jours 19 heures 56 minutes 16 secondes",
"uptime_val": 13550176,
"user_main_storage": "Disque dur",
"box_authenticated": True,
"serial": "762601T190510709",
"firmware_version": "4.2.5",
}
# sensors
DATA_CONNECTION_GET_STATUS = {
"type": "ethernet",
"rate_down": 198900,
"bytes_up": 12035728872949,
"ipv4_port_range": [0, 65535],
"rate_up": 1440000,
"bandwidth_up": 700000000,
"ipv6": "2a01:e35:ffff:ffff::1",
"bandwidth_down": 1000000000,
"media": "ftth",
"state": "up",
"bytes_down": 2355966141297,
"ipv4": "82.67.00.00",
}
DATA_CALL_GET_CALLS_LOG = [
{
"number": "0988290475",
"type": "missed",
"id": 94,
"duration": 15,
"datetime": 1613752718,
"contact_id": 0,
"line_id": 0,
"name": "0988290475",
"new": True,
},
{
"number": "0367250217",
"type": "missed",
"id": 93,
"duration": 25,
"datetime": 1613662328,
"contact_id": 0,
"line_id": 0,
"name": "0367250217",
"new": True,
},
{
"number": "0184726018",
"type": "missed",
"id": 92,
"duration": 25,
"datetime": 1613225098,
"contact_id": 0,
"line_id": 0,
"name": "0184726018",
"new": True,
},
]
DATA_STORAGE_GET_DISKS = [
{
"idle_duration": 0,
"read_error_requests": 0,
"read_requests": 110,
"spinning": True,
# "table_type": "ms-dos", API returns without dash, but codespell isn't agree
"firmware": "SC1D",
"type": "internal",
"idle": False,
"connector": 0,
"id": 0,
"write_error_requests": 0,
"state": "enabled",
"write_requests": 2708929,
"total_bytes": 250050000000,
"model": "ST9250311CS",
"active_duration": 0,
"temp": 40,
"serial": "6VCQY907",
"partitions": [
{
"fstype": "ext4",
"total_bytes": 244950000000,
"label": "Disque dur",
"id": 2,
"internal": True,
"fsck_result": "no_run_yet",
"state": "mounted",
"disk_id": 0,
"free_bytes": 227390000000,
"used_bytes": 5090000000,
"path": "L0Rpc3F1ZSBkdXI=",
}
],
}
]
# switch
WIFI_GET_GLOBAL_CONFIG = {"enabled": True, "mac_filter_state": "disabled"}
# device_tracker
DATA_LAN_GET_HOSTS_LIST = [
{
"l2ident": {"id": "8C:97:EA:00:00:00", "type": "mac_address"},
"active": True,
"persistent": False,
"names": [
{"name": "d633d0c8-958c-43cc-e807-d881b076924b", "source": "mdns"},
{"name": "Freebox Player POP", "source": "mdns_srv"},
],
"vendor_name": "Freebox SAS",
"host_type": "smartphone",
"interface": "pub",
"id": "ether-8c:97:ea:00:00:00",
"last_time_reachable": 1614107652,
"primary_name_manual": False,
"l3connectivities": [
{
"addr": "192.168.1.180",
"active": True,
"reachable": True,
"last_activity": 1614107614,
"af": "ipv4",
"last_time_reachable": 1614104242,
},
{
"addr": "fe80::dcef:dbba:6604:31d1",
"active": True,
"reachable": True,
"last_activity": 1614107645,
"af": "ipv6",
"last_time_reachable": 1614107645,
},
{
"addr": "2a01:e34:eda1:eb40:8102:4704:7ce0:2ace",
"active": False,
"reachable": False,
"last_activity": 1611574428,
"af": "ipv6",
"last_time_reachable": 1611574428,
},
{
"addr": "2a01:e34:eda1:eb40:c8e5:c524:c96d:5f5e",
"active": False,
"reachable": False,
"last_activity": 1612475101,
"af": "ipv6",
"last_time_reachable": 1612475101,
},
{
"addr": "2a01:e34:eda1:eb40:583a:49df:1df0:c2df",
"active": True,
"reachable": True,
"last_activity": 1614107652,
"af": "ipv6",
"last_time_reachable": 1614107652,
},
{
"addr": "2a01:e34:eda1:eb40:147e:3569:86ab:6aaa",
"active": False,
"reachable": False,
"last_activity": 1612486752,
"af": "ipv6",
"last_time_reachable": 1612486752,
},
],
"default_name": "Freebox Player POP",
"model": "fbx8am",
"reachable": True,
"last_activity": 1614107652,
"primary_name": "Freebox Player POP",
},
{
"l2ident": {"id": "DE:00:B0:00:00:00", "type": "mac_address"},
"active": False,
"persistent": False,
"vendor_name": "",
"host_type": "workstation",
"interface": "pub",
"id": "ether-de:00:b0:00:00:00",
"last_time_reachable": 1607125599,
"primary_name_manual": False,
"default_name": "",
"l3connectivities": [
{
"addr": "192.168.1.181",
"active": False,
"reachable": False,
"last_activity": 1607125599,
"af": "ipv4",
"last_time_reachable": 1607125599,
},
{
"addr": "192.168.1.182",
"active": False,
"reachable": False,
"last_activity": 1605958758,
"af": "ipv4",
"last_time_reachable": 1605958758,
},
{
"addr": "2a01:e34:eda1:eb40:dc00:b0ff:fedf:e30",
"active": False,
"reachable": False,
"last_activity": 1607125594,
"af": "ipv6",
"last_time_reachable": 1607125594,
},
],
"reachable": False,
"last_activity": 1607125599,
"primary_name": "",
},
{
"l2ident": {"id": "DC:00:B0:00:00:00", "type": "mac_address"},
"active": True,
"persistent": False,
"names": [
{"name": "Repeteur-Wifi-Freebox", "source": "mdns"},
{"name": "Repeteur Wifi Freebox", "source": "mdns_srv"},
],
"vendor_name": "",
"host_type": "freebox_wifi",
"interface": "pub",
"id": "ether-dc:00:b0:00:00:00",
"last_time_reachable": 1614107678,
"primary_name_manual": False,
"l3connectivities": [
{
"addr": "192.168.1.145",
"active": True,
"reachable": True,
"last_activity": 1614107678,
"af": "ipv4",
"last_time_reachable": 1614107678,
},
{
"addr": "fe80::de00:b0ff:fe52:6ef6",
"active": True,
"reachable": True,
"last_activity": 1614107608,
"af": "ipv6",
"last_time_reachable": 1614107603,
},
{
"addr": "2a01:e34:eda1:eb40:de00:b0ff:fe52:6ef6",
"active": True,
"reachable": True,
"last_activity": 1614107618,
"af": "ipv6",
"last_time_reachable": 1614107618,
},
],
"default_name": "Repeteur Wifi Freebox",
"model": "fbxwmr",
"reachable": True,
"last_activity": 1614107678,
"primary_name": "Repeteur Wifi Freebox",
},
{
"l2ident": {"id": "5E:65:55:00:00:00", "type": "mac_address"},
"active": False,
"persistent": False,
"names": [
{"name": "iPhoneofQuentin", "source": "dhcp"},
{"name": "iPhone-of-Quentin", "source": "mdns"},
],
"vendor_name": "",
"host_type": "smartphone",
"interface": "pub",
"id": "ether-5e:65:55:00:00:00",
"last_time_reachable": 1612611982,
"primary_name_manual": False,
"default_name": "iPhonedeQuentin",
"l3connectivities": [
{
"addr": "192.168.1.148",
"active": False,
"reachable": False,
"last_activity": 1612611973,
"af": "ipv4",
"last_time_reachable": 1612611973,
},
{
"addr": "fe80::14ca:6c30:938b:e281",
"active": False,
"reachable": False,
"last_activity": 1609693223,
"af": "ipv6",
"last_time_reachable": 1609693223,
},
{
"addr": "fe80::1c90:2b94:1ba2:bd8b",
"active": False,
"reachable": False,
"last_activity": 1610797303,
"af": "ipv6",
"last_time_reachable": 1610797303,
},
{
"addr": "fe80::8c8:e58b:838e:6785",
"active": False,
"reachable": False,
"last_activity": 1612611951,
"af": "ipv6",
"last_time_reachable": 1612611946,
},
{
"addr": "2a01:e34:eda1:eb40:f0e7:e198:3a69:58",
"active": False,
"reachable": False,
"last_activity": 1609693245,
"af": "ipv6",
"last_time_reachable": 1609693245,
},
{
"addr": "2a01:e34:eda1:eb40:1dc4:c6f8:aa20:c83b",
"active": False,
"reachable": False,
"last_activity": 1610797176,
"af": "ipv6",
"last_time_reachable": 1610797176,
},
{
"addr": "2a01:e34:eda1:eb40:6cf6:5811:1770:c662",
"active": False,
"reachable": False,
"last_activity": 1612611982,
"af": "ipv6",
"last_time_reachable": 1612611982,
},
{
"addr": "2a01:e34:eda1:eb40:438:9b2c:4f8f:f48a",
"active": False,
"reachable": False,
"last_activity": 1612611946,
"af": "ipv6",
"last_time_reachable": 1612611946,
},
],
"reachable": False,
"last_activity": 1612611982,
"primary_name": "iPhoneofQuentin",
},
]

View File

@ -1,23 +1,22 @@
"""Tests for the Freebox config flow.""" """Tests for the Freebox config flow."""
from unittest.mock import AsyncMock, patch from unittest.mock import Mock, patch
from freebox_api.exceptions import ( from freebox_api.exceptions import (
AuthorizationError, AuthorizationError,
HttpRequestError, HttpRequestError,
InvalidTokenError, InvalidTokenError,
) )
import pytest
from homeassistant import data_entry_flow from homeassistant import data_entry_flow
from homeassistant.components.freebox.const import DOMAIN from homeassistant.components.freebox.const import DOMAIN
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER, SOURCE_ZEROCONF from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER, SOURCE_ZEROCONF
from homeassistant.const import CONF_HOST, CONF_PORT from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.helpers.typing import HomeAssistantType
from .const import MOCK_HOST, MOCK_PORT
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
HOST = "myrouter.freeboxos.fr"
PORT = 1234
MOCK_ZEROCONF_DATA = { MOCK_ZEROCONF_DATA = {
"host": "192.168.0.254", "host": "192.168.0.254",
"port": 80, "port": 80,
@ -30,33 +29,15 @@ MOCK_ZEROCONF_DATA = {
"api_base_url": "/api/", "api_base_url": "/api/",
"uid": "b15ab20debb399f95001a9ca207d2777", "uid": "b15ab20debb399f95001a9ca207d2777",
"https_available": "1", "https_available": "1",
"https_port": f"{PORT}", "https_port": f"{MOCK_PORT}",
"box_model": "fbxgw-r2/full", "box_model": "fbxgw-r2/full",
"box_model_name": "Freebox Server (r2)", "box_model_name": "Freebox Server (r2)",
"api_domain": HOST, "api_domain": MOCK_HOST,
}, },
} }
@pytest.fixture(name="connect") async def test_user(hass: HomeAssistantType):
def mock_controller_connect():
"""Mock a successful connection."""
with patch("homeassistant.components.freebox.router.Freepybox") as service_mock:
service_mock.return_value.open = AsyncMock()
service_mock.return_value.system.get_config = AsyncMock(
return_value={
"mac": "abcd",
"model_info": {"pretty_name": "Pretty Model"},
"firmware_version": "123",
}
)
service_mock.return_value.lan.get_hosts_list = AsyncMock()
service_mock.return_value.connection.get_status = AsyncMock()
service_mock.return_value.close = AsyncMock()
yield service_mock
async def test_user(hass):
"""Test user config.""" """Test user config."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER} DOMAIN, context={"source": SOURCE_USER}
@ -68,24 +49,24 @@ async def test_user(hass):
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},
data={CONF_HOST: HOST, CONF_PORT: PORT}, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link" assert result["step_id"] == "link"
async def test_import(hass): async def test_import(hass: HomeAssistantType):
"""Test import step.""" """Test import step."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={"source": SOURCE_IMPORT}, context={"source": SOURCE_IMPORT},
data={CONF_HOST: HOST, CONF_PORT: PORT}, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link" assert result["step_id"] == "link"
async def test_zeroconf(hass): async def test_zeroconf(hass: HomeAssistantType):
"""Test zeroconf step.""" """Test zeroconf step."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
@ -96,53 +77,64 @@ async def test_zeroconf(hass):
assert result["step_id"] == "link" assert result["step_id"] == "link"
async def test_link(hass, connect): async def test_link(hass: HomeAssistantType, router: Mock):
"""Test linking.""" """Test linking."""
result = await hass.config_entries.flow.async_init( with patch(
DOMAIN, "homeassistant.components.freebox.async_setup", return_value=True
context={"source": SOURCE_USER}, ) as mock_setup, patch(
data={CONF_HOST: HOST, CONF_PORT: PORT}, "homeassistant.components.freebox.async_setup_entry",
) return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_USER},
data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
)
result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["result"].unique_id == HOST assert result["result"].unique_id == MOCK_HOST
assert result["title"] == HOST assert result["title"] == MOCK_HOST
assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_HOST] == MOCK_HOST
assert result["data"][CONF_PORT] == PORT assert result["data"][CONF_PORT] == MOCK_PORT
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_abort_if_already_setup(hass): async def test_abort_if_already_setup(hass: HomeAssistantType):
"""Test we abort if component is already setup.""" """Test we abort if component is already setup."""
MockConfigEntry( MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: HOST, CONF_PORT: PORT}, unique_id=HOST domain=DOMAIN,
data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
unique_id=MOCK_HOST,
).add_to_hass(hass) ).add_to_hass(hass)
# Should fail, same HOST (import) # Should fail, same MOCK_HOST (import)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={"source": SOURCE_IMPORT}, context={"source": SOURCE_IMPORT},
data={CONF_HOST: HOST, CONF_PORT: PORT}, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
# Should fail, same HOST (flow) # Should fail, same MOCK_HOST (flow)
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},
data={CONF_HOST: HOST, CONF_PORT: PORT}, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
async def test_on_link_failed(hass): async def test_on_link_failed(hass: HomeAssistantType):
"""Test when we have errors during linking the router.""" """Test when we have errors during linking the router."""
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},
data={CONF_HOST: HOST, CONF_PORT: PORT}, data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
) )
with patch( with patch(

View File

@ -0,0 +1,119 @@
"""Tests for the Freebox config flow."""
from unittest.mock import Mock, patch
from homeassistant.components.device_tracker import DOMAIN as DT_DOMAIN
from homeassistant.components.freebox.const import DOMAIN as DOMAIN, SERVICE_REBOOT
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.config_entries import ENTRY_STATE_LOADED, ENTRY_STATE_NOT_LOADED
from homeassistant.const import CONF_HOST, CONF_PORT, STATE_UNAVAILABLE
from homeassistant.helpers.typing import HomeAssistantType
from homeassistant.setup import async_setup_component
from .const import MOCK_HOST, MOCK_PORT
from tests.common import MockConfigEntry
async def test_setup(hass: HomeAssistantType, router: Mock):
"""Test setup of integration."""
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
unique_id=MOCK_HOST,
)
entry.add_to_hass(hass)
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
assert hass.config_entries.async_entries() == [entry]
assert router.call_count == 1
assert router().open.call_count == 1
assert hass.services.has_service(DOMAIN, SERVICE_REBOOT)
with patch(
"homeassistant.components.freebox.router.FreeboxRouter.reboot"
) as mock_service:
await hass.services.async_call(
DOMAIN,
SERVICE_REBOOT,
blocking=True,
)
await hass.async_block_till_done()
mock_service.assert_called_once()
async def test_setup_import(hass: HomeAssistantType, router: Mock):
"""Test setup of integration from import."""
await async_setup_component(hass, "persistent_notification", {})
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
unique_id=MOCK_HOST,
)
entry.add_to_hass(hass)
assert await async_setup_component(
hass, DOMAIN, {DOMAIN: {CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT}}
)
await hass.async_block_till_done()
assert hass.config_entries.async_entries() == [entry]
assert router.call_count == 1
assert router().open.call_count == 1
assert hass.services.has_service(DOMAIN, SERVICE_REBOOT)
async def test_unload_remove(hass: HomeAssistantType, router: Mock):
"""Test unload and remove of integration."""
entity_id_dt = f"{DT_DOMAIN}.freebox_server_r2"
entity_id_sensor = f"{SENSOR_DOMAIN}.freebox_download_speed"
entity_id_switch = f"{SWITCH_DOMAIN}.freebox_wifi"
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
)
entry.add_to_hass(hass)
config_entries = hass.config_entries.async_entries(DOMAIN)
assert len(config_entries) == 1
assert entry is config_entries[0]
assert await async_setup_component(hass, DOMAIN, {}) is True
await hass.async_block_till_done()
assert entry.state == ENTRY_STATE_LOADED
state_dt = hass.states.get(entity_id_dt)
assert state_dt
state_sensor = hass.states.get(entity_id_sensor)
assert state_sensor
state_switch = hass.states.get(entity_id_switch)
assert state_switch
await hass.config_entries.async_unload(entry.entry_id)
assert entry.state == ENTRY_STATE_NOT_LOADED
state_dt = hass.states.get(entity_id_dt)
assert state_dt.state == STATE_UNAVAILABLE
state_sensor = hass.states.get(entity_id_sensor)
assert state_sensor.state == STATE_UNAVAILABLE
state_switch = hass.states.get(entity_id_switch)
assert state_switch.state == STATE_UNAVAILABLE
assert router().close.call_count == 1
assert not hass.services.has_service(DOMAIN, SERVICE_REBOOT)
await hass.config_entries.async_remove(entry.entry_id)
await hass.async_block_till_done()
assert router().close.call_count == 1
assert entry.state == ENTRY_STATE_NOT_LOADED
state_dt = hass.states.get(entity_id_dt)
assert state_dt is None
state_sensor = hass.states.get(entity_id_sensor)
assert state_sensor is None
state_switch = hass.states.get(entity_id_switch)
assert state_switch is None