Allow parameterizing YAML config in tests (#87981)

* Add fixture to parameterize yaml config

* Apply to more tests

* Re-add @fixture label

* Add fixtures to patch yaml content and targets

* Typo

* Improve docstr

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Update references to mock_yaml_configuration

* Apply new fixtures

* Apply to check_config tests

* Follow up comments

* Rename fixtures, update docstr

* Split paths

* Patch load_yaml_config_file instead

* sort

* Fix tests

* improve docst

* Rename fixtures

* sorting

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Improve docstr

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Improve docstr

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Improve docstr

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>

* Improve docstr

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* Improve docstr

Co-authored-by: Erik Montnemery <erik@montnemery.com>

* Improve docstr

Co-authored-by: Erik Montnemery <erik@montnemery.com>

---------

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
Jan Bouwhuis
2023-02-20 16:57:12 +01:00
committed by GitHub
parent 1759f58fc1
commit 4f6a25b470
8 changed files with 498 additions and 383 deletions

View File

@@ -3,6 +3,7 @@ import importlib
import io
import os
import pathlib
from typing import Any
import unittest
from unittest.mock import patch
@@ -67,17 +68,17 @@ def test_simple_dict(try_both_loaders):
assert doc["key"] == "value"
def test_unhashable_key() -> None:
@pytest.mark.parametrize("hass_config_yaml", ["message:\n {{ states.state }}"])
def test_unhashable_key(mock_hass_config_yaml: None) -> None:
"""Test an unhashable key."""
files = {YAML_CONFIG_FILE: "message:\n {{ states.state }}"}
with pytest.raises(HomeAssistantError), patch_yaml_files(files):
with pytest.raises(HomeAssistantError):
load_yaml_config_file(YAML_CONFIG_FILE)
def test_no_key(try_both_loaders):
@pytest.mark.parametrize("hass_config_yaml", ["a: a\nnokeyhere"])
def test_no_key(try_both_loaders, mock_hass_config_yaml: None) -> None:
"""Test item without a key."""
files = {YAML_CONFIG_FILE: "a: a\nnokeyhere"}
with pytest.raises(HomeAssistantError), patch_yaml_files(files):
with pytest.raises(HomeAssistantError):
yaml.load_yaml(YAML_CONFIG_FILE)
@@ -106,35 +107,50 @@ def test_invalid_environment_variable(try_both_loaders):
yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
def test_include_yaml(try_both_loaders):
@pytest.mark.parametrize(
("hass_config_yaml_files", "value"),
[({"test.yaml": "value"}, "value"), ({"test.yaml": None}, {})],
)
def test_include_yaml(
try_both_loaders, mock_hass_config_yaml: None, value: Any
) -> None:
"""Test include yaml."""
with patch_yaml_files({"test.yaml": "value"}):
conf = "key: !include test.yaml"
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert doc["key"] == "value"
with patch_yaml_files({"test.yaml": None}):
conf = "key: !include test.yaml"
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert doc["key"] == {}
conf = "key: !include test.yaml"
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert doc["key"] == value
@patch("homeassistant.util.yaml.loader.os.walk")
def test_include_dir_list(mock_walk, try_both_loaders):
@pytest.mark.parametrize(
"hass_config_yaml_files", [{"/test/one.yaml": "one", "/test/two.yaml": "two"}]
)
def test_include_dir_list(
mock_walk, try_both_loaders, mock_hass_config_yaml: None
) -> None:
"""Test include dir list yaml."""
mock_walk.return_value = [["/test", [], ["two.yaml", "one.yaml"]]]
with patch_yaml_files({"/test/one.yaml": "one", "/test/two.yaml": "two"}):
conf = "key: !include_dir_list /test"
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert doc["key"] == sorted(["one", "two"])
conf = "key: !include_dir_list /test"
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert doc["key"] == sorted(["one", "two"])
@patch("homeassistant.util.yaml.loader.os.walk")
def test_include_dir_list_recursive(mock_walk, try_both_loaders):
@pytest.mark.parametrize(
"hass_config_yaml_files",
[
{
"/test/zero.yaml": "zero",
"/test/tmp2/one.yaml": "one",
"/test/tmp2/two.yaml": "two",
}
],
)
def test_include_dir_list_recursive(
mock_walk, try_both_loaders, mock_hass_config_yaml: None
) -> None:
"""Test include dir recursive list yaml."""
mock_walk.return_value = [
["/test", ["tmp2", ".ignore", "ignore"], ["zero.yaml"]],
@@ -142,41 +158,49 @@ def test_include_dir_list_recursive(mock_walk, try_both_loaders):
["/test/ignore", [], [".ignore.yaml"]],
]
with patch_yaml_files(
{
"/test/zero.yaml": "zero",
"/test/tmp2/one.yaml": "one",
"/test/tmp2/two.yaml": "two",
}
):
conf = "key: !include_dir_list /test"
with io.StringIO(conf) as file:
assert (
".ignore" in mock_walk.return_value[0][1]
), "Expecting .ignore in here"
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert "tmp2" in mock_walk.return_value[0][1]
assert ".ignore" not in mock_walk.return_value[0][1]
assert sorted(doc["key"]) == sorted(["zero", "one", "two"])
conf = "key: !include_dir_list /test"
with io.StringIO(conf) as file:
assert ".ignore" in mock_walk.return_value[0][1], "Expecting .ignore in here"
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert "tmp2" in mock_walk.return_value[0][1]
assert ".ignore" not in mock_walk.return_value[0][1]
assert sorted(doc["key"]) == sorted(["zero", "one", "two"])
@patch("homeassistant.util.yaml.loader.os.walk")
def test_include_dir_named(mock_walk, try_both_loaders):
@pytest.mark.parametrize(
"hass_config_yaml_files",
[{"/test/first.yaml": "one", "/test/second.yaml": "two"}],
)
def test_include_dir_named(
mock_walk, try_both_loaders, mock_hass_config_yaml: None
) -> None:
"""Test include dir named yaml."""
mock_walk.return_value = [
["/test", [], ["first.yaml", "second.yaml", "secrets.yaml"]]
]
with patch_yaml_files({"/test/first.yaml": "one", "/test/second.yaml": "two"}):
conf = "key: !include_dir_named /test"
correct = {"first": "one", "second": "two"}
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert doc["key"] == correct
conf = "key: !include_dir_named /test"
correct = {"first": "one", "second": "two"}
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert doc["key"] == correct
@patch("homeassistant.util.yaml.loader.os.walk")
def test_include_dir_named_recursive(mock_walk, try_both_loaders):
@pytest.mark.parametrize(
"hass_config_yaml_files",
[
{
"/test/first.yaml": "one",
"/test/tmp2/second.yaml": "two",
"/test/tmp2/third.yaml": "three",
}
],
)
def test_include_dir_named_recursive(
mock_walk, try_both_loaders, mock_hass_config_yaml: None
) -> None:
"""Test include dir named yaml."""
mock_walk.return_value = [
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
@@ -184,85 +208,99 @@ def test_include_dir_named_recursive(mock_walk, try_both_loaders):
["/test/ignore", [], [".ignore.yaml"]],
]
with patch_yaml_files(
{
"/test/first.yaml": "one",
"/test/tmp2/second.yaml": "two",
"/test/tmp2/third.yaml": "three",
}
):
conf = "key: !include_dir_named /test"
correct = {"first": "one", "second": "two", "third": "three"}
with io.StringIO(conf) as file:
assert (
".ignore" in mock_walk.return_value[0][1]
), "Expecting .ignore in here"
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert "tmp2" in mock_walk.return_value[0][1]
assert ".ignore" not in mock_walk.return_value[0][1]
assert doc["key"] == correct
conf = "key: !include_dir_named /test"
correct = {"first": "one", "second": "two", "third": "three"}
with io.StringIO(conf) as file:
assert ".ignore" in mock_walk.return_value[0][1], "Expecting .ignore in here"
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert "tmp2" in mock_walk.return_value[0][1]
assert ".ignore" not in mock_walk.return_value[0][1]
assert doc["key"] == correct
@patch("homeassistant.util.yaml.loader.os.walk")
def test_include_dir_merge_list(mock_walk, try_both_loaders):
@pytest.mark.parametrize(
"hass_config_yaml_files",
[{"/test/first.yaml": "- one", "/test/second.yaml": "- two\n- three"}],
)
def test_include_dir_merge_list(
mock_walk, try_both_loaders, mock_hass_config_yaml: None
) -> None:
"""Test include dir merge list yaml."""
mock_walk.return_value = [["/test", [], ["first.yaml", "second.yaml"]]]
with patch_yaml_files(
{"/test/first.yaml": "- one", "/test/second.yaml": "- two\n- three"}
):
conf = "key: !include_dir_merge_list /test"
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert sorted(doc["key"]) == sorted(["one", "two", "three"])
conf = "key: !include_dir_merge_list /test"
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert sorted(doc["key"]) == sorted(["one", "two", "three"])
@patch("homeassistant.util.yaml.loader.os.walk")
def test_include_dir_merge_list_recursive(mock_walk, try_both_loaders):
"""Test include dir merge list yaml."""
mock_walk.return_value = [
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
["/test/tmp2", [], ["second.yaml", "third.yaml"]],
["/test/ignore", [], [".ignore.yaml"]],
]
with patch_yaml_files(
@pytest.mark.parametrize(
"hass_config_yaml_files",
[
{
"/test/first.yaml": "- one",
"/test/tmp2/second.yaml": "- two",
"/test/tmp2/third.yaml": "- three\n- four",
}
):
conf = "key: !include_dir_merge_list /test"
with io.StringIO(conf) as file:
assert (
".ignore" in mock_walk.return_value[0][1]
), "Expecting .ignore in here"
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert "tmp2" in mock_walk.return_value[0][1]
assert ".ignore" not in mock_walk.return_value[0][1]
assert sorted(doc["key"]) == sorted(["one", "two", "three", "four"])
],
)
def test_include_dir_merge_list_recursive(
mock_walk, try_both_loaders, mock_hass_config_yaml: None
) -> None:
"""Test include dir merge list yaml."""
mock_walk.return_value = [
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
["/test/tmp2", [], ["second.yaml", "third.yaml"]],
["/test/ignore", [], [".ignore.yaml"]],
]
conf = "key: !include_dir_merge_list /test"
with io.StringIO(conf) as file:
assert ".ignore" in mock_walk.return_value[0][1], "Expecting .ignore in here"
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert "tmp2" in mock_walk.return_value[0][1]
assert ".ignore" not in mock_walk.return_value[0][1]
assert sorted(doc["key"]) == sorted(["one", "two", "three", "four"])
@patch("homeassistant.util.yaml.loader.os.walk")
def test_include_dir_merge_named(mock_walk, try_both_loaders):
@pytest.mark.parametrize(
"hass_config_yaml_files",
[
{
"/test/first.yaml": "key1: one",
"/test/second.yaml": "key2: two\nkey3: three",
}
],
)
def test_include_dir_merge_named(
mock_walk, try_both_loaders, mock_hass_config_yaml: None
) -> None:
"""Test include dir merge named yaml."""
mock_walk.return_value = [["/test", [], ["first.yaml", "second.yaml"]]]
files = {
"/test/first.yaml": "key1: one",
"/test/second.yaml": "key2: two\nkey3: three",
}
with patch_yaml_files(files):
conf = "key: !include_dir_merge_named /test"
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert doc["key"] == {"key1": "one", "key2": "two", "key3": "three"}
conf = "key: !include_dir_merge_named /test"
with io.StringIO(conf) as file:
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert doc["key"] == {"key1": "one", "key2": "two", "key3": "three"}
@patch("homeassistant.util.yaml.loader.os.walk")
def test_include_dir_merge_named_recursive(mock_walk, try_both_loaders):
@pytest.mark.parametrize(
"hass_config_yaml_files",
[
{
"/test/first.yaml": "key1: one",
"/test/tmp2/second.yaml": "key2: two",
"/test/tmp2/third.yaml": "key3: three\nkey4: four",
}
],
)
def test_include_dir_merge_named_recursive(
mock_walk, try_both_loaders, mock_hass_config_yaml: None
) -> None:
"""Test include dir merge named yaml."""
mock_walk.return_value = [
["/test", ["tmp2", ".ignore", "ignore"], ["first.yaml"]],
@@ -270,27 +308,18 @@ def test_include_dir_merge_named_recursive(mock_walk, try_both_loaders):
["/test/ignore", [], [".ignore.yaml"]],
]
with patch_yaml_files(
{
"/test/first.yaml": "key1: one",
"/test/tmp2/second.yaml": "key2: two",
"/test/tmp2/third.yaml": "key3: three\nkey4: four",
conf = "key: !include_dir_merge_named /test"
with io.StringIO(conf) as file:
assert ".ignore" in mock_walk.return_value[0][1], "Expecting .ignore in here"
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert "tmp2" in mock_walk.return_value[0][1]
assert ".ignore" not in mock_walk.return_value[0][1]
assert doc["key"] == {
"key1": "one",
"key2": "two",
"key3": "three",
"key4": "four",
}
):
conf = "key: !include_dir_merge_named /test"
with io.StringIO(conf) as file:
assert (
".ignore" in mock_walk.return_value[0][1]
), "Expecting .ignore in here"
doc = yaml_loader.yaml.load(file, Loader=yaml_loader.SafeLineLoader)
assert "tmp2" in mock_walk.return_value[0][1]
assert ".ignore" not in mock_walk.return_value[0][1]
assert doc["key"] == {
"key1": "one",
"key2": "two",
"key3": "three",
"key4": "four",
}
@patch("homeassistant.util.yaml.loader.open", create=True)
@@ -452,26 +481,31 @@ class TestSecrets(unittest.TestCase):
)
def test_representing_yaml_loaded_data(try_both_dumpers):
@pytest.mark.parametrize("hass_config_yaml", ['key: [1, "2", 3]'])
def test_representing_yaml_loaded_data(
try_both_dumpers, mock_hass_config_yaml: None
) -> None:
"""Test we can represent YAML loaded data."""
files = {YAML_CONFIG_FILE: 'key: [1, "2", 3]'}
with patch_yaml_files(files):
data = load_yaml_config_file(YAML_CONFIG_FILE)
data = load_yaml_config_file(YAML_CONFIG_FILE)
assert yaml.dump(data) == "key:\n- 1\n- '2'\n- 3\n"
def test_duplicate_key(caplog, try_both_loaders):
@pytest.mark.parametrize("hass_config_yaml", ["key: thing1\nkey: thing2"])
def test_duplicate_key(caplog, try_both_loaders, mock_hass_config_yaml: None) -> None:
"""Test duplicate dict keys."""
files = {YAML_CONFIG_FILE: "key: thing1\nkey: thing2"}
with patch_yaml_files(files):
load_yaml_config_file(YAML_CONFIG_FILE)
load_yaml_config_file(YAML_CONFIG_FILE)
assert "contains duplicate key" in caplog.text
def test_no_recursive_secrets(caplog, try_both_loaders):
@pytest.mark.parametrize(
"hass_config_yaml_files",
[{YAML_CONFIG_FILE: "key: !secret a", yaml.SECRET_YAML: "a: 1\nb: !secret a"}],
)
def test_no_recursive_secrets(
caplog, try_both_loaders, mock_hass_config_yaml: None
) -> None:
"""Test that loading of secrets from the secrets file fails correctly."""
files = {YAML_CONFIG_FILE: "key: !secret a", yaml.SECRET_YAML: "a: 1\nb: !secret a"}
with patch_yaml_files(files), pytest.raises(HomeAssistantError) as e:
with pytest.raises(HomeAssistantError) as e:
load_yaml_config_file(YAML_CONFIG_FILE)
assert e.value.args == ("Secrets not supported in this YAML file",)