ada8f4e346
This patch adds an additional field `options` to scm_dict, which can be used to provide additional information to the backends. It implements a single new option for GitWrapper. This option allows setting a custom git credentials wrapper. This can be useful if Pungi needs to get files from a git repository that requires authentication. The helper can be as simple as this (assuming the username is already provided in the url): #!/bin/sh echo password=i-am-secret The helper would need to be referenced by an absolute path from the pungi configuration, or prefixed with ! to have git interpret it as a shell script and look it up in PATH. See https://git-scm.com/docs/gitcredentials for more details. Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com> JIRA: RHELCMP-11808
545 lines
16 KiB
Python
545 lines
16 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
|
|
try:
|
|
import unittest2 as unittest
|
|
except ImportError:
|
|
import unittest
|
|
|
|
import six
|
|
import mock
|
|
|
|
from pungi import checks
|
|
from tests.helpers import load_config, PKGSET_REPOS
|
|
|
|
|
|
class ConfigTestCase(unittest.TestCase):
|
|
def assertValidation(self, cfg, errors=[], warnings=[]):
|
|
actual_errors, actual_warnings = checks.validate(cfg)
|
|
six.assertCountEqual(self, errors, actual_errors)
|
|
self.assertEqual(warnings, actual_warnings)
|
|
|
|
|
|
class PkgsetConfigTestCase(ConfigTestCase):
|
|
def test_validate_minimal_pkgset_koji(self):
|
|
cfg = load_config(
|
|
pkgset_source="koji",
|
|
)
|
|
|
|
self.assertValidation(cfg)
|
|
|
|
def test_validate_minimal_pkgset_repos(self):
|
|
cfg = load_config(
|
|
pkgset_source="repos",
|
|
pkgset_repos={"x86_64": "/first", "ppc64": "/second"},
|
|
)
|
|
|
|
self.assertValidation(cfg)
|
|
|
|
def test_pkgset_mismatch_repos(self):
|
|
cfg = load_config(
|
|
pkgset_source="repos",
|
|
pkgset_koji_tag="f25",
|
|
pkgset_koji_inherit=False,
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
[
|
|
checks.REQUIRES.format("pkgset_source", "repos", "pkgset_repos"),
|
|
checks.CONFLICTS.format("pkgset_source", "repos", "pkgset_koji_tag"),
|
|
checks.CONFLICTS.format(
|
|
"pkgset_source", "repos", "pkgset_koji_inherit"
|
|
),
|
|
],
|
|
)
|
|
|
|
def test_pkgset_mismatch_koji(self):
|
|
cfg = load_config(
|
|
pkgset_source="koji",
|
|
pkgset_repos={"whatever": "/foo"},
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg, [checks.CONFLICTS.format("pkgset_source", "koji", "pkgset_repos")]
|
|
)
|
|
|
|
def test_pkgset_multiple_koji_tags(self):
|
|
cfg = load_config(
|
|
pkgset_source="koji",
|
|
pkgset_koji_tag=["f25", "f25-extra"],
|
|
pkgset_koji_inherit=False,
|
|
)
|
|
self.assertValidation(cfg)
|
|
|
|
|
|
class ReleaseConfigTestCase(ConfigTestCase):
|
|
def test_set_release_is_layered(self):
|
|
cfg = load_config(PKGSET_REPOS, release_is_layered=True)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
warnings=[
|
|
"WARNING: Config option release_is_layered was removed and has no effect; remove it. It's layered if there's configuration for base product." # noqa: E501
|
|
],
|
|
)
|
|
|
|
def test_only_config_base_product_name(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
base_product_name="Prod",
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
[
|
|
checks.REQUIRES.format(
|
|
"base_product_name", "Prod", "base_product_short"
|
|
),
|
|
checks.REQUIRES.format(
|
|
"base_product_name", "Prod", "base_product_version"
|
|
),
|
|
checks.CONFLICTS.format(
|
|
"base_product_short", None, "base_product_name"
|
|
),
|
|
checks.CONFLICTS.format(
|
|
"base_product_version", None, "base_product_name"
|
|
),
|
|
],
|
|
)
|
|
|
|
def test_only_config_base_product_short(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
base_product_short="bp",
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
[
|
|
checks.REQUIRES.format("base_product_short", "bp", "base_product_name"),
|
|
checks.REQUIRES.format(
|
|
"base_product_short", "bp", "base_product_version"
|
|
),
|
|
checks.CONFLICTS.format(
|
|
"base_product_name", None, "base_product_short"
|
|
),
|
|
checks.CONFLICTS.format(
|
|
"base_product_version", None, "base_product_short"
|
|
),
|
|
],
|
|
)
|
|
|
|
def test_only_config_base_product_version(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
base_product_version="1.0",
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
[
|
|
checks.REQUIRES.format(
|
|
"base_product_version", "1.0", "base_product_name"
|
|
),
|
|
checks.REQUIRES.format(
|
|
"base_product_version", "1.0", "base_product_short"
|
|
),
|
|
checks.CONFLICTS.format(
|
|
"base_product_name", None, "base_product_version"
|
|
),
|
|
checks.CONFLICTS.format(
|
|
"base_product_short", None, "base_product_version"
|
|
),
|
|
],
|
|
)
|
|
|
|
|
|
class ImageNameConfigTestCase(ConfigTestCase):
|
|
def test_image_name_simple_string(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
image_name_format="foobar",
|
|
)
|
|
|
|
self.assertValidation(cfg, [])
|
|
|
|
def test_image_name_variant_mapping(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
image_name_format={"^Server$": "foobar"},
|
|
)
|
|
|
|
self.assertValidation(cfg, [])
|
|
|
|
|
|
class RunrootConfigTestCase(ConfigTestCase):
|
|
def test_set_runroot_true(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
runroot=True,
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
warnings=[
|
|
"WARNING: Config option runroot was removed and has no effect; remove it. Please specify 'runroot_method' if you want to enable runroot, otherwise run things locally." # noqa: E501
|
|
],
|
|
)
|
|
|
|
def test_set_runroot_false(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
runroot=False,
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
warnings=[
|
|
"WARNING: Config option runroot was removed and has no effect; remove it. Please specify 'runroot_method' if you want to enable runroot, otherwise run things locally." # noqa: E501
|
|
],
|
|
)
|
|
|
|
|
|
class BuildinstallConfigTestCase(ConfigTestCase):
|
|
def test_bootable_deprecated(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
bootable=True,
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
warnings=[
|
|
"WARNING: Config option bootable was removed and has no effect; remove it. Setting buildinstall_method option if you want a bootable installer." # noqa: E501
|
|
],
|
|
)
|
|
|
|
def test_buildinstall_method_without_bootable(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
buildinstall_method="lorax",
|
|
)
|
|
|
|
self.assertValidation(cfg, [])
|
|
|
|
def test_buildinstall_with_lorax_options(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
buildinstall_method="buildinstall",
|
|
lorax_options=[("^Server$", {})],
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
[
|
|
checks.CONFLICTS.format(
|
|
"buildinstall_method", "buildinstall", "lorax_options"
|
|
)
|
|
],
|
|
)
|
|
|
|
def test_lorax_with_lorax_options(self):
|
|
cfg = load_config(PKGSET_REPOS, buildinstall_method="lorax", lorax_options=[])
|
|
|
|
self.assertValidation(cfg)
|
|
|
|
def test_lorax_options_without_bootable_and_method(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
lorax_options=[("^Server$", {})],
|
|
buildinstall_kickstart="foo",
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
[
|
|
checks.CONFLICTS.format("buildinstall_method", "None", "lorax_options"),
|
|
checks.CONFLICTS.format(
|
|
"buildinstall_method", "None", "buildinstall_kickstart"
|
|
),
|
|
],
|
|
)
|
|
|
|
|
|
class CreaterepoConfigTestCase(ConfigTestCase):
|
|
def test_validate_minimal_pkgset_koji(self):
|
|
cfg = load_config(
|
|
pkgset_source="koji",
|
|
pkgset_koji_tag="f25",
|
|
product_id_allow_missing=True,
|
|
)
|
|
|
|
self.assertValidation(
|
|
cfg,
|
|
[checks.CONFLICTS.format("product_id", "None", "product_id_allow_missing")],
|
|
)
|
|
|
|
|
|
class GatherConfigTestCase(ConfigTestCase):
|
|
def test_dnf_backend_is_default_on_py3(self):
|
|
cfg = load_config(
|
|
pkgset_source="koji",
|
|
pkgset_koji_tag="f27",
|
|
)
|
|
|
|
with mock.patch("six.PY2", new=False):
|
|
self.assertValidation(cfg, [])
|
|
self.assertEqual(cfg["gather_backend"], "dnf")
|
|
|
|
def test_yum_backend_is_default_on_py2(self):
|
|
cfg = load_config(
|
|
pkgset_source="koji",
|
|
pkgset_koji_tag="f27",
|
|
)
|
|
|
|
with mock.patch("six.PY2", new=True):
|
|
self.assertValidation(cfg, [])
|
|
self.assertEqual(cfg["gather_backend"], "yum")
|
|
|
|
def test_yum_backend_is_rejected_on_py3(self):
|
|
cfg = load_config(
|
|
pkgset_source="koji",
|
|
pkgset_koji_tag="f27",
|
|
gather_backend="yum",
|
|
)
|
|
|
|
with mock.patch("six.PY2", new=False):
|
|
self.assertValidation(
|
|
cfg,
|
|
["Failed validation in gather_backend: 'yum' is not one of ['dnf']"],
|
|
)
|
|
|
|
|
|
class OSBSConfigTestCase(ConfigTestCase):
|
|
def test_validate(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
osbs={
|
|
"^Server$": {
|
|
"url": "http://example.com",
|
|
"target": "f25-build",
|
|
"git_branch": "f25",
|
|
}
|
|
},
|
|
)
|
|
|
|
self.assertValidation(cfg)
|
|
|
|
def test_validate_bad_conf(self):
|
|
cfg = load_config(PKGSET_REPOS, osbs="yes please")
|
|
|
|
self.assertNotEqual(checks.validate(cfg), ([], []))
|
|
|
|
|
|
class OstreeConfigTestCase(ConfigTestCase):
|
|
def test_validate(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
ostree=[
|
|
(
|
|
"^Atomic$",
|
|
{
|
|
"x86_64": {
|
|
"treefile": "fedora-atomic-docker-host.json",
|
|
"config_url": "https://git.fedorahosted.org/git/fedora-atomic.git", # noqa: E501
|
|
"repo": "Everything",
|
|
"ostree_repo": "/mnt/koji/compose/atomic/Rawhide/",
|
|
"version": "!OSTREE_VERSION_FROM_LABEL_DATE_TYPE_RESPIN",
|
|
}
|
|
},
|
|
)
|
|
],
|
|
)
|
|
|
|
self.assertValidation(cfg)
|
|
|
|
def test_validate_bad_conf(self):
|
|
cfg = load_config(PKGSET_REPOS, ostree="yes please")
|
|
|
|
self.assertNotEqual(checks.validate(cfg), ([], []))
|
|
|
|
|
|
class OstreeInstallerConfigTestCase(ConfigTestCase):
|
|
def test_validate(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
ostree_installer=[
|
|
(
|
|
"^Atomic$",
|
|
{
|
|
"x86_64": {
|
|
"repo": "Everything",
|
|
"release": None,
|
|
"installpkgs": ["fedora-productimg-atomic"],
|
|
"add_template": [
|
|
"/spin-kickstarts/atomic-installer/lorax-configure-repo.tmpl" # noqa: E501
|
|
],
|
|
"add_template_var": [
|
|
"ostree_osname=fedora-atomic",
|
|
"ostree_ref=fedora-atomic/Rawhide/x86_64/docker-host",
|
|
],
|
|
"add_arch_template": [
|
|
"/spin-kickstarts/atomic-installer/lorax-embed-repo.tmpl" # noqa: E501
|
|
],
|
|
"rootfs_size": "3",
|
|
"add_arch_template_var": [
|
|
"ostree_repo=https://kojipkgs.fedoraproject.org/compose/atomic/Rawhide/", # noqa: E501
|
|
"ostree_osname=fedora-atomic",
|
|
"ostree_ref=fedora-atomic/Rawhide/x86_64/docker-host",
|
|
],
|
|
}
|
|
},
|
|
)
|
|
],
|
|
)
|
|
|
|
self.assertValidation(cfg)
|
|
|
|
def test_validate_bad_conf(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
ostree_installer=[
|
|
(
|
|
"^Atomic$",
|
|
{
|
|
"x86_64": {
|
|
"repo": "Everything",
|
|
"release": None,
|
|
"installpkgs": ["fedora-productimg-atomic"],
|
|
"add_template": [
|
|
"/spin-kickstarts/atomic-installer/lorax-configure-repo.tmpl" # noqa: E501
|
|
],
|
|
"add_template_var": [
|
|
"ostree_osname=fedora-atomic",
|
|
"ostree_ref=fedora-atomic/Rawhide/x86_64/docker-host",
|
|
],
|
|
"add_arch_template": 15,
|
|
"add_arch_template_var": [
|
|
"ostree_repo=https://kojipkgs.fedoraproject.org/compose/atomic/Rawhide/", # noqa: E501
|
|
"ostree_osname=fedora-atomic",
|
|
"ostree_ref=fedora-atomic/Rawhide/x86_64/docker-host",
|
|
],
|
|
}
|
|
},
|
|
)
|
|
],
|
|
)
|
|
|
|
self.assertNotEqual(checks.validate(cfg), ([], []))
|
|
|
|
|
|
class LiveMediaConfigTestCase(ConfigTestCase):
|
|
@mock.patch("pungi.util.resolve_git_url")
|
|
def test_global_config_validation(self, resolve_git_url):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
live_media_ksurl="git://example.com/repo.git#HEAD",
|
|
live_media_target="f24",
|
|
live_media_release="RRR",
|
|
live_media_version="Rawhide",
|
|
)
|
|
|
|
resolve_git_url.side_effect = lambda x, _helper: x.replace("HEAD", "CAFE")
|
|
|
|
self.assertValidation(cfg)
|
|
self.assertEqual(cfg["live_media_ksurl"], "git://example.com/repo.git#CAFE")
|
|
|
|
def test_global_config_null_release(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
live_media_release=None,
|
|
)
|
|
|
|
self.assertValidation(cfg)
|
|
|
|
|
|
class TestSuggestions(ConfigTestCase):
|
|
def test_with_a_typo(self):
|
|
cfg = load_config(PKGSET_REPOS, product_pid=None)
|
|
|
|
self.assertValidation(
|
|
cfg, [], [checks.UNKNOWN_SUGGEST.format("product_pid", "product_id")]
|
|
)
|
|
|
|
|
|
class TestRegexValidation(ConfigTestCase):
|
|
def test_incorrect_regular_expression(self):
|
|
cfg = load_config(PKGSET_REPOS, multilib=[("^*$", {"*": []})])
|
|
|
|
msg = "Failed validation in multilib.0.0: incorrect regular expression: nothing to repeat" # noqa: E501
|
|
if six.PY3:
|
|
msg += " at position 1"
|
|
self.assertValidation(cfg, [msg], [])
|
|
|
|
|
|
class RepoclosureTestCase(ConfigTestCase):
|
|
def test_invalid_backend(self):
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
repoclosure_backend="fnd", # Intentionally with a typo
|
|
)
|
|
|
|
options = ["yum", "dnf"] if six.PY2 else ["dnf"]
|
|
self.assertValidation(
|
|
cfg,
|
|
[
|
|
"Failed validation in repoclosure_backend: 'fnd' is not one of %s"
|
|
% options
|
|
],
|
|
)
|
|
|
|
|
|
class VariantAsLookasideTestCase(ConfigTestCase):
|
|
def test_empty(self):
|
|
variant_as_lookaside = []
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
variant_as_lookaside=variant_as_lookaside,
|
|
)
|
|
self.assertValidation(cfg)
|
|
|
|
def test_basic(self):
|
|
variant_as_lookaside = [
|
|
("Client", "Base"),
|
|
("Server", "Client"),
|
|
("Everything", "Spin"),
|
|
]
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
variant_as_lookaside=variant_as_lookaside,
|
|
)
|
|
self.assertValidation(cfg)
|
|
|
|
|
|
class SkipPhasesTestCase(ConfigTestCase):
|
|
def test_empty(self):
|
|
skip_phases = []
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
skip_phases=skip_phases,
|
|
)
|
|
self.assertValidation(cfg)
|
|
|
|
def test_basic(self):
|
|
skip_phases = [
|
|
"buildinstall",
|
|
"gather",
|
|
]
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
skip_phases=skip_phases,
|
|
)
|
|
self.assertValidation(cfg)
|
|
|
|
def test_bad_phase_name(self):
|
|
skip_phases = [
|
|
"gather",
|
|
"non-existing-phase_name",
|
|
]
|
|
cfg = load_config(
|
|
PKGSET_REPOS,
|
|
skip_phases=skip_phases,
|
|
)
|
|
self.assertNotEqual(checks.validate(cfg), ([], []))
|