Add Fyta sensor tests (#117995)

* Add test for init

* update tests

* split common.py into const.py and __init__.py

* Update tests/components/fyta/__init__.py

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* add autospec, tidy up

* adjust len-test

* add test_sensor.py, amend tests for coordinator.py

* Update tests/components/fyta/conftest.py

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* move load_unload with expired token into own test

* Update tests/components/fyta/test_init.py

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>

* ruff change

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
pull/117229/head^2
dontinelli 2024-05-27 12:01:11 +02:00 committed by GitHub
parent 1565561c03
commit 2a8fc7f310
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 324 additions and 4 deletions

View File

@ -471,9 +471,6 @@ omit =
homeassistant/components/frontier_silicon/browse_media.py
homeassistant/components/frontier_silicon/media_player.py
homeassistant/components/futurenow/light.py
homeassistant/components/fyta/coordinator.py
homeassistant/components/fyta/entity.py
homeassistant/components/fyta/sensor.py
homeassistant/components/garadget/cover.py
homeassistant/components/garages_amsterdam/__init__.py
homeassistant/components/garages_amsterdam/binary_sensor.py

View File

@ -11,7 +11,7 @@ from homeassistant.const import CONF_ACCESS_TOKEN, CONF_PASSWORD, CONF_USERNAME
from .const import ACCESS_TOKEN, EXPIRATION, PASSWORD, USERNAME
from tests.common import MockConfigEntry
from tests.common import MockConfigEntry, load_json_object_fixture
@pytest.fixture
@ -27,6 +27,7 @@ def mock_config_entry() -> MockConfigEntry:
CONF_EXPIRATION: EXPIRATION,
},
minor_version=2,
entry_id="ce5f5431554d101905d31797e1232da8",
)
@ -39,6 +40,13 @@ def mock_fyta_connector():
tzinfo=UTC
)
mock_fyta_connector.client = AsyncMock(autospec=True)
mock_fyta_connector.update_all_plants.return_value = load_json_object_fixture(
"plant_status.json", FYTA_DOMAIN
)
mock_fyta_connector.plant_list = load_json_object_fixture(
"plant_list.json", FYTA_DOMAIN
)
mock_fyta_connector.login = AsyncMock(
return_value={
CONF_ACCESS_TOKEN: ACCESS_TOKEN,

View File

@ -0,0 +1,4 @@
{
"0": "Gummibaum",
"1": "Kakaobaum"
}

View File

@ -0,0 +1,14 @@
{
"0": {
"name": "Gummibaum",
"scientific_name": "Ficus elastica",
"status": 1,
"sw_version": "1.0"
},
"1": {
"name": "Kakaobaum",
"scientific_name": "Theobroma cacao",
"status": 2,
"sw_version": "1.0"
}
}

View File

@ -0,0 +1,213 @@
# serializer version: 1
# name: test_all_entities[sensor.gummibaum_plant_state-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'deleted',
'doing_great',
'need_attention',
'no_sensor',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.gummibaum_plant_state',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Plant state',
'platform': 'fyta',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'plant_status',
'unique_id': 'ce5f5431554d101905d31797e1232da8-0-status',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.gummibaum_plant_state-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Gummibaum Plant state',
'options': list([
'deleted',
'doing_great',
'need_attention',
'no_sensor',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.gummibaum_plant_state',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'doing_great',
})
# ---
# name: test_all_entities[sensor.gummibaum_scientific_name-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.gummibaum_scientific_name',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Scientific name',
'platform': 'fyta',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'scientific_name',
'unique_id': 'ce5f5431554d101905d31797e1232da8-0-scientific_name',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.gummibaum_scientific_name-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Gummibaum Scientific name',
}),
'context': <ANY>,
'entity_id': 'sensor.gummibaum_scientific_name',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'Ficus elastica',
})
# ---
# name: test_all_entities[sensor.kakaobaum_plant_state-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'deleted',
'doing_great',
'need_attention',
'no_sensor',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.kakaobaum_plant_state',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Plant state',
'platform': 'fyta',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'plant_status',
'unique_id': 'ce5f5431554d101905d31797e1232da8-1-status',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.kakaobaum_plant_state-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Kakaobaum Plant state',
'options': list([
'deleted',
'doing_great',
'need_attention',
'no_sensor',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.kakaobaum_plant_state',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'need_attention',
})
# ---
# name: test_all_entities[sensor.kakaobaum_scientific_name-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.kakaobaum_scientific_name',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Scientific name',
'platform': 'fyta',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'scientific_name',
'unique_id': 'ce5f5431554d101905d31797e1232da8-1-scientific_name',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.kakaobaum_scientific_name-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Kakaobaum Scientific name',
}),
'context': <ANY>,
'entity_id': 'sensor.kakaobaum_scientific_name',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'Theobroma cacao',
})
# ---

View File

@ -41,6 +41,23 @@ async def test_load_unload(
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
async def test_refresh_expired_token(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_fyta_connector: AsyncMock,
) -> None:
"""Test we refresh an expired token."""
mock_fyta_connector.expiration = datetime.fromisoformat(EXPIRATION_OLD).replace(
tzinfo=UTC
)
await setup_platform(hass, mock_config_entry, [Platform.SENSOR])
assert mock_config_entry.state is ConfigEntryState.LOADED
assert len(mock_fyta_connector.login.mock_calls) == 1
assert mock_config_entry.data[CONF_EXPIRATION] == EXPIRATION
@pytest.mark.parametrize(
"exception",
[
@ -84,6 +101,26 @@ async def test_raise_config_entry_not_ready_when_offline(
assert len(hass.config_entries.flow.async_progress()) == 0
async def test_raise_config_entry_not_ready_when_offline_and_expired(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_fyta_connector: AsyncMock,
) -> None:
"""Config entry state is SETUP_RETRY when FYTA is offline and access_token is expired."""
mock_fyta_connector.login.side_effect = FytaConnectionError
mock_fyta_connector.expiration = datetime.fromisoformat(EXPIRATION_OLD).replace(
tzinfo=UTC
)
await setup_platform(hass, mock_config_entry, [Platform.SENSOR])
await hass.async_block_till_done()
assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
assert len(hass.config_entries.flow.async_progress()) == 0
async def test_migrate_config_entry(
hass: HomeAssistant,
mock_fyta_connector: AsyncMock,

View File

@ -0,0 +1,47 @@
"""Test the Home Assistant fyta sensor module."""
from datetime import timedelta
from unittest.mock import AsyncMock
from freezegun.api import FrozenDateTimeFactory
from fyta_cli.fyta_exceptions import FytaConnectionError
from syrupy import SnapshotAssertion
from homeassistant.const import STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import setup_platform
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
async def test_all_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_fyta_connector: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
await setup_platform(hass, mock_config_entry, [Platform.SENSOR])
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
async def test_connection_error(
hass: HomeAssistant,
mock_fyta_connector: AsyncMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test connection error."""
await setup_platform(hass, mock_config_entry, [Platform.SENSOR])
mock_fyta_connector.update_all_plants.side_effect = FytaConnectionError
freezer.tick(delta=timedelta(hours=12))
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert hass.states.get("sensor.gummibaum_plant_state").state == STATE_UNAVAILABLE