Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MQTT based ecovacs vacuums #108167

Merged
merged 18 commits into from Jan 19, 2024
Merged
11 changes: 10 additions & 1 deletion tests/components/ecovacs/conftest.py
Expand Up @@ -34,17 +34,26 @@ def mock_config_entry() -> MockConfigEntry:


@pytest.fixture
def mock_authenticator() -> Mock:
def mock_authenticator() -> Generator[Mock, None, None]:
"""Mock the authenticator."""
mock_authenticator = Mock(spec_set=Authenticator)
mock_authenticator.authenticate.return_value = Credentials("token", "user_id", 0)
with patch(
"homeassistant.components.ecovacs.controller.Authenticator",
return_value=mock_authenticator,
), patch(
"homeassistant.components.ecovacs.config_flow.Authenticator",
return_value=mock_authenticator,
):
yield mock_authenticator


@pytest.fixture
def mock_authenticator_authenticate(mock_authenticator: Mock) -> AsyncMock:
"""Mock authenticator.authenticate."""
return mock_authenticator.authenticate


@pytest.fixture
def mock_api_client(mock_authenticator: Mock) -> Mock:
"""Mock the API client."""
Expand Down
40 changes: 15 additions & 25 deletions tests/components/ecovacs/test_config_flow.py
@@ -1,10 +1,8 @@
"""Test Ecovacs config flow."""
from collections.abc import Generator
from typing import Any
from unittest.mock import AsyncMock, Mock, patch
from unittest.mock import AsyncMock

from aiohttp import ClientError
from deebot_client.authentication import Authenticator
from deebot_client.exceptions import InvalidAuthenticationError
import pytest

Expand All @@ -20,16 +18,6 @@
from tests.common import MockConfigEntry


@pytest.fixture
def mock_authenticate() -> Generator[AsyncMock, None, None]:
"""Mock authenticator.authenticate."""
with patch(
"homeassistant.components.ecovacs.config_flow.Authenticator",
return_value=Mock(spec_set=Authenticator),
) as mock_authenticator:
yield mock_authenticator.return_value.authenticate


async def _test_user_flow(hass: HomeAssistant) -> dict[str, Any]:
"""Test config flow."""
result = await hass.config_entries.flow.async_init(
Expand All @@ -44,15 +32,17 @@ async def _test_user_flow(hass: HomeAssistant) -> dict[str, Any]:


async def test_user_flow(
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_authenticate: AsyncMock
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_authenticator_authenticate: AsyncMock,
) -> None:
"""Test the user config flow."""
result = await _test_user_flow(hass)
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == VALID_ENTRY_DATA[CONF_USERNAME]
assert result["data"] == VALID_ENTRY_DATA
mock_setup_entry.assert_called()
mock_authenticate.assert_called()
mock_authenticator_authenticate.assert_called()


@pytest.mark.parametrize(
Expand All @@ -68,20 +58,20 @@ async def test_user_flow_error(
side_effect: Exception,
reason: str,
mock_setup_entry: AsyncMock,
mock_authenticate: AsyncMock,
mock_authenticator_authenticate: AsyncMock,
) -> None:
"""Test handling invalid connection."""

mock_authenticate.side_effect = side_effect
mock_authenticator_authenticate.side_effect = side_effect

result = await _test_user_flow(hass)
assert result["type"] == FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {"base": reason}
mock_authenticate.assert_called()
mock_authenticator_authenticate.assert_called()
mock_setup_entry.assert_not_called()

mock_authenticate.reset_mock(side_effect=True)
mock_authenticator_authenticate.reset_mock(side_effect=True)
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=VALID_ENTRY_DATA,
Expand All @@ -90,22 +80,22 @@ async def test_user_flow_error(
assert result["title"] == VALID_ENTRY_DATA[CONF_USERNAME]
assert result["data"] == VALID_ENTRY_DATA
mock_setup_entry.assert_called()
mock_authenticate.assert_called()
mock_authenticator_authenticate.assert_called()


async def test_import_flow(
hass: HomeAssistant,
issue_registry: ir.IssueRegistry,
mock_setup_entry: AsyncMock,
mock_authenticate: AsyncMock,
mock_authenticator_authenticate: AsyncMock,
) -> None:
"""Test importing yaml config."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=IMPORT_DATA.copy(),
)
mock_authenticate.assert_called()
mock_authenticator_authenticate.assert_called()

assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == VALID_ENTRY_DATA[CONF_USERNAME]
Expand Down Expand Up @@ -144,10 +134,10 @@ async def test_import_flow_error(
side_effect: Exception,
reason: str,
issue_registry: ir.IssueRegistry,
mock_authenticate: AsyncMock,
mock_authenticator_authenticate: AsyncMock,
) -> None:
"""Test handling invalid connection."""
mock_authenticate.side_effect = side_effect
mock_authenticator_authenticate.side_effect = side_effect

result = await hass.config_entries.flow.async_init(
DOMAIN,
Expand All @@ -160,4 +150,4 @@ async def test_import_flow_error(
DOMAIN,
f"deprecated_yaml_import_issue_{reason}",
) in issue_registry.issues
mock_authenticate.assert_called()
mock_authenticator_authenticate.assert_called()
30 changes: 19 additions & 11 deletions tests/components/ecovacs/test_init.py
@@ -1,6 +1,6 @@
"""Test init of ecovacs."""
from typing import Any
from unittest.mock import Mock, patch
from unittest.mock import AsyncMock, Mock

from deebot_client.exceptions import DeebotError, InvalidAuthenticationError
import pytest
Expand Down Expand Up @@ -63,19 +63,27 @@ async def test_invalid_auth(


@pytest.mark.parametrize(
("config", "expect_call"),
("config", "config_entries_expected"),
[
({}, False),
({DOMAIN: IMPORT_DATA.copy()}, True),
({}, 0),
({DOMAIN: IMPORT_DATA.copy()}, 1),
],
)
async def test_async_setup_import(
hass: HomeAssistant, config: dict[str, Any], expect_call: bool
hass: HomeAssistant,
config: dict[str, Any],
config_entries_expected: int,
mock_setup_entry: AsyncMock,
mock_authenticator_authenticate: AsyncMock,
) -> None:
"""Test async_setup config import."""
with patch.object(hass.config_entries.flow, "async_init", autospec=True) as mock:
assert await async_setup_component(hass, DOMAIN, config)
if expect_call:
mock.assert_called_once()
else:
mock.assert_not_called()
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
assert await async_setup_component(hass, DOMAIN, config)
await hass.async_block_till_done()
assert len(hass.config_entries.async_entries(DOMAIN)) == config_entries_expected
if config_entries_expected:
mock_setup_entry.assert_called()
edenhaus marked this conversation as resolved.
Show resolved Hide resolved
mock_authenticator_authenticate.assert_called()
else:
mock_setup_entry.assert_not_called()
mock_authenticator_authenticate.assert_not_called()