mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-06-28 06:41:43 +00:00
expose trigger configuration schema
Note that this commit contains the following breaking changes: * remote pull and remote push triggers are now enabled by default (with empty target list) * remote pull and remote push triggers now require target option to be set (old behaviour had fallback on `gitremote`) * validation is now considered to be stable, so it is enabled by default in docker image (can be disabled however)
This commit is contained in:
@ -5,8 +5,9 @@ from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.application.handlers import Validate
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.configuration.schema import CONFIGURATION_SCHEMA, GITREMOTE_REMOTE_PULL_SCHEMA
|
||||
from ahriman.core.configuration.schema import CONFIGURATION_SCHEMA
|
||||
from ahriman.core.configuration.validator import Validator
|
||||
from ahriman.core.gitremote import RemotePullTrigger, RemotePushTrigger
|
||||
|
||||
|
||||
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
|
||||
@ -60,7 +61,6 @@ def test_schema(configuration: Configuration) -> None:
|
||||
assert schema.pop("console")
|
||||
assert schema.pop("email")
|
||||
assert schema.pop("github")
|
||||
assert schema.pop("gitremote")
|
||||
assert schema.pop("html")
|
||||
assert schema.pop("rsync")
|
||||
assert schema.pop("s3")
|
||||
@ -69,6 +69,14 @@ def test_schema(configuration: Configuration) -> None:
|
||||
assert schema == CONFIGURATION_SCHEMA
|
||||
|
||||
|
||||
def test_schema_invalid_trigger(configuration: Configuration) -> None:
|
||||
"""
|
||||
must skip trigger if it caused exception on load
|
||||
"""
|
||||
configuration.set_option("build", "triggers", "some.invalid.trigger.path.Trigger")
|
||||
assert Validate.schema("x86_64", configuration) == CONFIGURATION_SCHEMA
|
||||
|
||||
|
||||
def test_schema_erase_required() -> None:
|
||||
"""
|
||||
must remove required field from dictionaries recursively
|
||||
@ -77,24 +85,18 @@ def test_schema_erase_required() -> None:
|
||||
assert "required" not in json.dumps(Validate.schema_erase_required(CONFIGURATION_SCHEMA))
|
||||
|
||||
|
||||
def test_schema_insert(configuration: Configuration) -> None:
|
||||
def test_schema_merge() -> None:
|
||||
"""
|
||||
must insert child schema to root
|
||||
must merge schemas correctly
|
||||
"""
|
||||
result = Validate.schema_insert("x86_64", configuration, CONFIGURATION_SCHEMA, "remote-pull",
|
||||
lambda _: GITREMOTE_REMOTE_PULL_SCHEMA)
|
||||
assert result["gitremote"] == GITREMOTE_REMOTE_PULL_SCHEMA
|
||||
erased = Validate.schema_erase_required(CONFIGURATION_SCHEMA)
|
||||
assert Validate.schema_merge(erased, CONFIGURATION_SCHEMA) == CONFIGURATION_SCHEMA
|
||||
|
||||
|
||||
def test_schema_insert_skip(configuration: Configuration) -> None:
|
||||
"""
|
||||
must do nothing in case if there is no such section or option
|
||||
"""
|
||||
configuration.remove_section("remote-pull")
|
||||
|
||||
result = Validate.schema_insert("x86_64", configuration, CONFIGURATION_SCHEMA, "remote-pull",
|
||||
lambda _: GITREMOTE_REMOTE_PULL_SCHEMA)
|
||||
assert result == CONFIGURATION_SCHEMA
|
||||
merged = Validate.schema_merge(RemotePullTrigger.CONFIGURATION_SCHEMA, RemotePushTrigger.CONFIGURATION_SCHEMA)
|
||||
for key in RemotePullTrigger.CONFIGURATION_SCHEMA["gitremote"]["schema"]:
|
||||
assert key in merged["gitremote"]["schema"]
|
||||
for key in RemotePushTrigger.CONFIGURATION_SCHEMA["gitremote"]["schema"]:
|
||||
assert key in merged["gitremote"]["schema"]
|
||||
|
||||
|
||||
def test_disallow_auto_architecture_run() -> None:
|
||||
|
@ -207,6 +207,15 @@ def test_gettype(configuration: Configuration) -> None:
|
||||
assert provider == "s3"
|
||||
|
||||
|
||||
def test_gettype_with_fallback(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return same provider name as in fallback
|
||||
"""
|
||||
section, provider = configuration.gettype("rsync", "x86_64", fallback="abracadabra")
|
||||
assert section == "rsync"
|
||||
assert provider == "abracadabra"
|
||||
|
||||
|
||||
def test_gettype_from_section(configuration: Configuration) -> None:
|
||||
"""
|
||||
must extract type from section name
|
||||
|
@ -4,6 +4,17 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.gitremote import RemotePullTrigger
|
||||
|
||||
|
||||
def test_configuration_sections(configuration: Configuration) -> None:
|
||||
"""
|
||||
must correctly parse target list
|
||||
"""
|
||||
configuration.set_option("remote-pull", "target", "a b c")
|
||||
assert RemotePullTrigger.configuration_sections(configuration) == ["a", "b", "c"]
|
||||
|
||||
configuration.remove_option("remote-pull", "target")
|
||||
assert RemotePullTrigger.configuration_sections(configuration) == []
|
||||
|
||||
|
||||
def test_on_start(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must clone repo on start
|
||||
|
@ -8,6 +8,17 @@ from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_configuration_sections(configuration: Configuration) -> None:
|
||||
"""
|
||||
must correctly parse target list
|
||||
"""
|
||||
configuration.set_option("remote-push", "target", "a b c")
|
||||
assert RemotePushTrigger.configuration_sections(configuration) == ["a", "b", "c"]
|
||||
|
||||
configuration.remove_option("remote-push", "target")
|
||||
assert RemotePushTrigger.configuration_sections(configuration) == []
|
||||
|
||||
|
||||
def test_on_result(configuration: Configuration, result: Result, package_ahriman: Package,
|
||||
database: SQLite, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
|
@ -5,6 +5,17 @@ from ahriman.core.report import ReportTrigger
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_configuration_sections(configuration: Configuration) -> None:
|
||||
"""
|
||||
must correctly parse target list
|
||||
"""
|
||||
configuration.set_option("report", "target", "a b c")
|
||||
assert ReportTrigger.configuration_sections(configuration) == ["a", "b", "c"]
|
||||
|
||||
configuration.remove_option("report", "target")
|
||||
assert ReportTrigger.configuration_sections(configuration) == []
|
||||
|
||||
|
||||
def test_on_result(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run report for specified targets
|
||||
|
@ -28,4 +28,4 @@ def trigger_loader(configuration: Configuration) -> TriggerLoader:
|
||||
Returns:
|
||||
TriggerLoader: trigger loader test instance
|
||||
"""
|
||||
return TriggerLoader("x86_64", configuration)
|
||||
return TriggerLoader.load("x86_64", configuration)
|
||||
|
@ -1,9 +1,64 @@
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.report import ReportTrigger
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_configuration_schema(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return used configuration schema
|
||||
"""
|
||||
section = "console"
|
||||
configuration.set_option("report", "target", section)
|
||||
|
||||
expected = {section: ReportTrigger.CONFIGURATION_SCHEMA[section]}
|
||||
assert ReportTrigger.configuration_schema("x86_64", configuration) == expected
|
||||
|
||||
|
||||
def test_configuration_schema_no_section(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return nothing in case if section doesn't exist
|
||||
"""
|
||||
section = "abracadabra"
|
||||
configuration.set_option("report", "target", section)
|
||||
assert ReportTrigger.configuration_schema("x86_64", configuration) == {}
|
||||
|
||||
|
||||
def test_configuration_schema_no_schema(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return nothing in case if schema doesn't exist
|
||||
"""
|
||||
section = "abracadabra"
|
||||
configuration.set_option("report", "target", section)
|
||||
configuration.set_option(section, "key", "value")
|
||||
|
||||
assert ReportTrigger.configuration_schema("x86_64", configuration) == {}
|
||||
|
||||
|
||||
def test_configuration_schema_empty() -> None:
|
||||
"""
|
||||
must return default schema if no configuration set
|
||||
"""
|
||||
assert ReportTrigger.configuration_schema("x86_64", None) == ReportTrigger.CONFIGURATION_SCHEMA
|
||||
|
||||
|
||||
def test_configuration_schema_variables(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return empty schema
|
||||
"""
|
||||
assert Trigger.CONFIGURATION_SCHEMA == {}
|
||||
assert Trigger.CONFIGURATION_SCHEMA_FALLBACK is None
|
||||
|
||||
|
||||
def test_configuration_sections(configuration: Configuration) -> None:
|
||||
"""
|
||||
must return empty section list
|
||||
"""
|
||||
assert Trigger.configuration_sections(configuration) == []
|
||||
|
||||
|
||||
def test_on_result(trigger: Trigger) -> None:
|
||||
"""
|
||||
must pass execution nto run method
|
||||
|
@ -5,75 +5,97 @@ from pytest_mock import MockerFixture
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import ExtensionError
|
||||
from ahriman.core.report import ReportTrigger
|
||||
from ahriman.core.triggers import TriggerLoader
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_load_trigger_package(trigger_loader: TriggerLoader) -> None:
|
||||
def test_selected_triggers(configuration: Configuration) -> None:
|
||||
"""
|
||||
must load trigger from package
|
||||
must return used triggers
|
||||
"""
|
||||
assert trigger_loader.load_trigger("ahriman.core.report.ReportTrigger")
|
||||
configuration.set_option("build", "triggers", "a b c")
|
||||
assert TriggerLoader.selected_triggers(configuration) == ["a", "b", "c"]
|
||||
|
||||
configuration.remove_option("build", "triggers")
|
||||
assert TriggerLoader.selected_triggers(configuration) == []
|
||||
|
||||
|
||||
def test_load_trigger_package_invalid_import(trigger_loader: TriggerLoader, mocker: MockerFixture) -> None:
|
||||
def test_load_trigger(trigger_loader: TriggerLoader, configuration: Configuration) -> None:
|
||||
"""
|
||||
must raise InvalidExtension on invalid import
|
||||
must load trigger
|
||||
"""
|
||||
mocker.patch("ahriman.core.triggers.trigger_loader.importlib.import_module", side_effect=ModuleNotFoundError())
|
||||
with pytest.raises(ExtensionError):
|
||||
trigger_loader.load_trigger("random.module")
|
||||
loaded = trigger_loader.load_trigger("ahriman.core.report.ReportTrigger", "x86_64", configuration)
|
||||
assert loaded
|
||||
assert isinstance(loaded, ReportTrigger)
|
||||
|
||||
|
||||
def test_load_trigger_package_not_trigger(trigger_loader: TriggerLoader) -> None:
|
||||
"""
|
||||
must raise InvalidExtension if imported module is not a type
|
||||
"""
|
||||
with pytest.raises(ExtensionError):
|
||||
trigger_loader.load_trigger("ahriman.core.util.check_output")
|
||||
|
||||
|
||||
def test_load_trigger_package_error_on_creation(trigger_loader: TriggerLoader, mocker: MockerFixture) -> None:
|
||||
def test_load_trigger_package_error_on_creation(trigger_loader: TriggerLoader, configuration: Configuration,
|
||||
mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise InvalidException on trigger initialization if any exception is thrown
|
||||
"""
|
||||
mocker.patch("ahriman.core.triggers.trigger.Trigger.__init__", side_effect=Exception())
|
||||
with pytest.raises(ExtensionError):
|
||||
trigger_loader.load_trigger("ahriman.core.report.ReportTrigger")
|
||||
trigger_loader.load_trigger("ahriman.core.report.ReportTrigger", "x86_64", configuration)
|
||||
|
||||
|
||||
def test_load_trigger_package_is_not_trigger(trigger_loader: TriggerLoader) -> None:
|
||||
def test_load_trigger_class_package(trigger_loader: TriggerLoader) -> None:
|
||||
"""
|
||||
must load trigger class from package
|
||||
"""
|
||||
assert trigger_loader.load_trigger_class("ahriman.core.report.ReportTrigger") == ReportTrigger
|
||||
|
||||
|
||||
def test_load_trigger_class_package_invalid_import(trigger_loader: TriggerLoader, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must raise InvalidExtension on invalid import
|
||||
"""
|
||||
mocker.patch("ahriman.core.triggers.trigger_loader.importlib.import_module", side_effect=ModuleNotFoundError())
|
||||
with pytest.raises(ExtensionError):
|
||||
trigger_loader.load_trigger_class("random.module")
|
||||
|
||||
|
||||
def test_load_trigger_class_package_not_trigger(trigger_loader: TriggerLoader) -> None:
|
||||
"""
|
||||
must raise InvalidExtension if imported module is not a type
|
||||
"""
|
||||
with pytest.raises(ExtensionError):
|
||||
trigger_loader.load_trigger_class("ahriman.core.util.check_output")
|
||||
|
||||
|
||||
def test_load_trigger_class_package_is_not_trigger(trigger_loader: TriggerLoader) -> None:
|
||||
"""
|
||||
must raise InvalidExtension if loaded class is not a trigger
|
||||
"""
|
||||
with pytest.raises(ExtensionError):
|
||||
trigger_loader.load_trigger("ahriman.core.sign.gpg.GPG")
|
||||
trigger_loader.load_trigger_class("ahriman.core.sign.gpg.GPG")
|
||||
|
||||
|
||||
def test_load_trigger_path(trigger_loader: TriggerLoader, resource_path_root: Path) -> None:
|
||||
def test_load_trigger_class_path(trigger_loader: TriggerLoader, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must load trigger from path
|
||||
must load trigger class from path
|
||||
"""
|
||||
path = resource_path_root.parent.parent / "src" / "ahriman" / "core" / "report" / "report_trigger.py"
|
||||
assert trigger_loader.load_trigger(f"{path}.ReportTrigger")
|
||||
path = resource_path_root.parent.parent / "src" / "ahriman" / "core" / "report" / "__init__.py"
|
||||
assert trigger_loader.load_trigger_class(f"{path}.ReportTrigger") == ReportTrigger
|
||||
|
||||
|
||||
def test_load_trigger_path_directory(trigger_loader: TriggerLoader, resource_path_root: Path) -> None:
|
||||
def test_load_trigger_class_path_directory(trigger_loader: TriggerLoader, resource_path_root: Path) -> None:
|
||||
"""
|
||||
must raise InvalidExtension if provided import path is directory
|
||||
"""
|
||||
path = resource_path_root.parent.parent / "src" / "ahriman" / "core" / "report"
|
||||
with pytest.raises(ExtensionError):
|
||||
trigger_loader.load_trigger(f"{path}.ReportTrigger")
|
||||
trigger_loader.load_trigger_class(f"{path}.ReportTrigger")
|
||||
|
||||
|
||||
def test_load_trigger_path_not_found(trigger_loader: TriggerLoader) -> None:
|
||||
def test_load_trigger_class_path_not_found(trigger_loader: TriggerLoader) -> None:
|
||||
"""
|
||||
must raise InvalidExtension if file cannot be found
|
||||
"""
|
||||
with pytest.raises(ExtensionError):
|
||||
trigger_loader.load_trigger("/some/random/path.py.SomeRandomModule")
|
||||
trigger_loader.load_trigger_class("/some/random/path.py.SomeRandomModule")
|
||||
|
||||
|
||||
def test_on_result(trigger_loader: TriggerLoader, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
@ -119,9 +141,11 @@ def test_on_stop_with_on_start(configuration: Configuration, mocker: MockerFixtu
|
||||
"""
|
||||
must call on_stop on exit if on_start was called
|
||||
"""
|
||||
mocker.patch("ahriman.core.upload.UploadTrigger.on_start")
|
||||
mocker.patch("ahriman.core.report.ReportTrigger.on_start")
|
||||
on_stop_mock = mocker.patch("ahriman.core.triggers.trigger_loader.TriggerLoader.on_stop")
|
||||
|
||||
trigger_loader = TriggerLoader("x86_64", configuration)
|
||||
trigger_loader = TriggerLoader.load("x86_64", configuration)
|
||||
trigger_loader.on_start()
|
||||
del trigger_loader
|
||||
on_stop_mock.assert_called_once_with()
|
||||
@ -133,7 +157,7 @@ def test_on_stop_without_on_start(configuration: Configuration, mocker: MockerFi
|
||||
"""
|
||||
on_stop_mock = mocker.patch("ahriman.core.triggers.trigger_loader.TriggerLoader.on_stop")
|
||||
|
||||
trigger_loader = TriggerLoader("x86_64", configuration)
|
||||
trigger_loader = TriggerLoader.load("x86_64", configuration)
|
||||
del trigger_loader
|
||||
on_stop_mock.assert_not_called()
|
||||
|
||||
|
@ -5,6 +5,17 @@ from ahriman.core.upload import UploadTrigger
|
||||
from ahriman.models.result import Result
|
||||
|
||||
|
||||
def test_configuration_sections(configuration: Configuration) -> None:
|
||||
"""
|
||||
must correctly parse target list
|
||||
"""
|
||||
configuration.set_option("upload", "target", "a b c")
|
||||
assert UploadTrigger.configuration_sections(configuration) == ["a", "b", "c"]
|
||||
|
||||
configuration.remove_option("upload", "target")
|
||||
assert UploadTrigger.configuration_sections(configuration) == []
|
||||
|
||||
|
||||
def test_on_result(configuration: Configuration, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must run report for specified targets
|
||||
|
@ -45,7 +45,7 @@ push_url = https://github.com/arcan1s/repository.git
|
||||
pull_url = https://github.com/arcan1s/repository.git
|
||||
|
||||
[report]
|
||||
target =
|
||||
target = console
|
||||
|
||||
[email]
|
||||
host = 127.0.0.1
|
||||
|
Reference in New Issue
Block a user