From a9bdab4b49bb64812f3c0db53fa54defef3db256 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 12 Aug 2020 14:49:46 +0200 Subject: [PATCH] Fix validation issue addon options (#1898) * Fix validation issue addon options * Add some basic tests * Update supervisor/addons/validate.py Co-authored-by: Paulus Schoutsen Co-authored-by: Paulus Schoutsen --- supervisor/addons/validate.py | 10 +++++ tests/addons/test_options_schema.py | 65 +++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tests/addons/test_options_schema.py diff --git a/supervisor/addons/validate.py b/supervisor/addons/validate.py index 03f2747bd..e022897b4 100644 --- a/supervisor/addons/validate.py +++ b/supervisor/addons/validate.py @@ -424,6 +424,11 @@ def _nested_validate_list(coresys, typ, data_list, key): """Validate nested items.""" options = [] + # Make sure it is a list + if not isinstance(data_list, list): + raise vol.Invalid(f"Invalid list for {key}") + + # Process list for element in data_list: # Nested? if isinstance(typ, dict): @@ -439,6 +444,11 @@ def _nested_validate_dict(coresys, typ, data_dict, key): """Validate nested items.""" options = {} + # Make sure it is a dict + if not isinstance(data_dict, dict): + raise vol.Invalid(f"Invalid dict for {key}") + + # Process dict for c_key, c_value in data_dict.items(): # Ignore unknown options / remove from list if c_key not in typ: diff --git a/tests/addons/test_options_schema.py b/tests/addons/test_options_schema.py new file mode 100644 index 000000000..f44983adc --- /dev/null +++ b/tests/addons/test_options_schema.py @@ -0,0 +1,65 @@ +"""Test add-ons schema to UI schema convertion.""" + +import pytest +import voluptuous as vol + +from supervisor.addons.validate import validate_options + + +def test_simple_schema(coresys): + """Test with simple schema.""" + assert validate_options( + coresys, + {"name": "str", "password": "password", "fires": "bool", "alias": "str?"}, + )({"name": "Pascal", "password": "1234", "fires": True, "alias": "test"}) + + assert validate_options( + coresys, + {"name": "str", "password": "password", "fires": "bool", "alias": "str?"}, + )({"name": "Pascal", "password": "1234", "fires": True}) + + with pytest.raises(vol.error.Invalid): + validate_options( + coresys, + {"name": "str", "password": "password", "fires": "bool", "alias": "str?"}, + )({"name": "Pascal", "password": "1234", "fires": "hah"}) + + with pytest.raises(vol.error.Invalid): + validate_options( + coresys, + {"name": "str", "password": "password", "fires": "bool", "alias": "str?"}, + )({"name": "Pascal", "fires": True}) + + +def test_complex_schema_list(coresys): + """Test with complex list schema.""" + assert validate_options( + coresys, {"name": "str", "password": "password", "extend": ["str"]}, + )({"name": "Pascal", "password": "1234", "extend": ["test", "blu"]}) + + with pytest.raises(vol.error.Invalid): + validate_options( + coresys, {"name": "str", "password": "password", "extend": ["str"]}, + )({"name": "Pascal", "password": "1234", "extend": ["test", 1]}) + + with pytest.raises(vol.error.Invalid): + validate_options( + coresys, {"name": "str", "password": "password", "extend": ["str"]}, + )({"name": "Pascal", "password": "1234", "extend": "test"}) + + +def test_complex_schema_dict(coresys): + """Test with complex dict schema.""" + assert validate_options( + coresys, {"name": "str", "password": "password", "extend": {"test": "int"}}, + )({"name": "Pascal", "password": "1234", "extend": {"test": 1}}) + + with pytest.raises(vol.error.Invalid): + validate_options( + coresys, {"name": "str", "password": "password", "extend": {"test": "int"}}, + )({"name": "Pascal", "password": "1234", "extend": {"wrong": 1}}) + + with pytest.raises(vol.error.Invalid): + validate_options( + coresys, {"name": "str", "password": "password", "extend": ["str"]}, + )({"name": "Pascal", "password": "1234", "extend": "test"})