mirror of https://github.com/home-assistant/core
187 lines
5.2 KiB
Python
187 lines
5.2 KiB
Python
"""Test fitbit component."""
|
|
|
|
from collections.abc import Awaitable, Callable
|
|
from http import HTTPStatus
|
|
|
|
import pytest
|
|
from requests_mock.mocker import Mocker
|
|
|
|
from homeassistant.components.fitbit.const import (
|
|
CONF_CLIENT_ID,
|
|
CONF_CLIENT_SECRET,
|
|
OAUTH2_TOKEN,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntryState
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from .conftest import (
|
|
CLIENT_ID,
|
|
CLIENT_SECRET,
|
|
DEVICES_API_URL,
|
|
FAKE_ACCESS_TOKEN,
|
|
FAKE_REFRESH_TOKEN,
|
|
SERVER_ACCESS_TOKEN,
|
|
)
|
|
|
|
from tests.common import MockConfigEntry
|
|
from tests.test_util.aiohttp import AiohttpClientMocker
|
|
|
|
|
|
async def test_setup(
|
|
hass: HomeAssistant,
|
|
integration_setup: Callable[[], Awaitable[bool]],
|
|
config_entry: MockConfigEntry,
|
|
setup_credentials: None,
|
|
) -> None:
|
|
"""Test setting up the integration."""
|
|
assert config_entry.state is ConfigEntryState.NOT_LOADED
|
|
|
|
assert await integration_setup()
|
|
assert config_entry.state is ConfigEntryState.LOADED
|
|
|
|
assert await hass.config_entries.async_unload(config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert config_entry.state is ConfigEntryState.NOT_LOADED
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("token_expiration_time", "server_status"),
|
|
[
|
|
(12345, HTTPStatus.INTERNAL_SERVER_ERROR),
|
|
(12345, HTTPStatus.FORBIDDEN),
|
|
(12345, HTTPStatus.NOT_FOUND),
|
|
],
|
|
)
|
|
async def test_token_refresh_failure(
|
|
integration_setup: Callable[[], Awaitable[bool]],
|
|
config_entry: MockConfigEntry,
|
|
aioclient_mock: AiohttpClientMocker,
|
|
setup_credentials: None,
|
|
server_status: HTTPStatus,
|
|
) -> None:
|
|
"""Test where token is expired and the refresh attempt fails and will be retried."""
|
|
|
|
aioclient_mock.post(
|
|
OAUTH2_TOKEN,
|
|
status=server_status,
|
|
)
|
|
|
|
assert not await integration_setup()
|
|
assert config_entry.state is ConfigEntryState.SETUP_RETRY
|
|
|
|
|
|
@pytest.mark.parametrize("token_expiration_time", [12345])
|
|
async def test_token_refresh_success(
|
|
integration_setup: Callable[[], Awaitable[bool]],
|
|
config_entry: MockConfigEntry,
|
|
aioclient_mock: AiohttpClientMocker,
|
|
setup_credentials: None,
|
|
) -> None:
|
|
"""Test where token is expired and the refresh attempt succeeds."""
|
|
|
|
assert config_entry.data["token"]["access_token"] == FAKE_ACCESS_TOKEN
|
|
|
|
aioclient_mock.post(
|
|
OAUTH2_TOKEN,
|
|
json=SERVER_ACCESS_TOKEN,
|
|
)
|
|
|
|
assert await integration_setup()
|
|
assert config_entry.state is ConfigEntryState.LOADED
|
|
|
|
# Verify token request
|
|
assert len(aioclient_mock.mock_calls) == 1
|
|
assert aioclient_mock.mock_calls[0][2] == {
|
|
CONF_CLIENT_ID: CLIENT_ID,
|
|
CONF_CLIENT_SECRET: CLIENT_SECRET,
|
|
"grant_type": "refresh_token",
|
|
"refresh_token": FAKE_REFRESH_TOKEN,
|
|
}
|
|
|
|
# Verify updated token
|
|
assert (
|
|
config_entry.data["token"]["access_token"]
|
|
== SERVER_ACCESS_TOKEN["access_token"]
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("token_expiration_time", "server_status"),
|
|
[
|
|
(12345, HTTPStatus.UNAUTHORIZED),
|
|
(12345, HTTPStatus.BAD_REQUEST),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize("closing", [True, False])
|
|
async def test_token_requires_reauth(
|
|
hass: HomeAssistant,
|
|
integration_setup: Callable[[], Awaitable[bool]],
|
|
config_entry: MockConfigEntry,
|
|
aioclient_mock: AiohttpClientMocker,
|
|
setup_credentials: None,
|
|
server_status: HTTPStatus,
|
|
closing: bool,
|
|
) -> None:
|
|
"""Test where token is expired and the refresh attempt requires reauth."""
|
|
|
|
aioclient_mock.post(
|
|
OAUTH2_TOKEN,
|
|
status=server_status,
|
|
closing=closing,
|
|
)
|
|
|
|
assert not await integration_setup()
|
|
assert config_entry.state is ConfigEntryState.SETUP_ERROR
|
|
|
|
flows = hass.config_entries.flow.async_progress()
|
|
assert len(flows) == 1
|
|
assert flows[0]["step_id"] == "reauth_confirm"
|
|
|
|
|
|
async def test_device_update_coordinator_failure(
|
|
hass: HomeAssistant,
|
|
integration_setup: Callable[[], Awaitable[bool]],
|
|
config_entry: MockConfigEntry,
|
|
setup_credentials: None,
|
|
requests_mock: Mocker,
|
|
) -> None:
|
|
"""Test case where the device update coordinator fails on the first request."""
|
|
assert config_entry.state is ConfigEntryState.NOT_LOADED
|
|
|
|
requests_mock.register_uri(
|
|
"GET",
|
|
DEVICES_API_URL,
|
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
)
|
|
|
|
assert not await integration_setup()
|
|
assert config_entry.state is ConfigEntryState.SETUP_RETRY
|
|
|
|
|
|
async def test_device_update_coordinator_reauth(
|
|
hass: HomeAssistant,
|
|
integration_setup: Callable[[], Awaitable[bool]],
|
|
config_entry: MockConfigEntry,
|
|
setup_credentials: None,
|
|
requests_mock: Mocker,
|
|
) -> None:
|
|
"""Test case where the device update coordinator fails on the first request."""
|
|
assert config_entry.state is ConfigEntryState.NOT_LOADED
|
|
|
|
requests_mock.register_uri(
|
|
"GET",
|
|
DEVICES_API_URL,
|
|
status_code=HTTPStatus.UNAUTHORIZED,
|
|
json={
|
|
"errors": [{"errorType": "invalid_grant"}],
|
|
},
|
|
)
|
|
|
|
assert not await integration_setup()
|
|
assert config_entry.state is ConfigEntryState.SETUP_ERROR
|
|
|
|
flows = hass.config_entries.flow.async_progress()
|
|
assert len(flows) == 1
|
|
assert flows[0]["step_id"] == "reauth_confirm"
|