Raise ConfigEntryNotReady for MQTT connection exception (#22540)
* Raise ConfigEntryNotReady for connection exception Raise ConfigEntryNotReady for the connection exception like if the MQTT Server container/device is being restarted or was unavailable on boot. * Add new exception * grammar fix * Possibly resolve hound comments * raise `ConfigEntryNotReady` for mqtt connection error * revert exceptions.py * Update exceptions.py * modify test to handle exception * use constants to control exception scope * Raise ConfigEntryNotReady for connection exception Raise ConfigEntryNotReady for the connection exception like if the MQTT Server container/device is being restarted or was unavailable on boot. * Add new exception * Add new exception * grammar fix * Possibly resolve hound comments * raise `ConfigEntryNotReady` for mqtt connection error * revert exceptions.py * Update exceptions.py * modify test to handle exception * use constants to control exception scope * revert test change as it's not the same thing * Update test_init.py * Add test for MQTT OSError * revert file changes from a bad rebase * Rewrite test with valid syntax * rewrite test to be less ambiguous * add empty line * add back 'axis' * Remove empty line * Update tests and undo merge from earlier * correctly restore test for no connect broker * fix test mock correctly * line was too long. hit enter.
This commit is contained in:
parent
d81a627739
commit
a5a926bcc6
2 changed files with 29 additions and 7 deletions
|
@ -23,7 +23,8 @@ from homeassistant.const import (
|
||||||
CONF_PROTOCOL, CONF_USERNAME, CONF_VALUE_TEMPLATE,
|
CONF_PROTOCOL, CONF_USERNAME, CONF_VALUE_TEMPLATE,
|
||||||
EVENT_HOMEASSISTANT_STOP)
|
EVENT_HOMEASSISTANT_STOP)
|
||||||
from homeassistant.core import Event, ServiceCall, callback
|
from homeassistant.core import Event, ServiceCall, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError, Unauthorized
|
from homeassistant.exceptions import (
|
||||||
|
HomeAssistantError, Unauthorized, ConfigEntryNotReady)
|
||||||
from homeassistant.helpers import config_validation as cv, template
|
from homeassistant.helpers import config_validation as cv, template
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.typing import (
|
from homeassistant.helpers.typing import (
|
||||||
|
@ -104,6 +105,10 @@ ATTR_DISCOVERY_HASH = 'discovery_hash'
|
||||||
|
|
||||||
MAX_RECONNECT_WAIT = 300 # seconds
|
MAX_RECONNECT_WAIT = 300 # seconds
|
||||||
|
|
||||||
|
CONNECTION_SUCCESS = 'connection_success'
|
||||||
|
CONNECTION_FAILED = 'connection_failed'
|
||||||
|
CONNECTION_FAILED_RECOVERABLE = 'connection_failed_recoverable'
|
||||||
|
|
||||||
|
|
||||||
def valid_topic(value: Any) -> str:
|
def valid_topic(value: Any) -> str:
|
||||||
"""Validate that this is a valid topic name/filter."""
|
"""Validate that this is a valid topic name/filter."""
|
||||||
|
@ -569,11 +574,14 @@ async def async_setup_entry(hass, entry):
|
||||||
tls_version=tls_version,
|
tls_version=tls_version,
|
||||||
)
|
)
|
||||||
|
|
||||||
success = await hass.data[DATA_MQTT].async_connect() # type: bool
|
result = await hass.data[DATA_MQTT].async_connect() # type: str
|
||||||
|
|
||||||
if not success:
|
if result == CONNECTION_FAILED:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if result == CONNECTION_FAILED_RECOVERABLE:
|
||||||
|
raise ConfigEntryNotReady
|
||||||
|
|
||||||
async def async_stop_mqtt(event: Event):
|
async def async_stop_mqtt(event: Event):
|
||||||
"""Stop MQTT component."""
|
"""Stop MQTT component."""
|
||||||
await hass.data[DATA_MQTT].async_disconnect()
|
await hass.data[DATA_MQTT].async_disconnect()
|
||||||
|
@ -685,7 +693,7 @@ class MQTT:
|
||||||
await self.hass.async_add_job(
|
await self.hass.async_add_job(
|
||||||
self._mqttc.publish, topic, payload, qos, retain)
|
self._mqttc.publish, topic, payload, qos, retain)
|
||||||
|
|
||||||
async def async_connect(self) -> bool:
|
async def async_connect(self) -> str:
|
||||||
"""Connect to the host. Does process messages yet.
|
"""Connect to the host. Does process messages yet.
|
||||||
|
|
||||||
This method is a coroutine.
|
This method is a coroutine.
|
||||||
|
@ -696,15 +704,15 @@ class MQTT:
|
||||||
self._mqttc.connect, self.broker, self.port, self.keepalive)
|
self._mqttc.connect, self.broker, self.port, self.keepalive)
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
_LOGGER.error("Failed to connect due to exception: %s", err)
|
_LOGGER.error("Failed to connect due to exception: %s", err)
|
||||||
return False
|
return CONNECTION_FAILED_RECOVERABLE
|
||||||
|
|
||||||
if result != 0:
|
if result != 0:
|
||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
_LOGGER.error("Failed to connect: %s", mqtt.error_string(result))
|
_LOGGER.error("Failed to connect: %s", mqtt.error_string(result))
|
||||||
return False
|
return CONNECTION_FAILED
|
||||||
|
|
||||||
self._mqttc.loop_start()
|
self._mqttc.loop_start()
|
||||||
return True
|
return CONNECTION_SUCCESS
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_disconnect(self):
|
def async_disconnect(self):
|
||||||
|
|
|
@ -12,6 +12,7 @@ from homeassistant.const import (
|
||||||
ATTR_DOMAIN, ATTR_SERVICE, EVENT_CALL_SERVICE, EVENT_HOMEASSISTANT_STOP)
|
ATTR_DOMAIN, ATTR_SERVICE, EVENT_CALL_SERVICE, EVENT_HOMEASSISTANT_STOP)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
MockConfigEntry, async_fire_mqtt_message, async_mock_mqtt_component,
|
MockConfigEntry, async_fire_mqtt_message, async_mock_mqtt_component,
|
||||||
|
@ -621,6 +622,19 @@ async def test_setup_fails_if_no_connect_broker(hass):
|
||||||
assert not await mqtt.async_setup_entry(hass, entry)
|
assert not await mqtt.async_setup_entry(hass, entry)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_raises_ConfigEntryNotReady_if_no_connect_broker(hass):
|
||||||
|
"""Test for setup failure if connection to broker is missing."""
|
||||||
|
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={
|
||||||
|
mqtt.CONF_BROKER: 'test-broker'
|
||||||
|
})
|
||||||
|
|
||||||
|
with mock.patch('paho.mqtt.client.Client') as mock_client:
|
||||||
|
mock_client().connect = mock.Mock(
|
||||||
|
side_effect=OSError("Connection error"))
|
||||||
|
with pytest.raises(ConfigEntryNotReady):
|
||||||
|
await mqtt.async_setup_entry(hass, entry)
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_uses_certificate_on_certificate_set_to_auto(
|
async def test_setup_uses_certificate_on_certificate_set_to_auto(
|
||||||
hass, mock_MQTT):
|
hass, mock_MQTT):
|
||||||
"""Test setup uses bundled certs when certificate is set to auto."""
|
"""Test setup uses bundled certs when certificate is set to auto."""
|
||||||
|
|
Loading…
Add table
Reference in a new issue