async def test_reset_cancels_retry_setup(): """Test resetting a bridge while we're waiting to retry setup.""" hass = Mock() entry = Mock() entry.data = {'host': '1.2.3.4', 'username': '******'} hue_bridge = bridge.HueBridge(hass, entry, False, False) with patch.object(bridge, 'get_bridge', side_effect=errors.CannotConnect): assert await hue_bridge.async_setup() is False mock_call_later = hass.helpers.event.async_call_later assert len(mock_call_later.mock_calls) == 1 assert await hue_bridge.async_reset() assert len(mock_call_later.mock_calls) == 2 assert len(mock_call_later.return_value.mock_calls) == 1
async def test_reset_unloads_entry_if_setup(): """Test calling reset while the entry has been setup.""" hass = Mock() entry = Mock() entry.data = {"host": "1.2.3.4", "username": "******"} hue_bridge = bridge.HueBridge(hass, entry, False, False) with patch.object(bridge, "get_bridge", return_value=mock_coro(Mock())): assert await hue_bridge.async_setup() is True assert len(hass.services.async_register.mock_calls) == 1 assert len(hass.config_entries.async_forward_entry_setup.mock_calls) == 3 hass.config_entries.async_forward_entry_unload.return_value = mock_coro(True) assert await hue_bridge.async_reset() assert len(hass.config_entries.async_forward_entry_unload.mock_calls) == 3 assert len(hass.services.async_remove.mock_calls) == 1
async def test_reset_if_entry_had_wrong_auth(hass): """Test calling reset when the entry contained wrong auth.""" entry = Mock() entry.data = {"host": "1.2.3.4", "username": "******"} entry.options = { CONF_ALLOW_HUE_GROUPS: False, CONF_ALLOW_UNREACHABLE: False } hue_bridge = bridge.HueBridge(hass, entry) with patch.object(bridge, "authenticate_bridge", side_effect=errors.AuthenticationRequired), patch.object( bridge, "create_config_flow") as mock_create: assert await hue_bridge.async_setup() is False assert len(mock_create.mock_calls) == 1 assert await hue_bridge.async_reset()
async def test_bridge_setup(hass): """Test a successful setup.""" entry = Mock() api = Mock(initialize=AsyncMock()) entry.data = {"host": "1.2.3.4", "username": "******"} entry.options = { CONF_ALLOW_HUE_GROUPS: False, CONF_ALLOW_UNREACHABLE: False } hue_bridge = bridge.HueBridge(hass, entry) with patch("aiohue.Bridge", return_value=api), patch.object( hass.config_entries, "async_forward_entry_setup") as mock_forward: assert await hue_bridge.async_setup() is True assert hue_bridge.api is api assert len(mock_forward.mock_calls) == 3 forward_entries = {c[1][1] for c in mock_forward.mock_calls} assert forward_entries == {"light", "binary_sensor", "sensor"}
async def test_handle_unauthorized(hass): """Test handling an unauthorized error on update.""" entry = Mock(async_setup=AsyncMock()) entry.data = {"host": "1.2.3.4", "username": "******"} hue_bridge = bridge.HueBridge(hass, entry, False, False) with patch.object(bridge, "authenticate_bridge", return_value=Mock()), patch("aiohue.Bridge", return_value=Mock()): assert await hue_bridge.async_setup() is True assert hue_bridge.authorized is True with patch.object(bridge, "create_config_flow") as mock_create: await hue_bridge.handle_unauthorized_error() assert hue_bridge.authorized is False assert len(mock_create.mock_calls) == 1 assert mock_create.mock_calls[0][1][1] == "1.2.3.4"
async def test_hue_activate_scene_transition(hass, mock_api): """Test successful hue_activate_scene with transition.""" config_entry = config_entries.ConfigEntry( 1, hue.DOMAIN, "Mock Title", { "host": "mock-host", "username": "******" }, "test", config_entries.CONN_CLASS_LOCAL_POLL, system_options={}, options={ CONF_ALLOW_HUE_GROUPS: True, CONF_ALLOW_UNREACHABLE: False }, ) hue_bridge = bridge.HueBridge(hass, config_entry) mock_api.mock_group_responses.append(GROUP_RESPONSE) mock_api.mock_scene_responses.append(SCENE_RESPONSE) with patch("aiohue.Bridge", return_value=mock_api), patch.object( hass.config_entries, "async_forward_entry_setup"): assert await hue_bridge.async_setup() is True assert hue_bridge.api is mock_api call = Mock() call.data = { "group_name": "Group 1", "scene_name": "Cozy dinner", "transition": 30 } with patch("aiohue.Bridge", return_value=mock_api): assert await hue_bridge.hue_activate_scene(call) is None assert len(mock_api.mock_requests) == 3 assert mock_api.mock_requests[2]["json"]["scene"] == "scene_1" assert mock_api.mock_requests[2]["json"]["transitiontime"] == 30 assert mock_api.mock_requests[2]["path"] == "groups/group_1/action"
async def test_handle_unauthorized(): """Test handling an unauthorized error on update.""" hass = Mock() entry = Mock() entry.data = {"host": "1.2.3.4", "username": "******"} hue_bridge = bridge.HueBridge(hass, entry, False, False) with patch.object(bridge, "get_bridge", return_value=mock_coro(Mock())): assert await hue_bridge.async_setup() is True assert hue_bridge.authorized is True await hue_bridge.handle_unauthorized_error() assert hue_bridge.authorized is False assert len(hass.async_create_task.mock_calls) == 4 assert len(hass.config_entries.flow.async_init.mock_calls) == 1 assert hass.config_entries.flow.async_init.mock_calls[0][2]["data"] == { "host": "1.2.3.4" }
async def test_bridge_setup_timeout(hass): """Test we retry to connect if we cannot connect.""" entry = Mock() entry.data = { "host": "1.2.3.4", "api_key": "mock-api-key", "api_version": 1 } entry.options = { CONF_ALLOW_HUE_GROUPS: False, CONF_ALLOW_UNREACHABLE: False } hue_bridge = bridge.HueBridge(hass, entry) with patch.object( hue_bridge.api, "initialize", side_effect=client_exceptions.ServerDisconnectedError, ), pytest.raises(ConfigEntryNotReady): await hue_bridge.async_initialize_bridge()
async def test_handle_unauthorized(hass): """Test handling an unauthorized error on update.""" entry = Mock(async_setup=AsyncMock()) entry.data = {"host": "1.2.3.4", "username": "******"} entry.options = { CONF_ALLOW_HUE_GROUPS: False, CONF_ALLOW_UNREACHABLE: False } hue_bridge = bridge.HueBridge(hass, entry) with patch.object(bridge, "authenticate_bridge"), patch("aiohue.Bridge"): assert await hue_bridge.async_setup() is True assert hue_bridge.authorized is True with patch.object(bridge, "create_config_flow") as mock_create: await hue_bridge.handle_unauthorized_error() assert hue_bridge.authorized is False assert len(mock_create.mock_calls) == 1 assert mock_create.mock_calls[0][1][1] == "1.2.3.4"
async def test_bridge_setup_invalid_api_key(hass): """Test we start config flow if username is no longer whitelisted.""" entry = Mock() entry.data = { "host": "1.2.3.4", "api_key": "mock-api-key", "api_version": 1 } entry.options = { CONF_ALLOW_HUE_GROUPS: False, CONF_ALLOW_UNREACHABLE: False } hue_bridge = bridge.HueBridge(hass, entry) with patch.object(hue_bridge.api, "initialize", side_effect=Unauthorized), patch.object( hass.config_entries.flow, "async_init") as mock_init: assert await hue_bridge.async_initialize_bridge() is False assert len(mock_init.mock_calls) == 1 assert mock_init.mock_calls[0][2]["data"] == {"host": "1.2.3.4"}
async def test_reset_unloads_entry_if_setup(hass): """Test calling reset while the entry has been setup.""" entry = Mock() entry.data = {"host": "1.2.3.4", "username": "******"} entry.options = {CONF_ALLOW_HUE_GROUPS: False, CONF_ALLOW_UNREACHABLE: False} hue_bridge = bridge.HueBridge(hass, entry) with patch.object(bridge, "authenticate_bridge", return_value=Mock()), patch( "aiohue.Bridge", return_value=Mock() ), patch.object(hass.config_entries, "async_forward_entry_setup") as mock_forward: assert await hue_bridge.async_setup() is True assert len(hass.services.async_services()) == 0 assert len(mock_forward.mock_calls) == 3 with patch.object( hass.config_entries, "async_forward_entry_unload", return_value=True ) as mock_forward: assert await hue_bridge.async_reset() assert len(mock_forward.mock_calls) == 3 assert len(hass.services.async_services()) == 0
async def test_handle_unauthorized(hass, mock_api_v1): """Test handling an unauthorized error on update.""" config_entry = Mock(async_setup=AsyncMock()) config_entry.data = { "host": "1.2.3.4", "api_key": "mock-api-key", "api_version": 1 } config_entry.options = { CONF_ALLOW_HUE_GROUPS: False, CONF_ALLOW_UNREACHABLE: False } with patch.object(bridge, "HueBridgeV1", return_value=mock_api_v1): hue_bridge = bridge.HueBridge(hass, config_entry) assert await hue_bridge.async_initialize_bridge() is True with patch.object(bridge, "create_config_flow") as mock_create: await hue_bridge.handle_unauthorized_error() assert hue_bridge.authorized is False assert len(mock_create.mock_calls) == 1 assert mock_create.mock_calls[0][1][1] == "1.2.3.4"
async def test_reset_unloads_entry_if_setup(hass): """Test calling reset while the entry has been setup.""" entry = Mock() entry.data = {"host": "1.2.3.4", "username": "******"} hue_bridge = bridge.HueBridge(hass, entry, False, False) with patch.object(bridge, "authenticate_bridge", return_value=mock_coro(Mock())), patch( "aiohue.Bridge", return_value=Mock()), patch.object( hass.config_entries, "async_forward_entry_setup") as mock_forward: assert await hue_bridge.async_setup() is True assert len(hass.services.async_services()) == 1 assert len(mock_forward.mock_calls) == 3 with patch.object(hass.config_entries, "async_forward_entry_unload", return_value=mock_coro(True)) as mock_forward: assert await hue_bridge.async_reset() assert len(mock_forward.mock_calls) == 3 assert len(hass.services.async_services()) == 0
async def test_bridge_setup_v2(hass, mock_api_v2): """Test a successful setup for V2 bridge.""" config_entry = Mock() config_entry.data = { "host": "1.2.3.4", "api_key": "mock-api-key", "api_version": 2 } with patch.object(bridge, "HueBridgeV2", return_value=mock_api_v2), patch.object( hass.config_entries, "async_forward_entry_setup") as mock_forward: hue_bridge = bridge.HueBridge(hass, config_entry) assert await hue_bridge.async_initialize_bridge() is True assert hue_bridge.api is mock_api_v2 assert isinstance(hue_bridge.api, HueBridgeV2) assert hue_bridge.api_version == 2 assert len(mock_forward.mock_calls) == 5 forward_entries = {c[1][1] for c in mock_forward.mock_calls} assert forward_entries == { "light", "binary_sensor", "sensor", "switch", "scene" }
async def test_event_updates(hass, caplog): """Test calling reset while the entry has been setup.""" events = asyncio.Queue() async def iterate_queue(): while True: event = await events.get() if event is None: return yield event async def wait_empty_queue(): count = 0 while not events.empty() and count < 50: await asyncio.sleep(0) count += 1 hue_bridge = bridge.HueBridge(None, None) hue_bridge.api = Mock(listen_events=iterate_queue) subscription_task = asyncio.create_task(ORIG_SUBSCRIBE_EVENTS(hue_bridge)) calls = [] def obj_updated(): calls.append(True) unsub = hue_bridge.listen_updates("lights", "2", obj_updated) events.put_nowait(Mock(ITEM_TYPE="lights", id="1")) await wait_empty_queue() assert len(calls) == 0 events.put_nowait(Mock(ITEM_TYPE="lights", id="2")) await wait_empty_queue() assert len(calls) == 1 unsub() events.put_nowait(Mock(ITEM_TYPE="lights", id="2")) await wait_empty_queue() assert len(calls) == 1 # Test we can override update listener. def obj_updated_false(): calls.append(False) unsub = hue_bridge.listen_updates("lights", "2", obj_updated) unsub_false = hue_bridge.listen_updates("lights", "2", obj_updated_false) assert "Overwriting update callback" in caplog.text events.put_nowait(Mock(ITEM_TYPE="lights", id="2")) await wait_empty_queue() assert len(calls) == 2 assert calls[-1] is False # Also call multiple times to make sure that works. unsub() unsub() unsub_false() unsub_false() events.put_nowait(Mock(ITEM_TYPE="lights", id="2")) await wait_empty_queue() assert len(calls) == 2 events.put_nowait(None) await subscription_task