Catch ssl errors in rest (#91074)

* catch ssl.SSLError

* add test

* fail setup on ssl error

* adjust tests
This commit is contained in:
Michael 2023-04-12 06:51:41 +02:00 committed by GitHub
parent 2c9e9d0fde
commit 0916701a0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 0 deletions

View File

@ -1,6 +1,9 @@
"""Support for RESTful binary sensors."""
from __future__ import annotations
import logging
import ssl
import voluptuous as vol
from homeassistant.components.binary_sensor import (
@ -31,6 +34,8 @@ from .data import RestData
from .entity import RestEntity
from .schema import BINARY_SENSOR_SCHEMA, RESOURCE_SCHEMA
_LOGGER = logging.getLogger(__name__)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({**RESOURCE_SCHEMA, **BINARY_SENSOR_SCHEMA})
PLATFORM_SCHEMA = vol.All(
@ -59,6 +64,13 @@ async def async_setup_platform(
if rest.data is None:
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

View File

@ -2,6 +2,7 @@
from __future__ import annotations
import logging
import ssl
import httpx
@ -88,3 +89,11 @@ class RestData:
self.last_exception = ex
self.data = 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

View File

@ -2,6 +2,7 @@
from __future__ import annotations
import logging
import ssl
from xml.parsers.expat import ExpatError
from jsonpath import jsonpath
@ -67,6 +68,13 @@ async def async_setup_platform(
if rest.data is None:
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

View File

@ -2,6 +2,7 @@
import asyncio
from http import HTTPStatus
import ssl
from unittest.mock import MagicMock, patch
import httpx
@ -81,6 +82,28 @@ async def test_setup_failed_connect(
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
async def test_setup_timeout(hass: HomeAssistant) -> None:
"""Test setup when connection timeout occurs."""

View File

@ -3,8 +3,10 @@
import asyncio
from datetime import timedelta
from http import HTTPStatus
import ssl
from unittest.mock import patch
import pytest
import respx
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"
@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
async def test_setup_minimum_resource_template(hass: HomeAssistant) -> None:
"""Test setup with minimum configuration (resource_template)."""

View File

@ -1,6 +1,7 @@
"""The tests for the REST sensor platform."""
import asyncio
from http import HTTPStatus
import ssl
from unittest.mock import MagicMock, patch
import httpx
@ -77,6 +78,28 @@ async def test_setup_failed_connect(
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
async def test_setup_timeout(hass: HomeAssistant) -> None:
"""Test setup when connection timeout occurs."""