mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Plex external config flow (#26936)
* Plex external auth config flow * Update requirements_all * Test dependency * Bad await, delay variable * Use hass aiohttp session, bump plexauth * Bump requirements * Bump library version again * Use callback view instead of polling * Update tests for callback view * Reduce timeout with callback * Review feedback * F-string * Wrap sync call * Unused * Revert unnecessary async wrap
This commit is contained in:
parent
c1851a2d94
commit
571ab5a978
@ -2,10 +2,14 @@
|
|||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from aiohttp import web_response
|
||||||
import plexapi.exceptions
|
import plexapi.exceptions
|
||||||
|
from plexauth import PlexAuth
|
||||||
import requests.exceptions
|
import requests.exceptions
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.http.view import HomeAssistantView
|
||||||
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
|
from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -20,6 +24,8 @@ from homeassistant.core import callback
|
|||||||
from homeassistant.util.json import load_json
|
from homeassistant.util.json import load_json
|
||||||
|
|
||||||
from .const import ( # pylint: disable=unused-import
|
from .const import ( # pylint: disable=unused-import
|
||||||
|
AUTH_CALLBACK_NAME,
|
||||||
|
AUTH_CALLBACK_PATH,
|
||||||
CONF_SERVER,
|
CONF_SERVER,
|
||||||
CONF_SERVER_IDENTIFIER,
|
CONF_SERVER_IDENTIFIER,
|
||||||
CONF_USE_EPISODE_ART,
|
CONF_USE_EPISODE_ART,
|
||||||
@ -30,13 +36,15 @@ from .const import ( # pylint: disable=unused-import
|
|||||||
DOMAIN,
|
DOMAIN,
|
||||||
PLEX_CONFIG_FILE,
|
PLEX_CONFIG_FILE,
|
||||||
PLEX_SERVER_CONFIG,
|
PLEX_SERVER_CONFIG,
|
||||||
|
X_PLEX_DEVICE_NAME,
|
||||||
|
X_PLEX_VERSION,
|
||||||
|
X_PLEX_PRODUCT,
|
||||||
|
X_PLEX_PLATFORM,
|
||||||
)
|
)
|
||||||
from .errors import NoServersFound, ServerNotSpecified
|
from .errors import NoServersFound, ServerNotSpecified
|
||||||
from .server import PlexServer
|
from .server import PlexServer
|
||||||
|
|
||||||
USER_SCHEMA = vol.Schema(
|
USER_SCHEMA = vol.Schema({vol.Optional("manual_setup"): bool})
|
||||||
{vol.Optional(CONF_TOKEN): str, vol.Optional("manual_setup"): bool}
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__package__)
|
_LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
@ -67,6 +75,8 @@ class PlexFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
self.current_login = {}
|
self.current_login = {}
|
||||||
self.discovery_info = {}
|
self.discovery_info = {}
|
||||||
self.available_servers = None
|
self.available_servers = None
|
||||||
|
self.plexauth = None
|
||||||
|
self.token = None
|
||||||
|
|
||||||
async def async_step_user(self, user_input=None):
|
async def async_step_user(self, user_input=None):
|
||||||
"""Handle a flow initialized by the user."""
|
"""Handle a flow initialized by the user."""
|
||||||
@ -74,9 +84,8 @@ class PlexFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
if user_input.pop("manual_setup", False):
|
if user_input.pop("manual_setup", False):
|
||||||
return await self.async_step_manual_setup(user_input)
|
return await self.async_step_manual_setup(user_input)
|
||||||
if CONF_TOKEN in user_input:
|
|
||||||
return await self.async_step_server_validate(user_input)
|
return await self.async_step_plex_website_auth()
|
||||||
errors[CONF_TOKEN] = "no_token"
|
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="user", data_schema=USER_SCHEMA, errors=errors
|
step_id="user", data_schema=USER_SCHEMA, errors=errors
|
||||||
@ -225,6 +234,43 @@ class PlexFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
_LOGGER.debug("Imported Plex configuration")
|
_LOGGER.debug("Imported Plex configuration")
|
||||||
return await self.async_step_server_validate(import_config)
|
return await self.async_step_server_validate(import_config)
|
||||||
|
|
||||||
|
async def async_step_plex_website_auth(self):
|
||||||
|
"""Begin external auth flow on Plex website."""
|
||||||
|
self.hass.http.register_view(PlexAuthorizationCallbackView)
|
||||||
|
payload = {
|
||||||
|
"X-Plex-Device-Name": X_PLEX_DEVICE_NAME,
|
||||||
|
"X-Plex-Version": X_PLEX_VERSION,
|
||||||
|
"X-Plex-Product": X_PLEX_PRODUCT,
|
||||||
|
"X-Plex-Device": self.hass.config.location_name,
|
||||||
|
"X-Plex-Platform": X_PLEX_PLATFORM,
|
||||||
|
"X-Plex-Model": "Plex OAuth",
|
||||||
|
}
|
||||||
|
session = async_get_clientsession(self.hass)
|
||||||
|
self.plexauth = PlexAuth(payload, session)
|
||||||
|
await self.plexauth.initiate_auth()
|
||||||
|
forward_url = f"{self.hass.config.api.base_url}{AUTH_CALLBACK_PATH}?flow_id={self.flow_id}"
|
||||||
|
auth_url = self.plexauth.auth_url(forward_url)
|
||||||
|
return self.async_external_step(step_id="obtain_token", url=auth_url)
|
||||||
|
|
||||||
|
async def async_step_obtain_token(self, user_input=None):
|
||||||
|
"""Obtain token after external auth completed."""
|
||||||
|
token = await self.plexauth.token(10)
|
||||||
|
|
||||||
|
if not token:
|
||||||
|
return self.async_external_step_done(next_step_id="timed_out")
|
||||||
|
|
||||||
|
self.token = token
|
||||||
|
return self.async_external_step_done(next_step_id="use_external_token")
|
||||||
|
|
||||||
|
async def async_step_timed_out(self, user_input=None):
|
||||||
|
"""Abort flow when time expires."""
|
||||||
|
return self.async_abort(reason="token_request_timeout")
|
||||||
|
|
||||||
|
async def async_step_use_external_token(self, user_input=None):
|
||||||
|
"""Continue server validation with external token."""
|
||||||
|
server_config = {CONF_TOKEN: self.token}
|
||||||
|
return await self.async_step_server_validate(server_config)
|
||||||
|
|
||||||
|
|
||||||
class PlexOptionsFlowHandler(config_entries.OptionsFlow):
|
class PlexOptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
"""Handle Plex options."""
|
"""Handle Plex options."""
|
||||||
@ -263,3 +309,23 @@ class PlexOptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PlexAuthorizationCallbackView(HomeAssistantView):
|
||||||
|
"""Handle callback from external auth."""
|
||||||
|
|
||||||
|
url = AUTH_CALLBACK_PATH
|
||||||
|
name = AUTH_CALLBACK_NAME
|
||||||
|
requires_auth = False
|
||||||
|
|
||||||
|
async def get(self, request):
|
||||||
|
"""Receive authorization confirmation."""
|
||||||
|
hass = request.app["hass"]
|
||||||
|
await hass.config_entries.flow.async_configure(
|
||||||
|
flow_id=request.query["flow_id"], user_input=None
|
||||||
|
)
|
||||||
|
|
||||||
|
return web_response.Response(
|
||||||
|
headers={"content-type": "text/html"},
|
||||||
|
text="<script>window.close()</script>Success! This window can be closed",
|
||||||
|
)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
"""Constants for the Plex component."""
|
"""Constants for the Plex component."""
|
||||||
|
from homeassistant.const import __version__
|
||||||
|
|
||||||
DOMAIN = "plex"
|
DOMAIN = "plex"
|
||||||
NAME_FORMAT = "Plex {}"
|
NAME_FORMAT = "Plex {}"
|
||||||
|
|
||||||
@ -18,3 +20,11 @@ CONF_SERVER = "server"
|
|||||||
CONF_SERVER_IDENTIFIER = "server_id"
|
CONF_SERVER_IDENTIFIER = "server_id"
|
||||||
CONF_USE_EPISODE_ART = "use_episode_art"
|
CONF_USE_EPISODE_ART = "use_episode_art"
|
||||||
CONF_SHOW_ALL_CONTROLS = "show_all_controls"
|
CONF_SHOW_ALL_CONTROLS = "show_all_controls"
|
||||||
|
|
||||||
|
AUTH_CALLBACK_PATH = "/auth/plex/callback"
|
||||||
|
AUTH_CALLBACK_NAME = "auth:plex:callback"
|
||||||
|
|
||||||
|
X_PLEX_DEVICE_NAME = "Home Assistant"
|
||||||
|
X_PLEX_PLATFORM = "Home Assistant"
|
||||||
|
X_PLEX_PRODUCT = "Home Assistant"
|
||||||
|
X_PLEX_VERSION = __version__
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/components/plex",
|
"documentation": "https://www.home-assistant.io/components/plex",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"plexapi==3.0.6"
|
"plexapi==3.0.6",
|
||||||
|
"plexauth==0.0.4"
|
||||||
],
|
],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"codeowners": [
|
"codeowners": [
|
||||||
|
@ -11,9 +11,21 @@ from .const import (
|
|||||||
CONF_SHOW_ALL_CONTROLS,
|
CONF_SHOW_ALL_CONTROLS,
|
||||||
CONF_USE_EPISODE_ART,
|
CONF_USE_EPISODE_ART,
|
||||||
DEFAULT_VERIFY_SSL,
|
DEFAULT_VERIFY_SSL,
|
||||||
|
X_PLEX_DEVICE_NAME,
|
||||||
|
X_PLEX_PLATFORM,
|
||||||
|
X_PLEX_PRODUCT,
|
||||||
|
X_PLEX_VERSION,
|
||||||
)
|
)
|
||||||
from .errors import NoServersFound, ServerNotSpecified
|
from .errors import NoServersFound, ServerNotSpecified
|
||||||
|
|
||||||
|
# Set default headers sent by plexapi
|
||||||
|
plexapi.X_PLEX_DEVICE_NAME = X_PLEX_DEVICE_NAME
|
||||||
|
plexapi.X_PLEX_PLATFORM = X_PLEX_PLATFORM
|
||||||
|
plexapi.X_PLEX_PRODUCT = X_PLEX_PRODUCT
|
||||||
|
plexapi.X_PLEX_VERSION = X_PLEX_VERSION
|
||||||
|
plexapi.myplex.BASE_HEADERS = plexapi.reset_base_headers()
|
||||||
|
plexapi.server.BASE_HEADERS = plexapi.reset_base_headers()
|
||||||
|
|
||||||
|
|
||||||
class PlexServer:
|
class PlexServer:
|
||||||
"""Manages a single Plex server connection."""
|
"""Manages a single Plex server connection."""
|
||||||
|
@ -21,9 +21,8 @@
|
|||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"title": "Connect Plex server",
|
"title": "Connect Plex server",
|
||||||
"description": "Enter a Plex token for automatic setup or manually configure a server.",
|
"description": "Continue to authorize at plex.tv or manually configure a server.",
|
||||||
"data": {
|
"data": {
|
||||||
"token": "Plex token",
|
|
||||||
"manual_setup": "Manual setup"
|
"manual_setup": "Manual setup"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,14 +30,14 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"faulty_credentials": "Authorization failed",
|
"faulty_credentials": "Authorization failed",
|
||||||
"no_servers": "No servers linked to account",
|
"no_servers": "No servers linked to account",
|
||||||
"not_found": "Plex server not found",
|
"not_found": "Plex server not found"
|
||||||
"no_token": "Provide a token or select manual setup"
|
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"all_configured": "All linked servers already configured",
|
"all_configured": "All linked servers already configured",
|
||||||
"already_configured": "This Plex server is already configured",
|
"already_configured": "This Plex server is already configured",
|
||||||
"already_in_progress": "Plex is being configured",
|
"already_in_progress": "Plex is being configured",
|
||||||
"invalid_import": "Imported configuration is invalid",
|
"invalid_import": "Imported configuration is invalid",
|
||||||
|
"token_request_timeout": "Timed out obtaining token",
|
||||||
"unknown": "Failed for unknown reason"
|
"unknown": "Failed for unknown reason"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -964,6 +964,9 @@ pizzapi==0.0.3
|
|||||||
# homeassistant.components.plex
|
# homeassistant.components.plex
|
||||||
plexapi==3.0.6
|
plexapi==3.0.6
|
||||||
|
|
||||||
|
# homeassistant.components.plex
|
||||||
|
plexauth==0.0.4
|
||||||
|
|
||||||
# homeassistant.components.plum_lightpad
|
# homeassistant.components.plum_lightpad
|
||||||
plumlightpad==0.0.11
|
plumlightpad==0.0.11
|
||||||
|
|
||||||
|
@ -261,6 +261,9 @@ pillow==6.1.0
|
|||||||
# homeassistant.components.plex
|
# homeassistant.components.plex
|
||||||
plexapi==3.0.6
|
plexapi==3.0.6
|
||||||
|
|
||||||
|
# homeassistant.components.plex
|
||||||
|
plexauth==0.0.4
|
||||||
|
|
||||||
# homeassistant.components.mhz19
|
# homeassistant.components.mhz19
|
||||||
# homeassistant.components.serial_pm
|
# homeassistant.components.serial_pm
|
||||||
pmsensor==0.4
|
pmsensor==0.4
|
||||||
|
@ -113,6 +113,7 @@ TEST_REQUIREMENTS = (
|
|||||||
"pilight",
|
"pilight",
|
||||||
"pillow",
|
"pillow",
|
||||||
"plexapi",
|
"plexapi",
|
||||||
|
"plexauth",
|
||||||
"pmsensor",
|
"pmsensor",
|
||||||
"prometheus_client",
|
"prometheus_client",
|
||||||
"ptvsd",
|
"ptvsd",
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"""Mock classes used in tests."""
|
"""Mock classes used in tests."""
|
||||||
|
|
||||||
MOCK_HOST_1 = "1.2.3.4"
|
MOCK_HOST_1 = "1.2.3.4"
|
||||||
MOCK_PORT_1 = "32400"
|
MOCK_PORT_1 = 32400
|
||||||
MOCK_HOST_2 = "4.3.2.1"
|
MOCK_HOST_2 = "4.3.2.1"
|
||||||
MOCK_PORT_2 = "32400"
|
MOCK_PORT_2 = 32400
|
||||||
|
|
||||||
|
|
||||||
class MockAvailableServer: # pylint: disable=too-few-public-methods
|
class MockAvailableServer: # pylint: disable=too-few-public-methods
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
"""Tests for Plex config flow."""
|
"""Tests for Plex config flow."""
|
||||||
from unittest.mock import MagicMock, Mock, patch, PropertyMock
|
from unittest.mock import MagicMock, Mock, patch, PropertyMock
|
||||||
|
|
||||||
|
import asynctest
|
||||||
import plexapi.exceptions
|
import plexapi.exceptions
|
||||||
import requests.exceptions
|
import requests.exceptions
|
||||||
|
|
||||||
@ -12,6 +14,7 @@ from homeassistant.const import (
|
|||||||
CONF_TOKEN,
|
CONF_TOKEN,
|
||||||
CONF_URL,
|
CONF_URL,
|
||||||
)
|
)
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
@ -49,19 +52,28 @@ async def test_bad_credentials(hass):
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
with patch(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
"plexapi.myplex.MyPlexAccount", side_effect=plexapi.exceptions.Unauthorized
|
result["flow_id"], user_input={"manual_setup": True}
|
||||||
):
|
)
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "manual_setup"
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"plexapi.server.PlexServer", side_effect=plexapi.exceptions.Unauthorized
|
||||||
|
):
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={CONF_TOKEN: MOCK_TOKEN, "manual_setup": False},
|
user_input={
|
||||||
|
CONF_HOST: MOCK_HOST_1,
|
||||||
|
CONF_PORT: MOCK_PORT_1,
|
||||||
|
CONF_SSL: False,
|
||||||
|
CONF_VERIFY_SSL: False,
|
||||||
|
CONF_TOKEN: "BAD TOKEN",
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
assert result["errors"]["base"] == "faulty_credentials"
|
assert result["errors"]["base"] == "faulty_credentials"
|
||||||
@ -92,7 +104,6 @@ async def test_import_file_from_discovery(hass):
|
|||||||
context={"source": "discovery"},
|
context={"source": "discovery"},
|
||||||
data={CONF_HOST: MOCK_HOST_1, CONF_PORT: MOCK_PORT_1},
|
data={CONF_HOST: MOCK_HOST_1, CONF_PORT: MOCK_PORT_1},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == MOCK_NAME_1
|
assert result["title"] == MOCK_NAME_1
|
||||||
assert result["data"][config_flow.CONF_SERVER] == MOCK_NAME_1
|
assert result["data"][config_flow.CONF_SERVER] == MOCK_NAME_1
|
||||||
@ -112,7 +123,6 @@ async def test_discovery(hass):
|
|||||||
context={"source": "discovery"},
|
context={"source": "discovery"},
|
||||||
data={CONF_HOST: MOCK_HOST_1, CONF_PORT: MOCK_PORT_1},
|
data={CONF_HOST: MOCK_HOST_1, CONF_PORT: MOCK_PORT_1},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
@ -129,7 +139,6 @@ async def test_discovery_while_in_progress(hass):
|
|||||||
context={"source": "discovery"},
|
context={"source": "discovery"},
|
||||||
data={CONF_HOST: MOCK_HOST_1, CONF_PORT: MOCK_PORT_1},
|
data={CONF_HOST: MOCK_HOST_1, CONF_PORT: MOCK_PORT_1},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "already_configured"
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
@ -191,7 +200,6 @@ async def test_import_bad_hostname(hass):
|
|||||||
CONF_URL: f"http://{MOCK_HOST_1}:{MOCK_PORT_1}",
|
CONF_URL: f"http://{MOCK_HOST_1}:{MOCK_PORT_1}",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
assert result["errors"]["base"] == "not_found"
|
assert result["errors"]["base"] == "not_found"
|
||||||
@ -203,15 +211,25 @@ async def test_unknown_exception(hass):
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
with patch("plexapi.myplex.MyPlexAccount", side_effect=Exception):
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result = await hass.config_entries.flow.async_init(
|
result["flow_id"], user_input={"manual_setup": True}
|
||||||
config_flow.DOMAIN,
|
)
|
||||||
context={"source": "user"},
|
assert result["type"] == "form"
|
||||||
data={CONF_TOKEN: MOCK_TOKEN, "manual_setup": False},
|
assert result["step_id"] == "manual_setup"
|
||||||
|
|
||||||
|
with patch("plexapi.server.PlexServer", side_effect=Exception):
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={
|
||||||
|
CONF_HOST: MOCK_HOST_1,
|
||||||
|
CONF_PORT: MOCK_PORT_1,
|
||||||
|
CONF_SSL: True,
|
||||||
|
CONF_VERIFY_SSL: True,
|
||||||
|
CONF_TOKEN: MOCK_TOKEN,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
@ -221,23 +239,32 @@ async def test_unknown_exception(hass):
|
|||||||
async def test_no_servers_found(hass):
|
async def test_no_servers_found(hass):
|
||||||
"""Test when no servers are on an account."""
|
"""Test when no servers are on an account."""
|
||||||
|
|
||||||
|
await async_setup_component(hass, "http", {"http": {}})
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
mm_plex_account = MagicMock()
|
mm_plex_account = MagicMock()
|
||||||
mm_plex_account.resources = Mock(return_value=[])
|
mm_plex_account.resources = Mock(return_value=[])
|
||||||
|
|
||||||
with patch("plexapi.myplex.MyPlexAccount", return_value=mm_plex_account):
|
with patch(
|
||||||
|
"plexapi.myplex.MyPlexAccount", return_value=mm_plex_account
|
||||||
|
), asynctest.patch("plexauth.PlexAuth.initiate_auth"), asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.token", return_value=MOCK_TOKEN
|
||||||
|
):
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"], user_input={"manual_setup": False}
|
||||||
user_input={CONF_TOKEN: MOCK_TOKEN, "manual_setup": False},
|
|
||||||
)
|
)
|
||||||
|
assert result["type"] == "external"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
assert result["type"] == "external_done"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
assert result["errors"]["base"] == "no_servers"
|
assert result["errors"]["base"] == "no_servers"
|
||||||
@ -246,10 +273,11 @@ async def test_no_servers_found(hass):
|
|||||||
async def test_single_available_server(hass):
|
async def test_single_available_server(hass):
|
||||||
"""Test creating an entry with one server available."""
|
"""Test creating an entry with one server available."""
|
||||||
|
|
||||||
|
await async_setup_component(hass, "http", {"http": {}})
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
@ -261,7 +289,11 @@ async def test_single_available_server(hass):
|
|||||||
|
|
||||||
with patch("plexapi.myplex.MyPlexAccount", return_value=mm_plex_account), patch(
|
with patch("plexapi.myplex.MyPlexAccount", return_value=mm_plex_account), patch(
|
||||||
"plexapi.server.PlexServer"
|
"plexapi.server.PlexServer"
|
||||||
) as mock_plex_server:
|
) as mock_plex_server, asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.initiate_auth"
|
||||||
|
), asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.token", return_value=MOCK_TOKEN
|
||||||
|
):
|
||||||
type(mock_plex_server.return_value).machineIdentifier = PropertyMock(
|
type(mock_plex_server.return_value).machineIdentifier = PropertyMock(
|
||||||
return_value=MOCK_SERVER_1.clientIdentifier
|
return_value=MOCK_SERVER_1.clientIdentifier
|
||||||
)
|
)
|
||||||
@ -273,10 +305,14 @@ async def test_single_available_server(hass):
|
|||||||
)._baseurl = PropertyMock(return_value=mock_connections.connections[0].httpuri)
|
)._baseurl = PropertyMock(return_value=mock_connections.connections[0].httpuri)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"], user_input={"manual_setup": False}
|
||||||
user_input={CONF_TOKEN: MOCK_TOKEN, "manual_setup": False},
|
|
||||||
)
|
)
|
||||||
|
assert result["type"] == "external"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
assert result["type"] == "external_done"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == MOCK_SERVER_1.name
|
assert result["title"] == MOCK_SERVER_1.name
|
||||||
assert result["data"][config_flow.CONF_SERVER] == MOCK_SERVER_1.name
|
assert result["data"][config_flow.CONF_SERVER] == MOCK_SERVER_1.name
|
||||||
@ -294,10 +330,11 @@ async def test_single_available_server(hass):
|
|||||||
async def test_multiple_servers_with_selection(hass):
|
async def test_multiple_servers_with_selection(hass):
|
||||||
"""Test creating an entry with multiple servers available."""
|
"""Test creating an entry with multiple servers available."""
|
||||||
|
|
||||||
|
await async_setup_component(hass, "http", {"http": {}})
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
@ -308,7 +345,11 @@ async def test_multiple_servers_with_selection(hass):
|
|||||||
|
|
||||||
with patch("plexapi.myplex.MyPlexAccount", return_value=mm_plex_account), patch(
|
with patch("plexapi.myplex.MyPlexAccount", return_value=mm_plex_account), patch(
|
||||||
"plexapi.server.PlexServer"
|
"plexapi.server.PlexServer"
|
||||||
) as mock_plex_server:
|
) as mock_plex_server, asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.initiate_auth"
|
||||||
|
), asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.token", return_value=MOCK_TOKEN
|
||||||
|
):
|
||||||
type(mock_plex_server.return_value).machineIdentifier = PropertyMock(
|
type(mock_plex_server.return_value).machineIdentifier = PropertyMock(
|
||||||
return_value=MOCK_SERVER_1.clientIdentifier
|
return_value=MOCK_SERVER_1.clientIdentifier
|
||||||
)
|
)
|
||||||
@ -320,17 +361,20 @@ async def test_multiple_servers_with_selection(hass):
|
|||||||
)._baseurl = PropertyMock(return_value=mock_connections.connections[0].httpuri)
|
)._baseurl = PropertyMock(return_value=mock_connections.connections[0].httpuri)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"], user_input={"manual_setup": False}
|
||||||
user_input={CONF_TOKEN: MOCK_TOKEN, "manual_setup": False},
|
|
||||||
)
|
)
|
||||||
|
assert result["type"] == "external"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
assert result["type"] == "external_done"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "select_server"
|
assert result["step_id"] == "select_server"
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], user_input={config_flow.CONF_SERVER: MOCK_SERVER_1.name}
|
result["flow_id"], user_input={config_flow.CONF_SERVER: MOCK_SERVER_1.name}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == MOCK_SERVER_1.name
|
assert result["title"] == MOCK_SERVER_1.name
|
||||||
assert result["data"][config_flow.CONF_SERVER] == MOCK_SERVER_1.name
|
assert result["data"][config_flow.CONF_SERVER] == MOCK_SERVER_1.name
|
||||||
@ -348,6 +392,8 @@ async def test_multiple_servers_with_selection(hass):
|
|||||||
async def test_adding_last_unconfigured_server(hass):
|
async def test_adding_last_unconfigured_server(hass):
|
||||||
"""Test automatically adding last unconfigured server when multiple servers on account."""
|
"""Test automatically adding last unconfigured server when multiple servers on account."""
|
||||||
|
|
||||||
|
await async_setup_component(hass, "http", {"http": {}})
|
||||||
|
|
||||||
MockConfigEntry(
|
MockConfigEntry(
|
||||||
domain=config_flow.DOMAIN,
|
domain=config_flow.DOMAIN,
|
||||||
data={
|
data={
|
||||||
@ -359,7 +405,6 @@ async def test_adding_last_unconfigured_server(hass):
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
@ -370,7 +415,11 @@ async def test_adding_last_unconfigured_server(hass):
|
|||||||
|
|
||||||
with patch("plexapi.myplex.MyPlexAccount", return_value=mm_plex_account), patch(
|
with patch("plexapi.myplex.MyPlexAccount", return_value=mm_plex_account), patch(
|
||||||
"plexapi.server.PlexServer"
|
"plexapi.server.PlexServer"
|
||||||
) as mock_plex_server:
|
) as mock_plex_server, asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.initiate_auth"
|
||||||
|
), asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.token", return_value=MOCK_TOKEN
|
||||||
|
):
|
||||||
type(mock_plex_server.return_value).machineIdentifier = PropertyMock(
|
type(mock_plex_server.return_value).machineIdentifier = PropertyMock(
|
||||||
return_value=MOCK_SERVER_1.clientIdentifier
|
return_value=MOCK_SERVER_1.clientIdentifier
|
||||||
)
|
)
|
||||||
@ -382,10 +431,14 @@ async def test_adding_last_unconfigured_server(hass):
|
|||||||
)._baseurl = PropertyMock(return_value=mock_connections.connections[0].httpuri)
|
)._baseurl = PropertyMock(return_value=mock_connections.connections[0].httpuri)
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"], user_input={"manual_setup": False}
|
||||||
user_input={CONF_TOKEN: MOCK_TOKEN, "manual_setup": False},
|
|
||||||
)
|
)
|
||||||
|
assert result["type"] == "external"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
assert result["type"] == "external_done"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == MOCK_SERVER_1.name
|
assert result["title"] == MOCK_SERVER_1.name
|
||||||
assert result["data"][config_flow.CONF_SERVER] == MOCK_SERVER_1.name
|
assert result["data"][config_flow.CONF_SERVER] == MOCK_SERVER_1.name
|
||||||
@ -414,7 +467,9 @@ async def test_already_configured(hass):
|
|||||||
mm_plex_account.resources = Mock(return_value=[MOCK_SERVER_1])
|
mm_plex_account.resources = Mock(return_value=[MOCK_SERVER_1])
|
||||||
mm_plex_account.resource = Mock(return_value=mock_connections)
|
mm_plex_account.resource = Mock(return_value=mock_connections)
|
||||||
|
|
||||||
with patch("plexapi.server.PlexServer") as mock_plex_server:
|
with patch("plexapi.server.PlexServer") as mock_plex_server, asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.initiate_auth"
|
||||||
|
), asynctest.patch("plexauth.PlexAuth.token", return_value=MOCK_TOKEN):
|
||||||
type(mock_plex_server.return_value).machineIdentifier = PropertyMock(
|
type(mock_plex_server.return_value).machineIdentifier = PropertyMock(
|
||||||
return_value=MOCK_SERVER_1.clientIdentifier
|
return_value=MOCK_SERVER_1.clientIdentifier
|
||||||
)
|
)
|
||||||
@ -424,10 +479,10 @@ async def test_already_configured(hass):
|
|||||||
type( # pylint: disable=protected-access
|
type( # pylint: disable=protected-access
|
||||||
mock_plex_server.return_value
|
mock_plex_server.return_value
|
||||||
)._baseurl = PropertyMock(return_value=mock_connections.connections[0].httpuri)
|
)._baseurl = PropertyMock(return_value=mock_connections.connections[0].httpuri)
|
||||||
|
|
||||||
result = await flow.async_step_import(
|
result = await flow.async_step_import(
|
||||||
{CONF_TOKEN: MOCK_TOKEN, CONF_URL: f"http://{MOCK_HOST_1}:{MOCK_PORT_1}"}
|
{CONF_TOKEN: MOCK_TOKEN, CONF_URL: f"http://{MOCK_HOST_1}:{MOCK_PORT_1}"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "already_configured"
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
@ -435,6 +490,8 @@ async def test_already_configured(hass):
|
|||||||
async def test_all_available_servers_configured(hass):
|
async def test_all_available_servers_configured(hass):
|
||||||
"""Test when all available servers are already configured."""
|
"""Test when all available servers are already configured."""
|
||||||
|
|
||||||
|
await async_setup_component(hass, "http", {"http": {}})
|
||||||
|
|
||||||
MockConfigEntry(
|
MockConfigEntry(
|
||||||
domain=config_flow.DOMAIN,
|
domain=config_flow.DOMAIN,
|
||||||
data={
|
data={
|
||||||
@ -454,7 +511,6 @@ async def test_all_available_servers_configured(hass):
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
@ -463,13 +519,21 @@ async def test_all_available_servers_configured(hass):
|
|||||||
mm_plex_account.resources = Mock(return_value=[MOCK_SERVER_1, MOCK_SERVER_2])
|
mm_plex_account.resources = Mock(return_value=[MOCK_SERVER_1, MOCK_SERVER_2])
|
||||||
mm_plex_account.resource = Mock(return_value=mock_connections)
|
mm_plex_account.resource = Mock(return_value=mock_connections)
|
||||||
|
|
||||||
with patch("plexapi.myplex.MyPlexAccount", return_value=mm_plex_account):
|
with patch(
|
||||||
|
"plexapi.myplex.MyPlexAccount", return_value=mm_plex_account
|
||||||
|
), asynctest.patch("plexauth.PlexAuth.initiate_auth"), asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.token", return_value=MOCK_TOKEN
|
||||||
|
):
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"], user_input={"manual_setup": False}
|
||||||
user_input={CONF_TOKEN: MOCK_TOKEN, "manual_setup": False},
|
|
||||||
)
|
)
|
||||||
|
assert result["type"] == "external"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
assert result["type"] == "external_done"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
assert result["type"] == "abort"
|
assert result["type"] == "abort"
|
||||||
assert result["reason"] == "all_configured"
|
assert result["reason"] == "all_configured"
|
||||||
|
|
||||||
@ -480,14 +544,12 @@ async def test_manual_config(hass):
|
|||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], user_input={CONF_TOKEN: "", "manual_setup": True}
|
result["flow_id"], user_input={"manual_setup": True}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "manual_setup"
|
assert result["step_id"] == "manual_setup"
|
||||||
|
|
||||||
@ -508,13 +570,12 @@ async def test_manual_config(hass):
|
|||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
CONF_HOST: MOCK_HOST_1,
|
CONF_HOST: MOCK_HOST_1,
|
||||||
CONF_PORT: int(MOCK_PORT_1),
|
CONF_PORT: MOCK_PORT_1,
|
||||||
CONF_SSL: True,
|
CONF_SSL: True,
|
||||||
CONF_VERIFY_SSL: True,
|
CONF_VERIFY_SSL: True,
|
||||||
CONF_TOKEN: MOCK_TOKEN,
|
CONF_TOKEN: MOCK_TOKEN,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == MOCK_SERVER_1.name
|
assert result["title"] == MOCK_SERVER_1.name
|
||||||
assert result["data"][config_flow.CONF_SERVER] == MOCK_SERVER_1.name
|
assert result["data"][config_flow.CONF_SERVER] == MOCK_SERVER_1.name
|
||||||
@ -529,25 +590,6 @@ async def test_manual_config(hass):
|
|||||||
assert result["data"][config_flow.PLEX_SERVER_CONFIG][CONF_TOKEN] == MOCK_TOKEN
|
assert result["data"][config_flow.PLEX_SERVER_CONFIG][CONF_TOKEN] == MOCK_TOKEN
|
||||||
|
|
||||||
|
|
||||||
async def test_no_token(hass):
|
|
||||||
"""Test failing when no token provided."""
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
config_flow.DOMAIN, context={"source": "user"}
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "form"
|
|
||||||
assert result["step_id"] == "user"
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
|
||||||
result["flow_id"], user_input={"manual_setup": False}
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "form"
|
|
||||||
assert result["step_id"] == "user"
|
|
||||||
assert result["errors"][CONF_TOKEN] == "no_token"
|
|
||||||
|
|
||||||
|
|
||||||
async def test_option_flow(hass):
|
async def test_option_flow(hass):
|
||||||
"""Test config flow selection of one of two bridges."""
|
"""Test config flow selection of one of two bridges."""
|
||||||
|
|
||||||
@ -557,7 +599,6 @@ async def test_option_flow(hass):
|
|||||||
result = await hass.config_entries.options.flow.async_init(
|
result = await hass.config_entries.options.flow.async_init(
|
||||||
entry.entry_id, context={"source": "test"}, data=None
|
entry.entry_id, context={"source": "test"}, data=None
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
assert result["step_id"] == "plex_mp_settings"
|
assert result["step_id"] == "plex_mp_settings"
|
||||||
|
|
||||||
@ -575,3 +616,57 @@ async def test_option_flow(hass):
|
|||||||
config_flow.CONF_SHOW_ALL_CONTROLS: True,
|
config_flow.CONF_SHOW_ALL_CONTROLS: True,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_external_timed_out(hass):
|
||||||
|
"""Test when external flow times out."""
|
||||||
|
|
||||||
|
await async_setup_component(hass, "http", {"http": {}})
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
|
)
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
with asynctest.patch("plexauth.PlexAuth.initiate_auth"), asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.token", return_value=None
|
||||||
|
):
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={"manual_setup": False}
|
||||||
|
)
|
||||||
|
assert result["type"] == "external"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
assert result["type"] == "external_done"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "token_request_timeout"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_callback_view(hass, aiohttp_client):
|
||||||
|
"""Test callback view."""
|
||||||
|
|
||||||
|
await async_setup_component(hass, "http", {"http": {}})
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
config_flow.DOMAIN, context={"source": "user"}
|
||||||
|
)
|
||||||
|
assert result["type"] == "form"
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
with asynctest.patch("plexauth.PlexAuth.initiate_auth"), asynctest.patch(
|
||||||
|
"plexauth.PlexAuth.token", return_value=MOCK_TOKEN
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={"manual_setup": False}
|
||||||
|
)
|
||||||
|
assert result["type"] == "external"
|
||||||
|
|
||||||
|
client = await aiohttp_client(hass.http.app)
|
||||||
|
forward_url = f'{config_flow.AUTH_CALLBACK_PATH}?flow_id={result["flow_id"]}'
|
||||||
|
|
||||||
|
resp = await client.get(forward_url)
|
||||||
|
assert resp.status == 200
|
||||||
|
Loading…
x
Reference in New Issue
Block a user