mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Renovate Airvisual tests (#84892)
* Renovate AirVisual tests * Cleanup * Package scope * Update tests/components/airvisual/test_config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
9c88dea584
commit
6e9d3bf8e9
@ -132,15 +132,14 @@ class AirVisualFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
LOGGER.error(err)
|
LOGGER.error(err)
|
||||||
errors["base"] = "unknown"
|
errors["base"] = "unknown"
|
||||||
|
|
||||||
valid_keys.add(user_input[CONF_API_KEY])
|
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id=error_step, data_schema=error_schema, errors=errors
|
step_id=error_step, data_schema=error_schema, errors=errors
|
||||||
)
|
)
|
||||||
|
|
||||||
existing_entry = await self.async_set_unique_id(self._geo_id)
|
valid_keys.add(user_input[CONF_API_KEY])
|
||||||
if existing_entry:
|
|
||||||
|
if existing_entry := await self.async_set_unique_id(self._geo_id):
|
||||||
self.hass.config_entries.async_update_entry(existing_entry, data=user_input)
|
self.hass.config_entries.async_update_entry(existing_entry, data=user_input)
|
||||||
self.hass.async_create_task(
|
self.hass.async_create_task(
|
||||||
self.hass.config_entries.async_reload(existing_entry.entry_id)
|
self.hass.config_entries.async_reload(existing_entry.entry_id)
|
||||||
|
@ -4,29 +4,64 @@ from unittest.mock import AsyncMock, Mock, patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.airvisual.const import (
|
from homeassistant.components.airvisual import (
|
||||||
|
CONF_CITY,
|
||||||
CONF_INTEGRATION_TYPE,
|
CONF_INTEGRATION_TYPE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.airvisual.config_flow import async_get_geography_id
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_API_KEY,
|
CONF_API_KEY,
|
||||||
|
CONF_COUNTRY,
|
||||||
CONF_LATITUDE,
|
CONF_LATITUDE,
|
||||||
CONF_LONGITUDE,
|
CONF_LONGITUDE,
|
||||||
CONF_SHOW_ON_MAP,
|
CONF_SHOW_ON_MAP,
|
||||||
|
CONF_STATE,
|
||||||
)
|
)
|
||||||
from homeassistant.setup import async_setup_component
|
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, load_fixture
|
from tests.common import MockConfigEntry, load_fixture
|
||||||
|
|
||||||
|
TEST_API_KEY = "abcde12345"
|
||||||
|
TEST_LATITUDE = 51.528308
|
||||||
|
TEST_LONGITUDE = -0.3817765
|
||||||
|
|
||||||
|
COORDS_CONFIG = {
|
||||||
|
CONF_API_KEY: TEST_API_KEY,
|
||||||
|
CONF_LATITUDE: TEST_LATITUDE,
|
||||||
|
CONF_LONGITUDE: TEST_LONGITUDE,
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CITY = "Beijing"
|
||||||
|
TEST_STATE = "Beijing"
|
||||||
|
TEST_COUNTRY = "China"
|
||||||
|
|
||||||
|
NAME_CONFIG = {
|
||||||
|
CONF_API_KEY: TEST_API_KEY,
|
||||||
|
CONF_CITY: TEST_CITY,
|
||||||
|
CONF_STATE: TEST_STATE,
|
||||||
|
CONF_COUNTRY: TEST_COUNTRY,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="cloud_api")
|
||||||
|
def cloud_api_fixture(data_cloud):
|
||||||
|
"""Define a mock CloudAPI object."""
|
||||||
|
return Mock(
|
||||||
|
air_quality=Mock(
|
||||||
|
city=AsyncMock(return_value=data_cloud),
|
||||||
|
nearest_city=AsyncMock(return_value=data_cloud),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="config_entry")
|
@pytest.fixture(name="config_entry")
|
||||||
def config_entry_fixture(hass, config, config_entry_version, unique_id):
|
def config_entry_fixture(hass, config, config_entry_version, integration_type):
|
||||||
"""Define a config entry fixture."""
|
"""Define a config entry fixture."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
unique_id=unique_id,
|
unique_id=async_get_geography_id(config),
|
||||||
data={CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY_COORDS, **config},
|
data={**config, CONF_INTEGRATION_TYPE: integration_type},
|
||||||
options={CONF_SHOW_ON_MAP: True},
|
options={CONF_SHOW_ON_MAP: True},
|
||||||
version=config_entry_version,
|
version=config_entry_version,
|
||||||
)
|
)
|
||||||
@ -41,49 +76,61 @@ def config_entry_version_fixture():
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="config")
|
@pytest.fixture(name="config")
|
||||||
def config_fixture(hass):
|
def config_fixture():
|
||||||
"""Define a config entry data fixture."""
|
"""Define a config entry data fixture."""
|
||||||
return {
|
return COORDS_CONFIG
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_LATITUDE: 51.528308,
|
|
||||||
CONF_LONGITUDE: -0.3817765,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="data", scope="package")
|
@pytest.fixture(name="data_cloud", scope="package")
|
||||||
def data_fixture():
|
def data_cloud_fixture():
|
||||||
"""Define an update coordinator data example."""
|
"""Define an update coordinator data example."""
|
||||||
return json.loads(load_fixture("data.json", "airvisual"))
|
return json.loads(load_fixture("data.json", "airvisual"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="pro_data", scope="session")
|
@pytest.fixture(name="data_pro", scope="package")
|
||||||
def pro_data_fixture():
|
def data_pro_fixture():
|
||||||
"""Define an update coordinator data example for the Pro."""
|
"""Define an update coordinator data example for the Pro."""
|
||||||
return json.loads(load_fixture("data.json", "airvisual_pro"))
|
return json.loads(load_fixture("data.json", "airvisual_pro"))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="pro")
|
@pytest.fixture(name="integration_type")
|
||||||
def pro_fixture(pro_data):
|
def integration_type_fixture():
|
||||||
"""Define a mocked NodeSamba object."""
|
"""Define an integration type."""
|
||||||
return Mock(
|
return INTEGRATION_TYPE_GEOGRAPHY_COORDS
|
||||||
async_connect=AsyncMock(),
|
|
||||||
async_disconnect=AsyncMock(),
|
|
||||||
async_get_latest_measurements=AsyncMock(return_value=pro_data),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="setup_airvisual")
|
@pytest.fixture(name="mock_pyairvisual")
|
||||||
async def setup_airvisual_fixture(hass, config, data):
|
async def mock_pyairvisual_fixture(cloud_api, node_samba):
|
||||||
"""Define a fixture to set up AirVisual."""
|
"""Define a fixture to patch pyairvisual."""
|
||||||
with patch("pyairvisual.air_quality.AirQuality.city"), patch(
|
with patch(
|
||||||
"pyairvisual.air_quality.AirQuality.nearest_city", return_value=data
|
"homeassistant.components.airvisual.CloudAPI",
|
||||||
|
return_value=cloud_api,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.airvisual.config_flow.CloudAPI",
|
||||||
|
return_value=cloud_api,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.airvisual_pro.NodeSamba",
|
||||||
|
return_value=node_samba,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.airvisual_pro.config_flow.NodeSamba",
|
||||||
|
return_value=node_samba,
|
||||||
):
|
):
|
||||||
assert await async_setup_component(hass, DOMAIN, config)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="unique_id")
|
@pytest.fixture(name="node_samba")
|
||||||
def unique_id_fixture(hass):
|
def node_samba_fixture(data_pro):
|
||||||
"""Define a config entry unique ID fixture."""
|
"""Define a mock NodeSamba object."""
|
||||||
return "51.528308, -0.3817765"
|
return Mock(
|
||||||
|
async_connect=AsyncMock(),
|
||||||
|
async_disconnect=AsyncMock(),
|
||||||
|
async_get_latest_measurements=AsyncMock(return_value=data_pro),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="setup_config_entry")
|
||||||
|
async def setup_config_entry_fixture(hass, config_entry, mock_pyairvisual):
|
||||||
|
"""Define a fixture to set up airvisual."""
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
yield
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
"""Define tests for the AirVisual config flow."""
|
"""Define tests for the AirVisual config flow."""
|
||||||
from unittest.mock import patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
from pyairvisual.cloud_api import (
|
from pyairvisual.cloud_api import (
|
||||||
InvalidKeyError,
|
InvalidKeyError,
|
||||||
@ -13,307 +13,101 @@ import pytest
|
|||||||
from homeassistant import data_entry_flow
|
from homeassistant import data_entry_flow
|
||||||
from homeassistant.components.airvisual import (
|
from homeassistant.components.airvisual import (
|
||||||
CONF_CITY,
|
CONF_CITY,
|
||||||
CONF_COUNTRY,
|
|
||||||
CONF_GEOGRAPHIES,
|
|
||||||
CONF_INTEGRATION_TYPE,
|
CONF_INTEGRATION_TYPE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
||||||
INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
||||||
INTEGRATION_TYPE_NODE_PRO,
|
|
||||||
)
|
)
|
||||||
from homeassistant.components.airvisual_pro import DOMAIN as AIRVISUAL_PRO_DOMAIN
|
|
||||||
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER
|
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER
|
||||||
from homeassistant.const import (
|
from homeassistant.const import CONF_API_KEY, CONF_SHOW_ON_MAP
|
||||||
CONF_API_KEY,
|
|
||||||
CONF_IP_ADDRESS,
|
|
||||||
CONF_LATITUDE,
|
|
||||||
CONF_LONGITUDE,
|
|
||||||
CONF_PASSWORD,
|
|
||||||
CONF_SHOW_ON_MAP,
|
|
||||||
CONF_STATE,
|
|
||||||
)
|
|
||||||
from homeassistant.helpers import device_registry as dr, issue_registry as ir
|
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from .conftest import (
|
||||||
|
COORDS_CONFIG,
|
||||||
|
NAME_CONFIG,
|
||||||
async def test_duplicate_error(hass, config, config_entry, data, setup_airvisual):
|
TEST_CITY,
|
||||||
"""Test that errors are shown when duplicate entries are added."""
|
TEST_COUNTRY,
|
||||||
result = await hass.config_entries.flow.async_init(
|
TEST_LATITUDE,
|
||||||
DOMAIN,
|
TEST_LONGITUDE,
|
||||||
context={"source": SOURCE_USER},
|
TEST_STATE,
|
||||||
data={"type": INTEGRATION_TYPE_GEOGRAPHY_COORDS},
|
|
||||||
)
|
)
|
||||||
result = await hass.config_entries.flow.async_configure(
|
|
||||||
result["flow_id"], user_input=config
|
|
||||||
)
|
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.ABORT
|
|
||||||
assert result["reason"] == "already_configured"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"data,exc,errors,integration_type",
|
"integration_type,input_form_step,patched_method,config,entry_title",
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
{
|
INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
||||||
CONF_API_KEY: "abcde12345",
|
"geography_by_coords",
|
||||||
CONF_CITY: "Beijing",
|
"nearest_city",
|
||||||
CONF_STATE: "Beijing",
|
COORDS_CONFIG,
|
||||||
CONF_COUNTRY: "China",
|
f"Cloud API ({TEST_LATITUDE}, {TEST_LONGITUDE})",
|
||||||
},
|
|
||||||
InvalidKeyError,
|
|
||||||
{CONF_API_KEY: "invalid_api_key"},
|
|
||||||
INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{
|
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_CITY: "Beijing",
|
|
||||||
CONF_STATE: "Beijing",
|
|
||||||
CONF_COUNTRY: "China",
|
|
||||||
},
|
|
||||||
KeyExpiredError,
|
|
||||||
{CONF_API_KEY: "invalid_api_key"},
|
|
||||||
INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
{
|
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_CITY: "Beijing",
|
|
||||||
CONF_STATE: "Beijing",
|
|
||||||
CONF_COUNTRY: "China",
|
|
||||||
},
|
|
||||||
UnauthorizedError,
|
|
||||||
{CONF_API_KEY: "invalid_api_key"},
|
|
||||||
INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
{
|
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_CITY: "Beijing",
|
|
||||||
CONF_STATE: "Beijing",
|
|
||||||
CONF_COUNTRY: "China",
|
|
||||||
},
|
|
||||||
NotFoundError,
|
|
||||||
{CONF_CITY: "location_not_found"},
|
|
||||||
INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
{
|
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_CITY: "Beijing",
|
|
||||||
CONF_STATE: "Beijing",
|
|
||||||
CONF_COUNTRY: "China",
|
|
||||||
},
|
|
||||||
AirVisualError,
|
|
||||||
{"base": "unknown"},
|
|
||||||
INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
||||||
|
"geography_by_name",
|
||||||
|
"city",
|
||||||
|
NAME_CONFIG,
|
||||||
|
f"Cloud API ({TEST_CITY}, {TEST_STATE}, {TEST_COUNTRY})",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_errors(hass, data, exc, errors, integration_type):
|
@pytest.mark.parametrize(
|
||||||
"""Test that an exceptions show an error."""
|
"response,errors",
|
||||||
with patch("pyairvisual.air_quality.AirQuality.city", side_effect=exc):
|
[
|
||||||
|
(AsyncMock(side_effect=AirVisualError), {"base": "unknown"}),
|
||||||
|
(AsyncMock(side_effect=InvalidKeyError), {CONF_API_KEY: "invalid_api_key"}),
|
||||||
|
(AsyncMock(side_effect=KeyExpiredError), {CONF_API_KEY: "invalid_api_key"}),
|
||||||
|
(AsyncMock(side_effect=NotFoundError), {CONF_CITY: "location_not_found"}),
|
||||||
|
(AsyncMock(side_effect=UnauthorizedError), {CONF_API_KEY: "invalid_api_key"}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_create_entry(
|
||||||
|
hass,
|
||||||
|
cloud_api,
|
||||||
|
config,
|
||||||
|
entry_title,
|
||||||
|
errors,
|
||||||
|
input_form_step,
|
||||||
|
integration_type,
|
||||||
|
mock_pyairvisual,
|
||||||
|
patched_method,
|
||||||
|
response,
|
||||||
|
):
|
||||||
|
"""Test creating a config entry."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": SOURCE_USER}
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_USER}, data={"type": integration_type}
|
DOMAIN, context={"source": SOURCE_USER}, data={"type": integration_type}
|
||||||
)
|
)
|
||||||
|
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
|
assert result["step_id"] == input_form_step
|
||||||
|
|
||||||
|
# Test errors that can arise:
|
||||||
|
with patch.object(cloud_api.air_quality, patched_method, response):
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], user_input=data
|
result["flow_id"], user_input=config
|
||||||
)
|
)
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
assert result["errors"] == errors
|
assert result["errors"] == errors
|
||||||
|
|
||||||
|
# Test that we can recover and finish the flow after errors occur:
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"config,config_entry_version,unique_id",
|
|
||||||
[
|
|
||||||
(
|
|
||||||
{
|
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_GEOGRAPHIES: [
|
|
||||||
{CONF_LATITUDE: 51.528308, CONF_LONGITUDE: -0.3817765},
|
|
||||||
{
|
|
||||||
CONF_CITY: "Beijing",
|
|
||||||
CONF_STATE: "Beijing",
|
|
||||||
CONF_COUNTRY: "China",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
"abcde12345",
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
async def test_migration_1_2(hass, config, config_entry, setup_airvisual, unique_id):
|
|
||||||
"""Test migrating from version 1 to 2."""
|
|
||||||
config_entries = hass.config_entries.async_entries(DOMAIN)
|
|
||||||
assert len(config_entries) == 2
|
|
||||||
|
|
||||||
assert config_entries[0].unique_id == "51.528308, -0.3817765"
|
|
||||||
assert config_entries[0].title == "Cloud API (51.528308, -0.3817765)"
|
|
||||||
assert config_entries[0].data == {
|
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_LATITUDE: 51.528308,
|
|
||||||
CONF_LONGITUDE: -0.3817765,
|
|
||||||
CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
|
||||||
}
|
|
||||||
|
|
||||||
assert config_entries[1].unique_id == "Beijing, Beijing, China"
|
|
||||||
assert config_entries[1].title == "Cloud API (Beijing, Beijing, China)"
|
|
||||||
assert config_entries[1].data == {
|
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_CITY: "Beijing",
|
|
||||||
CONF_STATE: "Beijing",
|
|
||||||
CONF_COUNTRY: "China",
|
|
||||||
CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_migration_2_3(hass, pro):
|
|
||||||
"""Test migrating from version 2 to 3."""
|
|
||||||
old_pro_entry = MockConfigEntry(
|
|
||||||
domain=DOMAIN,
|
|
||||||
unique_id="192.168.1.100",
|
|
||||||
data={
|
|
||||||
CONF_IP_ADDRESS: "192.168.1.100",
|
|
||||||
CONF_PASSWORD: "abcde12345",
|
|
||||||
CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_NODE_PRO,
|
|
||||||
},
|
|
||||||
version=2,
|
|
||||||
)
|
|
||||||
old_pro_entry.add_to_hass(hass)
|
|
||||||
|
|
||||||
device_registry = dr.async_get(hass)
|
|
||||||
device_registry.async_get_or_create(
|
|
||||||
name="192.168.1.100",
|
|
||||||
config_entry_id=old_pro_entry.entry_id,
|
|
||||||
identifiers={(DOMAIN, "ABCDE12345")},
|
|
||||||
)
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.airvisual.automation.automations_with_device",
|
|
||||||
return_value=["automation.test_automation"],
|
|
||||||
), patch(
|
|
||||||
"homeassistant.components.airvisual_pro.NodeSamba", return_value=pro
|
|
||||||
), patch(
|
|
||||||
"homeassistant.components.airvisual_pro.config_flow.NodeSamba", return_value=pro
|
|
||||||
):
|
|
||||||
await hass.config_entries.async_setup(old_pro_entry.entry_id)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
for domain, entry_count in ((DOMAIN, 0), (AIRVISUAL_PRO_DOMAIN, 1)):
|
|
||||||
entries = hass.config_entries.async_entries(domain)
|
|
||||||
assert len(entries) == entry_count
|
|
||||||
|
|
||||||
issue_registry = ir.async_get(hass)
|
|
||||||
assert len(issue_registry.issues) == 1
|
|
||||||
|
|
||||||
|
|
||||||
async def test_options_flow(hass, config_entry):
|
|
||||||
"""Test config flow options."""
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.airvisual.async_setup_entry", return_value=True
|
|
||||||
):
|
|
||||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
|
||||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
|
||||||
|
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
|
||||||
assert result["step_id"] == "init"
|
|
||||||
|
|
||||||
result = await hass.config_entries.options.async_configure(
|
|
||||||
result["flow_id"], user_input={CONF_SHOW_ON_MAP: False}
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
|
||||||
assert config_entry.options == {CONF_SHOW_ON_MAP: False}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_step_geography_by_coords(hass, config, setup_airvisual):
|
|
||||||
"""Test setting up a geography entry by latitude/longitude."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": SOURCE_USER},
|
|
||||||
data={"type": INTEGRATION_TYPE_GEOGRAPHY_COORDS},
|
|
||||||
)
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], user_input=config
|
result["flow_id"], user_input=config
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
||||||
assert result["title"] == "Cloud API (51.528308, -0.3817765)"
|
assert result["title"] == entry_title
|
||||||
assert result["data"] == {
|
assert result["data"] == {**config, CONF_INTEGRATION_TYPE: integration_type}
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_LATITUDE: 51.528308,
|
|
||||||
CONF_LONGITUDE: -0.3817765,
|
|
||||||
CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
async def test_duplicate_error(hass, config, setup_config_entry):
|
||||||
"config",
|
"""Test that errors are shown when duplicate entries are added."""
|
||||||
[
|
|
||||||
{
|
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_CITY: "Beijing",
|
|
||||||
CONF_STATE: "Beijing",
|
|
||||||
CONF_COUNTRY: "China",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
)
|
|
||||||
async def test_step_geography_by_name(hass, config, setup_airvisual):
|
|
||||||
"""Test setting up a geography entry by city/state/country."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN,
|
|
||||||
context={"source": SOURCE_USER},
|
|
||||||
data={"type": INTEGRATION_TYPE_GEOGRAPHY_NAME},
|
|
||||||
)
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
|
||||||
result["flow_id"], user_input=config
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
|
||||||
assert result["title"] == "Cloud API (Beijing, Beijing, China)"
|
|
||||||
assert result["data"] == {
|
|
||||||
CONF_API_KEY: "abcde12345",
|
|
||||||
CONF_CITY: "Beijing",
|
|
||||||
CONF_STATE: "Beijing",
|
|
||||||
CONF_COUNTRY: "China",
|
|
||||||
CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_step_reauth(hass, config_entry, setup_airvisual):
|
|
||||||
"""Test that the reauth step works."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
DOMAIN, context={"source": SOURCE_REAUTH}, data=config_entry.data
|
|
||||||
)
|
|
||||||
assert result["step_id"] == "reauth_confirm"
|
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
|
||||||
assert result["step_id"] == "reauth_confirm"
|
|
||||||
|
|
||||||
new_api_key = "defgh67890"
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.airvisual.async_setup_entry", return_value=True
|
|
||||||
):
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
|
||||||
result["flow_id"], user_input={CONF_API_KEY: new_api_key}
|
|
||||||
)
|
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.ABORT
|
|
||||||
assert result["reason"] == "reauth_successful"
|
|
||||||
|
|
||||||
assert len(hass.config_entries.async_entries()) == 1
|
|
||||||
assert hass.config_entries.async_entries()[0].data[CONF_API_KEY] == new_api_key
|
|
||||||
|
|
||||||
|
|
||||||
async def test_step_user(hass):
|
|
||||||
"""Test the user ("pick the integration type") step."""
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": SOURCE_USER}
|
DOMAIN, context={"source": SOURCE_USER}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
@ -322,15 +116,48 @@ async def test_step_user(hass):
|
|||||||
context={"source": SOURCE_USER},
|
context={"source": SOURCE_USER},
|
||||||
data={"type": INTEGRATION_TYPE_GEOGRAPHY_COORDS},
|
data={"type": INTEGRATION_TYPE_GEOGRAPHY_COORDS},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
assert result["step_id"] == "geography_by_coords"
|
assert result["step_id"] == "geography_by_coords"
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
DOMAIN,
|
result["flow_id"], user_input=config
|
||||||
context={"source": SOURCE_USER},
|
|
||||||
data={"type": INTEGRATION_TYPE_GEOGRAPHY_NAME},
|
|
||||||
)
|
)
|
||||||
|
assert result["type"] == data_entry_flow.FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_options_flow(hass, config_entry, setup_config_entry):
|
||||||
|
"""Test config flow options."""
|
||||||
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
assert result["step_id"] == "geography_by_name"
|
assert result["step_id"] == "init"
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"], user_input={CONF_SHOW_ON_MAP: False}
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
||||||
|
assert config_entry.options == {CONF_SHOW_ON_MAP: False}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_step_reauth(hass, config_entry, setup_config_entry):
|
||||||
|
"""Test that the reauth step works."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": SOURCE_REAUTH}, data=config_entry.data
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "reauth_confirm"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
||||||
|
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "reauth_confirm"
|
||||||
|
|
||||||
|
new_api_key = "defgh67890"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], user_input={CONF_API_KEY: new_api_key}
|
||||||
|
)
|
||||||
|
assert result["type"] == data_entry_flow.FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "reauth_successful"
|
||||||
|
|
||||||
|
assert len(hass.config_entries.async_entries()) == 1
|
||||||
|
assert hass.config_entries.async_entries()[0].data[CONF_API_KEY] == new_api_key
|
||||||
|
@ -4,7 +4,7 @@ from homeassistant.components.diagnostics import REDACTED
|
|||||||
from tests.components.diagnostics import get_diagnostics_for_config_entry
|
from tests.components.diagnostics import get_diagnostics_for_config_entry
|
||||||
|
|
||||||
|
|
||||||
async def test_entry_diagnostics(hass, config_entry, hass_client, setup_airvisual):
|
async def test_entry_diagnostics(hass, config_entry, hass_client, setup_config_entry):
|
||||||
"""Test config entry diagnostics."""
|
"""Test config entry diagnostics."""
|
||||||
assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {
|
assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {
|
||||||
"entry": {
|
"entry": {
|
||||||
|
120
tests/components/airvisual/test_init.py
Normal file
120
tests/components/airvisual/test_init.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
"""Define tests for AirVisual init."""
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from homeassistant.components.airvisual import (
|
||||||
|
CONF_CITY,
|
||||||
|
CONF_GEOGRAPHIES,
|
||||||
|
CONF_INTEGRATION_TYPE,
|
||||||
|
DOMAIN,
|
||||||
|
INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
||||||
|
INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
||||||
|
INTEGRATION_TYPE_NODE_PRO,
|
||||||
|
)
|
||||||
|
from homeassistant.components.airvisual_pro import DOMAIN as AIRVISUAL_PRO_DOMAIN
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_API_KEY,
|
||||||
|
CONF_COUNTRY,
|
||||||
|
CONF_IP_ADDRESS,
|
||||||
|
CONF_LATITUDE,
|
||||||
|
CONF_LONGITUDE,
|
||||||
|
CONF_PASSWORD,
|
||||||
|
CONF_STATE,
|
||||||
|
)
|
||||||
|
from homeassistant.helpers import device_registry as dr, issue_registry as ir
|
||||||
|
|
||||||
|
from .conftest import (
|
||||||
|
COORDS_CONFIG,
|
||||||
|
NAME_CONFIG,
|
||||||
|
TEST_API_KEY,
|
||||||
|
TEST_CITY,
|
||||||
|
TEST_COUNTRY,
|
||||||
|
TEST_LATITUDE,
|
||||||
|
TEST_LONGITUDE,
|
||||||
|
TEST_STATE,
|
||||||
|
)
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_migration_1_2(hass, mock_pyairvisual):
|
||||||
|
"""Test migrating from version 1 to 2."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
unique_id=TEST_API_KEY,
|
||||||
|
data={
|
||||||
|
CONF_API_KEY: TEST_API_KEY,
|
||||||
|
CONF_GEOGRAPHIES: [
|
||||||
|
{
|
||||||
|
CONF_LATITUDE: TEST_LATITUDE,
|
||||||
|
CONF_LONGITUDE: TEST_LONGITUDE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CONF_CITY: TEST_CITY,
|
||||||
|
CONF_STATE: TEST_STATE,
|
||||||
|
CONF_COUNTRY: TEST_COUNTRY,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
version=1,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
config_entries = hass.config_entries.async_entries(DOMAIN)
|
||||||
|
assert len(config_entries) == 2
|
||||||
|
|
||||||
|
# Ensure that after migration, each configuration has its own config entry:
|
||||||
|
identifier1 = f"{TEST_LATITUDE}, {TEST_LONGITUDE}"
|
||||||
|
assert config_entries[0].unique_id == identifier1
|
||||||
|
assert config_entries[0].title == f"Cloud API ({identifier1})"
|
||||||
|
assert config_entries[0].data == {
|
||||||
|
**COORDS_CONFIG,
|
||||||
|
CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY_COORDS,
|
||||||
|
}
|
||||||
|
|
||||||
|
identifier2 = f"{TEST_CITY}, {TEST_STATE}, {TEST_COUNTRY}"
|
||||||
|
assert config_entries[1].unique_id == identifier2
|
||||||
|
assert config_entries[1].title == f"Cloud API ({identifier2})"
|
||||||
|
assert config_entries[1].data == {
|
||||||
|
**NAME_CONFIG,
|
||||||
|
CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_GEOGRAPHY_NAME,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_migration_2_3(hass, mock_pyairvisual):
|
||||||
|
"""Test migrating from version 2 to 3."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
unique_id="192.168.1.100",
|
||||||
|
data={
|
||||||
|
CONF_IP_ADDRESS: "192.168.1.100",
|
||||||
|
CONF_PASSWORD: "abcde12345",
|
||||||
|
CONF_INTEGRATION_TYPE: INTEGRATION_TYPE_NODE_PRO,
|
||||||
|
},
|
||||||
|
version=2,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
name="192.168.1.100",
|
||||||
|
config_entry_id=entry.entry_id,
|
||||||
|
identifiers={(DOMAIN, "SERIAL_NUMBER")},
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.airvisual.automation.automations_with_device",
|
||||||
|
return_value=["automation.test_automation"],
|
||||||
|
):
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Ensure that after migration, the AirVisual Pro device has been moved to the
|
||||||
|
# `airvisual_pro` domain and an issue has been created:
|
||||||
|
for domain, entry_count in ((DOMAIN, 0), (AIRVISUAL_PRO_DOMAIN, 1)):
|
||||||
|
assert len(hass.config_entries.async_entries(domain)) == entry_count
|
||||||
|
|
||||||
|
issue_registry = ir.async_get(hass)
|
||||||
|
assert len(issue_registry.issues) == 1
|
Loading…
x
Reference in New Issue
Block a user