diff --git a/homeassistant/components/yardian/__init__.py b/homeassistant/components/yardian/__init__.py index 24df2a41ff73..96daa42561bb 100644 --- a/homeassistant/components/yardian/__init__.py +++ b/homeassistant/components/yardian/__init__.py @@ -21,7 +21,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: YardianConfigEntry) -> b host = entry.data[CONF_HOST] access_token = entry.data[CONF_ACCESS_TOKEN] - controller = AsyncYardianClient(async_get_clientsession(hass), host, access_token) + # Change this line to use .create() + # This ensures the coordinator's controller knows if it is YP or YC + controller = await AsyncYardianClient.create( + async_get_clientsession(hass), host, token=access_token + ) + coordinator = YardianUpdateCoordinator(hass, entry, controller) await coordinator.async_config_entry_first_refresh() diff --git a/homeassistant/components/yardian/config_flow.py b/homeassistant/components/yardian/config_flow.py index 632ebc52e8ea..b7863918346a 100644 --- a/homeassistant/components/yardian/config_flow.py +++ b/homeassistant/components/yardian/config_flow.py @@ -34,10 +34,10 @@ class YardianConfigFlow(ConfigFlow, domain=DOMAIN): async def async_fetch_device_info(self, host: str, access_token: str) -> DeviceInfo: """Fetch device info from Yardian.""" - yarcli = AsyncYardianClient( + yarcli = await AsyncYardianClient.create( async_get_clientsession(self.hass), host, - access_token, + token=access_token, ) return await yarcli.fetch_device_info() diff --git a/tests/components/yardian/conftest.py b/tests/components/yardian/conftest.py index 045ae9aca90f..ca80dc796cec 100644 --- a/tests/components/yardian/conftest.py +++ b/tests/components/yardian/conftest.py @@ -32,7 +32,7 @@ def mock_config_entry() -> MockConfigEntry: CONF_ACCESS_TOKEN: "abc", CONF_NAME: "Yardian", "yid": "yid123", - "model": "PRO1902", + "model": "PRO1902C1", "serialNumber": "SN1", }, title="Yardian Smart Sprinkler", @@ -48,12 +48,17 @@ def mock_yardian_client() -> Generator[AsyncMock]: ) as client_cls, patch( "homeassistant.components.yardian.config_flow.AsyncYardianClient", - autospec=True, - ) as flow_client_cls, + new=client_cls, + ), ): client = client_cls.return_value - flow_client_cls.return_value = client + client_cls.create.return_value = client + + client.fetch_device_info.return_value = { + "name": "fake_name", + "yid": "fake_yid", + } client.fetch_device_state.return_value = YardianDeviceState( zones=[["Zone 1", 1], ["Zone 2", 0]], active_zones={0}, diff --git a/tests/components/yardian/test_config_flow.py b/tests/components/yardian/test_config_flow.py index 1630286733f0..580a1d914295 100644 --- a/tests/components/yardian/test_config_flow.py +++ b/tests/components/yardian/test_config_flow.py @@ -1,189 +1,76 @@ """Test the Yardian config flow.""" -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock import pytest from pyyardian import NetworkException, NotAuthorizedException -from homeassistant import config_entries from homeassistant.components.yardian.const import DOMAIN, PRODUCT_NAME +from homeassistant.config_entries import SOURCE_USER from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType -pytestmark = pytest.mark.usefixtures("mock_setup_entry") +pytestmark = pytest.mark.usefixtures("mock_setup_entry", "mock_yardian_client") -async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None: +async def test_form(hass: HomeAssistant) -> None: """Test we get the form.""" result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.SOURCE_USER} + DOMAIN, context={"source": SOURCE_USER} ) assert result["type"] is FlowResultType.FORM - assert result["errors"] == {} - with patch( - "homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info", - return_value={"name": "fake_name", "yid": "fake_yid"}, - ): - result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - "host": "fake_host", - "access_token": "fake_token", - }, - ) - await hass.async_block_till_done() + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {"host": "fake_host", "access_token": "fake_token"}, + ) + await hass.async_block_till_done() - assert result2["type"] is FlowResultType.CREATE_ENTRY - assert result2["title"] == PRODUCT_NAME - assert result2["data"] == { + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == PRODUCT_NAME + assert result["data"] == { "host": "fake_host", "access_token": "fake_token", "name": "fake_name", "yid": "fake_yid", } - assert len(mock_setup_entry.mock_calls) == 1 -async def test_form_invalid_auth( - hass: HomeAssistant, mock_setup_entry: AsyncMock +@pytest.mark.parametrize( + ("exception", "error"), + [ + (NotAuthorizedException, "invalid_auth"), + (NetworkException, "cannot_connect"), + (Exception, "unknown"), + ], +) +async def test_form_errors( + hass: HomeAssistant, + mock_yardian_client: AsyncMock, + exception: Exception, + error: str, ) -> None: - """Test we handle invalid auth.""" + """Test we handle errors and recover.""" + mock_yardian_client.fetch_device_info.side_effect = exception + result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.SOURCE_USER} + DOMAIN, context={"source": SOURCE_USER} ) - with patch( - "homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info", - side_effect=NotAuthorizedException, - ): - result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - "host": "fake_host", - "access_token": "fake_token", - }, - ) - - assert result2["type"] is FlowResultType.FORM - assert result2["errors"] == {"base": "invalid_auth"} - - # Should be recoverable after hits error - with patch( - "homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info", - return_value={"name": "fake_name", "yid": "fake_yid"}, - ): - result3 = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - "host": "fake_host", - "access_token": "fake_token", - }, - ) - await hass.async_block_till_done() - - assert result3["type"] is FlowResultType.CREATE_ENTRY - assert result3["title"] == PRODUCT_NAME - assert result3["data"] == { - "host": "fake_host", - "access_token": "fake_token", - "name": "fake_name", - "yid": "fake_yid", - } - assert len(mock_setup_entry.mock_calls) == 1 - - -async def test_form_cannot_connect( - hass: HomeAssistant, mock_setup_entry: AsyncMock -) -> None: - """Test we handle cannot connect error.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.SOURCE_USER} + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {"host": "fake_host", "access_token": "fake_token"}, ) - with patch( - "homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info", - side_effect=NetworkException, - ): - result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - "host": "fake_host", - "access_token": "fake_token", - }, - ) + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": error} - assert result2["type"] is FlowResultType.FORM - assert result2["errors"] == {"base": "cannot_connect"} + mock_yardian_client.fetch_device_info.side_effect = None - # Should be recoverable after hits error - with patch( - "homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info", - return_value={"name": "fake_name", "yid": "fake_yid"}, - ): - result3 = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - "host": "fake_host", - "access_token": "fake_token", - }, - ) - await hass.async_block_till_done() - - assert result3["type"] is FlowResultType.CREATE_ENTRY - assert result3["title"] == PRODUCT_NAME - assert result3["data"] == { - "host": "fake_host", - "access_token": "fake_token", - "name": "fake_name", - "yid": "fake_yid", - } - assert len(mock_setup_entry.mock_calls) == 1 - - -async def test_form_uncategorized_error( - hass: HomeAssistant, mock_setup_entry: AsyncMock -) -> None: - """Test we handle uncategorized error.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.SOURCE_USER} + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {"host": "fake_host", "access_token": "fake_token"}, ) + await hass.async_block_till_done() - with patch( - "homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info", - side_effect=Exception, - ): - result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - "host": "fake_host", - "access_token": "fake_token", - }, - ) - - assert result2["type"] is FlowResultType.FORM - assert result2["errors"] == {"base": "unknown"} - - # Should be recoverable after hits error - with patch( - "homeassistant.components.yardian.config_flow.AsyncYardianClient.fetch_device_info", - return_value={"name": "fake_name", "yid": "fake_yid"}, - ): - result3 = await hass.config_entries.flow.async_configure( - result["flow_id"], - { - "host": "fake_host", - "access_token": "fake_token", - }, - ) - await hass.async_block_till_done() - - assert result3["type"] is FlowResultType.CREATE_ENTRY - assert result3["title"] == PRODUCT_NAME - assert result3["data"] == { - "host": "fake_host", - "access_token": "fake_token", - "name": "fake_name", - "yid": "fake_yid", - } - assert len(mock_setup_entry.mock_calls) == 1 + assert result["type"] is FlowResultType.CREATE_ENTRY