From d422b0dcc22a01cb4c8cf05eaad573741a50aee5 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 13 Mar 2023 19:09:09 +0100 Subject: [PATCH] Make OTBR add newly created dataset to thread credential store (#89645) --- homeassistant/components/otbr/__init__.py | 5 +- .../components/otbr/websocket_api.py | 12 +++ tests/components/otbr/test_websocket_api.py | 73 ++++++++++++++++--- 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/otbr/__init__.py b/homeassistant/components/otbr/__init__.py index ca977e774f3..b1a9999f467 100644 --- a/homeassistant/components/otbr/__init__.py +++ b/homeassistant/components/otbr/__init__.py @@ -60,6 +60,7 @@ class OTBRData: url: str api: python_otbr_api.OTBR + dataset_source: str @_handle_otbr_error async def set_enabled(self, enabled: bool) -> None: @@ -137,7 +138,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up an Open Thread Border Router config entry.""" api = python_otbr_api.OTBR(entry.data["url"], async_get_clientsession(hass), 10) - otbrdata = OTBRData(entry.data["url"], api) + otbrdata = OTBRData(entry.data["url"], api, entry.title) try: dataset_tlvs = await otbrdata.get_active_dataset_tlvs() except ( @@ -148,7 +149,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: raise ConfigEntryNotReady("Unable to connect") from err if dataset_tlvs: _warn_on_default_network_settings(hass, entry, dataset_tlvs) - await async_add_dataset(hass, entry.title, dataset_tlvs.hex()) + await async_add_dataset(hass, otbrdata.dataset_source, dataset_tlvs.hex()) hass.data[DOMAIN] = otbrdata diff --git a/homeassistant/components/otbr/websocket_api.py b/homeassistant/components/otbr/websocket_api.py index 506a8cad1b7..8ea99336239 100644 --- a/homeassistant/components/otbr/websocket_api.py +++ b/homeassistant/components/otbr/websocket_api.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING import python_otbr_api from homeassistant.components import websocket_api +from homeassistant.components.thread import async_add_dataset from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError @@ -96,6 +97,17 @@ async def websocket_create_network( connection.send_error(msg["id"], "set_enabled_failed", str(exc)) return + try: + dataset_tlvs = await data.get_active_dataset_tlvs() + except HomeAssistantError as exc: + connection.send_error(msg["id"], "get_active_dataset_tlvs_failed", str(exc)) + return + if not dataset_tlvs: + connection.send_error(msg["id"], "get_active_dataset_tlvs_empty", "") + return + + await async_add_dataset(hass, data.dataset_source, dataset_tlvs.hex()) + connection.send_result(msg["id"]) diff --git a/tests/components/otbr/test_websocket_api.py b/tests/components/otbr/test_websocket_api.py index 32c5ae19e07..087b5bb4865 100644 --- a/tests/components/otbr/test_websocket_api.py +++ b/tests/components/otbr/test_websocket_api.py @@ -7,7 +7,7 @@ import python_otbr_api from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component -from . import BASE_URL +from . import BASE_URL, DATASET_CH16 from tests.test_util.aiohttp import AiohttpClientMocker from tests.typing import WebSocketGenerator @@ -27,13 +27,7 @@ async def test_get_info( ) -> None: """Test async_get_info.""" - mock_response = ( - "0E080000000000010000000300001035060004001FFFE00208F642646DA209B1C00708FDF57B5A" - "0FE2AAF60510DE98B5BA1A528FEE049D4B4B01835375030D4F70656E5468726561642048410102" - "25A40410F5DD18371BFD29E1A601EF6FFAD94C030C0402A0F7F8" - ) - - aioclient_mock.get(f"{BASE_URL}/node/dataset/active", text=mock_response) + aioclient_mock.get(f"{BASE_URL}/node/dataset/active", text=DATASET_CH16.hex()) await websocket_client.send_json( { @@ -47,7 +41,7 @@ async def test_get_info( assert msg["success"] assert msg["result"] == { "url": BASE_URL, - "active_dataset_tlvs": mock_response.lower(), + "active_dataset_tlvs": DATASET_CH16.hex().lower(), } @@ -110,7 +104,11 @@ async def test_create_network( "python_otbr_api.OTBR.create_active_dataset" ) as create_dataset_mock, patch( "python_otbr_api.OTBR.set_enabled" - ) as set_enabled_mock: + ) as set_enabled_mock, patch( + "python_otbr_api.OTBR.get_active_dataset_tlvs", return_value=DATASET_CH16 + ) as get_active_dataset_tlvs_mock, patch( + "homeassistant.components.thread.dataset_store.DatasetStore.async_add" + ) as mock_add: await websocket_client.send_json( { "id": 5, @@ -131,6 +129,8 @@ async def test_create_network( assert len(set_enabled_mock.mock_calls) == 2 assert set_enabled_mock.mock_calls[0][1][0] is False assert set_enabled_mock.mock_calls[1][1][0] is True + get_active_dataset_tlvs_mock.assert_called_once() + mock_add.assert_called_once_with("Open Thread Border Router", DATASET_CH16.hex()) async def test_create_network_no_entry( @@ -236,6 +236,59 @@ async def test_create_network_fails_3( assert msg["error"]["code"] == "set_enabled_failed" +async def test_create_network_fails_4( + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + otbr_config_entry, + websocket_client, +) -> None: + """Test create network.""" + await async_setup_component(hass, "otbr", {}) + + with patch("python_otbr_api.OTBR.set_enabled"), patch( + "python_otbr_api.OTBR.create_active_dataset" + ), patch( + "python_otbr_api.OTBR.get_active_dataset_tlvs", + side_effect=python_otbr_api.OTBRError, + ): + await websocket_client.send_json( + { + "id": 5, + "type": "otbr/create_network", + } + ) + msg = await websocket_client.receive_json() + + assert msg["id"] == 5 + assert not msg["success"] + assert msg["error"]["code"] == "get_active_dataset_tlvs_failed" + + +async def test_create_network_fails_5( + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + otbr_config_entry, + websocket_client, +) -> None: + """Test create network.""" + await async_setup_component(hass, "otbr", {}) + + with patch("python_otbr_api.OTBR.set_enabled"), patch( + "python_otbr_api.OTBR.create_active_dataset" + ), patch("python_otbr_api.OTBR.get_active_dataset_tlvs", return_value=None): + await websocket_client.send_json( + { + "id": 5, + "type": "otbr/create_network", + } + ) + msg = await websocket_client.receive_json() + + assert msg["id"] == 5 + assert not msg["success"] + assert msg["error"]["code"] == "get_active_dataset_tlvs_empty" + + async def test_get_extended_address( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker,