Add command error-path tests to Teslemetry (#174163)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Brett Adams
2026-06-18 17:23:27 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 9decee350f
commit 15aaddf4ac
6 changed files with 283 additions and 7 deletions
+46 -1
View File
@@ -4,6 +4,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from syrupy.assertion import SnapshotAssertion
from tesla_fleet_api.exceptions import InvalidCommand
from teslemetry_stream import Signal
from homeassistant.components.cover import (
@@ -15,10 +16,11 @@ from homeassistant.components.cover import (
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from . import assert_entities, setup_platform
from .const import COMMAND_OK, METADATA_NOSCOPE, VEHICLE_DATA_ALT
from .const import COMMAND_ERRORS, COMMAND_OK, METADATA_NOSCOPE, VEHICLE_DATA_ALT
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@@ -221,6 +223,49 @@ async def test_cover_services(
assert state.state == CoverState.CLOSED
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "mock_legacy")
@pytest.mark.parametrize("response", COMMAND_ERRORS)
async def test_cover_command_errors(hass: HomeAssistant, response: dict) -> None:
"""Tests that vehicle command failures raise HomeAssistantError."""
await setup_platform(hass, [Platform.COVER])
with (
patch(
"tesla_fleet_api.teslemetry.Vehicle.window_control",
return_value=response,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_OPEN_COVER,
{ATTR_ENTITY_ID: ["cover.test_windows"]},
blocking=True,
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default", "mock_legacy")
async def test_cover_command_exception(hass: HomeAssistant) -> None:
"""Tests that a command SDK exception raises HomeAssistantError."""
await setup_platform(hass, [Platform.COVER])
with (
patch(
"tesla_fleet_api.teslemetry.Vehicle.window_control",
side_effect=InvalidCommand,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
COVER_DOMAIN,
SERVICE_OPEN_COVER,
{ATTR_ENTITY_ID: ["cover.test_windows"]},
blocking=True,
)
async def test_cover_streaming(
hass: HomeAssistant,
mock_vehicle_data: AsyncMock,
+44 -2
View File
@@ -4,6 +4,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from syrupy.assertion import SnapshotAssertion
from tesla_fleet_api.exceptions import InvalidCommand
from teslemetry_stream.const import Signal
from homeassistant.components.lock import (
@@ -14,11 +15,11 @@ from homeassistant.components.lock import (
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import entity_registry as er
from . import assert_entities, reload_platform, setup_platform
from .const import COMMAND_OK, VEHICLE_DATA_ALT
from .const import COMMAND_ERRORS, COMMAND_OK, VEHICLE_DATA_ALT
async def test_lock(
@@ -109,6 +110,47 @@ async def test_lock_services(
call.assert_called_once()
@pytest.mark.parametrize("response", COMMAND_ERRORS)
async def test_lock_command_errors(hass: HomeAssistant, response: dict) -> None:
"""Tests that vehicle command failures raise HomeAssistantError."""
await setup_platform(hass, [Platform.LOCK])
with (
patch(
"tesla_fleet_api.teslemetry.Vehicle.door_lock",
return_value=response,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
LOCK_DOMAIN,
SERVICE_LOCK,
{ATTR_ENTITY_ID: "lock.test_lock"},
blocking=True,
)
async def test_lock_command_exception(hass: HomeAssistant) -> None:
"""Tests that a command SDK exception raises HomeAssistantError."""
await setup_platform(hass, [Platform.LOCK])
with (
patch(
"tesla_fleet_api.teslemetry.Vehicle.door_lock",
side_effect=InvalidCommand,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
LOCK_DOMAIN,
SERVICE_LOCK,
{ATTR_ENTITY_ID: "lock.test_lock"},
blocking=True,
)
async def test_lock_streaming(
hass: HomeAssistant,
mock_vehicle_data: AsyncMock,
@@ -4,6 +4,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from syrupy.assertion import SnapshotAssertion
from tesla_fleet_api.exceptions import InvalidCommand
from teslemetry_stream import Signal
from homeassistant.components.media_player import (
@@ -18,10 +19,11 @@ from homeassistant.components.media_player import (
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from . import assert_entities, assert_entities_alt, reload_platform, setup_platform
from .const import COMMAND_OK, METADATA_NOSCOPE, VEHICLE_DATA_ALT
from .const import COMMAND_ERRORS, COMMAND_OK, METADATA_NOSCOPE, VEHICLE_DATA_ALT
async def test_media_player(
@@ -144,6 +146,55 @@ async def test_media_player_services(
call.assert_called_once()
@pytest.mark.usefixtures("mock_legacy")
@pytest.mark.parametrize("response", COMMAND_ERRORS)
async def test_media_player_command_errors(hass: HomeAssistant, response: dict) -> None:
"""Tests that vehicle command failures raise HomeAssistantError."""
await setup_platform(hass, [Platform.MEDIA_PLAYER])
with (
patch(
"tesla_fleet_api.teslemetry.Vehicle.adjust_volume",
return_value=response,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
MEDIA_PLAYER_DOMAIN,
SERVICE_VOLUME_SET,
{
ATTR_ENTITY_ID: "media_player.test_media_player",
ATTR_MEDIA_VOLUME_LEVEL: 0.5,
},
blocking=True,
)
@pytest.mark.usefixtures("mock_legacy")
async def test_media_player_command_exception(hass: HomeAssistant) -> None:
"""Tests that a command SDK exception raises HomeAssistantError."""
await setup_platform(hass, [Platform.MEDIA_PLAYER])
with (
patch(
"tesla_fleet_api.teslemetry.Vehicle.adjust_volume",
side_effect=InvalidCommand,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
MEDIA_PLAYER_DOMAIN,
SERVICE_VOLUME_SET,
{
ATTR_ENTITY_ID: "media_player.test_media_player",
ATTR_MEDIA_VOLUME_LEVEL: 0.5,
},
blocking=True,
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_update_streaming(
hass: HomeAssistant,
+47 -1
View File
@@ -4,6 +4,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from syrupy.assertion import SnapshotAssertion
from tesla_fleet_api.exceptions import InvalidCommand
from teslemetry_stream import Signal
from homeassistant.components.number import (
@@ -13,10 +14,11 @@ from homeassistant.components.number import (
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from . import assert_entities, reload_platform, setup_platform
from .const import COMMAND_OK, VEHICLE_DATA_ALT
from .const import COMMAND_ERRORS, COMMAND_OK, VEHICLE_DATA_ALT
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@@ -104,6 +106,50 @@ async def test_number_services(
call.assert_called_once()
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@pytest.mark.parametrize("response", COMMAND_ERRORS)
async def test_number_command_errors(
hass: HomeAssistant, mock_vehicle_data: AsyncMock, response: dict
) -> None:
"""Tests that vehicle command failures raise HomeAssistantError."""
mock_vehicle_data.return_value = VEHICLE_DATA_ALT
await setup_platform(hass, [Platform.NUMBER])
with (
patch(
"tesla_fleet_api.teslemetry.Vehicle.set_charging_amps",
return_value=response,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
NUMBER_DOMAIN,
SERVICE_SET_VALUE,
{ATTR_ENTITY_ID: "number.test_charge_current", ATTR_VALUE: 16},
blocking=True,
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_number_command_exception(hass: HomeAssistant) -> None:
"""Tests that an energy command SDK exception raises HomeAssistantError."""
await setup_platform(hass, [Platform.NUMBER])
with (
patch(
"tesla_fleet_api.teslemetry.EnergySite.backup",
side_effect=InvalidCommand,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
NUMBER_DOMAIN,
SERVICE_SET_VALUE,
{ATTR_ENTITY_ID: "number.energy_site_backup_reserve", ATTR_VALUE: 80},
blocking=True,
)
async def test_number_streaming(
hass: HomeAssistant,
mock_vehicle_data: AsyncMock,
+48 -1
View File
@@ -7,6 +7,7 @@ from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy.assertion import SnapshotAssertion
from tesla_fleet_api.const import EnergyExportMode, EnergyOperationMode
from tesla_fleet_api.exceptions import InvalidCommand
from teslemetry_stream.const import Signal
from homeassistant.components.select import (
@@ -18,10 +19,11 @@ from homeassistant.components.teslemetry.coordinator import ENERGY_INFO_INTERVAL
from homeassistant.components.teslemetry.select import LOW
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from . import assert_entities, reload_platform, setup_platform
from .const import COMMAND_OK, SITE_INFO, VEHICLE_DATA_ALT
from .const import COMMAND_ERRORS, COMMAND_OK, SITE_INFO, VEHICLE_DATA_ALT
from tests.common import async_fire_time_changed
@@ -108,6 +110,51 @@ async def test_select_services(hass: HomeAssistant, mock_vehicle_data) -> None:
call.assert_called_once()
@pytest.mark.parametrize("response", COMMAND_ERRORS)
async def test_select_command_errors(
hass: HomeAssistant, mock_vehicle_data: AsyncMock, response: dict
) -> None:
"""Tests that vehicle command failures raise HomeAssistantError."""
mock_vehicle_data.return_value = VEHICLE_DATA_ALT
await setup_platform(hass, [Platform.SELECT])
with (
patch(
"tesla_fleet_api.teslemetry.Vehicle.remote_seat_heater_request",
return_value=response,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{ATTR_ENTITY_ID: "select.test_seat_heater_front_left", ATTR_OPTION: LOW},
blocking=True,
)
async def test_select_command_exception(hass: HomeAssistant) -> None:
"""Tests that an energy command SDK exception raises HomeAssistantError."""
await setup_platform(hass, [Platform.SELECT])
with (
patch(
"tesla_fleet_api.teslemetry.EnergySite.operation",
side_effect=InvalidCommand,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{
ATTR_ENTITY_ID: "select.energy_site_operation_mode",
ATTR_OPTION: EnergyOperationMode.AUTONOMOUS.value,
},
blocking=True,
)
async def test_select_invalid_data(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
+46 -1
View File
@@ -4,6 +4,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from syrupy.assertion import SnapshotAssertion
from tesla_fleet_api.exceptions import InvalidCommand
from teslemetry_stream import Signal
from homeassistant.components.switch import (
@@ -13,10 +14,11 @@ from homeassistant.components.switch import (
)
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from . import assert_entities, assert_entities_alt, reload_platform, setup_platform
from .const import COMMAND_OK, VEHICLE_DATA_ALT
from .const import COMMAND_ERRORS, COMMAND_OK, VEHICLE_DATA_ALT
async def test_switch(
@@ -124,6 +126,49 @@ async def test_switch_services(
call.assert_called_once()
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@pytest.mark.parametrize("response", COMMAND_ERRORS)
async def test_switch_command_errors(hass: HomeAssistant, response: dict) -> None:
"""Tests that vehicle command failures raise HomeAssistantError."""
await setup_platform(hass, [Platform.SWITCH])
with (
patch(
"tesla_fleet_api.teslemetry.Vehicle.charge_start",
return_value=response,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.test_charge"},
blocking=True,
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_switch_command_exception(hass: HomeAssistant) -> None:
"""Tests that an energy command SDK exception raises HomeAssistantError."""
await setup_platform(hass, [Platform.SWITCH])
with (
patch(
"tesla_fleet_api.teslemetry.EnergySite.storm_mode",
side_effect=InvalidCommand,
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.energy_site_storm_watch"},
blocking=True,
)
async def test_switch_streaming(
hass: HomeAssistant,
mock_vehicle_data: AsyncMock,