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