Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix integration failed when freebox is configured in bridge mode #103221

Merged
merged 61 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
e1210f4
Fix integration failed when freebox is configured in bridge mode
jflefebvre06 Nov 2, 2023
9cd3e5b
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 2, 2023
e84e624
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 2, 2023
ecd24ea
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 2, 2023
745f935
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 2, 2023
6cea036
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 2, 2023
3cee16e
Update router.py
jflefebvre06 Nov 2, 2023
d60e327
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 2, 2023
04d16e1
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 2, 2023
23c323c
Clean code
jflefebvre06 Nov 2, 2023
3a46a2b
fix Check blacl and ruff
jflefebvre06 Nov 2, 2023
f62c364
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 2, 2023
8abc10a
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 2, 2023
65b088b
fix Check blacl and ruff
jflefebvre06 Nov 2, 2023
645e16a
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 2, 2023
2499abc
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 3, 2023
e079920
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 3, 2023
59c80a5
fix ruff : imports order
jflefebvre06 Nov 3, 2023
02acab3
fix ruff : imports order
jflefebvre06 Nov 3, 2023
a272b8c
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 3, 2023
00c4ad5
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 3, 2023
7e5dd45
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 3, 2023
d52c092
Fix host fetch
Quentame Nov 3, 2023
5fed6d8
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 3, 2023
02ef5e2
json_resp test existance missing
jflefebvre06 Nov 3, 2023
3d93baf
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 4, 2023
adce98b
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 4, 2023
c727bdf
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 4, 2023
d036f1a
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 4, 2023
2b16e3e
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 4, 2023
1bd4251
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 5, 2023
cce2fa9
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 5, 2023
381cda6
Add test to get_host_list
jflefebvre06 Nov 5, 2023
df36c02
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 10, 2023
7c4bd25
Bad comment
jflefebvre06 Nov 10, 2023
1536a84
Improve regex
jflefebvre06 Nov 10, 2023
3bb7c47
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 17, 2023
8bd3351
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 17, 2023
6b33ff4
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 17, 2023
b0107a1
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 17, 2023
e261d2a
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 17, 2023
7047ca6
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 17, 2023
6b79aee
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 17, 2023
4e864f4
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 17, 2023
9754f57
Update homeassistant/components/freebox/router.py
jflefebvre06 Nov 17, 2023
7a896f8
Update tests/components/freebox/conftest.py
jflefebvre06 Nov 17, 2023
447a7e6
Fix tests
jflefebvre06 Nov 17, 2023
bc62dd3
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 17, 2023
e9c1b48
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 18, 2023
5d6bd03
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 18, 2023
e45b494
Add method is_json to clean the code and move test_get_hosts_list to …
jflefebvre06 Nov 18, 2023
0329b5c
is_json parameter only string
jflefebvre06 Nov 18, 2023
13bfdef
Improve router code in bridge maod and add test test_router_mode method
jflefebvre06 Nov 18, 2023
2c372b3
Improve router code in bridge maod and add test test_router_mode method
jflefebvre06 Nov 18, 2023
c7dca36
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 18, 2023
aaf015b
Change comment
jflefebvre06 Nov 18, 2023
4148c32
Format
jflefebvre06 Nov 18, 2023
e280b8c
Merge branch 'dev' into fix-freebox-bridge-mode
jflefebvre06 Nov 18, 2023
953235e
Update test_device_tracker.py
Quentame Nov 18, 2023
50cb008
Update test_device_tracker.py
Quentame Nov 18, 2023
4c67907
Untested files have been added to .coveragerc
jflefebvre06 Nov 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 43 additions & 1 deletion homeassistant/components/freebox/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
from collections.abc import Mapping
from contextlib import suppress
from datetime import datetime
import json
import logging
import os
from pathlib import Path
import re
from typing import Any

from freebox_api import Freepybox
Expand Down Expand Up @@ -36,6 +38,20 @@
_LOGGER = logging.getLogger(__name__)


def is_json(json_str):
"""Validate if a String is a JSON value or not."""
try:
json.loads(json_str)
return True
except (ValueError, TypeError) as err:
_LOGGER.error(
"Failed to parse JSON '%s', error '%s'",
json_str,
err,
)
return False


