Refactor the MQTT option and reconfigure flow (#133342)
* Move entry options to entry.options en remove broker setup from mqtt option flow * UPdate diagnostics to export both entry data and options * Parameterize entry options directly not depending on migration * Update tests to use v2 entry and add separate migration test * use start_reconfigure_flow helper * Update quality scale comment * Do minor entry upgrade, and do not force to upgrade entry * Ensure options are read from older entries * Add comment * Follow up on code review * Assert config entry version checking the broker connection * Update commentpull/127280/head^2
parent
b84a4dc120
commit
b93aa760c5
|
@ -69,6 +69,8 @@ from .const import ( # noqa: F401
|
|||
CONF_WILL_MESSAGE,
|
||||
CONF_WS_HEADERS,
|
||||
CONF_WS_PATH,
|
||||
CONFIG_ENTRY_MINOR_VERSION,
|
||||
CONFIG_ENTRY_VERSION,
|
||||
DEFAULT_DISCOVERY,
|
||||
DEFAULT_ENCODING,
|
||||
DEFAULT_PREFIX,
|
||||
|
@ -76,6 +78,7 @@ from .const import ( # noqa: F401
|
|||
DEFAULT_RETAIN,
|
||||
DOMAIN,
|
||||
ENTITY_PLATFORMS,
|
||||
ENTRY_OPTION_FIELDS,
|
||||
MQTT_CONNECTION_STATE,
|
||||
TEMPLATE_ERRORS,
|
||||
)
|
||||
|
@ -282,15 +285,45 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
return True
|
||||
|
||||
|
||||
async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Migrate the options from config entry data."""
|
||||
_LOGGER.debug("Migrating from version %s:%s", entry.version, entry.minor_version)
|
||||
data: dict[str, Any] = dict(entry.data)
|
||||
options: dict[str, Any] = dict(entry.options)
|
||||
if entry.version > 1:
|
||||
# This means the user has downgraded from a future version
|
||||
return False
|
||||
|
||||
if entry.version == 1 and entry.minor_version < 2:
|
||||
# Can be removed when config entry is bumped to version 2.1
|
||||
# with HA Core 2026.1.0. Read support for version 2.1 is expected before 2026.1
|
||||
# From 2026.1 we will write version 2.1
|
||||
for key in ENTRY_OPTION_FIELDS:
|
||||
if key not in data:
|
||||
continue
|
||||
options[key] = data.pop(key)
|
||||
hass.config_entries.async_update_entry(
|
||||
entry,
|
||||
data=data,
|
||||
options=options,
|
||||
version=CONFIG_ENTRY_VERSION,
|
||||
minor_version=CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
|
||||
_LOGGER.debug(
|
||||
"Migration to version %s:%s successful", entry.version, entry.minor_version
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Load a config entry."""
|
||||
conf: dict[str, Any]
|
||||
mqtt_data: MqttData
|
||||
|
||||
async def _setup_client() -> tuple[MqttData, dict[str, Any]]:
|
||||
"""Set up the MQTT client."""
|
||||
# Fetch configuration
|
||||
conf = dict(entry.data)
|
||||
conf = dict(entry.data | entry.options)
|
||||
hass_config = await conf_util.async_hass_config_yaml(hass)
|
||||
mqtt_yaml = CONFIG_SCHEMA(hass_config).get(DOMAIN, [])
|
||||
await async_create_certificate_temp_files(hass, conf)
|
||||
|
|
|
@ -76,6 +76,8 @@ from .const import (
|
|||
CONF_WILL_MESSAGE,
|
||||
CONF_WS_HEADERS,
|
||||
CONF_WS_PATH,
|
||||
CONFIG_ENTRY_MINOR_VERSION,
|
||||
CONFIG_ENTRY_VERSION,
|
||||
DEFAULT_BIRTH,
|
||||
DEFAULT_DISCOVERY,
|
||||
DEFAULT_ENCODING,
|
||||
|
@ -205,7 +207,9 @@ def update_password_from_user_input(
|
|||
class FlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow."""
|
||||
|
||||
VERSION = 1
|
||||
# Can be bumped to version 2.1 with HA Core 2026.1.0
|
||||
VERSION = CONFIG_ENTRY_VERSION # 1
|
||||
MINOR_VERSION = CONFIG_ENTRY_MINOR_VERSION # 2
|
||||
|
||||
_hassio_discovery: dict[str, Any] | None = None
|
||||
_addon_manager: AddonManager
|
||||
|
@ -496,7 +500,6 @@ class FlowHandler(ConfigFlow, domain=DOMAIN):
|
|||
reconfigure_entry,
|
||||
data=validated_user_input,
|
||||
)
|
||||
validated_user_input[CONF_DISCOVERY] = DEFAULT_DISCOVERY
|
||||
return self.async_create_entry(
|
||||
title=validated_user_input[CONF_BROKER],
|
||||
data=validated_user_input,
|
||||
|
@ -564,58 +567,17 @@ class FlowHandler(ConfigFlow, domain=DOMAIN):
|
|||
class MQTTOptionsFlowHandler(OptionsFlow):
|
||||
"""Handle MQTT options."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize MQTT options flow."""
|
||||
self.broker_config: dict[str, Any] = {}
|
||||
|
||||
async def async_step_init(self, user_input: None = None) -> ConfigFlowResult:
|
||||
"""Manage the MQTT options."""
|
||||
return await self.async_step_broker()
|
||||
|
||||
async def async_step_broker(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Manage the MQTT broker configuration."""
|
||||
errors: dict[str, str] = {}
|
||||
fields: OrderedDict[Any, Any] = OrderedDict()
|
||||
validated_user_input: dict[str, Any] = {}
|
||||
if await async_get_broker_settings(
|
||||
self,
|
||||
fields,
|
||||
self.config_entry.data,
|
||||
user_input,
|
||||
validated_user_input,
|
||||
errors,
|
||||
):
|
||||
self.broker_config.update(
|
||||
update_password_from_user_input(
|
||||
self.config_entry.data.get(CONF_PASSWORD), validated_user_input
|
||||
),
|
||||
)
|
||||
can_connect = await self.hass.async_add_executor_job(
|
||||
try_connection,
|
||||
self.broker_config,
|
||||
)
|
||||
|
||||
if can_connect:
|
||||
return await self.async_step_options()
|
||||
|
||||
errors["base"] = "cannot_connect"
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="broker",
|
||||
data_schema=vol.Schema(fields),
|
||||
errors=errors,
|
||||
last_step=False,
|
||||
)
|
||||
return await self.async_step_options()
|
||||
|
||||
async def async_step_options(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Manage the MQTT options."""
|
||||
errors = {}
|
||||
current_config = self.config_entry.data
|
||||
options_config: dict[str, Any] = {}
|
||||
|
||||
options_config: dict[str, Any] = dict(self.config_entry.options)
|
||||
bad_input: bool = False
|
||||
|
||||
def _birth_will(birt_or_will: str) -> dict[str, Any]:
|
||||
|
@ -674,26 +636,18 @@ class MQTTOptionsFlowHandler(OptionsFlow):
|
|||
options_config[CONF_WILL_MESSAGE] = {}
|
||||
|
||||
if not bad_input:
|
||||
updated_config = {}
|
||||
updated_config.update(self.broker_config)
|
||||
updated_config.update(options_config)
|
||||
self.hass.config_entries.async_update_entry(
|
||||
self.config_entry,
|
||||
data=updated_config,
|
||||
title=str(self.broker_config[CONF_BROKER]),
|
||||
)
|
||||
return self.async_create_entry(title="", data={})
|
||||
return self.async_create_entry(data=options_config)
|
||||
|
||||
birth = {
|
||||
**DEFAULT_BIRTH,
|
||||
**current_config.get(CONF_BIRTH_MESSAGE, {}),
|
||||
**options_config.get(CONF_BIRTH_MESSAGE, {}),
|
||||
}
|
||||
will = {
|
||||
**DEFAULT_WILL,
|
||||
**current_config.get(CONF_WILL_MESSAGE, {}),
|
||||
**options_config.get(CONF_WILL_MESSAGE, {}),
|
||||
}
|
||||
discovery = current_config.get(CONF_DISCOVERY, DEFAULT_DISCOVERY)
|
||||
discovery_prefix = current_config.get(CONF_DISCOVERY_PREFIX, DEFAULT_PREFIX)
|
||||
discovery = options_config.get(CONF_DISCOVERY, DEFAULT_DISCOVERY)
|
||||
discovery_prefix = options_config.get(CONF_DISCOVERY_PREFIX, DEFAULT_PREFIX)
|
||||
|
||||
# build form
|
||||
fields: OrderedDict[vol.Marker, Any] = OrderedDict()
|
||||
|
@ -706,8 +660,8 @@ class MQTTOptionsFlowHandler(OptionsFlow):
|
|||
fields[
|
||||
vol.Optional(
|
||||
"birth_enable",
|
||||
default=CONF_BIRTH_MESSAGE not in current_config
|
||||
or current_config[CONF_BIRTH_MESSAGE] != {},
|
||||
default=CONF_BIRTH_MESSAGE not in options_config
|
||||
or options_config[CONF_BIRTH_MESSAGE] != {},
|
||||
)
|
||||
] = BOOLEAN_SELECTOR
|
||||
fields[
|
||||
|
@ -729,8 +683,8 @@ class MQTTOptionsFlowHandler(OptionsFlow):
|
|||
fields[
|
||||
vol.Optional(
|
||||
"will_enable",
|
||||
default=CONF_WILL_MESSAGE not in current_config
|
||||
or current_config[CONF_WILL_MESSAGE] != {},
|
||||
default=CONF_WILL_MESSAGE not in options_config
|
||||
or options_config[CONF_WILL_MESSAGE] != {},
|
||||
)
|
||||
] = BOOLEAN_SELECTOR
|
||||
fields[
|
||||
|
|
|
@ -4,7 +4,7 @@ import logging
|
|||
|
||||
import jinja2
|
||||
|
||||
from homeassistant.const import CONF_PAYLOAD, Platform
|
||||
from homeassistant.const import CONF_DISCOVERY, CONF_PAYLOAD, Platform
|
||||
from homeassistant.exceptions import TemplateError
|
||||
|
||||
ATTR_DISCOVERY_HASH = "discovery_hash"
|
||||
|
@ -163,6 +163,20 @@ MQTT_CONNECTION_STATE = "mqtt_connection_state"
|
|||
PAYLOAD_EMPTY_JSON = "{}"
|
||||
PAYLOAD_NONE = "None"
|
||||
|
||||
CONFIG_ENTRY_VERSION = 1
|
||||
CONFIG_ENTRY_MINOR_VERSION = 2
|
||||
|
||||
# Split mqtt entry data and options
|
||||
# Can be removed when config entry is bumped to version 2.1
|
||||
# with HA Core 2026.1.0. Read support for version 2.1 is expected before 2026.1
|
||||
# From 2026.1 we will write version 2.1
|
||||
ENTRY_OPTION_FIELDS = (
|
||||
CONF_DISCOVERY,
|
||||
CONF_DISCOVERY_PREFIX,
|
||||
"birth_message",
|
||||
"will_message",
|
||||
)
|
||||
|
||||
ENTITY_PLATFORMS = [
|
||||
Platform.ALARM_CONTROL_PANEL,
|
||||
Platform.BINARY_SENSOR,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components import device_tracker
|
||||
from homeassistant.components.diagnostics import async_redact_data
|
||||
|
@ -18,7 +18,6 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er
|
|||
from homeassistant.helpers.device_registry import DeviceEntry
|
||||
|
||||
from . import debug_info, is_connected
|
||||
from .models import DATA_MQTT
|
||||
|
||||
REDACT_CONFIG = {CONF_PASSWORD, CONF_USERNAME}
|
||||
REDACT_STATE_DEVICE_TRACKER = {ATTR_LATITUDE, ATTR_LONGITUDE}
|
||||
|
@ -45,11 +44,10 @@ def _async_get_diagnostics(
|
|||
device: DeviceEntry | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a config entry."""
|
||||
mqtt_instance = hass.data[DATA_MQTT].client
|
||||
if TYPE_CHECKING:
|
||||
assert mqtt_instance is not None
|
||||
|
||||
redacted_config = async_redact_data(mqtt_instance.conf, REDACT_CONFIG)
|
||||
redacted_config = {
|
||||
"data": async_redact_data(dict(entry.data), REDACT_CONFIG),
|
||||
"options": dict(entry.options),
|
||||
}
|
||||
|
||||
data = {
|
||||
"connected": is_connected(hass),
|
||||
|
|
|
@ -89,10 +89,7 @@ rules:
|
|||
comment: >
|
||||
This is not possible because the integrations generates entities
|
||||
based on a user supplied config or discovery.
|
||||
reconfiguration-flow:
|
||||
status: done
|
||||
comment: >
|
||||
This integration can also be reconfigured via options flow.
|
||||
reconfiguration-flow: done
|
||||
dynamic-devices:
|
||||
status: done
|
||||
comment: |
|
||||
|
|
|
@ -18,7 +18,6 @@ from tests.common import MockConfigEntry
|
|||
from tests.typing import MqttMockPahoClient
|
||||
|
||||
ENTRY_DEFAULT_BIRTH_MESSAGE = {
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
mqtt.CONF_BIRTH_MESSAGE: {
|
||||
mqtt.ATTR_TOPIC: "homeassistant/status",
|
||||
mqtt.ATTR_PAYLOAD: "online",
|
||||
|
@ -77,6 +76,7 @@ def mock_debouncer(hass: HomeAssistant) -> Generator[asyncio.Event]:
|
|||
async def setup_with_birth_msg_client_mock(
|
||||
hass: HomeAssistant,
|
||||
mqtt_config_entry_data: dict[str, Any] | None,
|
||||
mqtt_config_entry_options: dict[str, Any] | None,
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
) -> AsyncGenerator[MqttMockPahoClient]:
|
||||
"""Test sending birth message."""
|
||||
|
@ -89,6 +89,9 @@ async def setup_with_birth_msg_client_mock(
|
|||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data=mqtt_config_entry_data or {mqtt.CONF_BROKER: "test-broker"},
|
||||
options=mqtt_config_entry_options or {},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
hass.config.components.add(mqtt.DOMAIN)
|
||||
|
|
|
@ -105,6 +105,8 @@ async def test_mqtt_await_ack_at_disconnect(hass: HomeAssistant) -> None:
|
|||
mqtt.CONF_BROKER: "test-broker",
|
||||
mqtt.CONF_DISCOVERY: False,
|
||||
},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
@ -132,7 +134,7 @@ async def test_mqtt_await_ack_at_disconnect(hass: HomeAssistant) -> None:
|
|||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mqtt_config_entry_data", [ENTRY_DEFAULT_BIRTH_MESSAGE])
|
||||
@pytest.mark.parametrize("mqtt_config_entry_options", [ENTRY_DEFAULT_BIRTH_MESSAGE])
|
||||
async def test_publish(
|
||||
hass: HomeAssistant, setup_with_birth_msg_client_mock: MqttMockPahoClient
|
||||
) -> None:
|
||||
|
@ -1022,8 +1024,8 @@ async def test_unsubscribe_race(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_DISCOVERY: False}],
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[({mqtt.CONF_BROKER: "mock-broker"}, {mqtt.CONF_DISCOVERY: False})],
|
||||
)
|
||||
async def test_restore_subscriptions_on_reconnect(
|
||||
hass: HomeAssistant,
|
||||
|
@ -1059,8 +1061,8 @@ async def test_restore_subscriptions_on_reconnect(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_DISCOVERY: False}],
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[({mqtt.CONF_BROKER: "mock-broker"}, {mqtt.CONF_DISCOVERY: False})],
|
||||
)
|
||||
async def test_restore_all_active_subscriptions_on_reconnect(
|
||||
hass: HomeAssistant,
|
||||
|
@ -1100,8 +1102,8 @@ async def test_restore_all_active_subscriptions_on_reconnect(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_DISCOVERY: False}],
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[({mqtt.CONF_BROKER: "mock-broker"}, {mqtt.CONF_DISCOVERY: False})],
|
||||
)
|
||||
async def test_subscribed_at_highest_qos(
|
||||
hass: HomeAssistant,
|
||||
|
@ -1136,7 +1138,12 @@ async def test_initial_setup_logs_error(
|
|||
mqtt_client_mock: MqttMockPahoClient,
|
||||
) -> None:
|
||||
"""Test for setup failure if initial client connection fails."""
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "test-broker"},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
mqtt_client_mock.connect.side_effect = MagicMock(return_value=1)
|
||||
try:
|
||||
|
@ -1239,7 +1246,12 @@ async def test_publish_error(
|
|||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test publish error."""
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "test-broker"},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
# simulate an Out of memory error
|
||||
|
@ -1381,7 +1393,10 @@ async def test_handle_mqtt_timeout_on_callback(
|
|||
)
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"}
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "test-broker"},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
|
@ -1414,7 +1429,12 @@ async def test_setup_raises_config_entry_not_ready_if_no_connect_broker(
|
|||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, exception: Exception
|
||||
) -> None:
|
||||
"""Test for setup failure if connection to broker is missing."""
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "test-broker"},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
|
@ -1495,17 +1515,19 @@ async def test_tls_version(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
mqtt.CONF_BIRTH_MESSAGE: {
|
||||
mqtt.ATTR_TOPIC: "birth",
|
||||
mqtt.ATTR_PAYLOAD: "birth",
|
||||
mqtt.ATTR_QOS: 0,
|
||||
mqtt.ATTR_RETAIN: False,
|
||||
(
|
||||
{mqtt.CONF_BROKER: "mock-broker"},
|
||||
{
|
||||
mqtt.CONF_BIRTH_MESSAGE: {
|
||||
mqtt.ATTR_TOPIC: "birth",
|
||||
mqtt.ATTR_PAYLOAD: "birth",
|
||||
mqtt.ATTR_QOS: 0,
|
||||
mqtt.ATTR_RETAIN: False,
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
],
|
||||
)
|
||||
@patch("homeassistant.components.mqtt.client.INITIAL_SUBSCRIBE_COOLDOWN", 0.0)
|
||||
|
@ -1515,11 +1537,18 @@ async def test_custom_birth_message(
|
|||
hass: HomeAssistant,
|
||||
mock_debouncer: asyncio.Event,
|
||||
mqtt_config_entry_data: dict[str, Any],
|
||||
mqtt_config_entry_options: dict[str, Any],
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
) -> None:
|
||||
"""Test sending birth message."""
|
||||
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data=mqtt_config_entry_data)
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data=mqtt_config_entry_data,
|
||||
options=mqtt_config_entry_options,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
hass.config.components.add(mqtt.DOMAIN)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
@ -1533,7 +1562,7 @@ async def test_custom_birth_message(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
"mqtt_config_entry_options",
|
||||
[ENTRY_DEFAULT_BIRTH_MESSAGE],
|
||||
)
|
||||
async def test_default_birth_message(
|
||||
|
@ -1548,8 +1577,8 @@ async def test_default_birth_message(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_BIRTH_MESSAGE: {}}],
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[({mqtt.CONF_BROKER: "mock-broker"}, {mqtt.CONF_BIRTH_MESSAGE: {}})],
|
||||
)
|
||||
@patch("homeassistant.components.mqtt.client.INITIAL_SUBSCRIBE_COOLDOWN", 0.0)
|
||||
@patch("homeassistant.components.mqtt.client.DISCOVERY_COOLDOWN", 0.0)
|
||||
|
@ -1559,10 +1588,17 @@ async def test_no_birth_message(
|
|||
record_calls: MessageCallbackType,
|
||||
mock_debouncer: asyncio.Event,
|
||||
mqtt_config_entry_data: dict[str, Any],
|
||||
mqtt_config_entry_options: dict[str, Any],
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
) -> None:
|
||||
"""Test disabling birth message."""
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data=mqtt_config_entry_data)
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data=mqtt_config_entry_data,
|
||||
options=mqtt_config_entry_options,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
hass.config.components.add(mqtt.DOMAIN)
|
||||
mock_debouncer.clear()
|
||||
|
@ -1582,20 +1618,27 @@ async def test_no_birth_message(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
[ENTRY_DEFAULT_BIRTH_MESSAGE],
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[({mqtt.CONF_BROKER: "mock-broker"}, ENTRY_DEFAULT_BIRTH_MESSAGE)],
|
||||
)
|
||||
@patch("homeassistant.components.mqtt.client.DISCOVERY_COOLDOWN", 0.2)
|
||||
async def test_delayed_birth_message(
|
||||
hass: HomeAssistant,
|
||||
mqtt_config_entry_data: dict[str, Any],
|
||||
mqtt_config_entry_options: dict[str, Any],
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
) -> None:
|
||||
"""Test sending birth message does not happen until Home Assistant starts."""
|
||||
hass.set_state(CoreState.starting)
|
||||
await hass.async_block_till_done()
|
||||
birth = asyncio.Event()
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data=mqtt_config_entry_data)
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data=mqtt_config_entry_data,
|
||||
options=mqtt_config_entry_options,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
hass.config.components.add(mqtt.DOMAIN)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
@ -1619,7 +1662,7 @@ async def test_delayed_birth_message(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
"mqtt_config_entry_options",
|
||||
[ENTRY_DEFAULT_BIRTH_MESSAGE],
|
||||
)
|
||||
async def test_subscription_done_when_birth_message_is_sent(
|
||||
|
@ -1637,26 +1680,37 @@ async def test_subscription_done_when_birth_message_is_sent(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
mqtt.CONF_WILL_MESSAGE: {
|
||||
mqtt.ATTR_TOPIC: "death",
|
||||
mqtt.ATTR_PAYLOAD: "death",
|
||||
mqtt.ATTR_QOS: 0,
|
||||
mqtt.ATTR_RETAIN: False,
|
||||
(
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
},
|
||||
}
|
||||
{
|
||||
mqtt.CONF_WILL_MESSAGE: {
|
||||
mqtt.ATTR_TOPIC: "death",
|
||||
mqtt.ATTR_PAYLOAD: "death",
|
||||
mqtt.ATTR_QOS: 0,
|
||||
mqtt.ATTR_RETAIN: False,
|
||||
},
|
||||
},
|
||||
)
|
||||
],
|
||||
)
|
||||
async def test_custom_will_message(
|
||||
hass: HomeAssistant,
|
||||
mqtt_config_entry_data: dict[str, Any],
|
||||
mqtt_config_entry_options: dict[str, Any],
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
) -> None:
|
||||
"""Test will message."""
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data=mqtt_config_entry_data)
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data=mqtt_config_entry_data,
|
||||
options=mqtt_config_entry_options,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
hass.config.components.add(mqtt.DOMAIN)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
@ -1678,16 +1732,23 @@ async def test_default_will_message(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_WILL_MESSAGE: {}}],
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[({mqtt.CONF_BROKER: "mock-broker"}, {mqtt.CONF_WILL_MESSAGE: {}})],
|
||||
)
|
||||
async def test_no_will_message(
|
||||
hass: HomeAssistant,
|
||||
mqtt_config_entry_data: dict[str, Any],
|
||||
mqtt_config_entry_options: dict[str, Any],
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
) -> None:
|
||||
"""Test will message."""
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data=mqtt_config_entry_data)
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data=mqtt_config_entry_data,
|
||||
options=mqtt_config_entry_options,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
hass.config.components.add(mqtt.DOMAIN)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
@ -1697,7 +1758,7 @@ async def test_no_will_message(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
"mqtt_config_entry_options",
|
||||
[ENTRY_DEFAULT_BIRTH_MESSAGE | {mqtt.CONF_DISCOVERY: False}],
|
||||
)
|
||||
async def test_mqtt_subscribes_topics_on_connect(
|
||||
|
@ -1730,7 +1791,7 @@ async def test_mqtt_subscribes_topics_on_connect(
|
|||
assert ("still/pending", 1) in subscribe_calls
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mqtt_config_entry_data", [ENTRY_DEFAULT_BIRTH_MESSAGE])
|
||||
@pytest.mark.parametrize("mqtt_config_entry_options", [ENTRY_DEFAULT_BIRTH_MESSAGE])
|
||||
async def test_mqtt_subscribes_wildcard_topics_in_correct_order(
|
||||
hass: HomeAssistant,
|
||||
mock_debouncer: asyncio.Event,
|
||||
|
@ -1789,7 +1850,7 @@ async def test_mqtt_subscribes_wildcard_topics_in_correct_order(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
"mqtt_config_entry_options",
|
||||
[ENTRY_DEFAULT_BIRTH_MESSAGE | {mqtt.CONF_DISCOVERY: False}],
|
||||
)
|
||||
async def test_mqtt_discovery_not_subscribes_when_disabled(
|
||||
|
@ -1822,7 +1883,7 @@ async def test_mqtt_discovery_not_subscribes_when_disabled(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
"mqtt_config_entry_options",
|
||||
[ENTRY_DEFAULT_BIRTH_MESSAGE],
|
||||
)
|
||||
async def test_mqtt_subscribes_in_single_call(
|
||||
|
@ -1848,7 +1909,7 @@ async def test_mqtt_subscribes_in_single_call(
|
|||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mqtt_config_entry_data", [ENTRY_DEFAULT_BIRTH_MESSAGE])
|
||||
@pytest.mark.parametrize("mqtt_config_entry_options", [ENTRY_DEFAULT_BIRTH_MESSAGE])
|
||||
@patch("homeassistant.components.mqtt.client.MAX_SUBSCRIBES_PER_CALL", 2)
|
||||
@patch("homeassistant.components.mqtt.client.MAX_UNSUBSCRIBES_PER_CALL", 2)
|
||||
async def test_mqtt_subscribes_and_unsubscribes_in_chunks(
|
||||
|
|
|
@ -1887,7 +1887,12 @@ async def help_test_reloadable(
|
|||
mqtt.DOMAIN: {domain: [old_config_1, old_config_2]},
|
||||
}
|
||||
# Start the MQTT entry with the old config
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "test-broker"},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
mqtt_client_mock.connect.return_value = 0
|
||||
with patch("homeassistant.config.load_yaml_config_file", return_value=old_config):
|
||||
|
|
|
@ -43,6 +43,28 @@ ADD_ON_DISCOVERY_INFO = {
|
|||
MOCK_CLIENT_CERT = b"## mock client certificate file ##"
|
||||
MOCK_CLIENT_KEY = b"## mock key file ##"
|
||||
|
||||
MOCK_ENTRY_DATA = {
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
CONF_PORT: 1234,
|
||||
CONF_USERNAME: "user",
|
||||
CONF_PASSWORD: "pass",
|
||||
}
|
||||
MOCK_ENTRY_OPTIONS = {
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
mqtt.CONF_BIRTH_MESSAGE: {
|
||||
mqtt.ATTR_TOPIC: "ha_state/online",
|
||||
mqtt.ATTR_PAYLOAD: "online",
|
||||
mqtt.ATTR_QOS: 1,
|
||||
mqtt.ATTR_RETAIN: True,
|
||||
},
|
||||
mqtt.CONF_WILL_MESSAGE: {
|
||||
mqtt.ATTR_TOPIC: "ha_state/offline",
|
||||
mqtt.ATTR_PAYLOAD: "offline",
|
||||
mqtt.ATTR_QOS: 2,
|
||||
mqtt.ATTR_RETAIN: False,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_finish_setup() -> Generator[MagicMock]:
|
||||
|
@ -243,8 +265,10 @@ async def test_user_connection_works(
|
|||
assert result["result"].data == {
|
||||
"broker": "127.0.0.1",
|
||||
"port": 1883,
|
||||
"discovery": True,
|
||||
}
|
||||
# Check we have the latest Config Entry version
|
||||
assert result["result"].version == 1
|
||||
assert result["result"].minor_version == 2
|
||||
# Check we tried the connection
|
||||
assert len(mock_try_connection.mock_calls) == 1
|
||||
# Check config entry got setup
|
||||
|
@ -283,7 +307,6 @@ async def test_user_connection_works_with_supervisor(
|
|||
assert result["result"].data == {
|
||||
"broker": "127.0.0.1",
|
||||
"port": 1883,
|
||||
"discovery": True,
|
||||
}
|
||||
# Check we tried the connection
|
||||
assert len(mock_try_connection.mock_calls) == 1
|
||||
|
@ -324,7 +347,6 @@ async def test_user_v5_connection_works(
|
|||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["result"].data == {
|
||||
"broker": "another-broker",
|
||||
"discovery": True,
|
||||
"port": 2345,
|
||||
"protocol": "5",
|
||||
}
|
||||
|
@ -383,14 +405,12 @@ async def test_manual_config_set(
|
|||
assert result["result"].data == {
|
||||
"broker": "127.0.0.1",
|
||||
"port": 1883,
|
||||
"discovery": True,
|
||||
}
|
||||
# Check we tried the connection, with precedence for config entry settings
|
||||
mock_try_connection.assert_called_once_with(
|
||||
{
|
||||
"broker": "127.0.0.1",
|
||||
"port": 1883,
|
||||
"discovery": True,
|
||||
},
|
||||
)
|
||||
# Check config entry got setup
|
||||
|
@ -401,7 +421,11 @@ async def test_manual_config_set(
|
|||
|
||||
async def test_user_single_instance(hass: HomeAssistant) -> None:
|
||||
"""Test we only allow a single config flow."""
|
||||
MockConfigEntry(domain="mqtt").add_to_hass(hass)
|
||||
MockConfigEntry(
|
||||
domain="mqtt",
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
).add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"mqtt", context={"source": config_entries.SOURCE_USER}
|
||||
|
@ -412,7 +436,11 @@ async def test_user_single_instance(hass: HomeAssistant) -> None:
|
|||
|
||||
async def test_hassio_already_configured(hass: HomeAssistant) -> None:
|
||||
"""Test we only allow a single config flow."""
|
||||
MockConfigEntry(domain="mqtt").add_to_hass(hass)
|
||||
MockConfigEntry(
|
||||
domain="mqtt",
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
).add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"mqtt", context={"source": config_entries.SOURCE_HASSIO}
|
||||
|
@ -424,7 +452,10 @@ async def test_hassio_already_configured(hass: HomeAssistant) -> None:
|
|||
async def test_hassio_ignored(hass: HomeAssistant) -> None:
|
||||
"""Test we supervisor discovered instance can be ignored."""
|
||||
MockConfigEntry(
|
||||
domain=mqtt.DOMAIN, source=config_entries.SOURCE_IGNORE
|
||||
domain=mqtt.DOMAIN,
|
||||
source=config_entries.SOURCE_IGNORE,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
).add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -934,43 +965,19 @@ async def test_addon_not_installed_failures(
|
|||
async def test_option_flow(
|
||||
hass: HomeAssistant,
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
mock_try_connection: MagicMock,
|
||||
) -> None:
|
||||
"""Test config flow options."""
|
||||
with patch(
|
||||
"homeassistant.config.async_hass_config_yaml", AsyncMock(return_value={})
|
||||
) as yaml_mock:
|
||||
mqtt_mock = await mqtt_mock_entry()
|
||||
mock_try_connection.return_value = True
|
||||
await mqtt_mock_entry()
|
||||
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
data={
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
CONF_PORT: 1234,
|
||||
},
|
||||
)
|
||||
|
||||
mqtt_mock.async_connect.reset_mock()
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
CONF_PORT: 2345,
|
||||
CONF_USERNAME: "user",
|
||||
CONF_PASSWORD: "pass",
|
||||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "options"
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert mqtt_mock.async_connect.call_count == 0
|
||||
|
||||
yaml_mock.reset_mock()
|
||||
|
||||
|
@ -992,12 +999,10 @@ async def test_option_flow(
|
|||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["data"] == {}
|
||||
assert config_entry.data == {
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
CONF_PORT: 2345,
|
||||
CONF_USERNAME: "user",
|
||||
CONF_PASSWORD: "pass",
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
assert config_entry.data == {mqtt.CONF_BROKER: "mock-broker"}
|
||||
assert config_entry.options == {
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
mqtt.CONF_DISCOVERY_PREFIX: "homeassistant",
|
||||
mqtt.CONF_BIRTH_MESSAGE: {
|
||||
|
@ -1015,8 +1020,7 @@ async def test_option_flow(
|
|||
}
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.title == "another-broker"
|
||||
# assert that the entry was reloaded with the new config
|
||||
# assert that the entry was reloaded with the new config
|
||||
assert yaml_mock.await_count
|
||||
|
||||
|
||||
|
@ -1071,7 +1075,7 @@ async def test_bad_certificate(
|
|||
test_input.pop(mqtt.CONF_CLIENT_KEY)
|
||||
|
||||
mqtt_mock = await mqtt_mock_entry()
|
||||
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
# Add at least one advanced option to get the full form
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
|
@ -1088,11 +1092,11 @@ async def test_bad_certificate(
|
|||
|
||||
mqtt_mock.async_connect.reset_mock()
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
result = await config_entry.start_reconfigure_flow(hass, show_advanced_options=True)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
|
@ -1109,14 +1113,14 @@ async def test_bad_certificate(
|
|||
test_input["set_ca_cert"] = set_ca_cert
|
||||
test_input["tls_insecure"] = tls_insecure
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=test_input,
|
||||
)
|
||||
if test_error is not None:
|
||||
assert result["errors"]["base"] == test_error
|
||||
return
|
||||
assert result["errors"] == {}
|
||||
assert "errors" not in result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -1148,7 +1152,7 @@ async def test_keepalive_validation(
|
|||
|
||||
mqtt_mock = await mqtt_mock_entry()
|
||||
mock_try_connection.return_value = True
|
||||
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
# Add at least one advanced option to get the full form
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
|
@ -1161,22 +1165,23 @@ async def test_keepalive_validation(
|
|||
|
||||
mqtt_mock.async_connect.reset_mock()
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
result = await config_entry.start_reconfigure_flow(hass, show_advanced_options=True)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
|
||||
if error:
|
||||
with pytest.raises(vol.Invalid):
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=test_input,
|
||||
)
|
||||
return
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=test_input,
|
||||
)
|
||||
assert not result["errors"]
|
||||
assert "errors" not in result
|
||||
assert result["reason"] == "reconfigure_successful"
|
||||
|
||||
|
||||
async def test_disable_birth_will(
|
||||
|
@ -1186,7 +1191,7 @@ async def test_disable_birth_will(
|
|||
mock_reload_after_entry_update: MagicMock,
|
||||
) -> None:
|
||||
"""Test disabling birth and will."""
|
||||
mqtt_mock = await mqtt_mock_entry()
|
||||
await mqtt_mock_entry()
|
||||
mock_try_connection.return_value = True
|
||||
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
hass.config_entries.async_update_entry(
|
||||
|
@ -1199,26 +1204,10 @@ async def test_disable_birth_will(
|
|||
await hass.async_block_till_done()
|
||||
mock_reload_after_entry_update.reset_mock()
|
||||
|
||||
mqtt_mock.async_connect.reset_mock()
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
CONF_PORT: 2345,
|
||||
CONF_USERNAME: "user",
|
||||
CONF_PASSWORD: "pass",
|
||||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "options"
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert mqtt_mock.async_connect.call_count == 0
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
|
@ -1238,12 +1227,14 @@ async def test_disable_birth_will(
|
|||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["data"] == {}
|
||||
assert config_entry.data == {
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
CONF_PORT: 2345,
|
||||
CONF_USERNAME: "user",
|
||||
CONF_PASSWORD: "pass",
|
||||
assert result["data"] == {
|
||||
"birth_message": {},
|
||||
"discovery": True,
|
||||
"discovery_prefix": "homeassistant",
|
||||
"will_message": {},
|
||||
}
|
||||
assert config_entry.data == {mqtt.CONF_BROKER: "test-broker", CONF_PORT: 1234}
|
||||
assert config_entry.options == {
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
mqtt.CONF_DISCOVERY_PREFIX: "homeassistant",
|
||||
mqtt.CONF_BIRTH_MESSAGE: {},
|
||||
|
@ -1270,6 +1261,8 @@ async def test_invalid_discovery_prefix(
|
|||
data={
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
CONF_PORT: 1234,
|
||||
},
|
||||
options={
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
mqtt.CONF_DISCOVERY_PREFIX: "homeassistant",
|
||||
},
|
||||
|
@ -1280,16 +1273,6 @@ async def test_invalid_discovery_prefix(
|
|||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
CONF_PORT: 2345,
|
||||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "options"
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
@ -1308,6 +1291,8 @@ async def test_invalid_discovery_prefix(
|
|||
assert config_entry.data == {
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
CONF_PORT: 1234,
|
||||
}
|
||||
assert config_entry.options == {
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
mqtt.CONF_DISCOVERY_PREFIX: "homeassistant",
|
||||
}
|
||||
|
@ -1356,6 +1341,8 @@ async def test_option_flow_default_suggested_values(
|
|||
CONF_PORT: 1234,
|
||||
CONF_USERNAME: "user",
|
||||
CONF_PASSWORD: "pass",
|
||||
},
|
||||
options={
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
mqtt.CONF_BIRTH_MESSAGE: {
|
||||
mqtt.ATTR_TOPIC: "ha_state/online",
|
||||
|
@ -1371,37 +1358,13 @@ async def test_option_flow_default_suggested_values(
|
|||
},
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Test default/suggested values from config
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
defaults = {
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
CONF_PORT: 1234,
|
||||
}
|
||||
suggested = {
|
||||
CONF_USERNAME: "user",
|
||||
CONF_PASSWORD: PWD_NOT_CHANGED,
|
||||
}
|
||||
for key, value in defaults.items():
|
||||
assert get_default(result["data_schema"].schema, key) == value
|
||||
for key, value in suggested.items():
|
||||
assert get_suggested(result["data_schema"].schema, key) == value
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
CONF_PORT: 2345,
|
||||
CONF_USERNAME: "us3r",
|
||||
CONF_PASSWORD: "p4ss",
|
||||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "options"
|
||||
defaults = {
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
"birth_qos": 1,
|
||||
"birth_retain": True,
|
||||
"will_qos": 2,
|
||||
|
@ -1421,7 +1384,6 @@ async def test_option_flow_default_suggested_values(
|
|||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_DISCOVERY: False,
|
||||
"birth_topic": "ha_state/onl1ne",
|
||||
"birth_payload": "onl1ne",
|
||||
"birth_qos": 2,
|
||||
|
@ -1437,28 +1399,8 @@ async def test_option_flow_default_suggested_values(
|
|||
# Test updated default/suggested values from config
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
defaults = {
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
CONF_PORT: 2345,
|
||||
}
|
||||
suggested = {
|
||||
CONF_USERNAME: "us3r",
|
||||
CONF_PASSWORD: PWD_NOT_CHANGED,
|
||||
}
|
||||
for key, value in defaults.items():
|
||||
assert get_default(result["data_schema"].schema, key) == value
|
||||
for key, value in suggested.items():
|
||||
assert get_suggested(result["data_schema"].schema, key) == value
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={mqtt.CONF_BROKER: "another-broker", CONF_PORT: 2345},
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "options"
|
||||
defaults = {
|
||||
mqtt.CONF_DISCOVERY: False,
|
||||
"birth_qos": 2,
|
||||
"birth_retain": False,
|
||||
"will_qos": 1,
|
||||
|
@ -1478,7 +1420,6 @@ async def test_option_flow_default_suggested_values(
|
|||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
"birth_topic": "ha_state/onl1ne",
|
||||
"birth_payload": "onl1ne",
|
||||
"birth_qos": 2,
|
||||
|
@ -1496,7 +1437,8 @@ async def test_option_flow_default_suggested_values(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("advanced_options", "step_id"), [(False, "options"), (True, "broker")]
|
||||
("advanced_options", "flow_result"),
|
||||
[(False, FlowResultType.ABORT), (True, FlowResultType.FORM)],
|
||||
)
|
||||
@pytest.mark.usefixtures("mock_reload_after_entry_update")
|
||||
async def test_skipping_advanced_options(
|
||||
|
@ -1504,41 +1446,35 @@ async def test_skipping_advanced_options(
|
|||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
mock_try_connection: MagicMock,
|
||||
advanced_options: bool,
|
||||
step_id: str,
|
||||
flow_result: FlowResultType,
|
||||
) -> None:
|
||||
"""Test advanced options option."""
|
||||
|
||||
test_input = {
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
CONF_PORT: 2345,
|
||||
"advanced_options": advanced_options,
|
||||
}
|
||||
if advanced_options:
|
||||
test_input["advanced_options"] = True
|
||||
|
||||
mqtt_mock = await mqtt_mock_entry()
|
||||
mock_try_connection.return_value = True
|
||||
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
# Initiate with a basic setup
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
data={
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
CONF_PORT: 1234,
|
||||
},
|
||||
)
|
||||
|
||||
config_entry: MockConfigEntry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
mqtt_mock.async_connect.reset_mock()
|
||||
|
||||
result = await hass.config_entries.options.async_init(
|
||||
config_entry.entry_id, context={"show_advanced_options": True}
|
||||
result = await config_entry.start_reconfigure_flow(
|
||||
hass, show_advanced_options=advanced_options
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
assert ("advanced_options" in result["data_schema"].schema) == advanced_options
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=test_input,
|
||||
)
|
||||
assert result["step_id"] == step_id
|
||||
assert result["type"] is flow_result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -1582,7 +1518,12 @@ async def test_step_reauth(
|
|||
"""Test that the reauth step works."""
|
||||
|
||||
# Prepare the config entry
|
||||
config_entry = MockConfigEntry(domain=mqtt.DOMAIN, data=test_input)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data=test_input,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
|
@ -1658,7 +1599,12 @@ async def test_step_hassio_reauth(
|
|||
addon_info["hostname"] = "core-mosquitto"
|
||||
|
||||
# Prepare the config entry
|
||||
config_entry = MockConfigEntry(domain=mqtt.DOMAIN, data=entry_data)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data=entry_data,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
|
@ -1740,7 +1686,12 @@ async def test_step_hassio_reauth_no_discovery_info(
|
|||
addon_info["hostname"] = "core-mosquitto"
|
||||
|
||||
# Prepare the config entry
|
||||
config_entry = MockConfigEntry(domain=mqtt.DOMAIN, data=entry_data)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data=entry_data,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
|
@ -1762,11 +1713,15 @@ async def test_step_hassio_reauth_no_discovery_info(
|
|||
mock_try_connection.assert_not_called()
|
||||
|
||||
|
||||
async def test_options_user_connection_fails(
|
||||
async def test_reconfigure_user_connection_fails(
|
||||
hass: HomeAssistant, mock_try_connection_time_out: MagicMock
|
||||
) -> None:
|
||||
"""Test if connection cannot be made."""
|
||||
config_entry = MockConfigEntry(domain=mqtt.DOMAIN)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
|
@ -1775,11 +1730,11 @@ async def test_options_user_connection_fails(
|
|||
CONF_PORT: 1234,
|
||||
},
|
||||
)
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
result = await config_entry.start_reconfigure_flow(hass, show_advanced_options=True)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
|
||||
mock_try_connection_time_out.reset_mock()
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={mqtt.CONF_BROKER: "bad-broker", CONF_PORT: 2345},
|
||||
)
|
||||
|
@ -1800,7 +1755,11 @@ async def test_options_bad_birth_message_fails(
|
|||
hass: HomeAssistant, mock_try_connection: MqttMockPahoClient
|
||||
) -> None:
|
||||
"""Test bad birth message."""
|
||||
config_entry = MockConfigEntry(domain=mqtt.DOMAIN)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
|
@ -1813,13 +1772,6 @@ async def test_options_bad_birth_message_fails(
|
|||
mock_try_connection.return_value = True
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={mqtt.CONF_BROKER: "another-broker", CONF_PORT: 2345},
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "options"
|
||||
|
||||
|
@ -1841,7 +1793,11 @@ async def test_options_bad_will_message_fails(
|
|||
hass: HomeAssistant, mock_try_connection: MagicMock
|
||||
) -> None:
|
||||
"""Test bad will message."""
|
||||
config_entry = MockConfigEntry(domain=mqtt.DOMAIN)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
|
@ -1854,13 +1810,6 @@ async def test_options_bad_will_message_fails(
|
|||
mock_try_connection.return_value = True
|
||||
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={mqtt.CONF_BROKER: "another-broker", CONF_PORT: 2345},
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "options"
|
||||
|
||||
|
@ -1878,15 +1827,16 @@ async def test_options_bad_will_message_fails(
|
|||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"hass_config", [{"mqtt": {"sensor": [{"state_topic": "some-topic"}]}}]
|
||||
)
|
||||
@pytest.mark.usefixtures("mock_ssl_context", "mock_process_uploaded_file")
|
||||
async def test_try_connection_with_advanced_parameters(
|
||||
hass: HomeAssistant, mock_try_connection_success: MqttMockPahoClient
|
||||
) -> None:
|
||||
"""Test config flow with advanced parameters from config."""
|
||||
config_entry = MockConfigEntry(domain=mqtt.DOMAIN)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
|
@ -1920,7 +1870,7 @@ async def test_try_connection_with_advanced_parameters(
|
|||
)
|
||||
|
||||
# Test default/suggested values from config
|
||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||
result = await config_entry.start_reconfigure_flow(hass, show_advanced_options=True)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
defaults = {
|
||||
|
@ -1944,9 +1894,8 @@ async def test_try_connection_with_advanced_parameters(
|
|||
assert get_suggested(result["data_schema"].schema, k) == v
|
||||
|
||||
# test we can change username and password
|
||||
# as it was configured as auto in configuration.yaml is is migrated now
|
||||
mock_try_connection_success.reset_mock()
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "another-broker",
|
||||
|
@ -1961,9 +1910,8 @@ async def test_try_connection_with_advanced_parameters(
|
|||
mqtt.CONF_WS_HEADERS: '{"h3": "v3"}',
|
||||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["errors"] == {}
|
||||
assert result["step_id"] == "options"
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "reconfigure_successful"
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# check if the username and password was set from config flow and not from configuration.yaml
|
||||
|
@ -1987,12 +1935,6 @@ async def test_try_connection_with_advanced_parameters(
|
|||
"/new/path",
|
||||
{"h3": "v3"},
|
||||
)
|
||||
# Accept default option
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={},
|
||||
)
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
|
@ -2005,7 +1947,11 @@ async def test_setup_with_advanced_settings(
|
|||
"""Test config flow setup with advanced parameters."""
|
||||
file_id = mock_process_uploaded_file.file_id
|
||||
|
||||
config_entry = MockConfigEntry(domain=mqtt.DOMAIN)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
|
@ -2017,15 +1963,13 @@ async def test_setup_with_advanced_settings(
|
|||
|
||||
mock_try_connection.return_value = True
|
||||
|
||||
result = await hass.config_entries.options.async_init(
|
||||
config_entry.entry_id, context={"show_advanced_options": True}
|
||||
)
|
||||
result = await config_entry.start_reconfigure_flow(hass, show_advanced_options=True)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "broker"
|
||||
assert result["data_schema"].schema["advanced_options"]
|
||||
|
||||
# first iteration, basic settings
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
|
@ -2049,7 +1993,7 @@ async def test_setup_with_advanced_settings(
|
|||
assert mqtt.CONF_CLIENT_KEY not in result["data_schema"].schema
|
||||
|
||||
# second iteration, advanced settings with request for client cert
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
|
@ -2080,7 +2024,7 @@ async def test_setup_with_advanced_settings(
|
|||
assert result["data_schema"].schema[mqtt.CONF_WS_HEADERS]
|
||||
|
||||
# third iteration, advanced settings with client cert and key set and bad json payload
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
|
@ -2105,7 +2049,7 @@ async def test_setup_with_advanced_settings(
|
|||
|
||||
# fourth iteration, advanced settings with client cert and key set
|
||||
# and correct json payload for ws_headers
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_BROKER: "test-broker",
|
||||
|
@ -2124,17 +2068,8 @@ async def test_setup_with_advanced_settings(
|
|||
},
|
||||
)
|
||||
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "options"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
mqtt.CONF_DISCOVERY_PREFIX: "homeassistant_test",
|
||||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "reconfigure_successful"
|
||||
|
||||
# Check config entry result
|
||||
assert config_entry.data == {
|
||||
|
@ -2153,8 +2088,6 @@ async def test_setup_with_advanced_settings(
|
|||
"header_2": "content_header_2",
|
||||
},
|
||||
mqtt.CONF_CERTIFICATE: "auto",
|
||||
mqtt.CONF_DISCOVERY: True,
|
||||
mqtt.CONF_DISCOVERY_PREFIX: "homeassistant_test",
|
||||
}
|
||||
|
||||
|
||||
|
@ -2163,7 +2096,11 @@ async def test_change_websockets_transport_to_tcp(
|
|||
hass: HomeAssistant, mock_try_connection: MagicMock
|
||||
) -> None:
|
||||
"""Test reconfiguration flow changing websockets transport settings."""
|
||||
config_entry = MockConfigEntry(domain=mqtt.DOMAIN)
|
||||
config_entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
|
@ -2254,3 +2191,95 @@ async def test_reconfigure_flow_form(
|
|||
mqtt.CONF_WS_PATH: "/some_new_path",
|
||||
}
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
(
|
||||
"version",
|
||||
"minor_version",
|
||||
"data",
|
||||
"options",
|
||||
"expected_version",
|
||||
"expected_minor_version",
|
||||
),
|
||||
[
|
||||
(1, 1, MOCK_ENTRY_DATA | MOCK_ENTRY_OPTIONS, {}, 1, 2),
|
||||
(1, 2, MOCK_ENTRY_DATA, MOCK_ENTRY_OPTIONS, 1, 2),
|
||||
(1, 3, MOCK_ENTRY_DATA, MOCK_ENTRY_OPTIONS, 1, 3),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("mock_reload_after_entry_update")
|
||||
async def test_migrate_config_entry(
|
||||
hass: HomeAssistant,
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
version: int,
|
||||
minor_version: int,
|
||||
data: dict[str, Any],
|
||||
options: dict[str, Any],
|
||||
expected_version: int,
|
||||
expected_minor_version: int,
|
||||
) -> None:
|
||||
"""Test migrating a config entry."""
|
||||
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
# Mock to a migratable or compatbible config entry version
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
data=data,
|
||||
options=options,
|
||||
version=version,
|
||||
minor_version=minor_version,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
# Start MQTT
|
||||
await mqtt_mock_entry()
|
||||
await hass.async_block_till_done()
|
||||
assert (
|
||||
config_entry.data | config_entry.options == MOCK_ENTRY_DATA | MOCK_ENTRY_OPTIONS
|
||||
)
|
||||
assert config_entry.version == expected_version
|
||||
assert config_entry.minor_version == expected_minor_version
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
(
|
||||
"version",
|
||||
"minor_version",
|
||||
"data",
|
||||
"options",
|
||||
"expected_version",
|
||||
"expected_minor_version",
|
||||
),
|
||||
[
|
||||
(2, 1, MOCK_ENTRY_DATA, MOCK_ENTRY_OPTIONS, 2, 1),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("mock_reload_after_entry_update")
|
||||
async def test_migrate_of_incompatible_config_entry(
|
||||
hass: HomeAssistant,
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
version: int,
|
||||
minor_version: int,
|
||||
data: dict[str, Any],
|
||||
options: dict[str, Any],
|
||||
expected_version: int,
|
||||
expected_minor_version: int,
|
||||
) -> None:
|
||||
"""Test migrating a config entry."""
|
||||
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
# Mock an incompatible config entry version
|
||||
hass.config_entries.async_update_entry(
|
||||
config_entry,
|
||||
data=data,
|
||||
options=options,
|
||||
version=version,
|
||||
minor_version=minor_version,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.version == expected_version
|
||||
assert config_entry.minor_version == expected_minor_version
|
||||
|
||||
# Try to start MQTT with incompatible config entry
|
||||
with pytest.raises(AssertionError):
|
||||
await mqtt_mock_entry()
|
||||
|
||||
assert config_entry.state is config_entries.ConfigEntryState.MIGRATION_ERROR
|
||||
|
|
|
@ -17,10 +17,12 @@ from tests.components.diagnostics import (
|
|||
)
|
||||
from tests.typing import ClientSessionGenerator, MqttMockHAClientGenerator
|
||||
|
||||
default_config = {
|
||||
"birth_message": {},
|
||||
default_entry_data = {
|
||||
"broker": "mock-broker",
|
||||
}
|
||||
default_entry_options = {
|
||||
"birth_message": {},
|
||||
}
|
||||
|
||||
|
||||
async def test_entry_diagnostics(
|
||||
|
@ -38,7 +40,7 @@ async def test_entry_diagnostics(
|
|||
assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {
|
||||
"connected": True,
|
||||
"devices": [],
|
||||
"mqtt_config": default_config,
|
||||
"mqtt_config": {"data": default_entry_data, "options": default_entry_options},
|
||||
"mqtt_debug_info": {"entities": [], "triggers": []},
|
||||
}
|
||||
|
||||
|
@ -123,7 +125,7 @@ async def test_entry_diagnostics(
|
|||
assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {
|
||||
"connected": True,
|
||||
"devices": [expected_device],
|
||||
"mqtt_config": default_config,
|
||||
"mqtt_config": {"data": default_entry_data, "options": default_entry_options},
|
||||
"mqtt_debug_info": expected_debug_info,
|
||||
}
|
||||
|
||||
|
@ -132,20 +134,24 @@ async def test_entry_diagnostics(
|
|||
) == {
|
||||
"connected": True,
|
||||
"device": expected_device,
|
||||
"mqtt_config": default_config,
|
||||
"mqtt_config": {"data": default_entry_data, "options": default_entry_options},
|
||||
"mqtt_debug_info": expected_debug_info,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
mqtt.CONF_BIRTH_MESSAGE: {},
|
||||
CONF_PASSWORD: "hunter2",
|
||||
CONF_USERNAME: "my_user",
|
||||
}
|
||||
(
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
CONF_PASSWORD: "hunter2",
|
||||
CONF_USERNAME: "my_user",
|
||||
},
|
||||
{
|
||||
mqtt.CONF_BIRTH_MESSAGE: {},
|
||||
},
|
||||
)
|
||||
],
|
||||
)
|
||||
async def test_redact_diagnostics(
|
||||
|
@ -157,9 +163,12 @@ async def test_redact_diagnostics(
|
|||
) -> None:
|
||||
"""Test redacting diagnostics."""
|
||||
mqtt_mock = await mqtt_mock_entry()
|
||||
expected_config = dict(default_config)
|
||||
expected_config["password"] = "**REDACTED**"
|
||||
expected_config["username"] = "**REDACTED**"
|
||||
expected_config = {
|
||||
"data": dict(default_entry_data),
|
||||
"options": dict(default_entry_options),
|
||||
}
|
||||
expected_config["data"]["password"] = "**REDACTED**"
|
||||
expected_config["data"]["username"] = "**REDACTED**"
|
||||
|
||||
config_entry = hass.config_entries.async_entries(mqtt.DOMAIN)[0]
|
||||
mqtt_mock.connected = True
|
||||
|
|
|
@ -195,8 +195,8 @@ async def mock_mqtt_flow(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
[{mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_DISCOVERY: False}],
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[({mqtt.CONF_BROKER: "mock-broker"}, {mqtt.CONF_DISCOVERY: False})],
|
||||
)
|
||||
async def test_subscribing_config_topic(
|
||||
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
|
||||
|
@ -1946,7 +1946,12 @@ async def test_cleanup_device_multiple_config_entries(
|
|||
mqtt_mock = await mqtt_mock_entry()
|
||||
ws_client = await hass_ws_client(hass)
|
||||
|
||||
config_entry = MockConfigEntry(domain="test", data={})
|
||||
config_entry = MockConfigEntry(
|
||||
domain="test",
|
||||
data={},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
|
@ -2042,7 +2047,12 @@ async def test_cleanup_device_multiple_config_entries_mqtt(
|
|||
) -> None:
|
||||
"""Test discovered device is cleaned up when removed through MQTT."""
|
||||
mqtt_mock = await mqtt_mock_entry()
|
||||
config_entry = MockConfigEntry(domain="test", data={})
|
||||
config_entry = MockConfigEntry(
|
||||
domain="test",
|
||||
data={},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
device_entry = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
|
@ -2437,12 +2447,14 @@ async def test_no_implicit_state_topic_switch(
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config_entry_data",
|
||||
("mqtt_config_entry_data", "mqtt_config_entry_options"),
|
||||
[
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
mqtt.CONF_DISCOVERY_PREFIX: "my_home/homeassistant/register",
|
||||
}
|
||||
(
|
||||
{mqtt.CONF_BROKER: "mock-broker"},
|
||||
{
|
||||
mqtt.CONF_DISCOVERY_PREFIX: "my_home/homeassistant/register",
|
||||
},
|
||||
)
|
||||
],
|
||||
)
|
||||
async def test_complex_discovery_topic_prefix(
|
||||
|
@ -2497,7 +2509,13 @@ async def test_mqtt_integration_discovery_flow_fitering_on_redundant_payload(
|
|||
"""Handle birth message."""
|
||||
birth.set()
|
||||
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data=ENTRY_DEFAULT_BIRTH_MESSAGE)
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "mock-broker"},
|
||||
options=ENTRY_DEFAULT_BIRTH_MESSAGE,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
with (
|
||||
patch(
|
||||
|
@ -2562,7 +2580,13 @@ async def test_mqtt_discovery_flow_starts_once(
|
|||
"""Handle birth message."""
|
||||
birth.set()
|
||||
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data=ENTRY_DEFAULT_BIRTH_MESSAGE)
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "mock-broker"},
|
||||
options=ENTRY_DEFAULT_BIRTH_MESSAGE,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with (
|
||||
|
|
|
@ -695,7 +695,12 @@ async def test_reload_entry_with_restored_subscriptions(
|
|||
) -> None:
|
||||
"""Test reloading the config entry with with subscriptions restored."""
|
||||
# Setup the MQTT entry
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "test-broker"})
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "test-broker"},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
hass.config.components.add(mqtt.DOMAIN)
|
||||
with patch("homeassistant.config.load_yaml_config_file", return_value={}):
|
||||
|
@ -800,7 +805,10 @@ async def test_default_entry_setting_are_applied(
|
|||
|
||||
# Config entry data is incomplete but valid according the schema
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN, data={"broker": "test-broker", "port": 1234}
|
||||
domain=mqtt.DOMAIN,
|
||||
data={"broker": "test-broker", "port": 1234},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
hass.config.components.add(mqtt.DOMAIN)
|
||||
|
@ -1614,6 +1622,8 @@ async def test_unload_config_entry(
|
|||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "test-broker"},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
|
|
|
@ -313,7 +313,12 @@ async def test_default_entity_and_device_name(
|
|||
hass.set_state(CoreState.starting)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={mqtt.CONF_BROKER: "mock-broker"})
|
||||
entry = MockConfigEntry(
|
||||
domain=mqtt.DOMAIN,
|
||||
data={mqtt.CONF_BROKER: "mock-broker"},
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
|
|
|
@ -231,6 +231,8 @@ async def test_waiting_for_client_not_loaded(
|
|||
domain=mqtt.DOMAIN,
|
||||
data={"broker": "test-broker"},
|
||||
state=ConfigEntryState.NOT_LOADED,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
|
@ -286,6 +288,8 @@ async def test_waiting_for_client_entry_fails(
|
|||
domain=mqtt.DOMAIN,
|
||||
data={"broker": "test-broker"},
|
||||
state=ConfigEntryState.NOT_LOADED,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
|
@ -314,6 +318,8 @@ async def test_waiting_for_client_setup_fails(
|
|||
domain=mqtt.DOMAIN,
|
||||
data={"broker": "test-broker"},
|
||||
state=ConfigEntryState.NOT_LOADED,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
|
@ -341,6 +347,8 @@ async def test_waiting_for_client_timeout(
|
|||
domain=mqtt.DOMAIN,
|
||||
data={"broker": "test-broker"},
|
||||
state=ConfigEntryState.NOT_LOADED,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
|
@ -360,6 +368,8 @@ async def test_waiting_for_client_with_disabled_entry(
|
|||
domain=mqtt.DOMAIN,
|
||||
data={"broker": "test-broker"},
|
||||
state=ConfigEntryState.NOT_LOADED,
|
||||
version=mqtt.CONFIG_ENTRY_VERSION,
|
||||
minor_version=mqtt.CONFIG_ENTRY_MINOR_VERSION,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
|
|
|
@ -924,7 +924,13 @@ def fail_on_log_exception(
|
|||
|
||||
@pytest.fixture
|
||||
def mqtt_config_entry_data() -> dict[str, Any] | None:
|
||||
"""Fixture to allow overriding MQTT config."""
|
||||
"""Fixture to allow overriding MQTT entry data."""
|
||||
return None
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mqtt_config_entry_options() -> dict[str, Any] | None:
|
||||
"""Fixture to allow overriding MQTT entry options."""
|
||||
return None
|
||||
|
||||
|
||||
|
@ -1001,6 +1007,7 @@ async def mqtt_mock(
|
|||
mock_hass_config: None,
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
mqtt_config_entry_data: dict[str, Any] | None,
|
||||
mqtt_config_entry_options: dict[str, Any] | None,
|
||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||
) -> AsyncGenerator[MqttMockHAClient]:
|
||||
"""Fixture to mock MQTT component."""
|
||||
|
@ -1012,6 +1019,7 @@ async def _mqtt_mock_entry(
|
|||
hass: HomeAssistant,
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
mqtt_config_entry_data: dict[str, Any] | None,
|
||||
mqtt_config_entry_options: dict[str, Any] | None,
|
||||
) -> AsyncGenerator[MqttMockHAClientGenerator]:
|
||||
"""Fixture to mock a delayed setup of the MQTT config entry."""
|
||||
# Local import to avoid processing MQTT modules when running a testcase
|
||||
|
@ -1019,17 +1027,19 @@ async def _mqtt_mock_entry(
|
|||
from homeassistant.components import mqtt # pylint: disable=import-outside-toplevel
|
||||
|
||||
if mqtt_config_entry_data is None:
|
||||
mqtt_config_entry_data = {
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
mqtt.CONF_BIRTH_MESSAGE: {},
|
||||
}
|
||||
mqtt_config_entry_data = {mqtt.CONF_BROKER: "mock-broker"}
|
||||
if mqtt_config_entry_options is None:
|
||||
mqtt_config_entry_options = {mqtt.CONF_BIRTH_MESSAGE: {}}
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entry = MockConfigEntry(
|
||||
data=mqtt_config_entry_data,
|
||||
options=mqtt_config_entry_options,
|
||||
domain=mqtt.DOMAIN,
|
||||
title="MQTT",
|
||||
version=1,
|
||||
minor_version=2,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
|
@ -1045,7 +1055,6 @@ async def _mqtt_mock_entry(
|
|||
|
||||
# Assert that MQTT is setup
|
||||
assert real_mqtt_instance is not None, "MQTT was not setup correctly"
|
||||
mock_mqtt_instance.conf = real_mqtt_instance.conf # For diagnostics
|
||||
mock_mqtt_instance._mqttc = mqtt_client_mock
|
||||
|
||||
# connected set to True to get a more realistic behavior when subscribing
|
||||
|
@ -1140,6 +1149,7 @@ async def mqtt_mock_entry(
|
|||
hass: HomeAssistant,
|
||||
mqtt_client_mock: MqttMockPahoClient,
|
||||
mqtt_config_entry_data: dict[str, Any] | None,
|
||||
mqtt_config_entry_options: dict[str, Any] | None,
|
||||
) -> AsyncGenerator[MqttMockHAClientGenerator]:
|
||||
"""Set up an MQTT config entry."""
|
||||
|
||||
|
@ -1156,7 +1166,7 @@ async def mqtt_mock_entry(
|
|||
return await mqtt_mock_entry(_async_setup_config_entry)
|
||||
|
||||
async with _mqtt_mock_entry(
|
||||
hass, mqtt_client_mock, mqtt_config_entry_data
|
||||
hass, mqtt_client_mock, mqtt_config_entry_data, mqtt_config_entry_options
|
||||
) as mqtt_mock_entry:
|
||||
yield _setup_mqtt_entry
|
||||
|
||||
|
|
Loading…
Reference in New Issue