Skip to content

Commit

Permalink
Add tests to emoncms (home-assistant#122547)
Browse files Browse the repository at this point in the history
* Add tests to emoncms

* Reduce snapshot size

* Reduce snapshot size

* run hassfest to update CODEOWNERS file

* Update requirements_test_all.txt

* Update tests/components/emoncms/test_sensor.py

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

* Dont use snapshot when testing state change

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
  • Loading branch information
alexandrecuer and joostlek authored Jul 24, 2024
1 parent 34b32ce commit fcccd85
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 0 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ build.json @home-assistant/supervisor
/tests/components/elvia/ @ludeeus
/homeassistant/components/emby/ @mezz64
/homeassistant/components/emoncms/ @borpin @alexandrecuer
/tests/components/emoncms/ @borpin @alexandrecuer
/homeassistant/components/emonitor/ @bdraco
/tests/components/emonitor/ @bdraco
/homeassistant/components/emulated_hue/ @bdraco @Tho85
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/emoncms/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
CONF_ONLY_INCLUDE_FEEDID = "include_only_feed_id"
CONF_MESSAGE = "message"
CONF_SUCCESS = "success"
DOMAIN = "emoncms"


LOGGER = logging.getLogger(__package__)
3 changes: 3 additions & 0 deletions requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1453,6 +1453,9 @@ pyefergy==22.5.0
# homeassistant.components.energenie_power_sockets
pyegps==0.2.5

# homeassistant.components.emoncms
pyemoncms==0.0.7

# homeassistant.components.enphase_envoy
pyenphase==1.20.6

Expand Down
1 change: 1 addition & 0 deletions tests/components/emoncms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for the emoncms component."""
47 changes: 47 additions & 0 deletions tests/components/emoncms/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Fixtures for emoncms integration tests."""

from collections.abc import AsyncGenerator
from unittest.mock import AsyncMock, patch

import pytest

UNITS = ["kWh", "Wh", "W", "V", "A", "VA", "°C", "°F", "K", "Hz", "hPa", ""]


def get_feed(
number: int, unit: str = "W", value: int = 18.04, timestamp: int = 1665509570
):
"""Generate feed details."""
return {
"id": str(number),
"userid": "1",
"name": f"parameter {number}",
"tag": "tag",
"size": "35809224",
"unit": unit,
"time": timestamp,
"value": value,
}


FEEDS = [get_feed(i + 1, unit=unit) for i, unit in enumerate(UNITS)]


EMONCMS_FAILURE = {"success": False, "message": "failure"}


@pytest.fixture
async def emoncms_client() -> AsyncGenerator[AsyncMock]:
"""Mock pyemoncms success response."""
with (
patch(
"homeassistant.components.emoncms.sensor.EmoncmsClient", autospec=True
) as mock_client,
patch(
"homeassistant.components.emoncms.coordinator.EmoncmsClient",
new=mock_client,
),
):
client = mock_client.return_value
client.async_request.return_value = {"success": True, "message": FEEDS}
yield client
24 changes: 24 additions & 0 deletions tests/components/emoncms/snapshots/test_sensor.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# serializer version: 1
# name: test_coordinator_update[sensor.emoncms_parameter_1]
StateSnapshot({
'attributes': ReadOnlyDict({
'FeedId': '1',
'FeedName': 'parameter 1',
'LastUpdated': 1665509570,
'LastUpdatedStr': '2022-10-11T10:32:50-07:00',
'Size': '35809224',
'Tag': 'tag',
'UserId': '1',
'device_class': 'temperature',
'friendly_name': 'EmonCMS parameter 1',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.emoncms_parameter_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '18.04',
})
# ---
90 changes: 90 additions & 0 deletions tests/components/emoncms/test_sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""Test emoncms sensor."""

from typing import Any
from unittest.mock import AsyncMock

from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.components.emoncms.const import CONF_ONLY_INCLUDE_FEEDID, DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.const import CONF_API_KEY, CONF_ID, CONF_PLATFORM, CONF_URL
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
from homeassistant.setup import async_setup_component

from .conftest import EMONCMS_FAILURE, FEEDS, get_feed

from tests.common import async_fire_time_changed

YAML = {
CONF_PLATFORM: "emoncms",
CONF_API_KEY: "my_api_key",
CONF_ID: 1,
CONF_URL: "http://1.1.1.1",
CONF_ONLY_INCLUDE_FEEDID: [1, 2],
"scan_interval": 30,
}


@pytest.fixture
def emoncms_yaml_config() -> ConfigType:
"""Mock emoncms configuration from yaml."""
return {"sensor": YAML}


def get_entity_ids(feeds: list[dict[str, Any]]) -> list[str]:
"""Get emoncms entity ids."""
return [
f"{SENSOR_DOMAIN}.{DOMAIN}_{feed["name"].replace(' ', '_')}" for feed in feeds
]


def get_feeds(nbs: list[int]) -> list[dict[str, Any]]:
"""Get feeds."""
return [feed for feed in FEEDS if feed["id"] in str(nbs)]


async def test_coordinator_update(
hass: HomeAssistant,
emoncms_yaml_config: ConfigType,
snapshot: SnapshotAssertion,
emoncms_client: AsyncMock,
caplog: pytest.LogCaptureFixture,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test coordinator update."""
emoncms_client.async_request.return_value = {
"success": True,
"message": [get_feed(1, unit="°C")],
}
await async_setup_component(hass, SENSOR_DOMAIN, emoncms_yaml_config)
await hass.async_block_till_done()
feeds = get_feeds([1])
for entity_id in get_entity_ids(feeds):
state = hass.states.get(entity_id)
assert state == snapshot(name=entity_id)

async def skip_time() -> None:
freezer.tick(60)
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)

emoncms_client.async_request.return_value = {
"success": True,
"message": [get_feed(1, unit="°C", value=24.04, timestamp=1665509670)],
}

await skip_time()

for entity_id in get_entity_ids(feeds):
state = hass.states.get(entity_id)
assert state.attributes["LastUpdated"] == 1665509670
assert state.state == "24.04"

emoncms_client.async_request.return_value = EMONCMS_FAILURE

await skip_time()

assert f"Error fetching {DOMAIN}_coordinator data" in caplog.text

0 comments on commit fcccd85

Please sign in to comment.