From 5f6d60898b0decca82239a41ae580bac2e3d66f8 Mon Sep 17 00:00:00 2001 From: Filip Valder Date: Nov 10 2021 10:35:25 +0000 Subject: Add module obsoletes tests --- diff --git a/obsoletes/.gitkeep b/obsoletes/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/obsoletes/.gitkeep diff --git a/tests/obsoletes/nodejs.yaml b/tests/obsoletes/nodejs.yaml new file mode 100644 index 0000000..1b849b3 --- /dev/null +++ b/tests/obsoletes/nodejs.yaml @@ -0,0 +1,10 @@ +document: modulemd-obsoletes +version: 1 +data: + modified: 2018-05-23T14:25Z + module: nodejs + stream: "11" + message: "Module stream nodejs:11 is no longer supported. It is recommended to switch to nodejs:12" + obsoleted_by: + module: nodejs + stream: "12" diff --git a/tests/validate.py b/tests/validate.py index e1cb943..ce4aa44 100755 --- a/tests/validate.py +++ b/tests/validate.py @@ -1,6 +1,5 @@ #!/usr/bin/python3 - import gi import git import os @@ -16,7 +15,7 @@ from gi.repository import Modulemd # noqa logging.getLogger().setLevel(logging.INFO) -def do_validate(filename): +def do_validate(filename, obsoletes=False): # Valid filenames must end in ".yaml" to be properly included by Pungi if not filename.endswith(".yaml"): error( @@ -49,11 +48,23 @@ def do_validate(filename): error("There must be exactly one module represented by this file") return False, None - # The files must have exactly one Modulemd.Defaults object + # The files must have exactly one Modulemd object module = idx.get_module(names[0]) - defaults = module.get_defaults() - if defaults is None: + if obsoletes: + mmds = module.get_obsoletes() + if not len(mmds) == 1: + error( + "There must be exactly one module obsoletes document for {}".format( + module.props.module_name + ) + ) + return False, None + mmd = mmds[0] + else: + mmd = module.get_defaults() + + if mmd is None: error( "No defaults document provided for {}".format( module.props.module_name @@ -69,21 +80,29 @@ def do_validate(filename): # Filenames must match their contents expected_name = os.path.basename(filename).rsplit(".", maxsplit=1)[0] - if expected_name != defaults.props.module_name: + if expected_name != mmd.props.module_name: error( 'Module name "{}" doesn\'t match filename "{}.yaml"'.format( - defaults.props.module_name, expected_name + mmd.props.module_name, expected_name ) ) return False, None - default_stream = defaults.get_default_stream() + if obsoletes: + is_valid = mmd.validate() + if is_valid: + info("{} obsoletes are valid".format(filename)) + else: + error("{} obsoletes are NOT valid".format(filename)) + return (mmd.validate(), mmd) + + default_stream = mmd.get_default_stream() if default_stream: # Default streams must also appear in the profiles list - if defaults.get_default_profiles_for_stream(default_stream) is None: + if mmd.get_default_profiles_for_stream(default_stream) is None: error( "Stream '{}' is missing from the profiles for '{}'".format( - default_stream, defaults.get_module_name() + default_stream, mmd.get_module_name() ) ) return False, None @@ -91,7 +110,7 @@ def do_validate(filename): # Modules in Fedora must not specify "Intents" # TODO: This needs a new interface exposed in libmodulemd v2 - info("{} is valid".format(filename)) + info("{} defaults are valid".format(filename)) return (True, idx) @@ -104,12 +123,23 @@ def main(): script_dir = os.path.dirname(os.path.realpath(__file__)) defaults_dir = os.path.abspath(os.path.join(script_dir, '..')) overrides_dir = os.path.join(defaults_dir, 'overrides') + #obsoletes_dir = os.path.abspath(os.path.join(defaults_dir, 'obsoletes')) + #obsoletes_tests_dir = os.path.abspath(os.path.join(script_dir, 'obsoletes')) # Get the repo we're running in repo = git.Repo(defaults_dir, search_parent_directories=True) # Get the list of files in this repository - files = [x for (x, y) in repo.index.entries.keys()] + defaults_files = list() + obsoletes_files = list() + obsoletes_test_files = list() + for (x, y) in repo.index.entries.keys(): + if x.startswith('obsoletes/'): + obsoletes_files.append(x) + elif x.startswith('tests/obsoletes/'): + obsoletes_test_files.append(x) + else: + defaults_files.append(x) # Get the list of excluded files exclusions = [] @@ -121,15 +151,24 @@ def main(): continue exclusions.append(line.strip()) - # Validate all of the files - for file in files: - excluded = False + # Validate module defaults files + for file in defaults_files: + for excl in exclusions: + if file.startswith(excl): + break + else: + (valid, _) = do_validate(file) + if not valid: + error("{} failed to validate".format(file)) + result = os.EX_DATAERR + + # Validate module obsoletes test files + for file in obsoletes_test_files: for excl in exclusions: if file.startswith(excl): - excluded = True break - if not excluded: - (valid, idx) = do_validate(file) + else: + (valid, _) = do_validate(file, obsoletes=True) if not valid: error("{} failed to validate".format(file)) result = os.EX_DATAERR @@ -141,9 +180,14 @@ def main(): # conflicts arise that weren't detected by the above tests. This should be # impossible. try: - idx = Modulemd.ModuleIndex() - idx.update_from_defaults_directory(path=defaults_dir, - strict=True) + idx_runtime = Modulemd.ModuleIndex() + idx_runtime.update_from_defaults_directory(path=defaults_dir, + strict=True) + # for obsoletes tests, because simple index copy is not possible + # due to: GObject descendants' instances are non-copyable + idx_tests = Modulemd.ModuleIndex() + idx_tests.update_from_defaults_directory(path=defaults_dir, + strict=True) except GLib.Error as e: error("Could not merge all defaults: {}".format(e.message)) result = os.EX_DATAERR @@ -153,14 +197,14 @@ def main(): print("\nDefault streams (Runtime):") print("================") - for m, s in idx.get_default_streams().items(): + for m, s in idx_runtime.get_default_streams().items(): print("{}:{}".format(m, s)) try: - idx = Modulemd.ModuleIndex() - idx.update_from_defaults_directory(path=defaults_dir, - overrides_path=overrides_dir, - strict=True) + idx_buildroot = Modulemd.ModuleIndex() + idx_buildroot.update_from_defaults_directory(path=defaults_dir, + overrides_path=overrides_dir, + strict=True) except GLib.Error as e: error("Could not merge all defaults: {}".format(e.message)) result = os.EX_DATAERR @@ -170,9 +214,51 @@ def main(): print("\nDefault streams (Buildroot):") print("================") - for m, s in idx.get_default_streams().items(): + for m, s in idx_buildroot.get_default_streams().items(): print("{}:{}".format(m, s)) + # Try merging TEST module obsoletes into the module defaults index. + for file in obsoletes_test_files: + for excl in exclusions: + if file.startswith(excl): + break + else: + (_, idx) = do_validate(file, obsoletes=True) + idx_tests.add_obsoletes(idx) + + print("\nObsoletes (tests):") + print("================") + for module_name in idx_tests.get_module_names(): + module = idx_tests.get_module(module_name) + obsoletes = module.get_obsoletes() + if not obsoletes: + continue + if len(obsoletes) > 1: + result = os.EX_DATAERR + break + print("{}:{}".format(module_name, obsoletes[0])) + + # Try merging module obsoletes into the module defaults index. + for file in obsoletes_files: + for excl in exclusions: + if file.startswith(excl): + break + else: + (_, idx) = do_validate(file, obsoletes=True) + idx_runtime.add_obsoletes(idx) + + print("\nObsoletes:") + print("================") + for module_name in idx_runtime.get_module_names(): + module = idx_runtime.get_module(module_name) + obsoletes = module.get_obsoletes() + if not obsoletes: + continue + if len(obsoletes) > 1: + result = os.EX_DATAERR + break + print("{}:{}".format(module_name, obsoletes[0])) + return result