diff --git a/homeassistant/components/openevse/sensor.py b/homeassistant/components/openevse/sensor.py index 85b376c4aec..6321c70e22c 100644 --- a/homeassistant/components/openevse/sensor.py +++ b/homeassistant/components/openevse/sensor.py @@ -10,7 +10,6 @@ from openevsehttp.__main__ import OpenEVSE import voluptuous as vol from homeassistant.components.sensor import ( - DOMAIN as HOMEASSISTANT_DOMAIN, PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA, SensorDeviceClass, SensorEntity, @@ -27,7 +26,7 @@ from homeassistant.const import ( UnitOfTemperature, UnitOfTime, ) -from homeassistant.core import HomeAssistant +from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant from homeassistant.data_entry_flow import FlowResultType from homeassistant.helpers import config_validation as cv, issue_registry as ir from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo diff --git a/homeassistant/components/openevse/strings.json b/homeassistant/components/openevse/strings.json index d5afcbfa951..f3f75f541d8 100644 --- a/homeassistant/components/openevse/strings.json +++ b/homeassistant/components/openevse/strings.json @@ -55,6 +55,10 @@ } }, "issues": { + "deprecated_yaml_import_issue_unavailable_host": { + "description": "Configuring {integration_title} using YAML is being removed but there was a connection error while trying to import the YAML configuration.\n\nEnsure your OpenEVSE charger is accessible and restart Home Assistant to try again.", + "title": "The {integration_title} YAML configuration import failed" + }, "yaml_deprecated": { "description": "Configuring OpenEVSE using YAML is being removed. Your existing YAML configuration has been imported into the UI automatically. Remove the `openevse` configuration from your configuration.yaml file and restart Home Assistant to fix this issue.", "title": "OpenEVSE YAML configuration is deprecated" diff --git a/tests/components/openevse/test_init.py b/tests/components/openevse/test_init.py new file mode 100644 index 00000000000..5d99806abc0 --- /dev/null +++ b/tests/components/openevse/test_init.py @@ -0,0 +1,41 @@ +"""Tests for the OpenEVSE integration.""" + +from unittest.mock import MagicMock + +from homeassistant.config_entries import ConfigEntryState +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry + + +async def test_setup_entry_timeout( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_charger: MagicMock, +) -> None: + """Test setup entry raises ConfigEntryNotReady on timeout.""" + mock_charger.test_and_get.side_effect = TimeoutError + + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY + + +async def test_unload_entry( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_charger: MagicMock, +) -> None: + """Test unload entry.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.state is ConfigEntryState.LOADED + + await hass.config_entries.async_unload(mock_config_entry.entry_id) + await hass.async_block_till_done() + + assert mock_config_entry.state is ConfigEntryState.NOT_LOADED diff --git a/tests/components/openevse/test_sensor.py b/tests/components/openevse/test_sensor.py index eed1f45afbc..67a656bf0d9 100644 --- a/tests/components/openevse/test_sensor.py +++ b/tests/components/openevse/test_sensor.py @@ -5,8 +5,12 @@ from unittest.mock import MagicMock import pytest from syrupy.assertion import SnapshotAssertion +from homeassistant.components.openevse.const import DOMAIN +from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN +from homeassistant.const import CONF_HOST, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant -from homeassistant.helpers import entity_registry as er +from homeassistant.helpers import entity_registry as er, issue_registry as ir +from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, snapshot_platform @@ -51,3 +55,89 @@ async def test_disabled_by_default_entities( assert entry assert entry.disabled assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION + + +async def test_sensor_unavailable_on_coordinator_timeout( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_charger: MagicMock, +) -> None: + """Test sensors become unavailable when coordinator times out.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + state = hass.states.get("sensor.openevse_mock_config_charging_status") + assert state + assert state.state != STATE_UNAVAILABLE + + mock_charger.update.side_effect = TimeoutError("Connection timed out") + await mock_config_entry.runtime_data.async_refresh() + await hass.async_block_till_done() + + state = hass.states.get("sensor.openevse_mock_config_charging_status") + assert state + assert state.state == STATE_UNAVAILABLE + + +async def test_yaml_import_success( + hass: HomeAssistant, + mock_charger: MagicMock, + issue_registry: ir.IssueRegistry, +) -> None: + """Test successful YAML import creates deprecated_yaml issue.""" + assert await async_setup_component( + hass, + SENSOR_DOMAIN, + {SENSOR_DOMAIN: {"platform": DOMAIN, CONF_HOST: "192.168.1.100"}}, + ) + await hass.async_block_till_done() + + issue = issue_registry.async_get_issue("homeassistant", "deprecated_yaml") + assert issue is not None + assert issue.issue_domain == DOMAIN + + +async def test_yaml_import_unavailable_host( + hass: HomeAssistant, + mock_charger: MagicMock, + issue_registry: ir.IssueRegistry, +) -> None: + """Test YAML import with unavailable host creates domain-specific issue.""" + mock_charger.test_and_get.side_effect = TimeoutError("Connection timed out") + + assert await async_setup_component( + hass, + SENSOR_DOMAIN, + {SENSOR_DOMAIN: {"platform": DOMAIN, CONF_HOST: "192.168.1.100"}}, + ) + await hass.async_block_till_done() + + issue = issue_registry.async_get_issue( + DOMAIN, "deprecated_yaml_import_issue_unavailable_host" + ) + assert issue is not None + + +async def test_yaml_import_already_configured( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_charger: MagicMock, + issue_registry: ir.IssueRegistry, +) -> None: + """Test YAML import when already configured creates deprecated_yaml issue.""" + # Only add the entry, don't set it up - this allows the YAML platform setup + # to run while the config flow will still see the existing entry + mock_config_entry.add_to_hass(hass) + + assert await async_setup_component( + hass, + SENSOR_DOMAIN, + {SENSOR_DOMAIN: {"platform": DOMAIN, CONF_HOST: "192.168.1.100"}}, + ) + await hass.async_block_till_done() + + # When already configured, it should still create deprecated_yaml issue + issue = issue_registry.async_get_issue("homeassistant", "deprecated_yaml") + assert issue is not None + assert issue.issue_domain == DOMAIN