New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add tests for System Monitor #107891
Add tests for System Monitor #107891
Conversation
@@ -70,6 +66,13 @@ | |||
SIGNAL_SYSTEMMONITOR_UPDATE = "systemmonitor_update" | |||
|
|||
|
|||
def get_cpu_icon() -> Literal["mdi:cpu-64-bit", "mdi:cpu-32-bit"]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has been added to test the icons in an easier manner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe decorate with @cache
since it never changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
diff --git a/homeassistant/components/systemmonitor/sensor.py b/homeassistant/components/systemmonitor/sensor.py
index ad770eae762..cdab34f71a9 100644
--- a/homeassistant/components/systemmonitor/sensor.py
+++ b/homeassistant/components/systemmonitor/sensor.py
@@ -10,6 +10,7 @@ import os
import socket
import sys
from typing import Any, Literal
+from functools import cache
import psutil
import voluptuous as vol
@@ -66,11 +67,10 @@ SENSOR_TYPE_MANDATORY_ARG = 4
SIGNAL_SYSTEMMONITOR_UPDATE = "systemmonitor_update"
+@cache
def get_cpu_icon() -> Literal["mdi:cpu-64-bit", "mdi:cpu-32-bit"]:
"""Return cpu icon."""
- if sys.maxsize > 2**32:
- return "mdi:cpu-64-bit"
- return "mdi:cpu-32-bit"
+ return "mdi:cpu-64-bit" if sys.maxsize > 2**32 else "mdi:cpu-32-bit"
@dataclass(frozen=True)
aa53fe8
to
73c34d2
Compare
async def test_sensor_icon_32bit() -> None: | ||
"""Test the sensor icon for 32bit system.""" | ||
|
||
with patch("sys.maxsize", 2**32): | ||
assert get_cpu_icon() == "mdi:cpu-32-bit" | ||
with patch("sys.maxsize", 2**64): | ||
assert get_cpu_icon() == "mdi:cpu-64-bit" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we would patch sys.maxsize
and write state to verify the icon instead of testing this directly (and i there is a cache it would be ok to clear the cache with .clear_cache
https://docs.python.org/3/library/functools.html#functools.lru_cache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that the icon is evaluated when the file is loaded so before the test even starts.
No idea how to patch sys.maxsize
in such case and I don't think clearing a cache helps as the icon has already been set in the entity descriptions then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can push a suggestion if you like
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
diff --git a/tests/components/systemmonitor/test_sensor.py b/tests/components/systemmonitor/test_sensor.py
index 25b6fd901fe..85ea38ddb70 100644
--- a/tests/components/systemmonitor/test_sensor.py
+++ b/tests/components/systemmonitor/test_sensor.py
@@ -5,7 +5,7 @@ from unittest.mock import Mock, patch
from freezegun.api import FrozenDateTimeFactory
from psutil._common import shwtemp, snetio, snicaddr
-from psutil._pslinux import svmem
+
import pytest
from syrupy.assertion import SnapshotAssertion
@@ -16,7 +16,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component
-from .conftest import MockProcess
+from .conftest import MockProcess, MockSvMem
from tests.common import MockConfigEntry, async_fire_time_changed
@@ -69,9 +69,10 @@ async def test_sensor_not_loading_veth_networks(
async def test_sensor_icon() -> None:
"""Test the sensor icon for 32bit/64bit system."""
-
+ get_cpu_icon.cache_clear()
with patch("sys.maxsize", 2**32):
assert get_cpu_icon() == "mdi:cpu-32-bit"
+ get_cpu_icon.cache_clear()
with patch("sys.maxsize", 2**64):
assert get_cpu_icon() == "mdi:cpu-64-bit"
But better to patch sys.maxsize
and clear the cache, move time forward, and wait for the update and verify the icon
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with patch("sys.maxsize", 2**32):
get_cpu_icon.cache_clear()
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
process_sensor = hass.states.get("sensor.system_monitor_process_python3")
assert process_sensor is not None
assert process_sensor.attributes["icon"] == "mdi:cpu-32-bit"
Not helping as it still comes out as 64-bit given my system.
entity descriptions are also a constant so not sure how the cache would help here. I only see it would work by moving it down to the entity but I would prefer to skip that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to push a change if you find a workable solution 👍
I'm not going to continue now until tomorrow.
|
||
from psutil import NoSuchProcess, Process | ||
from psutil._common import sdiskpart, sdiskusage, shwtemp, snetio, snicaddr, sswap | ||
from psutil._pslinux import svmem |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fails to import when testing on macos
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe something like
@dataclass
class MockSvMem:
total: int
available: int
percent: float
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FAILED tests/components/systemmonitor/test_init.py::test_load_unload_entry - AttributeError: Mock object has no attribute 'sensors_temperatures'
sensors_temperatures
also doesn't exist on macos
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sensors_temperatures
also doesn't exist on macos
According to psutil
it should https://github.com/giampaolo/psutil/blob/master/psutil/__init__.py#L2284
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ImportError while loading conftest '/Users/bdraco/home-assistant/tests/components/systemmonitor/conftest.py'.
tests/components/systemmonitor/conftest.py:10: in <module>
from psutil._pslinux import svmem
venv/lib/python3.12/site-packages/psutil/_pslinux.py:25: in <module>
from . import _psutil_linux as cext
E ImportError: cannot import name '_psutil_linux' from 'psutil' (/Users/bdraco/home-assistant/venv/lib/python3.12/site-packages/psutil/__init__.py). Did you mean: '_psutil_osx'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this helps
@pytest.fixture(autouse=True)
def mock_sys_platform() -> Generator[None, None, None]:
"""Mock sys platform to Linux."""
with patch("sys.platform", "linux"):
yield
|
diff --git a/tests/components/systemmonitor/conftest.py b/tests/components/systemmonitor/conftest.py
index ef29e54bb34..06bdfcf404b 100644
--- a/tests/components/systemmonitor/conftest.py
+++ b/tests/components/systemmonitor/conftest.py
@@ -174,6 +174,9 @@ def mock_psutil(mock_process: list[MockProcess]) -> Mock:
mock_psutil.cpu_percent.return_value = 10.0
mock_psutil.boot_time.return_value = 1703973338.0
mock_psutil.process_iter.return_value = mock_process
+ # sensors_temperatures not available on MacOS so we
+ # need to override the spec
+ mock_psutil.__setattr__("sensors_temperatures", Mock())
mock_psutil.sensors_temperatures.return_value = {
"cpu0-thermal": [shwtemp("cpu0-thermal", 50.0, 60.0, 70.0)]
}
@@ -218,6 +221,9 @@ def mock_util(mock_process) -> Mock:
}
mock_process = [MockProcess("python3")]
mock_util.process_iter.return_value = mock_process
+ # sensors_temperatures not available on MacOS so we
+ # need to override the spec
+ mock_util.__setattr__("sensors_temperatures", Mock())
mock_util.sensors_temperatures.return_value = {
"cpu0-thermal": [shwtemp("cpu0-thermal", 50.0, 60.0, 70.0)]
} The tests pass with this change |
|
||
process_sensor = hass.states.get("sensor.system_monitor_process_python3") | ||
assert process_sensor is not None | ||
# assert process_sensor.state == STATE_ON |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
old comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot this one, addressed in new PR
locally on macos |
👍 |
Proposed change
Adds test coverage for System Monitor
Type of change
Additional information
Checklist
ruff format homeassistant tests
)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest
.requirements_all.txt
.Updated by running
python3 -m script.gen_requirements_all
..coveragerc
.To help with the load of incoming pull requests: