Update legacy nest config flow tests to use modern best practices (#63019)

* Update legacy nest tests to use modern best practices

Update legacy nest integration config flow tests to test the config flow actually through the integration APIs rather
than interacting with the config flow object directly. This is a pre-factoring pulled out of a larger config flow revamp
where we want to exercise the actual production code for initializing configuration, config flows, and authentication
implementations.

* Revert some test name/comment changes

* Update setup calls to verify async_setup_legacy is called
This commit is contained in:
Allen Porter 2021-12-29 10:38:50 -08:00 committed by GitHub
parent 23384ee1e8
commit 788373a7ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,193 +1,227 @@
"""Tests for the Nest config flow."""
import asyncio
from unittest.mock import AsyncMock, Mock, patch
from unittest.mock import patch
from homeassistant import data_entry_flow
from homeassistant import config_entries, data_entry_flow
from homeassistant.components.nest import DOMAIN, config_flow
from homeassistant.setup import async_setup_component
from tests.common import mock_coro
from tests.common import MockConfigEntry
CONFIG = {DOMAIN: {"client_id": "bla", "client_secret": "bla"}}
async def test_abort_if_no_implementation_registered(hass):
"""Test we abort if no implementation is registered."""
flow = config_flow.NestFlowHandler()
flow.hass = hass
result = await flow.async_step_init()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "missing_configuration"
async def test_abort_if_single_instance_allowed(hass):
"""Test we abort if Nest is already setup."""
flow = config_flow.NestFlowHandler()
flow.hass = hass
existing_entry = MockConfigEntry(domain=DOMAIN, data={})
existing_entry.add_to_hass(hass)
with patch.object(hass.config_entries, "async_entries", return_value=[{}]):
result = await flow.async_step_init()
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "single_instance_allowed"
async def test_full_flow_implementation(hass):
"""Test registering an implementation and finishing flow works."""
gen_authorize_url = AsyncMock(return_value="https://example.com")
convert_code = AsyncMock(return_value={"access_token": "yoo"})
config_flow.register_flow_implementation(
hass, "test", "Test", gen_authorize_url, convert_code
)
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
# Register an additional implementation to select from during the flow
config_flow.register_flow_implementation(
hass, "test-other", "Test Other", None, None
)
flow = config_flow.NestFlowHandler()
flow.hass = hass
result = await flow.async_step_init()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "init"
result = await flow.async_step_init({"flow_impl": "test"})
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"flow_impl": "nest"},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
assert result["description_placeholders"] == {"url": "https://example.com"}
assert (
result["description_placeholders"]
.get("url")
.startswith("https://home.nest.com/login/oauth2?client_id=bla")
)
result = await flow.async_step_link({"code": "123ABC"})
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["data"]["tokens"] == {"access_token": "yoo"}
assert result["data"]["impl_domain"] == "test"
assert result["title"] == "Nest (via Test)"
def mock_login(auth):
assert auth.pin == "123ABC"
auth.auth_callback({"access_token": "yoo"})
with patch(
"homeassistant.components.nest.legacy.local_auth.NestAuth.login", new=mock_login
), patch(
"homeassistant.components.nest.async_setup_legacy_entry", return_value=True
) as mock_setup:
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"code": "123ABC"}
)
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["data"]["tokens"] == {"access_token": "yoo"}
assert result["data"]["impl_domain"] == "nest"
assert result["title"] == "Nest (via configuration.yaml)"
async def test_not_pick_implementation_if_only_one(hass):
"""Test we allow picking implementation if we have two."""
gen_authorize_url = AsyncMock(return_value="https://example.com")
config_flow.register_flow_implementation(
hass, "test", "Test", gen_authorize_url, None
)
"""Test we pick the default implementation when registered."""
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
flow = config_flow.NestFlowHandler()
flow.hass = hass
result = await flow.async_step_init()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
async def test_abort_if_timeout_generating_auth_url(hass):
"""Test we abort if generating authorize url fails."""
gen_authorize_url = Mock(side_effect=asyncio.TimeoutError)
config_flow.register_flow_implementation(
hass, "test", "Test", gen_authorize_url, None
)
with patch(
"homeassistant.components.nest.legacy.local_auth.generate_auth_url",
side_effect=asyncio.TimeoutError,
):
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
flow = config_flow.NestFlowHandler()
flow.hass = hass
result = await flow.async_step_init()
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "authorize_url_timeout"
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "authorize_url_timeout"
async def test_abort_if_exception_generating_auth_url(hass):
"""Test we abort if generating authorize url blows up."""
gen_authorize_url = Mock(side_effect=ValueError)
config_flow.register_flow_implementation(
hass, "test", "Test", gen_authorize_url, None
)
with patch(
"homeassistant.components.nest.legacy.local_auth.generate_auth_url",
side_effect=ValueError,
):
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
flow = config_flow.NestFlowHandler()
flow.hass = hass
result = await flow.async_step_init()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "unknown_authorize_url_generation"
async def test_verify_code_timeout(hass):
"""Test verify code timing out."""
gen_authorize_url = AsyncMock(return_value="https://example.com")
convert_code = Mock(side_effect=asyncio.TimeoutError)
config_flow.register_flow_implementation(
hass, "test", "Test", gen_authorize_url, convert_code
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
flow = config_flow.NestFlowHandler()
flow.hass = hass
result = await flow.async_step_init()
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
result = await flow.async_step_link({"code": "123ABC"})
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
assert result["errors"] == {"code": "timeout"}
with patch(
"homeassistant.components.nest.legacy.local_auth.NestAuth.login",
side_effect=asyncio.TimeoutError,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"code": "123ABC"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
assert result["errors"] == {"code": "timeout"}
async def test_verify_code_invalid(hass):
"""Test verify code invalid."""
gen_authorize_url = AsyncMock(return_value="https://example.com")
convert_code = Mock(side_effect=config_flow.CodeInvalid)
config_flow.register_flow_implementation(
hass, "test", "Test", gen_authorize_url, convert_code
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
flow = config_flow.NestFlowHandler()
flow.hass = hass
result = await flow.async_step_init()
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
result = await flow.async_step_link({"code": "123ABC"})
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
assert result["errors"] == {"code": "invalid_pin"}
with patch(
"homeassistant.components.nest.legacy.local_auth.NestAuth.login",
side_effect=config_flow.CodeInvalid,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"code": "123ABC"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
assert result["errors"] == {"code": "invalid_pin"}
async def test_verify_code_unknown_error(hass):
"""Test verify code unknown error."""
gen_authorize_url = AsyncMock(return_value="https://example.com")
convert_code = Mock(side_effect=config_flow.NestAuthError)
config_flow.register_flow_implementation(
hass, "test", "Test", gen_authorize_url, convert_code
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
flow = config_flow.NestFlowHandler()
flow.hass = hass
result = await flow.async_step_init()
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
result = await flow.async_step_link({"code": "123ABC"})
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
assert result["errors"] == {"code": "unknown"}
with patch(
"homeassistant.components.nest.legacy.local_auth.NestAuth.login",
side_effect=config_flow.NestAuthError,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"code": "123ABC"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
assert result["errors"] == {"code": "unknown"}
async def test_verify_code_exception(hass):
"""Test verify code blows up."""
gen_authorize_url = AsyncMock(return_value="https://example.com")
convert_code = Mock(side_effect=ValueError)
config_flow.register_flow_implementation(
hass, "test", "Test", gen_authorize_url, convert_code
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
flow = config_flow.NestFlowHandler()
flow.hass = hass
result = await flow.async_step_init()
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
result = await flow.async_step_link({"code": "123ABC"})
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
assert result["errors"] == {"code": "internal_error"}
with patch(
"homeassistant.components.nest.legacy.local_auth.NestAuth.login",
side_effect=ValueError,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"code": "123ABC"}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "link"
assert result["errors"] == {"code": "internal_error"}
async def test_step_import(hass):
"""Test that we trigger import when configuring with client."""
with patch("os.path.isfile", return_value=False):
assert await async_setup_component(
hass, DOMAIN, {DOMAIN: {"client_id": "bla", "client_secret": "bla"}}
)
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
flow = hass.config_entries.flow.async_progress()[0]
@ -203,12 +237,11 @@ async def test_step_import_with_token_cache(hass):
"homeassistant.components.nest.config_flow.load_json",
return_value={"access_token": "yo"},
), patch(
"homeassistant.components.nest.async_setup_entry", return_value=mock_coro(True)
):
assert await async_setup_component(
hass, DOMAIN, {DOMAIN: {"client_id": "bla", "client_secret": "bla"}}
)
"homeassistant.components.nest.async_setup_legacy_entry", return_value=True
) as mock_setup:
assert await async_setup_component(hass, DOMAIN, CONFIG)
await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1
entry = hass.config_entries.async_entries(DOMAIN)[0]