"""Tests for the Nest config flow.""" import asyncio from unittest.mock import Mock, patch from homeassistant import data_entry_flow from homeassistant.setup import async_setup_component from homeassistant.components.nest import config_flow, DOMAIN from tests.common import mock_coro 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() assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT assert result['reason'] == 'no_flows' async def test_abort_if_already_setup(hass): """Test we abort if Nest is already setup.""" flow = config_flow.NestFlowHandler() flow.hass = hass with patch.object(hass.config_entries, 'async_entries', return_value=[{}]): result = await flow.async_step_init() assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT assert result['reason'] == 'already_setup' async def test_full_flow_implementation(hass): """Test registering an implementation and finishing flow works.""" gen_authorize_url = Mock(return_value=mock_coro('https://example.com')) convert_code = Mock(return_value=mock_coro({'access_token': 'yoo'})) config_flow.register_flow_implementation( hass, 'test', 'Test', gen_authorize_url, convert_code) 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() assert result['type'] == data_entry_flow.RESULT_TYPE_FORM assert result['step_id'] == 'init' result = await flow.async_step_init({'flow_impl': 'test'}) assert result['type'] == data_entry_flow.RESULT_TYPE_FORM assert result['step_id'] == 'link' assert result['description_placeholders'] == { 'url': 'https://example.com', } 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)' async def test_not_pick_implementation_if_only_one(hass): """Test we allow picking implementation if we have two.""" gen_authorize_url = Mock(return_value=mock_coro('https://example.com')) config_flow.register_flow_implementation( hass, 'test', 'Test', gen_authorize_url, None) 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' 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) 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' 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) 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_fail' async def test_verify_code_timeout(hass): """Test verify code timing out.""" gen_authorize_url = Mock(return_value=mock_coro('https://example.com')) convert_code = Mock(side_effect=asyncio.TimeoutError) config_flow.register_flow_implementation( hass, 'test', 'Test', gen_authorize_url, convert_code) 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'} async def test_verify_code_invalid(hass): """Test verify code invalid.""" gen_authorize_url = Mock(return_value=mock_coro('https://example.com')) convert_code = Mock(side_effect=config_flow.CodeInvalid) config_flow.register_flow_implementation( hass, 'test', 'Test', gen_authorize_url, convert_code) 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_code'} async def test_verify_code_unknown_error(hass): """Test verify code unknown error.""" gen_authorize_url = Mock(return_value=mock_coro('https://example.com')) convert_code = Mock(side_effect=config_flow.NestAuthError) config_flow.register_flow_implementation( hass, 'test', 'Test', gen_authorize_url, convert_code) 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'} async def test_verify_code_exception(hass): """Test verify code blows up.""" gen_authorize_url = Mock(return_value=mock_coro('https://example.com')) convert_code = Mock(side_effect=ValueError) config_flow.register_flow_implementation( hass, 'test', 'Test', gen_authorize_url, convert_code) 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'} 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', }, }) await hass.async_block_till_done() flow = hass.config_entries.flow.async_progress()[0] result = await hass.config_entries.flow.async_configure(flow['flow_id']) assert result['type'] == data_entry_flow.RESULT_TYPE_FORM assert result['step_id'] == 'link' async def test_step_import_with_token_cache(hass): """Test that we import existing token cache.""" with patch('os.path.isfile', return_value=True), \ patch('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', }, }) await hass.async_block_till_done() entry = hass.config_entries.async_entries(DOMAIN)[0] assert entry.data == { 'impl_domain': 'nest', 'tokens': { 'access_token': 'yo' } }