async def get_api(hass: HomeAssistant, host: str) -> Freepybox:
"""Get the Freebox API."""
freebox_path = Store(hass, STORAGE_VERSION, STORAGE_KEY).path
Expand Down Expand Up @@ -69,6 +85,7 @@ def __init__(
self._sw_v: str = freebox_config["firmware_version"]
self._attrs: dict[str, Any] = {}

self.supports_hosts = True
self.devices: dict[str, dict[str, Any]] = {}
self.disks: dict[int, dict[str, Any]] = {}
self.supports_raid = True
Expand All @@ -89,7 +106,32 @@ async def update_all(self, now: datetime | None = None) -> None:
async def update_device_trackers(self) -> None:
"""Update Freebox devices."""
new_device = False
fbx_devices: list[dict[str, Any]] = await self._api.lan.get_hosts_list()

fbx_devices: list[dict[str, Any]] = []

# Access to Host list not available in bridge mode, API return error_code 'nodev'
if self.supports_hosts:
jflefebvre06 marked this conversation as resolved.
Show resolved Hide resolved
try:
fbx_devices = await self._api.lan.get_hosts_list()
except HttpRequestError as err:
if (
(
matcher := re.search(
r"Request failed \(APIResponse: (.+)\)", str(err)
)
jflefebvre06 marked this conversation as resolved.
Show resolved Hide resolved
)
and is_json(json_str := matcher.group(1))
and (json_resp := json.loads(json_str)).get("error_code") == "nodev"
):
# No need to retry, Host list not available
self.supports_hosts = False
_LOGGER.debug(
"Host list is not available using bridge mode (%s)",
json_resp.get("msg"),
)

else:
raise err

# Adds the Freebox itself
fbx_devices.append(
Expand Down
21 changes: 20 additions & 1 deletion tests/components/freebox/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Test helpers for Freebox."""
import json
from unittest.mock import AsyncMock, PropertyMock, patch

from freebox_api.exceptions import HttpRequestError
import pytest

from homeassistant.core import HomeAssistant
Expand All @@ -12,6 +14,7 @@
DATA_HOME_GET_NODES,
DATA_HOME_PIR_GET_VALUES,
DATA_LAN_GET_HOSTS_LIST,
DATA_LAN_GET_HOSTS_LIST_MODE_BRIDGE,
DATA_STORAGE_GET_DISKS,
DATA_STORAGE_GET_RAIDS,
DATA_SYSTEM_GET_CONFIG,
Expand Down Expand Up @@ -41,7 +44,9 @@ def enable_all_entities():


@pytest.fixture
def mock_device_registry_devices(hass: HomeAssistant, device_registry):
def mock_device_registry_devices(
hass: HomeAssistant, device_registry: dr.DeviceRegistry
):
"""Create device registry devices so the device tracker entities are enabled."""
config_entry = MockConfigEntry(domain="something_else")
config_entry.add_to_hass(hass)
Expand Down Expand Up @@ -87,3 +92,17 @@ def mock_router(mock_device_registry_devices):
)
instance.close = AsyncMock()
yield service_mock


@pytest.fixture(name="router_bridge_mode")
def mock_router_bridge_mode(mock_device_registry_devices, router):
"""Mock a successful connection to Freebox Bridge mode."""

router().lan.get_hosts_list = AsyncMock(
side_effect=HttpRequestError(
"Request failed (APIResponse: %s)"
% json.dumps(DATA_LAN_GET_HOSTS_LIST_MODE_BRIDGE)
)
)

return router
4 changes: 3 additions & 1 deletion tests/components/freebox/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@

# device_tracker
DATA_LAN_GET_HOSTS_LIST = load_json_array_fixture("freebox/lan_get_hosts_list.json")

DATA_LAN_GET_HOSTS_LIST_MODE_BRIDGE = load_json_object_fixture(
"freebox/lan_get_hosts_list_bridge.json"
)

# Home
# ALL
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"msg": "Erreur lors de la récupération de la liste des hôtes : Interface invalide",
"success": false,
"error_code": "nodev"
}
48 changes: 48 additions & 0 deletions tests/components/freebox/test_device_tracker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""Tests for the Freebox device trackers."""
from unittest.mock import Mock

from freezegun.api import FrozenDateTimeFactory

from homeassistant.components.device_tracker import DOMAIN as DEVICE_TRACKER_DOMAIN
from homeassistant.components.freebox import SCAN_INTERVAL
from homeassistant.core import HomeAssistant

from .common import setup_platform

from tests.common import async_fire_time_changed


Quentame marked this conversation as resolved.
Show resolved Hide resolved
async def test_router_mode(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
router: Mock,
) -> None:
"""Test get_hosts_list invoqued multiple times if freebox into router mode."""
await setup_platform(hass, DEVICE_TRACKER_DOMAIN)

assert router().lan.get_hosts_list.call_count == 1

# Simulate an update
freezer.tick(SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
Quentame marked this conversation as resolved.
Show resolved Hide resolved

assert router().lan.get_hosts_list.call_count == 2


async def test_bridge_mode(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
router_bridge_mode: Mock,
) -> None:
"""Test get_hosts_list invoqued once if freebox into bridge mode."""
await setup_platform(hass, DEVICE_TRACKER_DOMAIN)

Quentame marked this conversation as resolved.
Show resolved Hide resolved
assert router_bridge_mode().lan.get_hosts_list.call_count == 1
# Simulate an update
Quentame marked this conversation as resolved.
Show resolved Hide resolved
freezer.tick(SCAN_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()

# If get_hosts_list failed, not called again
assert router_bridge_mode().lan.get_hosts_list.call_count == 1
Quentame marked this conversation as resolved.
Show resolved Hide resolved
22 changes: 22 additions & 0 deletions tests/components/freebox/test_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Tests for the Freebox utility methods."""
import json

from homeassistant.components.freebox.router import is_json

from .const import DATA_LAN_GET_HOSTS_LIST_MODE_BRIDGE, WIFI_GET_GLOBAL_CONFIG


async def test_is_json() -> None:
"""Test is_json method."""

# Valid JSON values
assert is_json("{}")
assert is_json('{ "simple":"json" }')
assert is_json(json.dumps(WIFI_GET_GLOBAL_CONFIG))
assert is_json(json.dumps(DATA_LAN_GET_HOSTS_LIST_MODE_BRIDGE))

# Not valid JSON values
assert not is_json(None)
assert not is_json("")
assert not is_json("XXX")
assert not is_json("{XXX}")