mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
add more validation rules
This commit is contained in:
parent
4fb9335df9
commit
13faf66bdb
@ -1 +1 @@
|
|||||||
skips: ['B101', 'B105', 'B106', 'B404']
|
skips: ['B101', 'B104', 'B105', 'B106', 'B404']
|
||||||
|
@ -69,7 +69,7 @@ Build related configuration. Group name can refer to architecture, e.g. ``build:
|
|||||||
* ``makepkg_flags`` - additional flags passed to ``makepkg`` command, space separated list of strings, optional.
|
* ``makepkg_flags`` - additional flags passed to ``makepkg`` command, space separated list of strings, optional.
|
||||||
* ``makechrootpkg_flags`` - additional flags passed to ``makechrootpkg`` command, space separated list of strings, optional.
|
* ``makechrootpkg_flags`` - additional flags passed to ``makechrootpkg`` command, space separated list of strings, optional.
|
||||||
* ``triggers`` - list of ``ahriman.core.triggers.Trigger`` class implementation (e.g. ``ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger``) which will be loaded and run at the end of processing, space separated list of strings, optional. You can also specify triggers by their paths, e.g. ``/usr/lib/python3.10/site-packages/ahriman/core/report/report.py.ReportTrigger``. Triggers are run in the order of mention.
|
* ``triggers`` - list of ``ahriman.core.triggers.Trigger`` class implementation (e.g. ``ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger``) which will be loaded and run at the end of processing, space separated list of strings, optional. You can also specify triggers by their paths, e.g. ``/usr/lib/python3.10/site-packages/ahriman/core/report/report.py.ReportTrigger``. Triggers are run in the order of mention.
|
||||||
* ``vcs_allowed_age`` - maximal age in seconds of the VCS packages before their version will be updated with its remote source, int, optional, default ``0``.
|
* ``vcs_allowed_age`` - maximal age in seconds of the VCS packages before their version will be updated with its remote source, int, optional, default ``604800``.
|
||||||
|
|
||||||
``repository`` group
|
``repository`` group
|
||||||
--------------------
|
--------------------
|
||||||
|
@ -52,7 +52,7 @@ class Validate(Handler):
|
|||||||
unsafe(bool): if set no user check will be performed before path creation
|
unsafe(bool): if set no user check will be performed before path creation
|
||||||
"""
|
"""
|
||||||
schema = Validate.schema(architecture, configuration)
|
schema = Validate.schema(architecture, configuration)
|
||||||
validator = Validator(instance=configuration, schema=schema)
|
validator = Validator(configuration=configuration, schema=schema)
|
||||||
|
|
||||||
if validator.validate(configuration.dump()):
|
if validator.validate(configuration.dump()):
|
||||||
return # no errors found
|
return # no errors found
|
||||||
|
@ -64,6 +64,7 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
"mirror": {
|
"mirror": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": True,
|
"required": True,
|
||||||
|
"is_url": [],
|
||||||
},
|
},
|
||||||
"repositories": {
|
"repositories": {
|
||||||
"type": "list",
|
"type": "list",
|
||||||
@ -111,10 +112,13 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
},
|
},
|
||||||
"cookie_secret_key": {
|
"cookie_secret_key": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"minlength": 32,
|
||||||
|
"maxlength": 64, # we cannot verify maxlength, because base64 representation might be longer than bytes
|
||||||
},
|
},
|
||||||
"max_age": {
|
"max_age": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"coerce": "integer",
|
"coerce": "integer",
|
||||||
|
"min": 0,
|
||||||
},
|
},
|
||||||
"oauth_provider": {
|
"oauth_provider": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -162,6 +166,7 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
"vcs_allowed_age": {
|
"vcs_allowed_age": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"coerce": "integer",
|
"coerce": "integer",
|
||||||
|
"min": 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -204,6 +209,7 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
"schema": {
|
"schema": {
|
||||||
"address": {
|
"address": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"is_url": ["http", "https"],
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -220,9 +226,11 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"is_ip_address": ["localhost"],
|
||||||
},
|
},
|
||||||
"index_url": {
|
"index_url": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"is_url": ["http", "https"],
|
||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -258,44 +266,4 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"remote-pull": {
|
|
||||||
"type": "dict",
|
|
||||||
"schema": {
|
|
||||||
"target": {
|
|
||||||
"type": "list",
|
|
||||||
"coerce": "list",
|
|
||||||
"schema": {"type": "string"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"remote-push": {
|
|
||||||
"type": "dict",
|
|
||||||
"schema": {
|
|
||||||
"target": {
|
|
||||||
"type": "list",
|
|
||||||
"coerce": "list",
|
|
||||||
"schema": {"type": "string"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"report": {
|
|
||||||
"type": "dict",
|
|
||||||
"schema": {
|
|
||||||
"target": {
|
|
||||||
"type": "list",
|
|
||||||
"coerce": "list",
|
|
||||||
"schema": {"type": "string"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"upload": {
|
|
||||||
"type": "dict",
|
|
||||||
"schema": {
|
|
||||||
"target": {
|
|
||||||
"type": "list",
|
|
||||||
"coerce": "list",
|
|
||||||
"schema": {"type": "string"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,12 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
from cerberus import TypeDefinition, Validator as RootValidator # type: ignore
|
from cerberus import TypeDefinition, Validator as RootValidator # type: ignore
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, List
|
from typing import Any, List
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from ahriman.core.configuration import Configuration
|
from ahriman.core.configuration import Configuration
|
||||||
|
|
||||||
@ -29,7 +32,7 @@ class Validator(RootValidator): # type: ignore
|
|||||||
class which defines custom validation methods for the service configuration
|
class which defines custom validation methods for the service configuration
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
instance(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
types_mapping = RootValidator.types_mapping.copy()
|
types_mapping = RootValidator.types_mapping.copy()
|
||||||
@ -40,12 +43,12 @@ class Validator(RootValidator): # type: ignore
|
|||||||
default constructor
|
default constructor
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
instance(Configuration): configuration instance used for extraction
|
configuration(Configuration): configuration instance used for extraction
|
||||||
*args(Any): positional arguments to be passed to base validator
|
*args(Any): positional arguments to be passed to base validator
|
||||||
**kwargs(): keyword arguments to be passed to base validator
|
**kwargs(): keyword arguments to be passed to base validator
|
||||||
"""
|
"""
|
||||||
RootValidator.__init__(self, *args, **kwargs)
|
RootValidator.__init__(self, *args, **kwargs)
|
||||||
self.instance: Configuration = kwargs["instance"]
|
self.configuration: Configuration = kwargs["configuration"]
|
||||||
|
|
||||||
def _normalize_coerce_absolute_path(self, value: str) -> Path:
|
def _normalize_coerce_absolute_path(self, value: str) -> Path:
|
||||||
"""
|
"""
|
||||||
@ -57,7 +60,7 @@ class Validator(RootValidator): # type: ignore
|
|||||||
Returns:
|
Returns:
|
||||||
Path: value converted to path instance according to configuration rules
|
Path: value converted to path instance according to configuration rules
|
||||||
"""
|
"""
|
||||||
converted: Path = self.instance.converters["path"](value)
|
converted: Path = self.configuration.converters["path"](value)
|
||||||
return converted
|
return converted
|
||||||
|
|
||||||
def _normalize_coerce_boolean(self, value: str) -> bool:
|
def _normalize_coerce_boolean(self, value: str) -> bool:
|
||||||
@ -71,7 +74,7 @@ class Validator(RootValidator): # type: ignore
|
|||||||
bool: value converted to boolean according to configuration rules
|
bool: value converted to boolean according to configuration rules
|
||||||
"""
|
"""
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
converted: bool = self.instance._convert_to_boolean(value) # type: ignore
|
converted: bool = self.configuration._convert_to_boolean(value) # type: ignore
|
||||||
return converted
|
return converted
|
||||||
|
|
||||||
def _normalize_coerce_integer(self, value: str) -> int:
|
def _normalize_coerce_integer(self, value: str) -> int:
|
||||||
@ -97,9 +100,50 @@ class Validator(RootValidator): # type: ignore
|
|||||||
Returns:
|
Returns:
|
||||||
List[str]: value converted to string list instance according to configuration rules
|
List[str]: value converted to string list instance according to configuration rules
|
||||||
"""
|
"""
|
||||||
converted: List[str] = self.instance.converters["list"](value)
|
converted: List[str] = self.configuration.converters["list"](value)
|
||||||
return converted
|
return converted
|
||||||
|
|
||||||
|
def _validate_is_ip_address(self, constraint: List[str], field: str, value: str) -> None:
|
||||||
|
"""
|
||||||
|
check if the specified value is valid ip address
|
||||||
|
|
||||||
|
Args:
|
||||||
|
constraint(List[str]): optional list of allowed special words (e.g. ``localhost``)
|
||||||
|
field(str): field name to be checked
|
||||||
|
value(Path): value to be checked
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
The rule's arguments are validated against this schema:
|
||||||
|
{"type": "list", "schema": {"type": "string"}}
|
||||||
|
"""
|
||||||
|
if value in constraint:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(value)
|
||||||
|
except ValueError:
|
||||||
|
self._error(field, f"Value {value} must be valid IP address")
|
||||||
|
|
||||||
|
def _validate_is_url(self, constraint: List[str], field: str, value: str) -> None:
|
||||||
|
"""
|
||||||
|
check if the specified value is a valid url
|
||||||
|
|
||||||
|
Args:
|
||||||
|
constraint(List[str]): optional list of supported schemas. If empty, no schema validation will be performed
|
||||||
|
field(str): field name to be checked
|
||||||
|
value(str): value to be checked
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
The rule's arguments are validated against this schema:
|
||||||
|
{"type": "list", "schema": {"type": "string"}}
|
||||||
|
"""
|
||||||
|
url = urlparse(value) # it probably will never rise exceptions on parse
|
||||||
|
if not url.scheme:
|
||||||
|
self._error(field, f"Url scheme is not set for {value}")
|
||||||
|
if not url.netloc and url.scheme not in ("file",):
|
||||||
|
self._error(field, f"Location must be set for url {value} of scheme {url.scheme}")
|
||||||
|
if constraint and url.scheme not in constraint:
|
||||||
|
self._error(field, f"Url {value} scheme must be one of {constraint}")
|
||||||
|
|
||||||
def _validate_path_exists(self, constraint: bool, field: str, value: Path) -> None:
|
def _validate_path_exists(self, constraint: bool, field: str, value: Path) -> None:
|
||||||
"""
|
"""
|
||||||
check if paths exists
|
check if paths exists
|
||||||
|
@ -33,6 +33,16 @@ class RemotePullTrigger(Trigger):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
CONFIGURATION_SCHEMA = {
|
CONFIGURATION_SCHEMA = {
|
||||||
|
"remote-pull": {
|
||||||
|
"type": "dict",
|
||||||
|
"schema": {
|
||||||
|
"target": {
|
||||||
|
"type": "list",
|
||||||
|
"coerce": "list",
|
||||||
|
"schema": {"type": "string"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"gitremote": {
|
"gitremote": {
|
||||||
"type": "dict",
|
"type": "dict",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
@ -38,6 +38,16 @@ class RemotePushTrigger(Trigger):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
CONFIGURATION_SCHEMA = {
|
CONFIGURATION_SCHEMA = {
|
||||||
|
"remote-push": {
|
||||||
|
"type": "dict",
|
||||||
|
"schema": {
|
||||||
|
"target": {
|
||||||
|
"type": "list",
|
||||||
|
"coerce": "list",
|
||||||
|
"schema": {"type": "string"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"gitremote": {
|
"gitremote": {
|
||||||
"type": "dict",
|
"type": "dict",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
@ -35,6 +35,16 @@ class ReportTrigger(Trigger):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
CONFIGURATION_SCHEMA = {
|
CONFIGURATION_SCHEMA = {
|
||||||
|
"report": {
|
||||||
|
"type": "dict",
|
||||||
|
"schema": {
|
||||||
|
"target": {
|
||||||
|
"type": "list",
|
||||||
|
"coerce": "list",
|
||||||
|
"schema": {"type": "string"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"console": {
|
"console": {
|
||||||
"type": "dict",
|
"type": "dict",
|
||||||
"schema": {
|
"schema": {
|
||||||
@ -62,6 +72,7 @@ class ReportTrigger(Trigger):
|
|||||||
},
|
},
|
||||||
"homepage": {
|
"homepage": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"is_url": ["http", "https"],
|
||||||
},
|
},
|
||||||
"host": {
|
"host": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -70,6 +81,7 @@ class ReportTrigger(Trigger):
|
|||||||
"link_path": {
|
"link_path": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": True,
|
"required": True,
|
||||||
|
"is_url": [],
|
||||||
},
|
},
|
||||||
"no_empty_report": {
|
"no_empty_report": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -82,6 +94,8 @@ class ReportTrigger(Trigger):
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"coerce": "integer",
|
"coerce": "integer",
|
||||||
"required": True,
|
"required": True,
|
||||||
|
"min": 0,
|
||||||
|
"max": 65535,
|
||||||
},
|
},
|
||||||
"receivers": {
|
"receivers": {
|
||||||
"type": "list",
|
"type": "list",
|
||||||
@ -118,10 +132,12 @@ class ReportTrigger(Trigger):
|
|||||||
},
|
},
|
||||||
"homepage": {
|
"homepage": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"is_url": ["http", "https"],
|
||||||
},
|
},
|
||||||
"link_path": {
|
"link_path": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": True,
|
"required": True,
|
||||||
|
"is_url": [],
|
||||||
},
|
},
|
||||||
"path": {
|
"path": {
|
||||||
"type": "path",
|
"type": "path",
|
||||||
@ -153,10 +169,12 @@ class ReportTrigger(Trigger):
|
|||||||
},
|
},
|
||||||
"homepage": {
|
"homepage": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
"is_url": ["http", "https"],
|
||||||
},
|
},
|
||||||
"link_path": {
|
"link_path": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": True,
|
"required": True,
|
||||||
|
"is_url": [],
|
||||||
},
|
},
|
||||||
"template_path": {
|
"template_path": {
|
||||||
"type": "path",
|
"type": "path",
|
||||||
@ -171,6 +189,7 @@ class ReportTrigger(Trigger):
|
|||||||
"timeout": {
|
"timeout": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"coerce": "integer",
|
"coerce": "integer",
|
||||||
|
"min": 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -35,6 +35,16 @@ class UploadTrigger(Trigger):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
CONFIGURATION_SCHEMA = {
|
CONFIGURATION_SCHEMA = {
|
||||||
|
"upload": {
|
||||||
|
"type": "dict",
|
||||||
|
"schema": {
|
||||||
|
"target": {
|
||||||
|
"type": "list",
|
||||||
|
"coerce": "list",
|
||||||
|
"schema": {"type": "string"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"github": {
|
"github": {
|
||||||
"type": "dict",
|
"type": "dict",
|
||||||
"schema": {
|
"schema": {
|
||||||
@ -57,6 +67,7 @@ class UploadTrigger(Trigger):
|
|||||||
"timeout": {
|
"timeout": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"coerce": "integer",
|
"coerce": "integer",
|
||||||
|
"min": 0,
|
||||||
},
|
},
|
||||||
"username": {
|
"username": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -101,6 +112,7 @@ class UploadTrigger(Trigger):
|
|||||||
"chunk_size": {
|
"chunk_size": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"coerce": "integer",
|
"coerce": "integer",
|
||||||
|
"min": 0,
|
||||||
},
|
},
|
||||||
"region": {
|
"region": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -62,9 +62,11 @@ def test_schema(configuration: Configuration) -> None:
|
|||||||
assert schema.pop("email")
|
assert schema.pop("email")
|
||||||
assert schema.pop("github")
|
assert schema.pop("github")
|
||||||
assert schema.pop("html")
|
assert schema.pop("html")
|
||||||
|
assert schema.pop("report")
|
||||||
assert schema.pop("rsync")
|
assert schema.pop("rsync")
|
||||||
assert schema.pop("s3")
|
assert schema.pop("s3")
|
||||||
assert schema.pop("telegram")
|
assert schema.pop("telegram")
|
||||||
|
assert schema.pop("upload")
|
||||||
|
|
||||||
assert schema == CONFIGURATION_SCHEMA
|
assert schema == CONFIGURATION_SCHEMA
|
||||||
|
|
||||||
|
@ -16,4 +16,4 @@ def validator(configuration: Configuration) -> Validator:
|
|||||||
Returns:
|
Returns:
|
||||||
Validator: validator test instance
|
Validator: validator test instance
|
||||||
"""
|
"""
|
||||||
return Validator(instance=configuration, schema=CONFIGURATION_SCHEMA)
|
return Validator(configuration=configuration, schema=CONFIGURATION_SCHEMA)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock, call as MockCall
|
||||||
|
|
||||||
from ahriman.core.configuration.validator import Validator
|
from ahriman.core.configuration.validator import Validator
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ def test_normalize_coerce_absolute_path(validator: Validator) -> None:
|
|||||||
must convert string value to path by using configuration converters
|
must convert string value to path by using configuration converters
|
||||||
"""
|
"""
|
||||||
convert_mock = MagicMock()
|
convert_mock = MagicMock()
|
||||||
validator.instance.converters["path"] = convert_mock
|
validator.configuration.converters["path"] = convert_mock
|
||||||
|
|
||||||
validator._normalize_coerce_absolute_path("value")
|
validator._normalize_coerce_absolute_path("value")
|
||||||
convert_mock.assert_called_once_with("value")
|
convert_mock.assert_called_once_with("value")
|
||||||
@ -46,12 +46,56 @@ def test_normalize_coerce_list(validator: Validator) -> None:
|
|||||||
must convert string value to list by using configuration converters
|
must convert string value to list by using configuration converters
|
||||||
"""
|
"""
|
||||||
convert_mock = MagicMock()
|
convert_mock = MagicMock()
|
||||||
validator.instance.converters["list"] = convert_mock
|
validator.configuration.converters["list"] = convert_mock
|
||||||
|
|
||||||
validator._normalize_coerce_list("value")
|
validator._normalize_coerce_list("value")
|
||||||
convert_mock.assert_called_once_with("value")
|
convert_mock.assert_called_once_with("value")
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_is_ip_address(validator: Validator, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must validate addresses correctly
|
||||||
|
"""
|
||||||
|
error_mock = mocker.patch("ahriman.core.configuration.validator.Validator._error")
|
||||||
|
|
||||||
|
validator._validate_is_ip_address(["localhost"], "field", "localhost")
|
||||||
|
validator._validate_is_ip_address([], "field", "localhost")
|
||||||
|
|
||||||
|
validator._validate_is_ip_address([], "field", "127.0.0.1")
|
||||||
|
validator._validate_is_ip_address([], "field", "::")
|
||||||
|
validator._validate_is_ip_address([], "field", "0.0.0.0")
|
||||||
|
|
||||||
|
validator._validate_is_ip_address([], "field", "random string")
|
||||||
|
|
||||||
|
error_mock.assert_has_calls([
|
||||||
|
MockCall("field", "Value localhost must be valid IP address"),
|
||||||
|
MockCall("field", "Value random string must be valid IP address"),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_is_url(validator: Validator, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must validate url correctly
|
||||||
|
"""
|
||||||
|
error_mock = mocker.patch("ahriman.core.configuration.validator.Validator._error")
|
||||||
|
|
||||||
|
validator._validate_is_url([], "field", "http://example.com")
|
||||||
|
validator._validate_is_url([], "field", "https://example.com")
|
||||||
|
validator._validate_is_url([], "field", "file:///tmp")
|
||||||
|
|
||||||
|
validator._validate_is_url(["http", "https"], "field", "file:///tmp")
|
||||||
|
|
||||||
|
validator._validate_is_url([], "field", "http:///path")
|
||||||
|
|
||||||
|
validator._validate_is_url([], "field", "random string")
|
||||||
|
|
||||||
|
error_mock.assert_has_calls([
|
||||||
|
MockCall("field", "Url file:///tmp scheme must be one of ['http', 'https']"),
|
||||||
|
MockCall("field", "Location must be set for url http:///path of scheme http"),
|
||||||
|
MockCall("field", "Url scheme is not set for random string"),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
def test_validate_path_exists(validator: Validator, mocker: MockerFixture) -> None:
|
def test_validate_path_exists(validator: Validator, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
must validate that paths exists
|
must validate that paths exists
|
||||||
@ -67,4 +111,6 @@ def test_validate_path_exists(validator: Validator, mocker: MockerFixture) -> No
|
|||||||
mocker.patch("pathlib.Path.exists", return_value=True)
|
mocker.patch("pathlib.Path.exists", return_value=True)
|
||||||
validator._validate_path_exists(True, "field", Path("3"))
|
validator._validate_path_exists(True, "field", Path("3"))
|
||||||
|
|
||||||
error_mock.assert_called_once_with("field", "Path 2 must exist")
|
error_mock.assert_has_calls([
|
||||||
|
MockCall("field", "Path 2 must exist"),
|
||||||
|
])
|
||||||
|
Loading…
Reference in New Issue
Block a user