diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 19:54:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 19:58:39 +0000 |
commit | 129a1fb4dbc375be0fa926964aa1be46a0cdbbef (patch) | |
tree | 04c0088df47415b24a5be1325d3656b8c3881c04 /tests/test_plugin_tester.py | |
parent | Initial commit. (diff) | |
download | debputy-129a1fb4dbc375be0fa926964aa1be46a0cdbbef.tar.xz debputy-129a1fb4dbc375be0fa926964aa1be46a0cdbbef.zip |
Adding upstream version 0.1.21.upstream/0.1.21
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/test_plugin_tester.py')
-rw-r--r-- | tests/test_plugin_tester.py | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/tests/test_plugin_tester.py b/tests/test_plugin_tester.py new file mode 100644 index 0000000..8078a02 --- /dev/null +++ b/tests/test_plugin_tester.py @@ -0,0 +1,285 @@ +import json +import os.path +from typing import List, Tuple, Type, cast + +import pytest + +from debputy.exceptions import DebputyFSIsROError +from debputy.plugin.api import ( + DebputyPluginInitializer, + BinaryCtrlAccessor, + PackageProcessingContext, + VirtualPath, + virtual_path_def, +) +from debputy.exceptions import PluginConflictError, PluginAPIViolationError +from debputy.plugin.api.impl import DebputyPluginInitializerProvider +from debputy.plugin.api.impl_types import automatic_discard_rule_example +from debputy.plugin.api.test_api import ( + build_virtual_file_system, + package_metadata_context, + initialize_plugin_under_test, +) +from debputy.plugin.api.test_api.test_impl import ( + initialize_plugin_under_test_preloaded, + initialize_plugin_under_test_from_inline_json, +) + +CUSTOM_PLUGIN_JSON_FILE = os.path.join( + os.path.dirname(__file__), "data", "custom-plugin.json.in" +) + + +def bad_metadata_detector_fs_rw( + path: VirtualPath, + _ctrl: BinaryCtrlAccessor, + _context: PackageProcessingContext, +) -> None: + del path["foo"] + + +def conflicting_plugin(api: DebputyPluginInitializer) -> None: + api.packager_provided_file( + "logrotate", + "/some/where/that/is/not/etc/logrotate.d/{name}", + ) + + +def bad_plugin(api: DebputyPluginInitializer) -> None: + api.metadata_or_maintscript_detector("fs_rw", bad_metadata_detector_fs_rw) + + +def adr_inconsistent_example_plugin(api: DebputyPluginInitializerProvider) -> None: + api.automatic_discard_rule( + "adr-example-test", + lambda p: p.name == "discard-me", + examples=automatic_discard_rule_example( + "foo/discard-me", + ("bar/discard-me", False), + "baz/something", + ("discard-me/foo", False), + ), + ) + + +def test_conflict_with_debputy(): + with pytest.raises(PluginConflictError) as e_info: + initialize_plugin_under_test_preloaded( + 1, + conflicting_plugin, + plugin_name="conflicting-plugin", + ) + message = ( + 'The stem "logrotate" is registered twice for packager provided files.' + " Once by debputy and once by conflicting-plugin" + ) + assert message == e_info.value.args[0] + + +def test_metadata_read_only(): + plugin = initialize_plugin_under_test_preloaded( + 1, + bad_plugin, + plugin_name="bad-plugin", + ) + fs = build_virtual_file_system(["./foo"]) + with pytest.raises(PluginAPIViolationError) as e_info: + plugin.run_metadata_detector("fs_rw", fs) + + assert isinstance(e_info.value.__cause__, DebputyFSIsROError) + + +def test_packager_provided_files(): + plugin = initialize_plugin_under_test(plugin_desc_file=CUSTOM_PLUGIN_JSON_FILE) + assert plugin.packager_provided_files_by_stem().keys() == { + "my-file", + "test-file-from-json", + } + my_file = [p for p in plugin.packager_provided_files() if p.stem == "my-file"][0] + + assert my_file.stem == "my-file" + assert my_file.compute_dest("g++-3.1")[1] == "g__-3.1.conf" + + +def test_path_checks(): + symlink_path = "./foo" + with pytest.raises(ValueError) as e_info: + virtual_path_def(symlink_path, link_target="/bar", mode=0o0755) + assert ( + e_info.value.args[0] + == f'Please do not provide mode for symlinks. Triggered by "{symlink_path}"' + ) + with pytest.raises(ValueError) as e_info: + virtual_path_def(symlink_path + "/", link_target="/bar") + msg = ( + "Path name looks like a directory, but a symlink target was also provided." + f' Please remove the trailing slash OR the symlink_target. Triggered by "{symlink_path}/"' + ) + assert e_info.value.args[0] == msg + + +def test_metadata_detector_applies_to_check(): + plugin_name = "custom-plugin" + metadata_detector_id = "udeb-only" + plugin = initialize_plugin_under_test(plugin_desc_file=CUSTOM_PLUGIN_JSON_FILE) + with pytest.raises(ValueError) as e_info: + plugin.run_metadata_detector( + metadata_detector_id, + build_virtual_file_system(["./usr/share/doc/foo/copyright"]), + ) + msg = f'The detector "{metadata_detector_id}" from {plugin_name} does not apply to the given package.' + assert e_info.value.args[0].startswith(msg) + + metadata = plugin.run_metadata_detector( + metadata_detector_id, + build_virtual_file_system(["./usr/share/doc/foo/copyright"]), + context=package_metadata_context(package_fields={"Package-Type": "udeb"}), + ) + assert metadata.substvars["Test:Udeb-Metadata-Detector"] == "was-run" + + +@pytest.mark.parametrize( + "variables,exec_type", + [ + ( + [("DEBPUTY_VAR", "RESERVED")], + ValueError, + ), + ( + [("_DEBPUTY_VAR", "RESERVED")], + ValueError, + ), + ( + [("_FOO", "RESERVED")], + ValueError, + ), + ( + [("path:_var", "RESERVED")], + ValueError, + ), + ( + [("path:DEBPUTY_VAR", "RESERVED")], + ValueError, + ), + ( + [("DEB_VAR", "RESERVED")], + ValueError, + ), + ( + [("DPKG_VAR", "RESERVED")], + ValueError, + ), + ( + [("PACKAGE", "RESERVED")], + ValueError, + ), + ( + [("foo:var", "RESERVED")], + ValueError, + ), + ( + [("env:var", "RESERVED")], + ValueError, + ), + ( + [("SOURCE_DATE_EPOCH", "RESERVED")], + ValueError, + ), + ( + [("!MY_VAR", "INVALID_NAME")], + ValueError, + ), + ( + [("VALUE_DEPENDS_ON_VAR", "{{UNKNOWN_VAR}}")], + ValueError, + ), + ( + [("VALUE_DEPENDS_ON_VAR", "{{DEB_HOST_ARCH}}")], + ValueError, + ), + ( + [("DEFINED_TWICE", "ONCE"), ("DEFINED_TWICE", "TWICE")], + PluginConflictError, + ), + ], +) +def test_invalid_manifest_variables( + variables: List[Tuple[str, str]], + exec_type: Type[Exception], +) -> None: + def _initializer(api: DebputyPluginInitializer): + with pytest.raises(exec_type): + for varname, value in variables: + api.manifest_variable(varname, value) + + initialize_plugin_under_test_preloaded( + 1, + _initializer, + plugin_name="test-plugin", + load_debputy_plugin=False, + ) + + +def test_valid_manifest_variables() -> None: + variables = { + "PLUGIN_VAR": "TEST VALUE", + "ANOTHER_PLUGIN_VAR": "ANOTHER VALUE", + "path:SOMEWHERE_DIR": "/usr/share/some-where", + } + + def _initializer(api: DebputyPluginInitializer): + for k, v in variables.items(): + api.manifest_variable(k, v) + + plugin = initialize_plugin_under_test_preloaded( + 1, + _initializer, + plugin_name="test-plugin", + load_debputy_plugin=False, + ) + + assert plugin.declared_manifest_variables == variables.keys() + + +def test_valid_manifest_variables_json() -> None: + variables = { + "PLUGIN_VAR": "TEST VALUE", + "ANOTHER_PLUGIN_VAR": "ANOTHER VALUE", + "path:SOMEWHERE_DIR": "/usr/share/some-where", + } + content = { + "api-compat-version": 1, + "manifest-variables": [ + { + "name": k, + "value": v, + } + for k, v in variables.items() + ], + } + plugin = initialize_plugin_under_test_from_inline_json( + "test-plugin", + json.dumps(content), + ) + assert plugin.declared_manifest_variables == variables.keys() + + +def test_automatic_discard_rules_example() -> None: + plugin = initialize_plugin_under_test_preloaded( + 1, + # Internal API used + cast("PluginInitializationEntryPoint", adr_inconsistent_example_plugin), + # API is restricted + plugin_name="debputy", + load_debputy_plugin=False, + ) + issues = plugin.automatic_discard_rules_examples_with_issues() + assert len(issues) == 1 + issue = issues[0] + assert issue.name == "adr-example-test" + assert issue.example_index == 0 + assert set(issue.inconsistent_paths) == { + "/discard-me/foo", + "/bar/discard-me", + "/baz/something", + } |