mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 09:47:13 +00:00
Catch ssl errors in rest (#91074)
* catch ssl.SSLError * add test * fail setup on ssl error * adjust tests
This commit is contained in:
parent
2c9e9d0fde
commit
0916701a0b
@ -1,6 +1,9 @@
|
|||||||
"""Support for RESTful binary sensors."""
|
"""Support for RESTful binary sensors."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import ssl
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import (
|
from homeassistant.components.binary_sensor import (
|
||||||
@ -31,6 +34,8 @@ from .data import RestData
|
|||||||
from .entity import RestEntity
|
from .entity import RestEntity
|
||||||
from .schema import BINARY_SENSOR_SCHEMA, RESOURCE_SCHEMA
|
from .schema import BINARY_SENSOR_SCHEMA, RESOURCE_SCHEMA
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({**RESOURCE_SCHEMA, **BINARY_SENSOR_SCHEMA})
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({**RESOURCE_SCHEMA, **BINARY_SENSOR_SCHEMA})
|
||||||
|
|
||||||
PLATFORM_SCHEMA = vol.All(
|
PLATFORM_SCHEMA = vol.All(
|
||||||
@ -59,6 +64,13 @@ async def async_setup_platform(
|
|||||||
|
|
||||||
if rest.data is None:
|
if rest.data is None:
|
||||||
if rest.last_exception:
|
if rest.last_exception:
|
||||||
|
if isinstance(rest.last_exception, ssl.SSLError):
|
||||||
|
_LOGGER.error(
|
||||||
|
"Error connecting %s failed with %s",
|
||||||
|
conf[CONF_RESOURCE],
|
||||||
|
rest.last_exception,
|
||||||
|
)
|
||||||
|
return
|
||||||
raise PlatformNotReady from rest.last_exception
|
raise PlatformNotReady from rest.last_exception
|
||||||
raise PlatformNotReady
|
raise PlatformNotReady
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import ssl
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@ -88,3 +89,11 @@ class RestData:
|
|||||||
self.last_exception = ex
|
self.last_exception = ex
|
||||||
self.data = None
|
self.data = None
|
||||||
self.headers = None
|
self.headers = None
|
||||||
|
except ssl.SSLError as ex:
|
||||||
|
if log_errors:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Error connecting to %s failed with %s", self._resource, ex
|
||||||
|
)
|
||||||
|
self.last_exception = ex
|
||||||
|
self.data = None
|
||||||
|
self.headers = None
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import ssl
|
||||||
from xml.parsers.expat import ExpatError
|
from xml.parsers.expat import ExpatError
|
||||||
|
|
||||||
from jsonpath import jsonpath
|
from jsonpath import jsonpath
|
||||||
@ -67,6 +68,13 @@ async def async_setup_platform(
|
|||||||
|
|
||||||
if rest.data is None:
|
if rest.data is None:
|
||||||
if rest.last_exception:
|
if rest.last_exception:
|
||||||
|
if isinstance(rest.last_exception, ssl.SSLError):
|
||||||
|
_LOGGER.error(
|
||||||
|
"Error connecting %s failed with %s",
|
||||||
|
conf[CONF_RESOURCE],
|
||||||
|
rest.last_exception,
|
||||||
|
)
|
||||||
|
return
|
||||||
raise PlatformNotReady from rest.last_exception
|
raise PlatformNotReady from rest.last_exception
|
||||||
raise PlatformNotReady
|
raise PlatformNotReady
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
import ssl
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
@ -81,6 +82,28 @@ async def test_setup_failed_connect(
|
|||||||
assert "server offline" in caplog.text
|
assert "server offline" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@respx.mock
|
||||||
|
async def test_setup_fail_on_ssl_erros(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test setup when connection error occurs."""
|
||||||
|
respx.get("https://localhost").mock(side_effect=ssl.SSLError("ssl error"))
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
BINARY_SENSOR_DOMAIN,
|
||||||
|
{
|
||||||
|
BINARY_SENSOR_DOMAIN: {
|
||||||
|
"platform": DOMAIN,
|
||||||
|
"resource": "https://localhost",
|
||||||
|
"method": "GET",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(hass.states.async_all(BINARY_SENSOR_DOMAIN)) == 0
|
||||||
|
assert "ssl error" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
@respx.mock
|
@respx.mock
|
||||||
async def test_setup_timeout(hass: HomeAssistant) -> None:
|
async def test_setup_timeout(hass: HomeAssistant) -> None:
|
||||||
"""Test setup when connection timeout occurs."""
|
"""Test setup when connection timeout occurs."""
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
import ssl
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
import respx
|
import respx
|
||||||
|
|
||||||
from homeassistant import config as hass_config
|
from homeassistant import config as hass_config
|
||||||
@ -133,6 +135,46 @@ async def test_setup_with_endpoint_timeout_with_recovery(hass: HomeAssistant) ->
|
|||||||
assert hass.states.get("binary_sensor.binary_sensor2").state == "off"
|
assert hass.states.get("binary_sensor.binary_sensor2").state == "off"
|
||||||
|
|
||||||
|
|
||||||
|
@respx.mock
|
||||||
|
async def test_setup_with_ssl_error(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test setup with an ssl error."""
|
||||||
|
await async_setup_component(hass, "homeassistant", {})
|
||||||
|
|
||||||
|
respx.get("https://localhost").mock(side_effect=ssl.SSLError("ssl error"))
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
{
|
||||||
|
DOMAIN: [
|
||||||
|
{
|
||||||
|
"resource": "https://localhost",
|
||||||
|
"method": "GET",
|
||||||
|
"verify_ssl": "false",
|
||||||
|
"timeout": 30,
|
||||||
|
"sensor": [
|
||||||
|
{
|
||||||
|
"unit_of_measurement": UnitOfInformation.MEGABYTES,
|
||||||
|
"name": "sensor1",
|
||||||
|
"value_template": "{{ value_json.sensor1 }}",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"binary_sensor": [
|
||||||
|
{
|
||||||
|
"name": "binary_sensor1",
|
||||||
|
"value_template": "{{ value_json.binary_sensor1 }}",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(hass.states.async_all()) == 0
|
||||||
|
assert "ssl error" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
@respx.mock
|
@respx.mock
|
||||||
async def test_setup_minimum_resource_template(hass: HomeAssistant) -> None:
|
async def test_setup_minimum_resource_template(hass: HomeAssistant) -> None:
|
||||||
"""Test setup with minimum configuration (resource_template)."""
|
"""Test setup with minimum configuration (resource_template)."""
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""The tests for the REST sensor platform."""
|
"""The tests for the REST sensor platform."""
|
||||||
import asyncio
|
import asyncio
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
import ssl
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
@ -77,6 +78,28 @@ async def test_setup_failed_connect(
|
|||||||
assert "server offline" in caplog.text
|
assert "server offline" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@respx.mock
|
||||||
|
async def test_setup_fail_on_ssl_erros(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test setup when connection error occurs."""
|
||||||
|
respx.get("https://localhost").mock(side_effect=ssl.SSLError("ssl error"))
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
SENSOR_DOMAIN,
|
||||||
|
{
|
||||||
|
SENSOR_DOMAIN: {
|
||||||
|
"platform": DOMAIN,
|
||||||
|
"resource": "https://localhost",
|
||||||
|
"method": "GET",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(hass.states.async_all(SENSOR_DOMAIN)) == 0
|
||||||
|
assert "ssl error" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
@respx.mock
|
@respx.mock
|
||||||
async def test_setup_timeout(hass: HomeAssistant) -> None:
|
async def test_setup_timeout(hass: HomeAssistant) -> None:
|
||||||
"""Test setup when connection timeout occurs."""
|
"""Test setup when connection timeout occurs."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user