Fix bug in fitbit credential import for expired tokens (#103024)

* Fix bug in fitbit credential import on token refresh

* Use stable test ids

* Update homeassistant/components/fitbit/sensor.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

---------

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
Allen Porter 2023-10-29 14:26:10 -07:00 committed by GitHub
parent b323295aa1
commit d75f1b2b3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 23 additions and 11 deletions

View File

@ -581,7 +581,9 @@ async def async_setup_platform(
refresh_cb=lambda x: None, refresh_cb=lambda x: None,
) )
try: try:
await hass.async_add_executor_job(authd_client.client.refresh_token) updated_token = await hass.async_add_executor_job(
authd_client.client.refresh_token
)
except OAuth2Error as err: except OAuth2Error as err:
_LOGGER.debug("Unable to import fitbit OAuth2 credentials: %s", err) _LOGGER.debug("Unable to import fitbit OAuth2 credentials: %s", err)
translation_key = "deprecated_yaml_import_issue_cannot_connect" translation_key = "deprecated_yaml_import_issue_cannot_connect"
@ -599,9 +601,10 @@ async def async_setup_platform(
data={ data={
"auth_implementation": DOMAIN, "auth_implementation": DOMAIN,
CONF_TOKEN: { CONF_TOKEN: {
ATTR_ACCESS_TOKEN: config_file[ATTR_ACCESS_TOKEN], ATTR_ACCESS_TOKEN: updated_token[ATTR_ACCESS_TOKEN],
ATTR_REFRESH_TOKEN: config_file[ATTR_REFRESH_TOKEN], ATTR_REFRESH_TOKEN: updated_token[ATTR_REFRESH_TOKEN],
"expires_at": config_file[ATTR_LAST_SAVED_AT], "expires_at": updated_token["expires_at"],
"scope": " ".join(updated_token.get("scope", [])),
}, },
CONF_CLOCK_FORMAT: config[CONF_CLOCK_FORMAT], CONF_CLOCK_FORMAT: config[CONF_CLOCK_FORMAT],
CONF_UNIT_SYSTEM: config[CONF_UNIT_SYSTEM], CONF_UNIT_SYSTEM: config[CONF_UNIT_SYSTEM],

View File

@ -41,10 +41,11 @@ TIMESERIES_API_URL_FORMAT = (
# These constants differ from values in the config entry or fitbit.conf # These constants differ from values in the config entry or fitbit.conf
SERVER_ACCESS_TOKEN = { SERVER_ACCESS_TOKEN = {
"refresh_token": "server-access-token", "refresh_token": "server-refresh-token",
"access_token": "server-refresh-token", "access_token": "server-access-token",
"type": "Bearer", "type": "Bearer",
"expires_in": 60, "expires_in": 60,
"scope": " ".join(OAUTH_SCOPES),
} }

View File

@ -2,6 +2,7 @@
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from http import HTTPStatus from http import HTTPStatus
import time
from typing import Any from typing import Any
from unittest.mock import patch from unittest.mock import patch
@ -16,9 +17,7 @@ from homeassistant.helpers import config_entry_oauth2_flow, issue_registry as ir
from .conftest import ( from .conftest import (
CLIENT_ID, CLIENT_ID,
FAKE_ACCESS_TOKEN,
FAKE_AUTH_IMPL, FAKE_AUTH_IMPL,
FAKE_REFRESH_TOKEN,
PROFILE_API_URL, PROFILE_API_URL,
PROFILE_USER_ID, PROFILE_USER_ID,
SERVER_ACCESS_TOKEN, SERVER_ACCESS_TOKEN,
@ -204,6 +203,11 @@ async def test_config_entry_already_exists(
assert result.get("reason") == "already_configured" assert result.get("reason") == "already_configured"
@pytest.mark.parametrize(
"token_expiration_time",
[time.time() + 86400, time.time() - 86400],
ids=("token_active", "token_expired"),
)
async def test_import_fitbit_config( async def test_import_fitbit_config(
hass: HomeAssistant, hass: HomeAssistant,
fitbit_config_setup: None, fitbit_config_setup: None,
@ -235,16 +239,20 @@ async def test_import_fitbit_config(
assert config_entry.unique_id == PROFILE_USER_ID assert config_entry.unique_id == PROFILE_USER_ID
data = dict(config_entry.data) data = dict(config_entry.data)
# Verify imported values from fitbit.conf and configuration.yaml and
# that the token is updated.
assert "token" in data assert "token" in data
expires_at = data["token"]["expires_at"]
assert expires_at > time.time()
del data["token"]["expires_at"] del data["token"]["expires_at"]
# Verify imported values from fitbit.conf and configuration.yaml
assert dict(config_entry.data) == { assert dict(config_entry.data) == {
"auth_implementation": DOMAIN, "auth_implementation": DOMAIN,
"clock_format": "24H", "clock_format": "24H",
"monitored_resources": ["activities/steps"], "monitored_resources": ["activities/steps"],
"token": { "token": {
"access_token": FAKE_ACCESS_TOKEN, "access_token": "server-access-token",
"refresh_token": FAKE_REFRESH_TOKEN, "refresh_token": "server-refresh-token",
"scope": "activity heartrate nutrition profile settings sleep weight",
}, },
"unit_system": "default", "unit_system": "default",
} }