Add hassio discovery to VLC telnet (#57815)

This commit is contained in:
Michael 2021-10-16 23:53:57 +02:00 committed by GitHub
parent c09c8f424f
commit 2fa08ae6ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 178 additions and 28 deletions

View file

@ -70,6 +70,7 @@ class VLCTelnetConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1 VERSION = 1
entry: ConfigEntry | None = None entry: ConfigEntry | None = None
hassio_discovery: dict[str, Any] | None = None
async def async_step_user( async def async_step_user(
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
@ -150,6 +151,43 @@ class VLCTelnetConfigFlow(ConfigFlow, domain=DOMAIN):
errors=errors, errors=errors,
) )
async def async_step_hassio(self, discovery_info: dict[str, Any]) -> FlowResult:
"""Handle the discovery step via hassio."""
await self.async_set_unique_id("hassio")
self._abort_if_unique_id_configured(discovery_info)
self.hassio_discovery = discovery_info
self.context["title_placeholders"] = {"host": discovery_info[CONF_HOST]}
return await self.async_step_hassio_confirm()
async def async_step_hassio_confirm(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Confirm Supervisor discovery."""
assert self.hassio_discovery
if user_input is None:
return self.async_show_form(
step_id="hassio_confirm",
data_schema=vol.Schema({}),
description_placeholders={"addon": self.hassio_discovery["addon"]},
)
self.hassio_discovery.pop("addon")
try:
info = await validate_input(self.hass, self.hassio_discovery)
except CannotConnect:
return self.async_abort(reason="cannot_connect")
except InvalidAuth:
return self.async_abort(reason="invalid_auth")
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
return self.async_abort(reason="unknown")
else:
return self.async_create_entry(
title=info["title"], data=self.hassio_discovery
)
class CannotConnect(exceptions.HomeAssistantError): class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect.""" """Error to indicate we cannot connect."""

View file

@ -15,11 +15,17 @@
"password": "[%key:common::config_flow::data::password%]", "password": "[%key:common::config_flow::data::password%]",
"name": "[%key:common::config_flow::data::name%]" "name": "[%key:common::config_flow::data::name%]"
} }
},
"hassio_confirm": {
"description": "Do you want to connect to add-on {addon}?"
} }
}, },
"abort": { "abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]", "already_configured": "[%key:common::config_flow::abort::already_configured_service%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
}, },
"error": { "error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",

View file

@ -2,7 +2,10 @@
"config": { "config": {
"abort": { "abort": {
"already_configured": "Service is already configured", "already_configured": "Service is already configured",
"reauth_successful": "Re-authentication was successful" "cannot_connect": "Failed to connect",
"invalid_auth": "Invalid authentication",
"reauth_successful": "Re-authentication was successful",
"unknown": "Unexpected error"
}, },
"error": { "error": {
"cannot_connect": "Failed to connect", "cannot_connect": "Failed to connect",
@ -11,6 +14,9 @@
}, },
"flow_title": "{host}", "flow_title": "{host}",
"step": { "step": {
"hassio_confirm": {
"description": "Do you want to connect to add-on {addon}?"
},
"reauth_confirm": { "reauth_confirm": {
"data": { "data": {
"password": "Password" "password": "Password"

View file

@ -10,6 +10,11 @@ import pytest
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.vlc_telnet.const import DOMAIN from homeassistant.components.vlc_telnet.const import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import (
RESULT_TYPE_ABORT,
RESULT_TYPE_CREATE_ENTRY,
RESULT_TYPE_FORM,
)
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
@ -50,7 +55,7 @@ async def test_user_flow(
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER} DOMAIN, context={"source": config_entries.SOURCE_USER}
) )
assert result["type"] == "form" assert result["type"] == RESULT_TYPE_FORM
assert result["errors"] is None assert result["errors"] is None
with patch("homeassistant.components.vlc_telnet.config_flow.Client.connect"), patch( with patch("homeassistant.components.vlc_telnet.config_flow.Client.connect"), patch(
@ -67,7 +72,7 @@ async def test_user_flow(
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result["type"] == "create_entry" assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == entry_data["host"] assert result["title"] == entry_data["host"]
assert result["data"] == entry_data assert result["data"] == entry_data
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@ -75,6 +80,12 @@ async def test_user_flow(
async def test_import_flow(hass: HomeAssistant) -> None: async def test_import_flow(hass: HomeAssistant) -> None:
"""Test successful import flow.""" """Test successful import flow."""
test_data = {
"password": "test-password",
"host": "1.1.1.1",
"port": 8888,
"name": "custom name",
}
with patch("homeassistant.components.vlc_telnet.config_flow.Client.connect"), patch( with patch("homeassistant.components.vlc_telnet.config_flow.Client.connect"), patch(
"homeassistant.components.vlc_telnet.config_flow.Client.login" "homeassistant.components.vlc_telnet.config_flow.Client.login"
), patch( ), patch(
@ -86,23 +97,13 @@ async def test_import_flow(hass: HomeAssistant) -> None:
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={"source": config_entries.SOURCE_IMPORT}, context={"source": config_entries.SOURCE_IMPORT},
data={ data=test_data,
"password": "test-password",
"host": "1.1.1.1",
"port": 8888,
"name": "custom name",
},
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result["type"] == "create_entry" assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "custom name" assert result["title"] == test_data["name"]
assert result["data"] == { assert result["data"] == test_data
"password": "test-password",
"host": "1.1.1.1",
"port": 8888,
"name": "custom name",
}
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@ -127,7 +128,7 @@ async def test_abort_already_configured(hass: HomeAssistant, source: str) -> Non
data=entry_data, data=entry_data,
) )
assert result["type"] == "abort" assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
@ -168,7 +169,7 @@ async def test_errors(
{"password": "test-password"}, {"password": "test-password"},
) )
assert result2["type"] == "form" assert result2["type"] == RESULT_TYPE_FORM
assert result2["errors"] == {"base": error} assert result2["errors"] == {"base": error}
@ -208,15 +209,10 @@ async def test_reauth_flow(hass: HomeAssistant) -> None:
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result["type"] == "abort" assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "reauth_successful" assert result["reason"] == "reauth_successful"
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert dict(entry.data) == { assert dict(entry.data) == {**entry_data, "password": "new-password"}
"password": "new-password",
"host": "1.1.1.1",
"port": 8888,
"name": "custom name",
}
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -268,5 +264,109 @@ async def test_reauth_errors(
{"password": "test-password"}, {"password": "test-password"},
) )
assert result2["type"] == "form" assert result2["type"] == RESULT_TYPE_FORM
assert result2["errors"] == {"base": error} assert result2["errors"] == {"base": error}
async def test_hassio_flow(hass: HomeAssistant) -> None:
"""Test successful hassio flow."""
with patch("homeassistant.components.vlc_telnet.config_flow.Client.connect"), patch(
"homeassistant.components.vlc_telnet.config_flow.Client.login"
), patch(
"homeassistant.components.vlc_telnet.config_flow.Client.disconnect"
), patch(
"homeassistant.components.vlc_telnet.async_setup_entry",
return_value=True,
) as mock_setup_entry:
test_data = {
"password": "test-password",
"host": "1.1.1.1",
"port": 8888,
"name": "custom name",
"addon": "vlc",
}
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_HASSIO},
data=test_data,
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_FORM
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
assert result2["title"] == test_data["name"]
assert result2["data"] == test_data
assert len(mock_setup_entry.mock_calls) == 1
async def test_hassio_already_configured(hass: HomeAssistant) -> None:
"""Test successful hassio flow."""
entry_data = {
"password": "test-password",
"host": "1.1.1.1",
"port": 8888,
"name": "custom name",
"addon": "vlc",
}
entry = MockConfigEntry(domain=DOMAIN, data=entry_data, unique_id="hassio")
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_HASSIO},
data=entry_data,
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_ABORT
@pytest.mark.parametrize(
"error, connect_side_effect, login_side_effect",
[
("invalid_auth", None, AuthError),
("cannot_connect", ConnectError, None),
("unknown", Exception, None),
],
)
async def test_hassio_errors(
hass: HomeAssistant,
error: str,
connect_side_effect: Exception | None,
login_side_effect: Exception | None,
) -> None:
"""Test we handle hassio errors."""
with patch(
"homeassistant.components.vlc_telnet.config_flow.Client.connect",
side_effect=connect_side_effect,
), patch(
"homeassistant.components.vlc_telnet.config_flow.Client.login",
side_effect=login_side_effect,
), patch(
"homeassistant.components.vlc_telnet.config_flow.Client.disconnect"
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_HASSIO},
data={
"password": "test-password",
"host": "1.1.1.1",
"port": 8888,
"name": "custom name",
"addon": "vlc",
},
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_FORM
result2 = await hass.config_entries.flow.async_configure(result["flow_id"], {})
assert result2["type"] == RESULT_TYPE_ABORT
assert result2["reason"] == error