Improve config tests (#81898)

* Improve config tests

* Fix stale docstring

* Use os.path.basename
This commit is contained in:
Erik Montnemery 2022-11-14 11:13:20 +01:00 committed by GitHub
parent 096ef85c68
commit de313dcc3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 259 additions and 226 deletions

View File

@ -0,0 +1,73 @@
"""Test fixtures for the config integration."""
from contextlib import contextmanager
from copy import deepcopy
import json
import logging
from os.path import basename
from unittest.mock import patch
import pytest
from homeassistant.core import HomeAssistant
from tests.common import raise_contains_mocks
_LOGGER = logging.getLogger(__name__)
@contextmanager
def mock_config_store(data=None):
"""Mock config yaml store.
Data is a dict {'key': {'version': version, 'data': data}}
Written data will be converted to JSON to ensure JSON parsing works.
"""
if data is None:
data = {}
def mock_read(path):
"""Mock version of load."""
file_name = basename(path)
_LOGGER.info("Reading data from %s: %s", file_name, data.get(file_name))
return deepcopy(data.get(file_name))
def mock_write(path, data_to_write):
"""Mock version of write."""
file_name = basename(path)
_LOGGER.info("Writing data to %s: %s", file_name, data_to_write)
raise_contains_mocks(data_to_write)
# To ensure that the data can be serialized
data[file_name] = json.loads(json.dumps(data_to_write))
async def mock_async_hass_config_yaml(hass: HomeAssistant) -> dict:
"""Mock version of async_hass_config_yaml."""
result = {}
# Return a configuration.yaml with "automation" mapped to the contents of
# automations.yaml and so on.
for key, value in data.items():
result[key.partition(".")[0][0:-1]] = deepcopy(value)
_LOGGER.info("Reading data from configuration.yaml: %s", result)
return result
with patch(
"homeassistant.components.config._read",
side_effect=mock_read,
autospec=True,
), patch(
"homeassistant.components.config._write",
side_effect=mock_write,
autospec=True,
), patch(
"homeassistant.config.async_hass_config_yaml",
side_effect=mock_async_hass_config_yaml,
autospec=True,
):
yield data
@pytest.fixture
def hass_config_store():
"""Fixture to mock config yaml store."""
with mock_config_store() as stored_data:
yield stored_data

View File

@ -7,6 +7,7 @@ import pytest
from homeassistant.bootstrap import async_setup_component
from homeassistant.components import config
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa: F401
@ -23,19 +24,18 @@ async def setup_automation(
@pytest.mark.parametrize("automation_config", ({},))
async def test_get_device_config(hass, hass_client, setup_automation):
"""Test getting device config."""
async def test_get_automation_config(
hass: HomeAssistant, hass_client, hass_config_store, setup_automation
):
"""Test getting automation config."""
with patch.object(config, "SECTIONS", ["automation"]):
await async_setup_component(hass, "config", {})
client = await hass_client()
def mock_read(path):
"""Mock reading data."""
return [{"id": "sun"}, {"id": "moon"}]
hass_config_store["automations.yaml"] = [{"id": "sun"}, {"id": "moon"}]
with patch("homeassistant.components.config._read", mock_read):
resp = await client.get("/api/config/automation/config/moon")
resp = await client.get("/api/config/automation/config/moon")
assert resp.status == HTTPStatus.OK
result = await resp.json()
@ -44,85 +44,81 @@ async def test_get_device_config(hass, hass_client, setup_automation):
@pytest.mark.parametrize("automation_config", ({},))
async def test_update_device_config(hass, hass_client, setup_automation):
"""Test updating device config."""
async def test_update_automation_config(
hass: HomeAssistant, hass_client, hass_config_store, setup_automation
):
"""Test updating automation config."""
with patch.object(config, "SECTIONS", ["automation"]):
await async_setup_component(hass, "config", {})
assert sorted(hass.states.async_entity_ids("automation")) == []
client = await hass_client()
orig_data = [{"id": "sun"}, {"id": "moon"}]
hass_config_store["automations.yaml"] = orig_data
def mock_read(path):
"""Mock reading data."""
return orig_data
written = []
def mock_write(path, data):
"""Mock writing data."""
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
), patch("homeassistant.config.async_hass_config_yaml", return_value={}):
resp = await client.post(
"/api/config/automation/config/moon",
data=json.dumps({"trigger": [], "action": [], "condition": []}),
)
resp = await client.post(
"/api/config/automation/config/moon",
data=json.dumps({"trigger": [], "action": [], "condition": []}),
)
await hass.async_block_till_done()
assert sorted(hass.states.async_entity_ids("automation")) == [
"automation.automation_0"
]
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
assert list(orig_data[1]) == ["id", "trigger", "condition", "action"]
assert orig_data[1] == {"id": "moon", "trigger": [], "condition": [], "action": []}
assert written[0] == orig_data
new_data = hass_config_store["automations.yaml"]
assert list(new_data[1]) == ["id", "trigger", "condition", "action"]
assert new_data[1] == {"id": "moon", "trigger": [], "condition": [], "action": []}
@pytest.mark.parametrize("automation_config", ({},))
async def test_update_remove_key_device_config(hass, hass_client, setup_automation):
"""Test updating device config while removing a key."""
async def test_update_remove_key_automation_config(
hass: HomeAssistant, hass_client, hass_config_store, setup_automation
):
"""Test updating automation config while removing a key."""
with patch.object(config, "SECTIONS", ["automation"]):
await async_setup_component(hass, "config", {})
assert sorted(hass.states.async_entity_ids("automation")) == []
client = await hass_client()
orig_data = [{"id": "sun", "key": "value"}, {"id": "moon", "key": "value"}]
hass_config_store["automations.yaml"] = orig_data
def mock_read(path):
"""Mock reading data."""
return orig_data
written = []
def mock_write(path, data):
"""Mock writing data."""
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
), patch("homeassistant.config.async_hass_config_yaml", return_value={}):
resp = await client.post(
"/api/config/automation/config/moon",
data=json.dumps({"trigger": [], "action": [], "condition": []}),
)
resp = await client.post(
"/api/config/automation/config/moon",
data=json.dumps({"trigger": [], "action": [], "condition": []}),
)
await hass.async_block_till_done()
assert sorted(hass.states.async_entity_ids("automation")) == [
"automation.automation_0"
]
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
assert list(orig_data[1]) == ["id", "trigger", "condition", "action"]
assert orig_data[1] == {"id": "moon", "trigger": [], "condition": [], "action": []}
assert written[0] == orig_data
new_data = hass_config_store["automations.yaml"]
assert list(new_data[1]) == ["id", "trigger", "condition", "action"]
assert new_data[1] == {"id": "moon", "trigger": [], "condition": [], "action": []}
@pytest.mark.parametrize("automation_config", ({},))
async def test_bad_formatted_automations(hass, hass_client, setup_automation):
async def test_bad_formatted_automations(
hass: HomeAssistant, hass_client, hass_config_store, setup_automation
):
"""Test that we handle automations without ID."""
with patch.object(config, "SECTIONS", ["automation"]):
await async_setup_component(hass, "config", {})
assert sorted(hass.states.async_entity_ids("automation")) == []
client = await hass_client()
orig_data = [
@ -132,34 +128,25 @@ async def test_bad_formatted_automations(hass, hass_client, setup_automation):
},
{"id": "moon"},
]
hass_config_store["automations.yaml"] = orig_data
def mock_read(path):
"""Mock reading data."""
return orig_data
written = []
def mock_write(path, data):
"""Mock writing data."""
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
), patch("homeassistant.config.async_hass_config_yaml", return_value={}):
resp = await client.post(
"/api/config/automation/config/moon",
data=json.dumps({"trigger": [], "action": [], "condition": []}),
)
await hass.async_block_till_done()
resp = await client.post(
"/api/config/automation/config/moon",
data=json.dumps({"trigger": [], "action": [], "condition": []}),
)
await hass.async_block_till_done()
assert sorted(hass.states.async_entity_ids("automation")) == [
"automation.automation_0"
]
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
# Verify ID added to orig_data
assert "id" in orig_data[0]
assert orig_data[1] == {"id": "moon", "trigger": [], "condition": [], "action": []}
# Verify ID added
new_data = hass_config_store["automations.yaml"]
assert "id" in new_data[0]
assert new_data[1] == {"id": "moon", "trigger": [], "condition": [], "action": []}
@pytest.mark.parametrize(
@ -179,7 +166,9 @@ async def test_bad_formatted_automations(hass, hass_client, setup_automation):
],
),
)
async def test_delete_automation(hass, hass_client, setup_automation):
async def test_delete_automation(
hass: HomeAssistant, hass_client, hass_config_store, setup_automation
):
"""Test deleting an automation."""
ent_reg = er.async_get(hass)
@ -188,31 +177,27 @@ async def test_delete_automation(hass, hass_client, setup_automation):
with patch.object(config, "SECTIONS", ["automation"]):
assert await async_setup_component(hass, "config", {})
assert sorted(hass.states.async_entity_ids("automation")) == [
"automation.automation_0",
"automation.automation_1",
]
client = await hass_client()
orig_data = [{"id": "sun"}, {"id": "moon"}]
hass_config_store["automations.yaml"] = orig_data
def mock_read(path):
"""Mock reading data."""
return orig_data
resp = await client.delete("/api/config/automation/config/sun")
await hass.async_block_till_done()
written = []
def mock_write(path, data):
"""Mock writing data."""
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
), patch("homeassistant.config.async_hass_config_yaml", return_value={}):
resp = await client.delete("/api/config/automation/config/sun")
await hass.async_block_till_done()
assert sorted(hass.states.async_entity_ids("automation")) == [
"automation.automation_1",
]
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
assert len(written) == 1
assert written[0][0]["id"] == "moon"
assert hass_config_store["automations.yaml"] == [{"id": "moon"}]
assert len(ent_reg.entities) == 1

