mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Refactor nest test_init_sdm tests to use fixtures with varied config types (#64736)
This commit is contained in:
parent
15532c38d7
commit
cdf7742c3e
@ -1,7 +1,9 @@
|
|||||||
"""Common libraries for test setup."""
|
"""Common libraries for test setup."""
|
||||||
|
|
||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
|
from dataclasses import dataclass
|
||||||
import time
|
import time
|
||||||
|
from typing import Any, Generator, TypeVar
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from google_nest_sdm.device_manager import DeviceManager
|
from google_nest_sdm.device_manager import DeviceManager
|
||||||
@ -15,17 +17,22 @@ from homeassistant.setup import async_setup_component
|
|||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
# Typing helpers
|
||||||
|
PlatformSetup = Callable[[], Awaitable[None]]
|
||||||
|
T = TypeVar("T")
|
||||||
|
YieldFixture = Generator[T, None, None]
|
||||||
|
|
||||||
PROJECT_ID = "some-project-id"
|
PROJECT_ID = "some-project-id"
|
||||||
CLIENT_ID = "some-client-id"
|
CLIENT_ID = "some-client-id"
|
||||||
CLIENT_SECRET = "some-client-secret"
|
CLIENT_SECRET = "some-client-secret"
|
||||||
|
SUBSCRIBER_ID = "projects/example/subscriptions/subscriber-id-9876"
|
||||||
|
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"nest": {
|
"nest": {
|
||||||
"client_id": CLIENT_ID,
|
"client_id": CLIENT_ID,
|
||||||
"client_secret": CLIENT_SECRET,
|
"client_secret": CLIENT_SECRET,
|
||||||
# Required fields for using SDM API
|
|
||||||
"project_id": PROJECT_ID,
|
"project_id": PROJECT_ID,
|
||||||
"subscriber_id": "projects/example/subscriptions/subscriber-id-9876",
|
"subscriber_id": SUBSCRIBER_ID,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,24 +40,64 @@ FAKE_TOKEN = "some-token"
|
|||||||
FAKE_REFRESH_TOKEN = "some-refresh-token"
|
FAKE_REFRESH_TOKEN = "some-refresh-token"
|
||||||
|
|
||||||
|
|
||||||
def create_config_entry(hass, token_expiration_time=None) -> MockConfigEntry:
|
def create_token_entry(token_expiration_time=None):
|
||||||
"""Create a ConfigEntry and add it to Home Assistant."""
|
"""Create OAuth 'token' data for a ConfigEntry."""
|
||||||
if token_expiration_time is None:
|
if token_expiration_time is None:
|
||||||
token_expiration_time = time.time() + 86400
|
token_expiration_time = time.time() + 86400
|
||||||
config_entry_data = {
|
return {
|
||||||
"sdm": {}, # Indicates new SDM API, not legacy API
|
|
||||||
"auth_implementation": "nest",
|
|
||||||
"token": {
|
|
||||||
"access_token": FAKE_TOKEN,
|
"access_token": FAKE_TOKEN,
|
||||||
"refresh_token": FAKE_REFRESH_TOKEN,
|
"refresh_token": FAKE_REFRESH_TOKEN,
|
||||||
"scope": " ".join(SDM_SCOPES),
|
"scope": " ".join(SDM_SCOPES),
|
||||||
"token_type": "Bearer",
|
"token_type": "Bearer",
|
||||||
"expires_at": token_expiration_time,
|
"expires_at": token_expiration_time,
|
||||||
},
|
|
||||||
}
|
}
|
||||||
config_entry = MockConfigEntry(domain=DOMAIN, data=config_entry_data)
|
|
||||||
config_entry.add_to_hass(hass)
|
|
||||||
return config_entry
|
def create_config_entry(token_expiration_time=None) -> MockConfigEntry:
|
||||||
|
"""Create a ConfigEntry and add it to Home Assistant."""
|
||||||
|
config_entry_data = {
|
||||||
|
"sdm": {}, # Indicates new SDM API, not legacy API
|
||||||
|
"auth_implementation": "nest",
|
||||||
|
"token": create_token_entry(token_expiration_time),
|
||||||
|
}
|
||||||
|
return MockConfigEntry(domain=DOMAIN, data=config_entry_data)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NestTestConfig:
|
||||||
|
"""Holder for integration configuration."""
|
||||||
|
|
||||||
|
config: dict[str, Any]
|
||||||
|
config_entry_data: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
# Exercises mode where all configuration is in configuration.yaml
|
||||||
|
TEST_CONFIG_YAML_ONLY = NestTestConfig(
|
||||||
|
config=CONFIG,
|
||||||
|
config_entry_data={
|
||||||
|
"sdm": {},
|
||||||
|
"auth_implementation": "nest",
|
||||||
|
"token": create_token_entry(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Exercises mode where subscriber id is created in the config flow, but
|
||||||
|
# all authentication is defined in configuration.yaml
|
||||||
|
TEST_CONFIG_HYBRID = NestTestConfig(
|
||||||
|
config={
|
||||||
|
"nest": {
|
||||||
|
"client_id": CLIENT_ID,
|
||||||
|
"client_secret": CLIENT_SECRET,
|
||||||
|
"project_id": PROJECT_ID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
config_entry_data={
|
||||||
|
"sdm": {},
|
||||||
|
"auth_implementation": "nest",
|
||||||
|
"token": create_token_entry(),
|
||||||
|
"subscriber_id": SUBSCRIBER_ID,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class FakeSubscriber(GoogleNestSubscriber):
|
class FakeSubscriber(GoogleNestSubscriber):
|
||||||
@ -100,7 +147,7 @@ async def async_setup_sdm_platform(
|
|||||||
):
|
):
|
||||||
"""Set up the platform and prerequisites."""
|
"""Set up the platform and prerequisites."""
|
||||||
if with_config:
|
if with_config:
|
||||||
create_config_entry(hass)
|
create_config_entry().add_to_hass(hass)
|
||||||
subscriber = FakeSubscriber()
|
subscriber = FakeSubscriber()
|
||||||
device_manager = await subscriber.async_get_device_manager()
|
device_manager = await subscriber.async_get_device_manager()
|
||||||
if devices:
|
if devices:
|
||||||
|
@ -1,13 +1,34 @@
|
|||||||
"""Common libraries for test setup."""
|
"""Common libraries for test setup."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import copy
|
||||||
import shutil
|
import shutil
|
||||||
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from google_nest_sdm.auth import AbstractAuth
|
from google_nest_sdm.auth import AbstractAuth
|
||||||
|
from google_nest_sdm.device_manager import DeviceManager
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.nest import DOMAIN
|
||||||
|
from homeassistant.components.nest.const import CONF_SUBSCRIBER_ID
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from .common import (
|
||||||
|
SUBSCRIBER_ID,
|
||||||
|
TEST_CONFIG_HYBRID,
|
||||||
|
TEST_CONFIG_YAML_ONLY,
|
||||||
|
FakeSubscriber,
|
||||||
|
NestTestConfig,
|
||||||
|
PlatformSetup,
|
||||||
|
YieldFixture,
|
||||||
|
)
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
class FakeAuth(AbstractAuth):
|
class FakeAuth(AbstractAuth):
|
||||||
"""A fake implementation of the auth class that records requests.
|
"""A fake implementation of the auth class that records requests.
|
||||||
@ -76,3 +97,100 @@ def cleanup_media_storage(hass):
|
|||||||
with patch("homeassistant.components.nest.media_source.MEDIA_PATH", new=tmp_path):
|
with patch("homeassistant.components.nest.media_source.MEDIA_PATH", new=tmp_path):
|
||||||
yield
|
yield
|
||||||
shutil.rmtree(hass.config.path(tmp_path), ignore_errors=True)
|
shutil.rmtree(hass.config.path(tmp_path), ignore_errors=True)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def subscriber() -> YieldFixture[FakeSubscriber]:
|
||||||
|
"""Set up the FakeSusbcriber."""
|
||||||
|
subscriber = FakeSubscriber()
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.nest.api.GoogleNestSubscriber",
|
||||||
|
return_value=subscriber,
|
||||||
|
):
|
||||||
|
yield subscriber
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def device_manager(subscriber: FakeSubscriber) -> DeviceManager:
|
||||||
|
"""Set up the DeviceManager."""
|
||||||
|
return await subscriber.async_get_device_manager()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def platforms() -> list[str]:
|
||||||
|
"""Fixture to specify platforms to test."""
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def subscriber_id() -> str:
|
||||||
|
"""Fixture to let tests override subscriber id regardless of configuration type used."""
|
||||||
|
return SUBSCRIBER_ID
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(
|
||||||
|
params=[TEST_CONFIG_YAML_ONLY, TEST_CONFIG_HYBRID],
|
||||||
|
ids=["yaml-config-only", "hybrid-config"],
|
||||||
|
)
|
||||||
|
def nest_test_config(request) -> NestTestConfig:
|
||||||
|
"""Fixture that sets up the configuration used for the test."""
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def config(
|
||||||
|
subscriber_id: str | None, nest_test_config: NestTestConfig
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Fixture that sets up the configuration.yaml for the test."""
|
||||||
|
config = copy.deepcopy(nest_test_config.config)
|
||||||
|
if CONF_SUBSCRIBER_ID in config.get(DOMAIN, {}):
|
||||||
|
if subscriber_id:
|
||||||
|
config[DOMAIN][CONF_SUBSCRIBER_ID] = subscriber_id
|
||||||
|
else:
|
||||||
|
del config[DOMAIN][CONF_SUBSCRIBER_ID]
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def config_entry(
|
||||||
|
subscriber_id: str | None, nest_test_config: NestTestConfig
|
||||||
|
) -> MockConfigEntry | None:
|
||||||
|
"""Fixture that sets up the ConfigEntry for the test."""
|
||||||
|
if nest_test_config.config_entry_data is None:
|
||||||
|
return None
|
||||||
|
data = copy.deepcopy(nest_test_config.config_entry_data)
|
||||||
|
if CONF_SUBSCRIBER_ID in data:
|
||||||
|
if subscriber_id:
|
||||||
|
data[CONF_SUBSCRIBER_ID] = subscriber_id
|
||||||
|
else:
|
||||||
|
del data[CONF_SUBSCRIBER_ID]
|
||||||
|
return MockConfigEntry(domain=DOMAIN, data=data)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def setup_base_platform(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
platforms: list[str],
|
||||||
|
config: dict[str, Any],
|
||||||
|
config_entry: MockConfigEntry | None,
|
||||||
|
) -> YieldFixture[PlatformSetup]:
|
||||||
|
"""Fixture to setup the integration platform."""
|
||||||
|
if config_entry:
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
|
||||||
|
), patch("homeassistant.components.nest.PLATFORMS", platforms):
|
||||||
|
|
||||||
|
async def _setup_func() -> bool:
|
||||||
|
assert await async_setup_component(hass, DOMAIN, config)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
yield _setup_func
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def setup_platform(
|
||||||
|
setup_base_platform: PlatformSetup, subscriber: FakeSubscriber
|
||||||
|
) -> PlatformSetup:
|
||||||
|
"""Fixture to setup the integration platform and subscriber."""
|
||||||
|
return setup_base_platform
|
||||||
|
@ -39,7 +39,7 @@ async def test_auth(hass, aioclient_mock):
|
|||||||
"""Exercise authentication library creates valid credentials."""
|
"""Exercise authentication library creates valid credentials."""
|
||||||
|
|
||||||
expiration_time = time.time() + 86400
|
expiration_time = time.time() + 86400
|
||||||
create_config_entry(hass, expiration_time)
|
create_config_entry(expiration_time).add_to_hass(hass)
|
||||||
|
|
||||||
# Prepare to capture credentials in API request. Empty payloads just mean
|
# Prepare to capture credentials in API request. Empty payloads just mean
|
||||||
# no devices or structures are loaded.
|
# no devices or structures are loaded.
|
||||||
@ -88,7 +88,7 @@ async def test_auth_expired_token(hass, aioclient_mock):
|
|||||||
"""Verify behavior of an expired token."""
|
"""Verify behavior of an expired token."""
|
||||||
|
|
||||||
expiration_time = time.time() - 86400
|
expiration_time = time.time() - 86400
|
||||||
create_config_entry(hass, expiration_time)
|
create_config_entry(expiration_time).add_to_hass(hass)
|
||||||
|
|
||||||
# Prepare a token refresh response
|
# Prepare a token refresh response
|
||||||
aioclient_mock.post(
|
aioclient_mock.post(
|
||||||
|
@ -70,7 +70,8 @@ async def test_entry_diagnostics(hass, hass_client):
|
|||||||
|
|
||||||
async def test_setup_susbcriber_failure(hass, hass_client):
|
async def test_setup_susbcriber_failure(hass, hass_client):
|
||||||
"""Test configuration error."""
|
"""Test configuration error."""
|
||||||
config_entry = create_config_entry(hass)
|
config_entry = create_config_entry()
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
|
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
|
||||||
), patch(
|
), patch(
|
||||||
|
@ -3,10 +3,14 @@ Test for setup methods for the SDM API.
|
|||||||
|
|
||||||
The tests fake out the subscriber/devicemanager and simulate setup behavior
|
The tests fake out the subscriber/devicemanager and simulate setup behavior
|
||||||
and failure modes.
|
and failure modes.
|
||||||
|
|
||||||
|
By default all tests use test fixtures that run in each possible configuration
|
||||||
|
mode (e.g. yaml, ConfigEntry, etc) however some tests override and just run in
|
||||||
|
relevant modes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import copy
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from google_nest_sdm.exceptions import (
|
from google_nest_sdm.exceptions import (
|
||||||
@ -15,44 +19,75 @@ from google_nest_sdm.exceptions import (
|
|||||||
ConfigurationException,
|
ConfigurationException,
|
||||||
SubscriberException,
|
SubscriberException,
|
||||||
)
|
)
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.nest import DOMAIN
|
from homeassistant.components.nest import DOMAIN
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.setup import async_setup_component
|
|
||||||
|
|
||||||
from .common import CONFIG, async_setup_sdm_platform, create_config_entry
|
from .common import (
|
||||||
|
TEST_CONFIG_HYBRID,
|
||||||
|
TEST_CONFIG_YAML_ONLY,
|
||||||
|
FakeSubscriber,
|
||||||
|
NestTestConfig,
|
||||||
|
YieldFixture,
|
||||||
|
)
|
||||||
|
|
||||||
PLATFORM = "sensor"
|
PLATFORM = "sensor"
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_success(hass, caplog):
|
@pytest.fixture
|
||||||
"""Test successful setup."""
|
def platforms() -> list[str]:
|
||||||
|
"""Fixture to setup the platforms to test."""
|
||||||
|
return ["sensor"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def error_caplog(caplog):
|
||||||
|
"""Fixture to capture nest init error messages."""
|
||||||
with caplog.at_level(logging.ERROR, logger="homeassistant.components.nest"):
|
with caplog.at_level(logging.ERROR, logger="homeassistant.components.nest"):
|
||||||
await async_setup_sdm_platform(hass, PLATFORM)
|
yield caplog
|
||||||
assert not caplog.records
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def warning_caplog(caplog):
|
||||||
|
"""Fixture to capture nest init warning messages."""
|
||||||
|
with caplog.at_level(logging.WARNING, logger="homeassistant.components.nest"):
|
||||||
|
yield caplog
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def subscriber_side_effect() -> None:
|
||||||
|
"""Fixture to inject failures into FakeSubscriber start."""
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def failing_subscriber(subscriber_side_effect: Any) -> YieldFixture[FakeSubscriber]:
|
||||||
|
"""Fixture overriding default subscriber behavior to allow failure injection."""
|
||||||
|
subscriber = FakeSubscriber()
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.nest.api.GoogleNestSubscriber.start_async",
|
||||||
|
side_effect=subscriber_side_effect,
|
||||||
|
):
|
||||||
|
yield subscriber
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_success(hass, error_caplog, setup_platform):
|
||||||
|
"""Test successful setup."""
|
||||||
|
await setup_platform()
|
||||||
|
assert not error_caplog.records
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert entries[0].state is ConfigEntryState.LOADED
|
assert entries[0].state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_sdm(hass, config=CONFIG, with_config=True):
|
@pytest.mark.parametrize("subscriber_id", [("invalid-subscriber-format")])
|
||||||
"""Prepare test setup."""
|
async def test_setup_configuration_failure(
|
||||||
if with_config:
|
hass, caplog, subscriber_id, setup_base_platform
|
||||||
create_config_entry(hass)
|
):
|
||||||
with patch(
|
|
||||||
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
|
|
||||||
):
|
|
||||||
return await async_setup_component(hass, DOMAIN, config)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_configuration_failure(hass, caplog):
|
|
||||||
"""Test configuration error."""
|
"""Test configuration error."""
|
||||||
config = copy.deepcopy(CONFIG)
|
await setup_base_platform()
|
||||||
config[DOMAIN]["subscriber_id"] = "invalid-subscriber-format"
|
|
||||||
|
|
||||||
result = await async_setup_sdm(hass, config)
|
|
||||||
assert result
|
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
@ -63,49 +98,43 @@ async def test_setup_configuration_failure(hass, caplog):
|
|||||||
assert "Subscription misconfigured. Expected subscriber_id" in caplog.text
|
assert "Subscription misconfigured. Expected subscriber_id" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_susbcriber_failure(hass, caplog):
|
@pytest.mark.parametrize("subscriber_side_effect", [SubscriberException()])
|
||||||
|
async def test_setup_susbcriber_failure(
|
||||||
|
hass, error_caplog, failing_subscriber, setup_base_platform
|
||||||
|
):
|
||||||
"""Test configuration error."""
|
"""Test configuration error."""
|
||||||
with patch(
|
await setup_base_platform()
|
||||||
"homeassistant.components.nest.api.GoogleNestSubscriber.start_async",
|
assert "Subscriber error:" in error_caplog.text
|
||||||
side_effect=SubscriberException(),
|
|
||||||
), caplog.at_level(logging.ERROR, logger="homeassistant.components.nest"):
|
|
||||||
result = await async_setup_sdm(hass)
|
|
||||||
assert result
|
|
||||||
assert "Subscriber error:" in caplog.text
|
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert entries[0].state is ConfigEntryState.SETUP_RETRY
|
assert entries[0].state is ConfigEntryState.SETUP_RETRY
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_device_manager_failure(hass, caplog):
|
async def test_setup_device_manager_failure(hass, error_caplog, setup_base_platform):
|
||||||
"""Test configuration error."""
|
"""Test device manager api failure."""
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.nest.api.GoogleNestSubscriber.start_async"
|
"homeassistant.components.nest.api.GoogleNestSubscriber.start_async"
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.nest.api.GoogleNestSubscriber.async_get_device_manager",
|
"homeassistant.components.nest.api.GoogleNestSubscriber.async_get_device_manager",
|
||||||
side_effect=ApiException(),
|
side_effect=ApiException(),
|
||||||
), caplog.at_level(
|
|
||||||
logging.ERROR, logger="homeassistant.components.nest"
|
|
||||||
):
|
):
|
||||||
result = await async_setup_sdm(hass)
|
await setup_base_platform()
|
||||||
assert result
|
|
||||||
assert len(caplog.messages) == 1
|
assert len(error_caplog.messages) == 1
|
||||||
assert "Device manager error:" in caplog.text
|
assert "Device manager error:" in error_caplog.text
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert entries[0].state is ConfigEntryState.SETUP_RETRY
|
assert entries[0].state is ConfigEntryState.SETUP_RETRY
|
||||||
|
|
||||||
|
|
||||||
async def test_subscriber_auth_failure(hass, caplog):
|
@pytest.mark.parametrize("subscriber_side_effect", [AuthException()])
|
||||||
"""Test configuration error."""
|
async def test_subscriber_auth_failure(
|
||||||
with patch(
|
hass, caplog, setup_base_platform, failing_subscriber
|
||||||
"homeassistant.components.nest.api.GoogleNestSubscriber.start_async",
|
):
|
||||||
side_effect=AuthException(),
|
"""Test subscriber throws an authentication error."""
|
||||||
):
|
await setup_base_platform()
|
||||||
result = await async_setup_sdm(hass, CONFIG)
|
|
||||||
assert result
|
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
@ -116,70 +145,45 @@ async def test_subscriber_auth_failure(hass, caplog):
|
|||||||
assert flows[0]["step_id"] == "reauth_confirm"
|
assert flows[0]["step_id"] == "reauth_confirm"
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_missing_subscriber_id(hass, caplog):
|
@pytest.mark.parametrize("subscriber_id", [(None)])
|
||||||
"""Test missing susbcriber id from config and config entry."""
|
async def test_setup_missing_subscriber_id(hass, warning_caplog, setup_base_platform):
|
||||||
config = copy.deepcopy(CONFIG)
|
"""Test missing susbcriber id from configuration."""
|
||||||
del config[DOMAIN]["subscriber_id"]
|
await setup_base_platform()
|
||||||
|
assert "Configuration option" in warning_caplog.text
|
||||||
with caplog.at_level(logging.WARNING, logger="homeassistant.components.nest"):
|
|
||||||
result = await async_setup_sdm(hass, config)
|
|
||||||
assert result
|
|
||||||
assert "Configuration option" in caplog.text
|
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert entries[0].state is ConfigEntryState.SETUP_ERROR
|
assert entries[0].state is ConfigEntryState.SETUP_ERROR
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_subscriber_id_config_entry(hass, caplog):
|
@pytest.mark.parametrize("subscriber_side_effect", [(ConfigurationException())])
|
||||||
"""Test successful setup with subscriber id in ConfigEntry."""
|
async def test_subscriber_configuration_failure(
|
||||||
config = copy.deepcopy(CONFIG)
|
hass, error_caplog, setup_base_platform, failing_subscriber
|
||||||
subscriber_id = config[DOMAIN]["subscriber_id"]
|
):
|
||||||
del config[DOMAIN]["subscriber_id"]
|
|
||||||
|
|
||||||
config_entry = create_config_entry(hass)
|
|
||||||
data = {**config_entry.data}
|
|
||||||
data["subscriber_id"] = subscriber_id
|
|
||||||
hass.config_entries.async_update_entry(config_entry, data=data)
|
|
||||||
|
|
||||||
with caplog.at_level(logging.ERROR, logger="homeassistant.components.nest"):
|
|
||||||
await async_setup_sdm_platform(hass, PLATFORM, with_config=False)
|
|
||||||
assert not caplog.records
|
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
|
||||||
assert len(entries) == 1
|
|
||||||
assert entries[0].state is ConfigEntryState.LOADED
|
|
||||||
|
|
||||||
|
|
||||||
async def test_subscriber_configuration_failure(hass, caplog):
|
|
||||||
"""Test configuration error."""
|
"""Test configuration error."""
|
||||||
with patch(
|
await setup_base_platform()
|
||||||
"homeassistant.components.nest.api.GoogleNestSubscriber.start_async",
|
assert "Configuration error: " in error_caplog.text
|
||||||
side_effect=ConfigurationException(),
|
|
||||||
), caplog.at_level(logging.ERROR, logger="homeassistant.components.nest"):
|
|
||||||
result = await async_setup_sdm(hass, CONFIG)
|
|
||||||
assert result
|
|
||||||
assert "Configuration error: " in caplog.text
|
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
assert entries[0].state is ConfigEntryState.SETUP_ERROR
|
assert entries[0].state is ConfigEntryState.SETUP_ERROR
|
||||||
|
|
||||||
|
|
||||||
async def test_empty_config(hass, caplog):
|
@pytest.mark.parametrize(
|
||||||
"""Test successful setup."""
|
"nest_test_config", [NestTestConfig(config={}, config_entry_data=None)]
|
||||||
with caplog.at_level(logging.ERROR, logger="homeassistant.components.nest"):
|
)
|
||||||
result = await async_setup_component(hass, DOMAIN, {})
|
async def test_empty_config(hass, error_caplog, config, setup_platform):
|
||||||
assert result
|
"""Test setup is a no-op with not config."""
|
||||||
assert not caplog.records
|
await setup_platform()
|
||||||
|
assert not error_caplog.records
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 0
|
assert len(entries) == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_unload_entry(hass, caplog):
|
async def test_unload_entry(hass, setup_platform):
|
||||||
"""Test successful unload of a ConfigEntry."""
|
"""Test successful unload of a ConfigEntry."""
|
||||||
await async_setup_sdm_platform(hass, PLATFORM)
|
await setup_platform()
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
@ -190,33 +194,27 @@ async def test_unload_entry(hass, caplog):
|
|||||||
assert entry.state == ConfigEntryState.NOT_LOADED
|
assert entry.state == ConfigEntryState.NOT_LOADED
|
||||||
|
|
||||||
|
|
||||||
async def test_remove_entry(hass, caplog):
|
@pytest.mark.parametrize(
|
||||||
|
"nest_test_config,delete_called",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
TEST_CONFIG_YAML_ONLY,
|
||||||
|
False,
|
||||||
|
), # User manually created subscriber, preserve on remove
|
||||||
|
(
|
||||||
|
TEST_CONFIG_HYBRID,
|
||||||
|
True,
|
||||||
|
), # Integration created subscriber, garbage collect on remove
|
||||||
|
],
|
||||||
|
ids=["yaml-config-only", "hybrid-config"],
|
||||||
|
)
|
||||||
|
async def test_remove_entry(hass, nest_test_config, setup_base_platform, delete_called):
|
||||||
"""Test successful unload of a ConfigEntry."""
|
"""Test successful unload of a ConfigEntry."""
|
||||||
await async_setup_sdm_platform(hass, PLATFORM)
|
with patch(
|
||||||
|
"homeassistant.components.nest.api.GoogleNestSubscriber",
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
return_value=FakeSubscriber(),
|
||||||
assert len(entries) == 1
|
):
|
||||||
entry = entries[0]
|
await setup_base_platform()
|
||||||
assert entry.state is ConfigEntryState.LOADED
|
|
||||||
|
|
||||||
assert await hass.config_entries.async_remove(entry.entry_id)
|
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
|
||||||
assert not entries
|
|
||||||
|
|
||||||
|
|
||||||
async def test_remove_entry_deletes_subscriber(hass, caplog):
|
|
||||||
"""Test ConfigEntry unload deletes a subscription."""
|
|
||||||
config = copy.deepcopy(CONFIG)
|
|
||||||
subscriber_id = config[DOMAIN]["subscriber_id"]
|
|
||||||
del config[DOMAIN]["subscriber_id"]
|
|
||||||
|
|
||||||
config_entry = create_config_entry(hass)
|
|
||||||
data = {**config_entry.data}
|
|
||||||
data["subscriber_id"] = subscriber_id
|
|
||||||
hass.config_entries.async_update_entry(config_entry, data=data)
|
|
||||||
|
|
||||||
await async_setup_sdm_platform(hass, PLATFORM, with_config=False)
|
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
@ -224,27 +222,29 @@ async def test_remove_entry_deletes_subscriber(hass, caplog):
|
|||||||
assert entry.state is ConfigEntryState.LOADED
|
assert entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
|
"homeassistant.components.nest.api.GoogleNestSubscriber.subscriber_id"
|
||||||
|
), patch(
|
||||||
"homeassistant.components.nest.api.GoogleNestSubscriber.delete_subscription",
|
"homeassistant.components.nest.api.GoogleNestSubscriber.delete_subscription",
|
||||||
) as delete:
|
) as delete:
|
||||||
assert await hass.config_entries.async_remove(entry.entry_id)
|
assert await hass.config_entries.async_remove(entry.entry_id)
|
||||||
assert delete.called
|
assert delete.called == delete_called
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert not entries
|
assert not entries
|
||||||
|
|
||||||
|
|
||||||
async def test_remove_entry_delete_subscriber_failure(hass, caplog):
|
@pytest.mark.parametrize(
|
||||||
|
"nest_test_config", [TEST_CONFIG_HYBRID], ids=["hyrbid-config"]
|
||||||
|
)
|
||||||
|
async def test_remove_entry_delete_subscriber_failure(
|
||||||
|
hass, nest_test_config, setup_base_platform
|
||||||
|
):
|
||||||
"""Test a failure when deleting the subscription."""
|
"""Test a failure when deleting the subscription."""
|
||||||
config = copy.deepcopy(CONFIG)
|
with patch(
|
||||||
subscriber_id = config[DOMAIN]["subscriber_id"]
|
"homeassistant.components.nest.api.GoogleNestSubscriber",
|
||||||
del config[DOMAIN]["subscriber_id"]
|
return_value=FakeSubscriber(),
|
||||||
|
):
|
||||||
config_entry = create_config_entry(hass)
|
await setup_base_platform()
|
||||||
data = {**config_entry.data}
|
|
||||||
data["subscriber_id"] = subscriber_id
|
|
||||||
hass.config_entries.async_update_entry(config_entry, data=data)
|
|
||||||
|
|
||||||
await async_setup_sdm_platform(hass, PLATFORM, with_config=False)
|
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert len(entries) == 1
|
assert len(entries) == 1
|
||||||
@ -254,8 +254,9 @@ async def test_remove_entry_delete_subscriber_failure(hass, caplog):
|
|||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.nest.api.GoogleNestSubscriber.delete_subscription",
|
"homeassistant.components.nest.api.GoogleNestSubscriber.delete_subscription",
|
||||||
side_effect=SubscriberException(),
|
side_effect=SubscriberException(),
|
||||||
):
|
) as delete:
|
||||||
assert await hass.config_entries.async_remove(entry.entry_id)
|
assert await hass.config_entries.async_remove(entry.entry_id)
|
||||||
|
assert delete.called
|
||||||
|
|
||||||
entries = hass.config_entries.async_entries(DOMAIN)
|
entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
assert not entries
|
assert not entries
|
||||||
|
@ -1043,7 +1043,8 @@ async def test_media_store_persistence(hass, auth, hass_client, event_store):
|
|||||||
# Fetch media for events when published
|
# Fetch media for events when published
|
||||||
subscriber.cache_policy.fetch = True
|
subscriber.cache_policy.fetch = True
|
||||||
|
|
||||||
config_entry = create_config_entry(hass)
|
config_entry = create_config_entry()
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
|
"homeassistant.helpers.config_entry_oauth2_flow.async_get_config_entry_implementation"
|
||||||
|
@ -6,7 +6,9 @@ pubsub subscriber.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from google_nest_sdm.device import Device
|
from google_nest_sdm.device import Device
|
||||||
|
from google_nest_sdm.device_manager import DeviceManager
|
||||||
from google_nest_sdm.event import EventMessage
|
from google_nest_sdm.event import EventMessage
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.sensor import ATTR_STATE_CLASS, STATE_CLASS_MEASUREMENT
|
from homeassistant.components.sensor import ATTR_STATE_CLASS, STATE_CLASS_MEASUREMENT
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -17,24 +19,26 @@ from homeassistant.const import (
|
|||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
TEMP_CELSIUS,
|
TEMP_CELSIUS,
|
||||||
)
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
|
|
||||||
from .common import async_setup_sdm_platform
|
from .common import FakeSubscriber, PlatformSetup
|
||||||
|
|
||||||
PLATFORM = "sensor"
|
|
||||||
|
|
||||||
THERMOSTAT_TYPE = "sdm.devices.types.THERMOSTAT"
|
THERMOSTAT_TYPE = "sdm.devices.types.THERMOSTAT"
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_sensor(hass, devices={}, structures={}):
|
@pytest.fixture
|
||||||
"""Set up the platform and prerequisites."""
|
def platforms() -> list[str]:
|
||||||
return await async_setup_sdm_platform(hass, PLATFORM, devices, structures)
|
"""Fixture to setup the platforms to test."""
|
||||||
|
return ["sensor"]
|
||||||
|
|
||||||
|
|
||||||
async def test_thermostat_device(hass):
|
async def test_thermostat_device(
|
||||||
|
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
|
||||||
|
):
|
||||||
"""Test a thermostat with temperature and humidity sensors."""
|
"""Test a thermostat with temperature and humidity sensors."""
|
||||||
devices = {
|
device_manager.add_device(
|
||||||
"some-device-id": Device.MakeDevice(
|
Device.MakeDevice(
|
||||||
{
|
{
|
||||||
"name": "some-device-id",
|
"name": "some-device-id",
|
||||||
"type": THERMOSTAT_TYPE,
|
"type": THERMOSTAT_TYPE,
|
||||||
@ -52,8 +56,8 @@ async def test_thermostat_device(hass):
|
|||||||
},
|
},
|
||||||
auth=None,
|
auth=None,
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
await async_setup_sensor(hass, devices)
|
await setup_platform()
|
||||||
|
|
||||||
temperature = hass.states.get("sensor.my_sensor_temperature")
|
temperature = hass.states.get("sensor.my_sensor_temperature")
|
||||||
assert temperature is not None
|
assert temperature is not None
|
||||||
@ -87,9 +91,9 @@ async def test_thermostat_device(hass):
|
|||||||
assert device.identifiers == {("nest", "some-device-id")}
|
assert device.identifiers == {("nest", "some-device-id")}
|
||||||
|
|
||||||
|
|
||||||
async def test_no_devices(hass):
|
async def test_no_devices(hass: HomeAssistant, setup_platform: PlatformSetup):
|
||||||
"""Test no devices returned by the api."""
|
"""Test no devices returned by the api."""
|
||||||
await async_setup_sensor(hass)
|
await setup_platform()
|
||||||
|
|
||||||
temperature = hass.states.get("sensor.my_sensor_temperature")
|
temperature = hass.states.get("sensor.my_sensor_temperature")
|
||||||
assert temperature is None
|
assert temperature is None
|
||||||
@ -98,10 +102,12 @@ async def test_no_devices(hass):
|
|||||||
assert humidity is None
|
assert humidity is None
|
||||||
|
|
||||||
|
|
||||||
async def test_device_no_sensor_traits(hass):
|
async def test_device_no_sensor_traits(
|
||||||
|
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
|
||||||
|
) -> None:
|
||||||
"""Test a device with applicable sensor traits."""
|
"""Test a device with applicable sensor traits."""
|
||||||
devices = {
|
device_manager.add_device(
|
||||||
"some-device-id": Device.MakeDevice(
|
Device.MakeDevice(
|
||||||
{
|
{
|
||||||
"name": "some-device-id",
|
"name": "some-device-id",
|
||||||
"type": THERMOSTAT_TYPE,
|
"type": THERMOSTAT_TYPE,
|
||||||
@ -109,8 +115,8 @@ async def test_device_no_sensor_traits(hass):
|
|||||||
},
|
},
|
||||||
auth=None,
|
auth=None,
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
await async_setup_sensor(hass, devices)
|
await setup_platform()
|
||||||
|
|
||||||
temperature = hass.states.get("sensor.my_sensor_temperature")
|
temperature = hass.states.get("sensor.my_sensor_temperature")
|
||||||
assert temperature is None
|
assert temperature is None
|
||||||
@ -119,10 +125,12 @@ async def test_device_no_sensor_traits(hass):
|
|||||||
assert humidity is None
|
assert humidity is None
|
||||||
|
|
||||||
|
|
||||||
async def test_device_name_from_structure(hass):
|
async def test_device_name_from_structure(
|
||||||
|
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
|
||||||
|
) -> None:
|
||||||
"""Test a device without a custom name, inferring name from structure."""
|
"""Test a device without a custom name, inferring name from structure."""
|
||||||
devices = {
|
device_manager.add_device(
|
||||||
"some-device-id": Device.MakeDevice(
|
Device.MakeDevice(
|
||||||
{
|
{
|
||||||
"name": "some-device-id",
|
"name": "some-device-id",
|
||||||
"type": THERMOSTAT_TYPE,
|
"type": THERMOSTAT_TYPE,
|
||||||
@ -137,18 +145,23 @@ async def test_device_name_from_structure(hass):
|
|||||||
},
|
},
|
||||||
auth=None,
|
auth=None,
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
await async_setup_sensor(hass, devices)
|
await setup_platform()
|
||||||
|
|
||||||
temperature = hass.states.get("sensor.some_room_temperature")
|
temperature = hass.states.get("sensor.some_room_temperature")
|
||||||
assert temperature is not None
|
assert temperature is not None
|
||||||
assert temperature.state == "25.2"
|
assert temperature.state == "25.2"
|
||||||
|
|
||||||
|
|
||||||
async def test_event_updates_sensor(hass):
|
async def test_event_updates_sensor(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
subscriber: FakeSubscriber,
|
||||||
|
device_manager: DeviceManager,
|
||||||
|
setup_platform: PlatformSetup,
|
||||||
|
) -> None:
|
||||||
"""Test a pubsub message received by subscriber to update temperature."""
|
"""Test a pubsub message received by subscriber to update temperature."""
|
||||||
devices = {
|
device_manager.add_device(
|
||||||
"some-device-id": Device.MakeDevice(
|
Device.MakeDevice(
|
||||||
{
|
{
|
||||||
"name": "some-device-id",
|
"name": "some-device-id",
|
||||||
"type": THERMOSTAT_TYPE,
|
"type": THERMOSTAT_TYPE,
|
||||||
@ -163,8 +176,8 @@ async def test_event_updates_sensor(hass):
|
|||||||
},
|
},
|
||||||
auth=None,
|
auth=None,
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
subscriber = await async_setup_sensor(hass, devices)
|
await setup_platform()
|
||||||
|
|
||||||
temperature = hass.states.get("sensor.my_sensor_temperature")
|
temperature = hass.states.get("sensor.my_sensor_temperature")
|
||||||
assert temperature is not None
|
assert temperature is not None
|
||||||
@ -194,10 +207,12 @@ async def test_event_updates_sensor(hass):
|
|||||||
assert temperature.state == "26.2"
|
assert temperature.state == "26.2"
|
||||||
|
|
||||||
|
|
||||||
async def test_device_with_unknown_type(hass):
|
async def test_device_with_unknown_type(
|
||||||
|
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
|
||||||
|
) -> None:
|
||||||
"""Test a device without a custom name, inferring name from structure."""
|
"""Test a device without a custom name, inferring name from structure."""
|
||||||
devices = {
|
device_manager.add_device(
|
||||||
"some-device-id": Device.MakeDevice(
|
Device.MakeDevice(
|
||||||
{
|
{
|
||||||
"name": "some-device-id",
|
"name": "some-device-id",
|
||||||
"type": "some-unknown-type",
|
"type": "some-unknown-type",
|
||||||
@ -212,8 +227,8 @@ async def test_device_with_unknown_type(hass):
|
|||||||
},
|
},
|
||||||
auth=None,
|
auth=None,
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
await async_setup_sensor(hass, devices)
|
await setup_platform()
|
||||||
|
|
||||||
temperature = hass.states.get("sensor.my_sensor_temperature")
|
temperature = hass.states.get("sensor.my_sensor_temperature")
|
||||||
assert temperature is not None
|
assert temperature is not None
|
||||||
@ -232,10 +247,12 @@ async def test_device_with_unknown_type(hass):
|
|||||||
assert device.identifiers == {("nest", "some-device-id")}
|
assert device.identifiers == {("nest", "some-device-id")}
|
||||||
|
|
||||||
|
|
||||||
async def test_temperature_rounding(hass):
|
async def test_temperature_rounding(
|
||||||
|
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
|
||||||
|
) -> None:
|
||||||
"""Test the rounding of overly precise temperatures."""
|
"""Test the rounding of overly precise temperatures."""
|
||||||
devices = {
|
device_manager.add_device(
|
||||||
"some-device-id": Device.MakeDevice(
|
Device.MakeDevice(
|
||||||
{
|
{
|
||||||
"name": "some-device-id",
|
"name": "some-device-id",
|
||||||
"type": THERMOSTAT_TYPE,
|
"type": THERMOSTAT_TYPE,
|
||||||
@ -250,8 +267,8 @@ async def test_temperature_rounding(hass):
|
|||||||
},
|
},
|
||||||
auth=None,
|
auth=None,
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
await async_setup_sensor(hass, devices)
|
await setup_platform()
|
||||||
|
|
||||||
temperature = hass.states.get("sensor.my_sensor_temperature")
|
temperature = hass.states.get("sensor.my_sensor_temperature")
|
||||||
assert temperature.state == "25.2"
|
assert temperature.state == "25.2"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user