Update nest climate and sensor test fixtures (#64800)

Update nest climate tests to use shared fixtures for component setup. Add an additional
fixture for creating devices shared between the climate and sensor tests.
pull/64815/head
Allen Porter 2022-01-23 16:06:04 -08:00 committed by GitHub
parent 1e3b947fb4
commit ebaaa13759
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 427 additions and 315 deletions

View File

@ -1,11 +1,14 @@
"""Common libraries for test setup."""
from collections.abc import Awaitable, Callable
import copy
from dataclasses import dataclass
import time
from typing import Any, Generator, TypeVar
from unittest.mock import patch
from google_nest_sdm.auth import AbstractAuth
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_media import CachePolicy
@ -142,20 +145,45 @@ class FakeSubscriber(GoogleNestSubscriber):
await self._device_manager.async_handle_event(event_message)
DEVICE_ID = "enterprise/project-id/devices/device-id"
DEVICE_COMMAND = f"{DEVICE_ID}:executeCommand"
class CreateDevice:
"""Fixture used for creating devices."""
def __init__(
self,
device_manager: DeviceManager,
auth: AbstractAuth,
) -> None:
"""Initialize CreateDevice."""
self.device_manager = device_manager
self.auth = auth
self.data = {"traits": {}}
def create(
self, raw_traits: dict[str, Any] = None, raw_data: dict[str, Any] = None
) -> None:
"""Create a new device with the specifeid traits."""
data = copy.deepcopy(self.data)
data.update(raw_data if raw_data else {})
data["traits"].update(raw_traits if raw_traits else {})
self.device_manager.add_device(Device.MakeDevice(data, auth=self.auth))
async def async_setup_sdm_platform(
hass, platform, devices={}, structures={}, with_config=True
hass,
platform,
devices={},
):
"""Set up the platform and prerequisites."""
if with_config:
create_config_entry().add_to_hass(hass)
create_config_entry().add_to_hass(hass)
subscriber = FakeSubscriber()
device_manager = await subscriber.async_get_device_manager()
if devices:
for device in devices.values():
device_manager.add_device(device)
if structures:
for structure in structures.values():
device_manager.add_structure(structure)
platforms = []
if platform:
platforms = [platform]

View File

@ -18,9 +18,11 @@ from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from .common import (
DEVICE_ID,
SUBSCRIBER_ID,
TEST_CONFIG_HYBRID,
TEST_CONFIG_YAML_ONLY,
CreateDevice,
FakeSubscriber,
NestTestConfig,
PlatformSetup,
@ -116,6 +118,44 @@ async def device_manager(subscriber: FakeSubscriber) -> DeviceManager:
return await subscriber.async_get_device_manager()
@pytest.fixture
async def device_id() -> str:
"""Fixture to set default device id used when creating devices."""
return DEVICE_ID
@pytest.fixture
async def device_type() -> str:
"""Fixture to set default device type used when creating devices."""
return "sdm.devices.types.THERMOSTAT"
@pytest.fixture
async def device_traits() -> dict[str, Any]:
"""Fixture to set default device traits used when creating devices."""
return {}
@pytest.fixture
async def create_device(
device_manager: DeviceManager,
auth: FakeAuth,
device_id: str,
device_type: str,
device_traits: dict[str, Any],
) -> None:
"""Fixture for creating devices."""
factory = CreateDevice(device_manager, auth)
factory.data.update(
{
"name": device_id,
"type": device_type,
"traits": device_traits,
}
)
return factory
@pytest.fixture
def platforms() -> list[str]:
"""Fixture to specify platforms to test."""

View File

@ -5,7 +5,10 @@ These tests fake out the subscriber/devicemanager, and are not using a real
pubsub subscriber.
"""
from google_nest_sdm.device import Device
from collections.abc import Awaitable, Callable
from typing import Any
from google_nest_sdm.auth import AbstractAuth
from google_nest_sdm.event import EventMessage
import pytest
@ -37,49 +40,83 @@ from homeassistant.components.climate.const import (
PRESET_SLEEP,
)
from homeassistant.const import ATTR_TEMPERATURE
from homeassistant.core import HomeAssistant
from .common import async_setup_sdm_platform
from .common import (
DEVICE_COMMAND,
DEVICE_ID,
CreateDevice,
FakeSubscriber,
PlatformSetup,
)
from .conftest import FakeAuth
from tests.components.climate import common
PLATFORM = "climate"
CreateEvent = Callable[[dict[str, Any]], Awaitable[None]]
EVENT_ID = "some-event-id"
async def setup_climate(hass, raw_traits=None, auth=None):
"""Load Nest climate devices."""
devices = None
if raw_traits:
traits = raw_traits
traits["sdm.devices.traits.Info"] = {"customName": "My Thermostat"}
devices = {
"some-device-id": Device.MakeDevice(
@pytest.fixture
def platforms() -> list[str]:
"""Fixture to specify platforms to test."""
return ["climate"]
@pytest.fixture
def device_traits() -> dict[str, Any]:
"""Fixture that sets default traits used for devices."""
return {"sdm.devices.traits.Info": {"customName": "My Thermostat"}}
@pytest.fixture
async def create_event(
hass: HomeAssistant,
auth: AbstractAuth,
subscriber: FakeSubscriber,
) -> CreateEvent:
"""Fixture to send a pub/sub event."""
async def create_event(traits: dict[str, Any]) -> None:
await subscriber.async_receive_event(
EventMessage(
{
"name": "some-device-id",
"type": "sdm.devices.types.Thermostat",
"traits": traits,
"eventId": EVENT_ID,
"timestamp": "2019-01-01T00:00:01Z",
"resourceUpdate": {
"name": DEVICE_ID,
"traits": traits,
},
},
auth=auth,
),
}
return await async_setup_sdm_platform(hass, PLATFORM, devices)
)
)
await hass.async_block_till_done()
return create_event
async def test_no_devices(hass):
async def test_no_devices(hass: HomeAssistant, setup_platform: PlatformSetup) -> None:
"""Test no devices returned by the api."""
await setup_climate(hass)
await setup_platform()
assert len(hass.states.async_all()) == 0
async def test_climate_devices(hass):
async def test_climate_devices(
hass: HomeAssistant, setup_platform: PlatformSetup, create_device: CreateDevice
) -> None:
"""Test no eligible climate devices returned by the api."""
await setup_climate(hass, {"sdm.devices.traits.CameraImage": {}})
create_device.create({"sdm.devices.traits.CameraImage": {}})
await setup_platform()
assert len(hass.states.async_all()) == 0
async def test_thermostat_off(hass):
async def test_thermostat_off(
hass: HomeAssistant, setup_platform: PlatformSetup, create_device: CreateDevice
):
"""Test a thermostat that is not running."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatMode": {
@ -91,6 +128,7 @@ async def test_thermostat_off(hass):
},
},
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -113,10 +151,11 @@ async def test_thermostat_off(hass):
assert ATTR_FAN_MODES not in thermostat.attributes
async def test_thermostat_heat(hass):
async def test_thermostat_heat(
hass: HomeAssistant, setup_platform: PlatformSetup, create_device: CreateDevice
):
"""Test a thermostat that is heating."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {
"status": "HEATING",
@ -133,6 +172,7 @@ async def test_thermostat_heat(hass):
},
},
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -153,10 +193,11 @@ async def test_thermostat_heat(hass):
assert ATTR_PRESET_MODES not in thermostat.attributes
async def test_thermostat_cool(hass):
async def test_thermostat_cool(
hass: HomeAssistant, setup_platform: PlatformSetup, create_device: CreateDevice
):
"""Test a thermostat that is cooling."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {
"status": "COOLING",
@ -173,6 +214,7 @@ async def test_thermostat_cool(hass):
},
},
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -193,10 +235,11 @@ async def test_thermostat_cool(hass):
assert ATTR_PRESET_MODES not in thermostat.attributes
async def test_thermostat_heatcool(hass):
async def test_thermostat_heatcool(
hass: HomeAssistant, setup_platform: PlatformSetup, create_device: CreateDevice
):
"""Test a thermostat that is cooling in heatcool mode."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {
"status": "COOLING",
@ -214,6 +257,7 @@ async def test_thermostat_heatcool(hass):
},
},
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -234,10 +278,11 @@ async def test_thermostat_heatcool(hass):
assert ATTR_PRESET_MODES not in thermostat.attributes
async def test_thermostat_eco_off(hass):
async def test_thermostat_eco_off(
hass: HomeAssistant, setup_platform: PlatformSetup, create_device: CreateDevice
) -> None:
"""Test a thermostat cooling with eco off."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {
"status": "COOLING",
@ -261,6 +306,7 @@ async def test_thermostat_eco_off(hass):
},
},
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -281,10 +327,11 @@ async def test_thermostat_eco_off(hass):
assert thermostat.attributes[ATTR_PRESET_MODES] == [PRESET_ECO, PRESET_NONE]
async def test_thermostat_eco_on(hass):
async def test_thermostat_eco_on(
hass: HomeAssistant, setup_platform: PlatformSetup, create_device: CreateDevice
) -> None:
"""Test a thermostat in eco mode."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {
"status": "COOLING",
@ -308,6 +355,7 @@ async def test_thermostat_eco_on(hass):
},
},
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -328,10 +376,11 @@ async def test_thermostat_eco_on(hass):
assert thermostat.attributes[ATTR_PRESET_MODES] == [PRESET_ECO, PRESET_NONE]
async def test_thermostat_eco_heat_only(hass):
async def test_thermostat_eco_heat_only(
hass: HomeAssistant, setup_platform: PlatformSetup, create_device: CreateDevice
) -> None:
"""Test a thermostat in eco mode that only supports heat."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {
"status": "OFF",
@ -352,6 +401,7 @@ async def test_thermostat_eco_heat_only(hass):
"sdm.devices.traits.ThermostatTemperatureSetpoint": {},
},
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -370,19 +420,24 @@ async def test_thermostat_eco_heat_only(hass):
assert thermostat.attributes[ATTR_PRESET_MODES] == [PRESET_ECO, PRESET_NONE]
async def test_thermostat_set_hvac_mode(hass, auth):
async def test_thermostat_set_hvac_mode(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
create_device: CreateDevice,
create_event: CreateEvent,
) -> None:
"""Test a thermostat changing hvac modes."""
subscriber = await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatMode": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "OFF",
},
},
auth=auth,
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -394,7 +449,7 @@ async def test_thermostat_set_hvac_mode(hass, auth):
await hass.async_block_till_done()
assert auth.method == "post"
assert auth.url == "some-device-id:executeCommand"
assert auth.url == DEVICE_COMMAND
assert auth.json == {
"command": "sdm.devices.commands.ThermostatMode.SetMode",
"params": {"mode": "HEAT"},
@ -407,24 +462,14 @@ async def test_thermostat_set_hvac_mode(hass, auth):
assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_OFF
# Simulate pubsub message when mode changes
event = EventMessage(
await create_event(
{
"eventId": "some-event-id",
"timestamp": "2019-01-01T00:00:01Z",
"resourceUpdate": {
"name": "some-device-id",
"traits": {
"sdm.devices.traits.ThermostatMode": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "HEAT",
},
},
"sdm.devices.traits.ThermostatMode": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "HEAT",
},
},
auth=None,
}
)
await subscriber.async_receive_event(event)
await hass.async_block_till_done() # Process dispatch/update signal
thermostat = hass.states.get("climate.my_thermostat")
assert thermostat is not None
@ -432,23 +477,13 @@ async def test_thermostat_set_hvac_mode(hass, auth):
assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_IDLE
# Simulate pubsub message when the thermostat starts heating
event = EventMessage(
await create_event(
{
"eventId": "some-event-id",
"timestamp": "2019-01-01T00:00:01Z",
"resourceUpdate": {
"name": "some-device-id",
"traits": {
"sdm.devices.traits.ThermostatHvac": {
"status": "HEATING",
},
},
"sdm.devices.traits.ThermostatHvac": {
"status": "HEATING",
},
},
auth=None,
}
)
await subscriber.async_receive_event(event)
await hass.async_block_till_done() # Process dispatch/update signal
thermostat = hass.states.get("climate.my_thermostat")
assert thermostat is not None
@ -456,19 +491,23 @@ async def test_thermostat_set_hvac_mode(hass, auth):
assert thermostat.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_HEAT
async def test_thermostat_invalid_hvac_mode(hass, auth):
async def test_thermostat_invalid_hvac_mode(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
create_device: CreateDevice,
) -> None:
"""Test setting an hvac_mode that is not supported."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatMode": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "OFF",
},
},
auth=auth,
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -484,10 +523,15 @@ async def test_thermostat_invalid_hvac_mode(hass, auth):
assert auth.method is None # No communication with API
async def test_thermostat_set_eco_preset(hass, auth):
async def test_thermostat_set_eco_preset(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
create_device: CreateDevice,
create_event: CreateEvent,
) -> None:
"""Test a thermostat put into eco mode."""
subscriber = await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatEco": {
@ -500,9 +544,9 @@ async def test_thermostat_set_eco_preset(hass, auth):
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "OFF",
},
},
auth=auth,
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -516,7 +560,7 @@ async def test_thermostat_set_eco_preset(hass, auth):
await hass.async_block_till_done()
assert auth.method == "post"
assert auth.url == "some-device-id:executeCommand"
assert auth.url == DEVICE_COMMAND
assert auth.json == {
"command": "sdm.devices.commands.ThermostatEco.SetMode",
"params": {"mode": "MANUAL_ECO"},
@ -530,26 +574,16 @@ async def test_thermostat_set_eco_preset(hass, auth):
assert thermostat.attributes[ATTR_PRESET_MODE] == PRESET_NONE
# Simulate pubsub message when mode changes
event = EventMessage(
await create_event(
{
"eventId": "some-event-id",
"timestamp": "2019-01-01T00:00:01Z",
"resourceUpdate": {
"name": "some-device-id",
"traits": {
"sdm.devices.traits.ThermostatEco": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "MANUAL_ECO",
"heatCelsius": 15.0,
"coolCelsius": 28.0,
},
},
"sdm.devices.traits.ThermostatEco": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "MANUAL_ECO",
"heatCelsius": 15.0,
"coolCelsius": 28.0,
},
},
auth=auth,
}
)
await subscriber.async_receive_event(event)
await hass.async_block_till_done() # Process dispatch/update signal
thermostat = hass.states.get("climate.my_thermostat")
assert thermostat is not None
@ -562,17 +596,21 @@ async def test_thermostat_set_eco_preset(hass, auth):
await hass.async_block_till_done()
assert auth.method == "post"
assert auth.url == "some-device-id:executeCommand"
assert auth.url == DEVICE_COMMAND
assert auth.json == {
"command": "sdm.devices.commands.ThermostatEco.SetMode",
"params": {"mode": "OFF"},
}
async def test_thermostat_set_cool(hass, auth):
async def test_thermostat_set_cool(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
create_device: CreateDevice,
) -> None:
"""Test a thermostat in cool mode with a temperature change."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatMode": {
@ -583,8 +621,8 @@ async def test_thermostat_set_cool(hass, auth):
"coolCelsius": 25.0,
},
},
auth=auth,
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -595,17 +633,21 @@ async def test_thermostat_set_cool(hass, auth):
await hass.async_block_till_done()
assert auth.method == "post"
assert auth.url == "some-device-id:executeCommand"
assert auth.url == DEVICE_COMMAND
assert auth.json == {
"command": "sdm.devices.commands.ThermostatTemperatureSetpoint.SetCool",
"params": {"coolCelsius": 24.0},
}
async def test_thermostat_set_heat(hass, auth):
async def test_thermostat_set_heat(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
create_device: CreateDevice,
) -> None:
"""Test a thermostat heating mode with a temperature change."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatMode": {
@ -615,9 +657,9 @@ async def test_thermostat_set_heat(hass, auth):
"sdm.devices.traits.ThermostatTemperatureSetpoint": {
"heatCelsius": 19.0,
},
},
auth=auth,
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -628,17 +670,21 @@ async def test_thermostat_set_heat(hass, auth):
await hass.async_block_till_done()
assert auth.method == "post"
assert auth.url == "some-device-id:executeCommand"
assert auth.url == DEVICE_COMMAND
assert auth.json == {
"command": "sdm.devices.commands.ThermostatTemperatureSetpoint.SetHeat",
"params": {"heatCelsius": 20.0},
}
async def test_thermostat_set_heat_cool(hass, auth):
async def test_thermostat_set_heat_cool(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
create_device: CreateDevice,
) -> None:
"""Test a thermostat in heatcool mode with a temperature change."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatMode": {
@ -649,9 +695,9 @@ async def test_thermostat_set_heat_cool(hass, auth):
"heatCelsius": 19.0,
"coolCelsius": 25.0,
},
},
auth=auth,
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -664,17 +710,20 @@ async def test_thermostat_set_heat_cool(hass, auth):
await hass.async_block_till_done()
assert auth.method == "post"
assert auth.url == "some-device-id:executeCommand"
assert auth.url == DEVICE_COMMAND
assert auth.json == {
"command": "sdm.devices.commands.ThermostatTemperatureSetpoint.SetRange",
"params": {"heatCelsius": 20.0, "coolCelsius": 24.0},
}
async def test_thermostat_fan_off(hass):
async def test_thermostat_fan_off(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test a thermostat with the fan not running."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.Fan": {
"timerMode": "OFF",
@ -688,8 +737,9 @@ async def test_thermostat_fan_off(hass):
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 16.2,
},
},
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -708,10 +758,13 @@ async def test_thermostat_fan_off(hass):
assert thermostat.attributes[ATTR_FAN_MODES] == [FAN_ON, FAN_OFF]
async def test_thermostat_fan_on(hass):
async def test_thermostat_fan_on(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test a thermostat with the fan running."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.Fan": {
"timerMode": "ON",
@ -727,8 +780,9 @@ async def test_thermostat_fan_on(hass):
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 16.2,
},
},
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -747,10 +801,13 @@ async def test_thermostat_fan_on(hass):
assert thermostat.attributes[ATTR_FAN_MODES] == [FAN_ON, FAN_OFF]
async def test_thermostat_cool_with_fan(hass):
async def test_thermostat_cool_with_fan(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test a thermostat cooling while the fan is on."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.Fan": {
"timerMode": "ON",
@ -765,6 +822,7 @@ async def test_thermostat_cool_with_fan(hass):
},
},
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -782,10 +840,14 @@ async def test_thermostat_cool_with_fan(hass):
assert thermostat.attributes[ATTR_FAN_MODES] == [FAN_ON, FAN_OFF]
async def test_thermostat_set_fan(hass, auth):
async def test_thermostat_set_fan(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
create_device: CreateDevice,
) -> None:
"""Test a thermostat enabling the fan."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.Fan": {
"timerMode": "ON",
@ -798,9 +860,9 @@ async def test_thermostat_set_fan(hass, auth):
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "OFF",
},
},
auth=auth,
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -814,7 +876,7 @@ async def test_thermostat_set_fan(hass, auth):
await hass.async_block_till_done()
assert auth.method == "post"
assert auth.url == "some-device-id:executeCommand"
assert auth.url == DEVICE_COMMAND
assert auth.json == {
"command": "sdm.devices.commands.Fan.SetTimer",
"params": {"timerMode": "OFF"},
@ -825,7 +887,7 @@ async def test_thermostat_set_fan(hass, auth):
await hass.async_block_till_done()
assert auth.method == "post"
assert auth.url == "some-device-id:executeCommand"
assert auth.url == DEVICE_COMMAND
assert auth.json == {
"command": "sdm.devices.commands.Fan.SetTimer",
"params": {
@ -835,10 +897,13 @@ async def test_thermostat_set_fan(hass, auth):
}
async def test_thermostat_fan_empty(hass):
async def test_thermostat_fan_empty(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test a fan trait with an empty response."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.Fan": {},
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
@ -849,8 +914,9 @@ async def test_thermostat_fan_empty(hass):
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 16.2,
},
},
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -875,10 +941,13 @@ async def test_thermostat_fan_empty(hass):
assert ATTR_FAN_MODES not in thermostat.attributes
async def test_thermostat_invalid_fan_mode(hass):
async def test_thermostat_invalid_fan_mode(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test setting a fan mode that is not supported."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.Fan": {
"timerMode": "ON",
@ -892,8 +961,9 @@ async def test_thermostat_invalid_fan_mode(hass):
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 16.2,
},
},
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -916,10 +986,14 @@ async def test_thermostat_invalid_fan_mode(hass):
await hass.async_block_till_done()
async def test_thermostat_set_hvac_fan_only(hass, auth):
async def test_thermostat_set_hvac_fan_only(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
create_device: CreateDevice,
) -> None:
"""Test a thermostat enabling the fan via hvac_mode."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.Fan": {
"timerMode": "OFF",
@ -932,9 +1006,9 @@ async def test_thermostat_set_hvac_fan_only(hass, auth):
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "OFF",
},
},
auth=auth,
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -950,24 +1024,28 @@ async def test_thermostat_set_hvac_fan_only(hass, auth):
(method, url, json, headers) = auth.captured_requests.pop(0)
assert method == "post"
assert url == "some-device-id:executeCommand"
assert url == DEVICE_COMMAND
assert json == {
"command": "sdm.devices.commands.Fan.SetTimer",
"params": {"duration": "43200s", "timerMode": "ON"},
}
(method, url, json, headers) = auth.captured_requests.pop(0)
assert method == "post"
assert url == "some-device-id:executeCommand"
assert url == DEVICE_COMMAND
assert json == {
"command": "sdm.devices.commands.ThermostatMode.SetMode",
"params": {"mode": "OFF"},
}
async def test_thermostat_target_temp(hass, auth):
async def test_thermostat_target_temp(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
create_event: CreateEvent,
) -> None:
"""Test a thermostat changing hvac modes and affected on target temps."""
subscriber = await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {
"status": "HEATING",
@ -982,9 +1060,9 @@ async def test_thermostat_target_temp(hass, auth):
"sdm.devices.traits.ThermostatTemperatureSetpoint": {
"heatCelsius": 23.0,
},
},
auth=auth,
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -995,28 +1073,18 @@ async def test_thermostat_target_temp(hass, auth):
assert thermostat.attributes[ATTR_TARGET_TEMP_HIGH] is None
# Simulate pubsub message changing modes
event = EventMessage(
await create_event(
{
"eventId": "some-event-id",
"timestamp": "2019-01-01T00:00:01Z",
"resourceUpdate": {
"name": "some-device-id",
"traits": {
"sdm.devices.traits.ThermostatMode": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "HEATCOOL",
},
"sdm.devices.traits.ThermostatTemperatureSetpoint": {
"heatCelsius": 22.0,
"coolCelsius": 28.0,
},
},
"sdm.devices.traits.ThermostatMode": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "HEATCOOL",
},
},
auth=None,
"sdm.devices.traits.ThermostatTemperatureSetpoint": {
"heatCelsius": 22.0,
"coolCelsius": 28.0,
},
}
)
await subscriber.async_receive_event(event)
await hass.async_block_till_done() # Process dispatch/update signal
thermostat = hass.states.get("climate.my_thermostat")
assert thermostat is not None
@ -1026,14 +1094,18 @@ async def test_thermostat_target_temp(hass, auth):
assert thermostat.attributes[ATTR_TEMPERATURE] is None
async def test_thermostat_missing_mode_traits(hass):
async def test_thermostat_missing_mode_traits(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test a thermostat missing many thermostat traits in api response."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
},
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -1059,18 +1131,22 @@ async def test_thermostat_missing_mode_traits(hass):
assert ATTR_PRESET_MODE not in thermostat.attributes
async def test_thermostat_missing_temperature_trait(hass):
async def test_thermostat_missing_temperature_trait(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test a thermostat missing many thermostat traits in api response."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatMode": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF"],
"mode": "HEAT",
},
},
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -1097,14 +1173,18 @@ async def test_thermostat_missing_temperature_trait(hass):
assert thermostat.attributes[ATTR_TEMPERATURE] is None
async def test_thermostat_unexpected_hvac_status(hass):
async def test_thermostat_unexpected_hvac_status(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test a thermostat missing many thermostat traits in api response."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "UNEXPECTED"},
},
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -1127,10 +1207,13 @@ async def test_thermostat_unexpected_hvac_status(hass):
assert thermostat.state == HVAC_MODE_OFF
async def test_thermostat_missing_set_point(hass):
async def test_thermostat_missing_set_point(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test a thermostat missing many thermostat traits in api response."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatMode": {
@ -1139,6 +1222,7 @@ async def test_thermostat_missing_set_point(hass):
},
},
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -1161,18 +1245,22 @@ async def test_thermostat_missing_set_point(hass):
assert ATTR_FAN_MODES not in thermostat.attributes
async def test_thermostat_unexepected_hvac_mode(hass):
async def test_thermostat_unexepected_hvac_mode(
hass: HomeAssistant,
setup_platform: PlatformSetup,
create_device: CreateDevice,
) -> None:
"""Test a thermostat missing many thermostat traits in api response."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatMode": {
"availableModes": ["HEAT", "COOL", "HEATCOOL", "OFF", "UNEXPECTED"],
"mode": "UNEXPECTED",
},
},
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")
@ -1195,10 +1283,14 @@ async def test_thermostat_unexepected_hvac_mode(hass):
assert ATTR_FAN_MODES not in thermostat.attributes
async def test_thermostat_invalid_set_preset_mode(hass, auth):
async def test_thermostat_invalid_set_preset_mode(
hass: HomeAssistant,
setup_platform: PlatformSetup,
auth: FakeAuth,
create_device: CreateDevice,
) -> None:
"""Test a thermostat set with an invalid preset mode."""
await setup_climate(
hass,
create_device.create(
{
"sdm.devices.traits.ThermostatHvac": {"status": "OFF"},
"sdm.devices.traits.ThermostatEco": {
@ -1207,9 +1299,9 @@ async def test_thermostat_invalid_set_preset_mode(hass, auth):
"heatCelsius": 15.0,
"coolCelsius": 28.0,
},
},
auth=auth,
}
)
await setup_platform()
assert len(hass.states.async_all()) == 1
thermostat = hass.states.get("climate.my_thermostat")

View File

@ -5,8 +5,8 @@ These tests fake out the subscriber/devicemanager, and are not using a real
pubsub subscriber.
"""
from google_nest_sdm.device import Device
from google_nest_sdm.device_manager import DeviceManager
from typing import Any
from google_nest_sdm.event import EventMessage
import pytest
@ -22,9 +22,7 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from .common import FakeSubscriber, PlatformSetup
THERMOSTAT_TYPE = "sdm.devices.types.THERMOSTAT"
from .common import DEVICE_ID, CreateDevice, FakeSubscriber, PlatformSetup
@pytest.fixture
@ -33,29 +31,25 @@ def platforms() -> list[str]:
return ["sensor"]
@pytest.fixture
def device_traits() -> dict[str, Any]:
"""Fixture that sets default traits used for devices."""
return {"sdm.devices.traits.Info": {"customName": "My Sensor"}}
async def test_thermostat_device(
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
hass: HomeAssistant, create_device: CreateDevice, setup_platform: PlatformSetup
):
"""Test a thermostat with temperature and humidity sensors."""
device_manager.add_device(
Device.MakeDevice(
{
"name": "some-device-id",
"type": THERMOSTAT_TYPE,
"traits": {
"sdm.devices.traits.Info": {
"customName": "My Sensor",
},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.1,
},
"sdm.devices.traits.Humidity": {
"ambientHumidityPercent": 35.0,
},
},
create_device.create(
{
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.1,
},
auth=None,
)
"sdm.devices.traits.Humidity": {
"ambientHumidityPercent": 35.0,
},
}
)
await setup_platform()
@ -75,12 +69,12 @@ async def test_thermostat_device(
registry = er.async_get(hass)
entry = registry.async_get("sensor.my_sensor_temperature")
assert entry.unique_id == "some-device-id-temperature"
assert entry.unique_id == f"{DEVICE_ID}-temperature"
assert entry.original_name == "My Sensor Temperature"
assert entry.domain == "sensor"
entry = registry.async_get("sensor.my_sensor_humidity")
assert entry.unique_id == "some-device-id-humidity"
assert entry.unique_id == f"{DEVICE_ID}-humidity"
assert entry.original_name == "My Sensor Humidity"
assert entry.domain == "sensor"
@ -88,7 +82,7 @@ async def test_thermostat_device(
device = device_registry.async_get(entry.device_id)
assert device.name == "My Sensor"
assert device.model == "Thermostat"
assert device.identifiers == {("nest", "some-device-id")}
assert device.identifiers == {("nest", DEVICE_ID)}
async def test_no_devices(hass: HomeAssistant, setup_platform: PlatformSetup):
@ -103,19 +97,10 @@ async def test_no_devices(hass: HomeAssistant, setup_platform: PlatformSetup):
async def test_device_no_sensor_traits(
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
hass: HomeAssistant, create_device: CreateDevice, setup_platform: PlatformSetup
) -> None:
"""Test a device with applicable sensor traits."""
device_manager.add_device(
Device.MakeDevice(
{
"name": "some-device-id",
"type": THERMOSTAT_TYPE,
"traits": {},
},
auth=None,
)
)
create_device.create({})
await setup_platform()
temperature = hass.states.get("sensor.my_sensor_temperature")
@ -125,26 +110,22 @@ async def test_device_no_sensor_traits(
assert humidity is None
@pytest.mark.parametrize("device_traits", [{}]) # Disable default name
async def test_device_name_from_structure(
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
hass: HomeAssistant, create_device: CreateDevice, setup_platform: PlatformSetup
) -> None:
"""Test a device without a custom name, inferring name from structure."""
device_manager.add_device(
Device.MakeDevice(
{
"name": "some-device-id",
"type": THERMOSTAT_TYPE,
"traits": {
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.2,
},
},
"parentRelations": [
{"parent": "some-structure-id", "displayName": "Some Room"}
],
create_device.create(
raw_traits={
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.2,
},
auth=None,
)
},
raw_data={
"parentRelations": [
{"parent": "some-structure-id", "displayName": "Some Room"}
],
},
)
await setup_platform()
@ -156,26 +137,16 @@ async def test_device_name_from_structure(
async def test_event_updates_sensor(
hass: HomeAssistant,
subscriber: FakeSubscriber,
device_manager: DeviceManager,
create_device: CreateDevice,
setup_platform: PlatformSetup,
) -> None:
"""Test a pubsub message received by subscriber to update temperature."""
device_manager.add_device(
Device.MakeDevice(
{
"name": "some-device-id",
"type": THERMOSTAT_TYPE,
"traits": {
"sdm.devices.traits.Info": {
"customName": "My Sensor",
},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.1,
},
},
create_device.create(
{
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.1,
},
auth=None,
)
}
)
await setup_platform()
@ -189,7 +160,7 @@ async def test_event_updates_sensor(
"eventId": "some-event-id",
"timestamp": "2019-01-01T00:00:01Z",
"resourceUpdate": {
"name": "some-device-id",
"name": DEVICE_ID,
"traits": {
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 26.2,
@ -207,26 +178,17 @@ async def test_event_updates_sensor(
assert temperature.state == "26.2"
@pytest.mark.parametrize("device_type", ["some-unknown-type"])
async def test_device_with_unknown_type(
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
hass: HomeAssistant, create_device: CreateDevice, setup_platform: PlatformSetup
) -> None:
"""Test a device without a custom name, inferring name from structure."""
device_manager.add_device(
Device.MakeDevice(
{
"name": "some-device-id",
"type": "some-unknown-type",
"traits": {
"sdm.devices.traits.Info": {
"customName": "My Sensor",
},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.1,
},
},
create_device.create(
{
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.1,
},
auth=None,
)
}
)
await setup_platform()
@ -236,7 +198,7 @@ async def test_device_with_unknown_type(
registry = er.async_get(hass)
entry = registry.async_get("sensor.my_sensor_temperature")
assert entry.unique_id == "some-device-id-temperature"
assert entry.unique_id == f"{DEVICE_ID}-temperature"
assert entry.original_name == "My Sensor Temperature"
assert entry.domain == "sensor"
@ -244,29 +206,19 @@ async def test_device_with_unknown_type(
device = device_registry.async_get(entry.device_id)
assert device.name == "My Sensor"
assert device.model is None
assert device.identifiers == {("nest", "some-device-id")}
assert device.identifiers == {("nest", DEVICE_ID)}
async def test_temperature_rounding(
hass: HomeAssistant, device_manager: DeviceManager, setup_platform: PlatformSetup
hass: HomeAssistant, create_device: CreateDevice, setup_platform: PlatformSetup
) -> None:
"""Test the rounding of overly precise temperatures."""
device_manager.add_device(
Device.MakeDevice(
{
"name": "some-device-id",
"type": THERMOSTAT_TYPE,
"traits": {
"sdm.devices.traits.Info": {
"customName": "My Sensor",
},
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.15678,
},
},
create_device.create(
{
"sdm.devices.traits.Temperature": {
"ambientTemperatureCelsius": 25.15678,
},
auth=None,
)
}
)
await setup_platform()