diff --git a/coordinator.py b/coordinator.py index 4efa8b4..a8aa8d3 100644 --- a/coordinator.py +++ b/coordinator.py @@ -13,6 +13,7 @@ import logging import socket import sys +from errno import ENETUNREACH, EHOSTUNREACH from pathlib import Path from typing import Any @@ -162,7 +163,7 @@ async def async_execute(self, data: dict[str, Any]) -> dict[str, Any]: translation_key="connection_timed_out", ) from exc except OSError as exc: - if isinstance(exc, socket.gaierror): + if isinstance(exc, socket.gaierror) or exc.errno in (ENETUNREACH, EHOSTUNREACH): _LOGGER.warning("Host %s is not reachable: %s", host, exc) raise ServiceValidationError( "Host is not reachable.", diff --git a/tests/integration_tests/test_integration.py b/tests/integration_tests/test_integration.py index 8728c4c..43e030e 100644 --- a/tests/integration_tests/test_integration.py +++ b/tests/integration_tests/test_integration.py @@ -658,6 +658,27 @@ async def test_host_not_reachable(self, hass: HomeAssistant) -> None: assert exc_info.value.translation_key == "host_not_reachable" + async def test_network_unreachable(self, hass: HomeAssistant) -> None: + from errno import ENETUNREACH + + err = OSError(ENETUNREACH, "Connect call failed ('192.0.2.1', 22)") + entry = _make_entry() + await _setup_entry(hass, entry) + + with patch("custom_components.ssh_command.coordinator.connect", + return_value=_MockConnectRaises(err)): + with patch("pathlib.Path.exists", return_value=False): + with pytest.raises(ServiceValidationError) as exc_info: + await hass.services.async_call( + DOMAIN, + SERVICE_EXECUTE, + SERVICE_DATA_BASE, + blocking=True, + return_response=True, + ) + + assert exc_info.value.translation_key == "host_not_reachable" + async def test_other_oserror_is_reraised(self, hass: HomeAssistant) -> None: err = OSError("something else") entry = _make_entry() diff --git a/tests/unit_tests/test_coordinator.py b/tests/unit_tests/test_coordinator.py index c6a8957..f4f639b 100644 --- a/tests/unit_tests/test_coordinator.py +++ b/tests/unit_tests/test_coordinator.py @@ -108,6 +108,16 @@ async def test_async_execute_name_resolution_failure(self): self.assertEqual(ctx.exception.translation_key, "host_not_reachable") + async def test_async_execute_network_unreachable(self): + from errno import ENETUNREACH + + err = OSError(ENETUNREACH, "Connect call failed ('192.0.2.1', 22)") + with patch("ssh_command.coordinator.connect", return_value=_MockConnectRaises(err)): + with self.assertRaises(ServiceValidationError) as ctx: + await self.coordinator.async_execute(EXECUTE_DATA_BASE) + + self.assertEqual(ctx.exception.translation_key, "host_not_reachable") + async def test_async_execute_other_oserror_reraised(self): err = OSError("something else")