View File

@ -1,14 +1,13 @@
"""Test Automation config panel."""
from http import HTTPStatus
import json
from unittest.mock import patch
from unittest.mock import ANY, patch
import pytest
from homeassistant.bootstrap import async_setup_component
from homeassistant.components import config
from homeassistant.helpers import entity_registry as er
from homeassistant.util.yaml import dump
@pytest.fixture
@ -18,114 +17,98 @@ async def setup_scene(hass, scene_config):
@pytest.mark.parametrize("scene_config", ({},))
async def test_create_scene(hass, hass_client, setup_scene):
async def test_create_scene(hass, hass_client, hass_config_store, setup_scene):
"""Test creating a scene."""
with patch.object(config, "SECTIONS", ["scene"]):
await async_setup_component(hass, "config", {})
assert sorted(hass.states.async_entity_ids("scene")) == []
client = await hass_client()
def mock_read(path):
"""Mock reading data."""
return None
orig_data = {}
hass_config_store["scenes.yaml"] = orig_data
written = []
resp = await client.post(
"/api/config/scene/config/light_off",
data=json.dumps(
{
# "id": "light_off", # The id should be added when writing
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
}
),
)
await hass.async_block_till_done()
def mock_write(path, data):
"""Mock writing data."""
data = dump(data)
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
), patch("homeassistant.config.async_hass_config_yaml", return_value={}):
resp = await client.post(
"/api/config/scene/config/light_off",
data=json.dumps(
{
# "id": "light_off",
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
}
),
)
assert sorted(hass.states.async_entity_ids("scene")) == [
"scene.lights_off",
]
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
assert len(written) == 1
written_yaml = written[0]
assert (
written_yaml
== """- id: light_off
name: Lights off
entities:
light.bedroom:
state: 'off'
"""
)
assert hass_config_store["scenes.yaml"] == [
{
"id": "light_off",
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
}
]
@pytest.mark.parametrize("scene_config", ({},))
async def test_update_scene(hass, hass_client, setup_scene):
async def test_update_scene(hass, hass_client, hass_config_store, setup_scene):
"""Test updating a scene."""
with patch.object(config, "SECTIONS", ["scene"]):
await async_setup_component(hass, "config", {})
assert sorted(hass.states.async_entity_ids("scene")) == []
client = await hass_client()
orig_data = [{"id": "light_on"}, {"id": "light_off"}]
hass_config_store["scenes.yaml"] = orig_data
def mock_read(path):
"""Mock reading data."""
return orig_data
resp = await client.post(
"/api/config/scene/config/light_off",
data=json.dumps(
{
"id": "light_off",
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
}
),
)
await hass.async_block_till_done()
written = []
def mock_write(path, data):
"""Mock writing data."""
data = dump(data)
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
), patch("homeassistant.config.async_hass_config_yaml", return_value={}):
resp = await client.post(
"/api/config/scene/config/light_off",
data=json.dumps(
{
"id": "light_off",
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
}
),
)
assert sorted(hass.states.async_entity_ids("scene")) == [
"scene.lights_off",
]
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
assert len(written) == 1
written_yaml = written[0]
assert (
written_yaml
== """- id: light_on
- id: light_off
name: Lights off
entities:
light.bedroom:
state: 'off'
"""
)
assert hass_config_store["scenes.yaml"] == [
{"id": "light_on"},
{
"id": "light_off",
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
},
]
@pytest.mark.parametrize("scene_config", ({},))
async def test_bad_formatted_scene(hass, hass_client, setup_scene):
async def test_bad_formatted_scene(hass, hass_client, hass_config_store, setup_scene):
"""Test that we handle scene without ID."""
with patch.object(config, "SECTIONS", ["scene"]):
await async_setup_component(hass, "config", {})
assert sorted(hass.states.async_entity_ids("scene")) == []
client = await hass_client()
orig_data = [
@ -135,43 +118,40 @@ async def test_bad_formatted_scene(hass, hass_client, setup_scene):
},
{"id": "light_off"},
]
hass_config_store["scenes.yaml"] = orig_data
def mock_read(path):
"""Mock reading data."""
return orig_data
resp = await client.post(
"/api/config/scene/config/light_off",
data=json.dumps(
{
"id": "light_off",
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
}
),
)
await hass.async_block_till_done()
written = []
def mock_write(path, data):
"""Mock writing data."""
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
), patch("homeassistant.config.async_hass_config_yaml", return_value={}):
resp = await client.post(
"/api/config/scene/config/light_off",
data=json.dumps(
{
"id": "light_off",
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
}
),
)
assert sorted(hass.states.async_entity_ids("scene")) == [
"scene.lights_off",
]
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
# Verify ID added to orig_data
assert "id" in orig_data[0]
assert orig_data[1] == {
"id": "light_off",
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
}
assert hass_config_store["scenes.yaml"] == [
{
"id": ANY,
"entities": {"light.bedroom": "on"},
},
{
"id": "light_off",
"name": "Lights off",
"entities": {"light.bedroom": {"state": "off"}},
},
]
@pytest.mark.parametrize(
@ -183,7 +163,7 @@ async def test_bad_formatted_scene(hass, hass_client, setup_scene):
],
),
)
async def test_delete_scene(hass, hass_client, setup_scene):
async def test_delete_scene(hass, hass_client, hass_config_store, setup_scene):
"""Test deleting a scene."""
ent_reg = er.async_get(hass)
@ -192,31 +172,29 @@ async def test_delete_scene(hass, hass_client, setup_scene):
with patch.object(config, "SECTIONS", ["scene"]):
assert await async_setup_component(hass, "config", {})
assert sorted(hass.states.async_entity_ids("scene")) == [
"scene.light_off",
"scene.light_on",
]
client = await hass_client()
orig_data = [{"id": "light_on"}, {"id": "light_off"}]
hass_config_store["scenes.yaml"] = orig_data
def mock_read(path):
"""Mock reading data."""
return orig_data
resp = await client.delete("/api/config/scene/config/light_on")
await hass.async_block_till_done()
written = []
def mock_write(path, data):
"""Mock writing data."""
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
), patch("homeassistant.config.async_hass_config_yaml", return_value={}):
resp = await client.delete("/api/config/scene/config/light_on")
await hass.async_block_till_done()
assert sorted(hass.states.async_entity_ids("scene")) == [
"scene.light_off",
]
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
assert len(written) == 1
assert written[0][0]["id"] == "light_off"
assert hass_config_store["scenes.yaml"] == [
{"id": "light_off"},
]
assert len(ent_reg.entities) == 1

