Mullvad integration improvements (#46987)

This commit is contained in:
Franck Nijhof 2021-02-24 13:43:44 +01:00 committed by GitHub
parent b0d56970a5
commit 45b50c53ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 23 deletions

View File

@ -8,6 +8,7 @@ from mullvad_api import MullvadAPI
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import update_coordinator
from .const import DOMAIN
@ -17,7 +18,6 @@ PLATFORMS = ["binary_sensor"]
async def async_setup(hass: HomeAssistant, config: dict):
"""Set up the Mullvad VPN integration."""
return True
@ -29,14 +29,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: dict):
api = await hass.async_add_executor_job(MullvadAPI)
return api.data
hass.data[DOMAIN] = update_coordinator.DataUpdateCoordinator(
coordinator = update_coordinator.DataUpdateCoordinator(
hass,
logging.getLogger(__name__),
name=DOMAIN,
update_method=async_get_mullvad_api_data,
update_interval=timedelta(minutes=1),
)
await hass.data[DOMAIN].async_refresh()
await coordinator.async_refresh()
if not coordinator.last_update_success:
raise ConfigEntryNotReady
hass.data[DOMAIN] = coordinator
for component in PLATFORMS:
hass.async_create_task(

View File

@ -47,6 +47,6 @@ class MullvadBinarySensor(CoordinatorEntity, BinarySensorEntity):
return self._name
@property
def state(self):
def is_on(self):
"""Return the state for this binary sensor."""
return self.coordinator.data[self.id]

View File

@ -1,6 +1,8 @@
"""Config flow for Mullvad VPN integration."""
import logging
from mullvad_api import MullvadAPI, MullvadAPIError
from homeassistant import config_entries
from .const import DOMAIN # pylint:disable=unused-import
@ -19,7 +21,15 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
if self.hass.config_entries.async_entries(DOMAIN):
return self.async_abort(reason="already_configured")
errors = {}
if user_input is not None:
return self.async_create_entry(title="Mullvad VPN", data=user_input)
try:
await self.hass.async_add_executor_job(MullvadAPI)
except MullvadAPIError:
errors["base"] = "cannot_connect"
except Exception: # pylint: disable=broad-except
errors["base"] = "unknown"
else:
return self.async_create_entry(title="Mullvad VPN", data=user_input)
return self.async_show_form(step_id="user")
return self.async_show_form(step_id="user", errors=errors)

View File

@ -5,17 +5,11 @@
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"step": {
"user": {
"description": "Set up the Mullvad VPN integration?",
"data": {
"host": "[%key:common::config_flow::data::host%]",
"password": "[%key:common::config_flow::data::password%]",
"username": "[%key:common::config_flow::data::username%]"
}
"description": "Set up the Mullvad VPN integration?"
}
}
}

View File

@ -5,16 +5,10 @@
},
"error": {
"cannot_connect": "Failed to connect",
"invalid_auth": "Invalid authentication",
"unknown": "Unexpected error"
},
"step": {
"user": {
"data": {
"host": "Host",
"password": "Password",
"username": "Username"
},
"description": "Set up the Mullvad VPN integration?"
}
}

View File

@ -1,8 +1,11 @@
"""Test the Mullvad config flow."""
from unittest.mock import patch
from mullvad_api import MullvadAPIError
from homeassistant import config_entries, setup
from homeassistant.components.mullvad.const import DOMAIN
from homeassistant.data_entry_flow import RESULT_TYPE_ABORT, RESULT_TYPE_FORM
from tests.common import MockConfigEntry
@ -13,15 +16,17 @@ async def test_form_user(hass):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["errors"] is None
assert result["type"] == RESULT_TYPE_FORM
assert not result["errors"]
with patch(
"homeassistant.components.mullvad.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.mullvad.async_setup_entry",
return_value=True,
) as mock_setup_entry:
) as mock_setup_entry, patch(
"homeassistant.components.mullvad.config_flow.MullvadAPI"
) as mock_mullvad_api:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{},
@ -33,6 +38,7 @@ async def test_form_user(hass):
assert result2["data"] == {}
assert len(mock_setup.mock_calls) == 0
assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_mullvad_api.mock_calls) == 1
async def test_form_user_only_once(hass):
@ -42,5 +48,47 @@ async def test_form_user_only_once(hass):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "abort"
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
async def test_connection_error(hass):
"""Test we show an error when we have trouble connecting."""
await setup.async_setup_component(hass, DOMAIN, {})
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.mullvad.config_flow.MullvadAPI",
side_effect=MullvadAPIError,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{},
)
await hass.async_block_till_done()
assert result2["type"] == RESULT_TYPE_FORM
assert result2["errors"] == {"base": "cannot_connect"}
async def test_unknown_error(hass):
"""Test we show an error when an unknown error occurs."""
await setup.async_setup_component(hass, DOMAIN, {})
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
with patch(
"homeassistant.components.mullvad.config_flow.MullvadAPI",
side_effect=Exception,
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{},
)
await hass.async_block_till_done()
assert result2["type"] == RESULT_TYPE_FORM
assert result2["errors"] == {"base": "unknown"}