jenkins-job-builder/tests/conftest.py
Vsevolod Fedorov 67645a46eb Fix legacy plugin version comparison; Remove cap on setuptools version
LegacyVersion class is removed from newer setuptools package. But
support for legacy versions is added in python-jenkins 1.8.2.
Switch to that implementation.

Fix broken plugin version comparison for legacy versions.

Assume latest plugin version if no plugin version is found.

Story: 2010990
Story: 2009943
Story: 2009819
Story: 2010842
Task: 49236
Task: 44852
Task: 44396
Task: 48448

Change-Id: Id7f0be1c42357454bd9bedcdee3fefb174943d81
2023-12-19 12:10:43 +03:00

238 lines
7.2 KiB
Python

import configparser
import pkg_resources
import xml.etree.ElementTree as XML
from pathlib import Path
import pytest
import yaml
from jenkins.plugins import Plugin
from jenkins_jobs.alphanum import AlphanumSort
from jenkins_jobs.config import JJBConfig
from jenkins_jobs.loader import Loader
from jenkins_jobs.modules import project_externaljob
from jenkins_jobs.modules import project_flow
from jenkins_jobs.modules import project_githuborg
from jenkins_jobs.modules import project_matrix
from jenkins_jobs.modules import project_maven
from jenkins_jobs.modules import project_multibranch
from jenkins_jobs.modules import project_multijob
from jenkins_jobs.registry import ModuleRegistry
from jenkins_jobs.xml_config import XmlJob, XmlJobGenerator, XmlViewGenerator
from jenkins_jobs import utils
from jenkins_jobs.roots import Roots
from jenkins_jobs.loader import load_files
# Avoid writing to ~/.cache/jenkins_jobs.
@pytest.fixture(autouse=True)
def job_cache_mocked(mocker):
mocker.patch("jenkins_jobs.builder.JobCache", autospec=True)
@pytest.fixture
def config_path(scenario):
return scenario.config_path
@pytest.fixture
def jjb_config(config_path):
config = JJBConfig(config_path)
config.validate()
return config
@pytest.fixture
def mock_iter_entry_points():
config = configparser.ConfigParser()
config.read(Path(__file__).parent / "../setup.cfg")
groups = {}
for key in config["entry_points"]:
groups[key] = list()
for line in config["entry_points"][key].split("\n"):
if "" == line.strip():
continue
groups[key].append(
pkg_resources.EntryPoint.parse(line, dist=pkg_resources.Distribution())
)
def iter_entry_points(group, name=None):
return (entry for entry in groups[group] if name is None or name == entry.name)
return iter_entry_points
@pytest.fixture
def input(scenario, jjb_config):
loader = Loader.empty(jjb_config)
return loader.load_path(scenario.in_path)
@pytest.fixture
def plugins_info(scenario):
if not scenario.plugins_info_path.exists():
return None
plugin_dict_list = yaml.safe_load(scenario.plugins_info_path.read_text())
return [Plugin(**plugin_dict) for plugin_dict in plugin_dict_list]
@pytest.fixture
def registry(mocker, mock_iter_entry_points, jjb_config, plugins_info):
mocker.patch("pkg_resources.iter_entry_points", side_effect=mock_iter_entry_points)
return ModuleRegistry(jjb_config, plugins_info)
@pytest.fixture
def project(input, registry):
type_to_class = {
"maven": project_maven.Maven,
"matrix": project_matrix.Matrix,
"flow": project_flow.Flow,
"githuborg": project_githuborg.GithubOrganization,
"multijob": project_multijob.MultiJob,
"multibranch": project_multibranch.WorkflowMultiBranch,
"multibranch-defaults": project_multibranch.WorkflowMultiBranchDefaults,
"externaljob": project_externaljob.ExternalJob,
}
try:
class_name = input["project-type"]
except KeyError:
return None
if class_name == "freestyle":
return None
cls = type_to_class[class_name]
return cls(registry)
@pytest.fixture
def expected_output(scenario):
if not scenario.out_paths:
# Do not check output if there are no files for it.
return None
return "".join(path.read_text() for path in sorted(scenario.out_paths))
@pytest.fixture
def expected_error(scenario):
if scenario.error_path.exists():
return scenario.error_path.read_text().rstrip()
else:
return None
# Tests use output files directories as expected folder name.
def check_folders(scenario, job_xml_list):
root_dir = scenario.in_path.parent
def name_parent(name):
*dirs, name = name.split("/")
return "/".join(dirs)
def path_parent(path):
if scenario.in_path.is_dir():
# In directory tests, output file directory does not
# indicate expected job folder.
base_dir = scenario.in_path
else:
base_dir = root_dir
dir = str(path.relative_to(base_dir).parent)
if dir == ".":
return ""
else:
return dir
actual_dirs = list(sorted(set(name_parent(jx.name) for jx in job_xml_list)))
expected_dirs = list(sorted(path_parent(path) for path in scenario.out_paths))
assert expected_dirs == actual_dirs
@pytest.fixture
def check_generator(scenario, input, expected_output, jjb_config, registry, project):
def check(Generator):
if project:
xml = project.root_xml(input)
else:
xml = XML.Element("project")
generator = Generator(registry)
generator.gen_xml(xml, input)
pretty_xml = XmlJob(xml, "fixturejob").output().decode()
assert expected_output == pretty_xml
return check
@pytest.fixture
def check_parser(jjb_config, registry):
def check(in_path):
roots = Roots(jjb_config)
load_files(jjb_config, roots, [in_path])
registry.set_macros(roots.macros)
job_data_list = roots.generate_jobs()
view_data_list = roots.generate_views()
generator = XmlJobGenerator(registry)
_ = generator.generateXML(job_data_list)
_ = generator.generateXML(view_data_list)
return check
@pytest.fixture
def check_job(scenario, expected_output, jjb_config, registry):
def check():
roots = Roots(jjb_config)
if jjb_config.recursive:
path_list = [Path(p) for p in utils.recurse_path(str(scenario.in_path))]
else:
path_list = [scenario.in_path]
load_files(jjb_config, roots, path_list)
registry.set_macros(roots.macros)
job_data_list = roots.generate_jobs()
registry.amend_job_dicts(job_data_list)
generator = XmlJobGenerator(registry)
job_xml_list = generator.generateXML(job_data_list)
job_xml_list.sort(key=AlphanumSort)
pretty_xml = (
"\n".join(job.output().decode() for job in job_xml_list)
.strip()
.replace("\n\n", "\n")
)
if expected_output is None:
return
stripped_expected_output = (
expected_output.strip().replace("<BLANKLINE>", "").replace("\n\n", "\n")
)
assert stripped_expected_output == pretty_xml
check_folders(scenario, job_xml_list)
return check
@pytest.fixture
def check_view(scenario, expected_output, jjb_config, registry):
def check():
roots = Roots(jjb_config)
load_files(jjb_config, roots, [scenario.in_path])
registry.set_macros(roots.macros)
view_data_list = roots.generate_views()
generator = XmlViewGenerator(registry)
view_xml_list = generator.generateXML(view_data_list)
view_xml_list.sort(key=AlphanumSort)
pretty_xml = (
"\n".join(view.output().decode() for view in view_xml_list)
.strip()
.replace("\n\n", "\n")
)
if expected_output is None:
return
stripped_expected_output = (
expected_output.strip().replace("<BLANKLINE>", "").replace("\n\n", "\n")
)
assert stripped_expected_output == pretty_xml
return check