View File

@ -26,38 +26,35 @@ async def setup_script(hass, script_config, stub_blueprint_populate): # noqa: F
},
),
)
async def test_delete_script(hass, hass_client):
async def test_delete_script(hass, hass_client, hass_config_store):
"""Test deleting a script."""
with patch.object(config, "SECTIONS", ["script"]):
await async_setup_component(hass, "config", {})
assert sorted(hass.states.async_entity_ids("script")) == [
"script.one",
"script.two",
]
ent_reg = er.async_get(hass)
assert len(ent_reg.entities) == 2
client = await hass_client()
orig_data = {"one": {}, "two": {}}
hass_config_store["scripts.yaml"] = orig_data
def mock_read(path):
"""Mock reading data."""
return orig_data
resp = await client.delete("/api/config/script/config/two")
await hass.async_block_till_done()
written = []
def mock_write(path, data):
"""Mock writing data."""
written.append(data)
with patch("homeassistant.components.config._read", mock_read), patch(
"homeassistant.components.config._write", mock_write
):
resp = await client.delete("/api/config/script/config/two")
assert sorted(hass.states.async_entity_ids("script")) == [
"script.one",
]
assert resp.status == HTTPStatus.OK
result = await resp.json()
assert result == {"result": "ok"}
assert len(written) == 1
assert written[0] == {"one": {}}
assert hass_config_store["scripts.yaml"] == {"one": {}}
assert len(ent_reg.entities) == 1