Fix cloud tts loading (#107714)
This commit is contained in:
parent
ce11366b9c
commit
f8318bbbc7
6 changed files with 108 additions and 24 deletions
|
@ -294,7 +294,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
}
|
}
|
||||||
|
|
||||||
async def _on_start() -> None:
|
async def _on_start() -> None:
|
||||||
"""Discover platforms."""
|
"""Handle cloud started after login."""
|
||||||
nonlocal loaded
|
nonlocal loaded
|
||||||
|
|
||||||
# Prevent multiple discovery
|
# Prevent multiple discovery
|
||||||
|
@ -302,14 +302,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
return
|
return
|
||||||
loaded = True
|
loaded = True
|
||||||
|
|
||||||
tts_info = {"platform_loaded": tts_platform_loaded}
|
|
||||||
|
|
||||||
await async_load_platform(hass, Platform.TTS, DOMAIN, tts_info, config)
|
|
||||||
await tts_platform_loaded.wait()
|
|
||||||
|
|
||||||
# The config entry should be loaded after the legacy tts platform is loaded
|
|
||||||
# to make sure that the tts integration is setup before we try to migrate
|
|
||||||
# old assist pipelines in the cloud stt entity.
|
|
||||||
await hass.config_entries.flow.async_init(DOMAIN, context={"source": "system"})
|
await hass.config_entries.flow.async_init(DOMAIN, context={"source": "system"})
|
||||||
|
|
||||||
async def _on_connect() -> None:
|
async def _on_connect() -> None:
|
||||||
|
@ -338,6 +330,16 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
|
||||||
account_link.async_setup(hass)
|
account_link.async_setup(hass)
|
||||||
|
|
||||||
|
hass.async_create_task(
|
||||||
|
async_load_platform(
|
||||||
|
hass,
|
||||||
|
Platform.TTS,
|
||||||
|
DOMAIN,
|
||||||
|
{"platform_loaded": tts_platform_loaded},
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
async_call_later(
|
async_call_later(
|
||||||
hass=hass,
|
hass=hass,
|
||||||
delay=timedelta(hours=STARTUP_REPAIR_DELAY),
|
delay=timedelta(hours=STARTUP_REPAIR_DELAY),
|
||||||
|
|
|
@ -76,16 +76,9 @@ async def cloud_fixture() -> AsyncGenerator[MagicMock, None]:
|
||||||
|
|
||||||
# Attributes that we mock with default values.
|
# Attributes that we mock with default values.
|
||||||
|
|
||||||
mock_cloud.id_token = jwt.encode(
|
mock_cloud.id_token = None
|
||||||
{
|
mock_cloud.access_token = None
|
||||||
"email": "hello@home-assistant.io",
|
mock_cloud.refresh_token = None
|
||||||
"custom:sub-exp": "2018-01-03",
|
|
||||||
"cognito:username": "abcdefghjkl",
|
|
||||||
},
|
|
||||||
"test",
|
|
||||||
)
|
|
||||||
mock_cloud.access_token = "test_access_token"
|
|
||||||
mock_cloud.refresh_token = "test_refresh_token"
|
|
||||||
|
|
||||||
# Properties that we keep as properties.
|
# Properties that we keep as properties.
|
||||||
|
|
||||||
|
@ -122,11 +115,31 @@ async def cloud_fixture() -> AsyncGenerator[MagicMock, None]:
|
||||||
|
|
||||||
When called, it should call the on_start callback.
|
When called, it should call the on_start callback.
|
||||||
"""
|
"""
|
||||||
|
mock_cloud.id_token = jwt.encode(
|
||||||
|
{
|
||||||
|
"email": "hello@home-assistant.io",
|
||||||
|
"custom:sub-exp": "2018-01-03",
|
||||||
|
"cognito:username": "abcdefghjkl",
|
||||||
|
},
|
||||||
|
"test",
|
||||||
|
)
|
||||||
|
mock_cloud.access_token = "test_access_token"
|
||||||
|
mock_cloud.refresh_token = "test_refresh_token"
|
||||||
on_start_callback = mock_cloud.register_on_start.call_args[0][0]
|
on_start_callback = mock_cloud.register_on_start.call_args[0][0]
|
||||||
await on_start_callback()
|
await on_start_callback()
|
||||||
|
|
||||||
mock_cloud.login.side_effect = mock_login
|
mock_cloud.login.side_effect = mock_login
|
||||||
|
|
||||||
|
async def mock_logout() -> None:
|
||||||
|
"""Mock logout."""
|
||||||
|
mock_cloud.id_token = None
|
||||||
|
mock_cloud.access_token = None
|
||||||
|
mock_cloud.refresh_token = None
|
||||||
|
await mock_cloud.stop()
|
||||||
|
await mock_cloud.client.logout_cleanups()
|
||||||
|
|
||||||
|
mock_cloud.logout.side_effect = mock_logout
|
||||||
|
|
||||||
yield mock_cloud
|
yield mock_cloud
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -113,8 +113,8 @@ async def setup_cloud_fixture(hass: HomeAssistant, cloud: MagicMock) -> None:
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
on_start_callback = cloud.register_on_start.call_args[0][0]
|
await cloud.login("test-user", "test-pass")
|
||||||
await on_start_callback()
|
cloud.login.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
async def test_google_actions_sync(
|
async def test_google_actions_sync(
|
||||||
|
|
|
@ -19,7 +19,7 @@ from homeassistant.core import Context, HomeAssistant
|
||||||
from homeassistant.exceptions import Unauthorized
|
from homeassistant.exceptions import Unauthorized
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from tests.common import MockUser
|
from tests.common import MockConfigEntry, MockUser
|
||||||
|
|
||||||
|
|
||||||
async def test_constructor_loads_info_from_config(hass: HomeAssistant) -> None:
|
async def test_constructor_loads_info_from_config(hass: HomeAssistant) -> None:
|
||||||
|
@ -230,6 +230,7 @@ async def test_async_get_or_create_cloudhook(
|
||||||
"""Test async_get_or_create_cloudhook."""
|
"""Test async_get_or_create_cloudhook."""
|
||||||
assert await async_setup_component(hass, "cloud", {"cloud": {}})
|
assert await async_setup_component(hass, "cloud", {"cloud": {}})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
await cloud.login("test-user", "test-pass")
|
||||||
|
|
||||||
webhook_id = "mock-webhook-id"
|
webhook_id = "mock-webhook-id"
|
||||||
cloudhook_url = "https://cloudhook.nabu.casa/abcdefg"
|
cloudhook_url = "https://cloudhook.nabu.casa/abcdefg"
|
||||||
|
@ -262,7 +263,7 @@ async def test_async_get_or_create_cloudhook(
|
||||||
async_create_cloudhook_mock.assert_not_called()
|
async_create_cloudhook_mock.assert_not_called()
|
||||||
|
|
||||||
# Simulate logged out
|
# Simulate logged out
|
||||||
cloud.id_token = None
|
await cloud.logout()
|
||||||
|
|
||||||
# Not logged in
|
# Not logged in
|
||||||
with pytest.raises(CloudNotAvailable):
|
with pytest.raises(CloudNotAvailable):
|
||||||
|
@ -274,3 +275,18 @@ async def test_async_get_or_create_cloudhook(
|
||||||
# Not connected
|
# Not connected
|
||||||
with pytest.raises(CloudNotConnected):
|
with pytest.raises(CloudNotConnected):
|
||||||
await async_get_or_create_cloudhook(hass, webhook_id)
|
await async_get_or_create_cloudhook(hass, webhook_id)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_cloud_logout(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
cloud: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test cloud setup with existing config entry when user is logged out."""
|
||||||
|
assert cloud.is_logged_in is False
|
||||||
|
|
||||||
|
mock_config_entry = MockConfigEntry(domain=DOMAIN)
|
||||||
|
mock_config_entry.add_to_hass(hass)
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {"cloud": {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert cloud.is_logged_in is False
|
||||||
|
|
|
@ -42,6 +42,7 @@ async def test_cloud_system_health(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
await cloud.login("test-user", "test-pass")
|
||||||
|
|
||||||
cloud.remote.snitun_server = "us-west-1"
|
cloud.remote.snitun_server = "us-west-1"
|
||||||
cloud.remote.certificate_status = CertificateStatus.READY
|
cloud.remote.certificate_status = CertificateStatus.READY
|
||||||
|
|
|
@ -4,7 +4,7 @@ from http import HTTPStatus
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import AsyncMock, MagicMock
|
from unittest.mock import AsyncMock, MagicMock
|
||||||
|
|
||||||
from hass_nabucasa.voice import MAP_VOICE, VoiceError
|
from hass_nabucasa.voice import MAP_VOICE, VoiceError, VoiceTokenError
|
||||||
import pytest
|
import pytest
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
@ -189,3 +189,55 @@ async def test_get_tts_audio(
|
||||||
assert mock_process_tts.call_args.kwargs["language"] == "en-US"
|
assert mock_process_tts.call_args.kwargs["language"] == "en-US"
|
||||||
assert mock_process_tts.call_args.kwargs["gender"] == "female"
|
assert mock_process_tts.call_args.kwargs["gender"] == "female"
|
||||||
assert mock_process_tts.call_args.kwargs["output"] == "mp3"
|
assert mock_process_tts.call_args.kwargs["output"] == "mp3"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("data", "expected_url_suffix"),
|
||||||
|
[
|
||||||
|
({"platform": DOMAIN}, DOMAIN),
|
||||||
|
({"engine_id": DOMAIN}, DOMAIN),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_get_tts_audio_logged_out(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
hass_client: ClientSessionGenerator,
|
||||||
|
cloud: MagicMock,
|
||||||
|
data: dict[str, Any],
|
||||||
|
expected_url_suffix: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test cloud get tts audio when user is logged out."""
|
||||||
|
mock_process_tts = AsyncMock(
|
||||||
|
side_effect=VoiceTokenError("No token!"),
|
||||||
|
)
|
||||||
|
cloud.voice.process_tts = mock_process_tts
|
||||||
|
assert await async_setup_component(hass, "homeassistant", {})
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
client = await hass_client()
|
||||||
|
|
||||||
|
url = "/api/tts_get_url"
|
||||||
|
data |= {"message": "There is someone at the door."}
|
||||||
|
|
||||||
|
req = await client.post(url, json=data)
|
||||||
|
assert req.status == HTTPStatus.OK
|
||||||
|
response = await req.json()
|
||||||
|
|
||||||
|
assert response == {
|
||||||
|
"url": (
|
||||||
|
"http://example.local:8123/api/tts_proxy/"
|
||||||
|
"42f18378fd4393d18c8dd11d03fa9563c1e54491"
|
||||||
|
f"_en-us_e09b5a0968_{expected_url_suffix}.mp3"
|
||||||
|
),
|
||||||
|
"path": (
|
||||||
|
"/api/tts_proxy/42f18378fd4393d18c8dd11d03fa9563c1e54491"
|
||||||
|
f"_en-us_e09b5a0968_{expected_url_suffix}.mp3"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert mock_process_tts.call_count == 1
|
||||||
|
assert mock_process_tts.call_args is not None
|
||||||
|
assert mock_process_tts.call_args.kwargs["text"] == "There is someone at the door."
|
||||||
|
assert mock_process_tts.call_args.kwargs["language"] == "en-US"
|
||||||
|
assert mock_process_tts.call_args.kwargs["gender"] == "female"
|
||||||
|
assert mock_process_tts.call_args.kwargs["output"] == "mp3"
|
||||||
|
|
Loading…
Add table
Reference in a new issue