Files
fm-orchestrator/tests/test_utils/test_utils_mse.py
mprahl 14098cea08 Migrate to libmodulemd v2
This also moves the methods load_mmd and load_mmd_file to
module_build_service.utils.general.

This also removes some MSE unit tests with a mix of positive and
negative streams since this is not supported in libmodulemd v2. The
user will be presented with a syntax error if they try to submit
such a modulemd file.
2019-05-13 13:40:37 -04:00

454 lines
19 KiB
Python

# Copyright (c) 2017 Red Hat, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import os
import pytest
import module_build_service.utils
from module_build_service import Modulemd
from module_build_service.errors import StreamAmbigous
from tests import db, clean_database, make_module, init_data, base_dir
class TestUtilsModuleStreamExpansion:
def setup_method(self, test_method):
clean_database(False)
def teardown_method(self, test_method):
clean_database()
def _get_mmds_required_by_module_recursively(self, module_build):
"""
Convenience wrapper around get_mmds_required_by_module_recursively
returning the list with nsvc strings of modules returned by this the wrapped
method.
"""
mmd = module_build.mmd()
module_build_service.utils.expand_mse_streams(db.session, mmd)
modules = module_build_service.utils.get_mmds_required_by_module_recursively(mmd)
nsvcs = [
m.get_nsvc()
for m in modules
]
return nsvcs
def _generate_default_modules(self):
"""
Generates gtk:1, gtk:2, foo:1 and foo:2 modules requiring the
platform:f28 and platform:f29 modules.
"""
platform_f28 = make_module("platform:f28:0:c10", {}, {})
platform_f29 = make_module("platform:f29:0:c11", {}, {})
make_module("gtk:1:0:c2", {"platform": ["f28"]}, {}, platform_f28)
make_module("gtk:1:0:c3", {"platform": ["f29"]}, {}, platform_f29)
make_module("gtk:2:0:c4", {"platform": ["f28"]}, {}, platform_f28)
make_module("gtk:2:0:c5", {"platform": ["f29"]}, {}, platform_f29)
make_module("foo:1:0:c2", {"platform": ["f28"]}, {}, platform_f28)
make_module("foo:1:0:c3", {"platform": ["f29"]}, {}, platform_f29)
make_module("foo:2:0:c4", {"platform": ["f28"]}, {}, platform_f28)
make_module("foo:2:0:c5", {"platform": ["f29"]}, {}, platform_f29)
make_module("app:1:0:c6", {"platform": ["f29"]}, {}, platform_f29)
def test_generate_expanded_mmds_context(self):
self._generate_default_modules()
module_build = make_module(
"app:1:0:c1", {"gtk": ["1", "2"]}, {"platform": ["f28"], "gtk": ["1", "2"]})
mmds = module_build_service.utils.generate_expanded_mmds(db.session, module_build.mmd())
contexts = set([mmd.get_context() for mmd in mmds])
assert set(["e1e005fb", "ce132a1e"]) == contexts
@pytest.mark.parametrize(
"requires,build_requires,stream_ambigous,expected_xmd,expected_buildrequires",
[
(
{"gtk": ["1", "2"]},
{"platform": ["f28"], "gtk": ["1", "2"]},
True,
set(
[
frozenset(["platform:f28:0:c10", "gtk:2:0:c4"]),
frozenset(["platform:f28:0:c10", "gtk:1:0:c2"]),
]
),
set([frozenset(["gtk:1", "platform:f28"]), frozenset(["gtk:2", "platform:f28"])]),
),
(
{"foo": ["1"]},
{"platform": ["f28"], "foo": ["1"], "gtk": ["1", "2"]},
True,
set(
[
frozenset(["foo:1:0:c2", "gtk:1:0:c2", "platform:f28:0:c10"]),
frozenset(["foo:1:0:c2", "gtk:2:0:c4", "platform:f28:0:c10"]),
]
),
set(
[
frozenset(["foo:1", "gtk:1", "platform:f28"]),
frozenset(["foo:1", "gtk:2", "platform:f28"]),
]
),
),
(
{"gtk": ["1"], "foo": ["1"]},
{"platform": ["f28"], "gtk": ["1"], "foo": ["1"]},
False,
set([frozenset(["foo:1:0:c2", "gtk:1:0:c2", "platform:f28:0:c10"])]),
set([frozenset(["foo:1", "gtk:1", "platform:f28"])]),
),
(
{"gtk": ["1"], "foo": ["1"]},
{"gtk": ["1"], "foo": ["1"], "platform": ["f28"]},
False,
set([frozenset(["foo:1:0:c2", "gtk:1:0:c2", "platform:f28:0:c10"])]),
set([frozenset(["foo:1", "gtk:1", "platform:f28"])]),
),
(
{"gtk": ["-2"], "foo": ["-2"]},
{"platform": ["f28"], "gtk": ["-2"], "foo": ["-2"]},
True,
set([frozenset(["foo:1:0:c2", "gtk:1:0:c2", "platform:f28:0:c10"])]),
set([frozenset(["foo:1", "gtk:1", "platform:f28"])]),
),
(
{"gtk": ["1"], "foo": ["1"]},
{"platform": ["f28"], "gtk": ["1"]},
False,
set([frozenset(["gtk:1:0:c2", "platform:f28:0:c10"])]),
set([frozenset(["gtk:1", "platform:f28"])]),
),
(
{"gtk": []},
{"platform": ["f28"], "gtk": ["1"]},
True,
set([frozenset(["gtk:1:0:c2", "platform:f28:0:c10"])]),
set([frozenset(["gtk:1", "platform:f28"])]),
),
(
{},
{"platform": ["f29"], "app": ["1"]},
False,
set([frozenset(["app:1:0:c6", "platform:f29:0:c11"])]),
set([frozenset(["app:1", "platform:f29"])]),
),
],
)
def test_generate_expanded_mmds_buildrequires(
self, requires, build_requires, stream_ambigous, expected_xmd, expected_buildrequires
):
self._generate_default_modules()
module_build = make_module("app:1:0:c1", requires, build_requires)
# Check that generate_expanded_mmds raises an exception if stream is ambigous
# and also that it does not raise an exception otherwise.
if stream_ambigous:
with pytest.raises(StreamAmbigous):
module_build_service.utils.generate_expanded_mmds(
db.session, module_build.mmd(), raise_if_stream_ambigous=True)
else:
module_build_service.utils.generate_expanded_mmds(
db.session, module_build.mmd(), raise_if_stream_ambigous=True)
# Check that if stream is ambigous and we define the stream, it does not raise
# an exception.
if stream_ambigous:
default_streams = {}
for ns in list(expected_buildrequires)[0]:
name, stream = ns.split(":")
default_streams[name] = stream
module_build_service.utils.generate_expanded_mmds(
db.session,
module_build.mmd(),
raise_if_stream_ambigous=True,
default_streams=default_streams,
)
mmds = module_build_service.utils.generate_expanded_mmds(db.session, module_build.mmd())
buildrequires_per_mmd_xmd = set()
buildrequires_per_mmd_buildrequires = set()
for mmd in mmds:
xmd = mmd.get_xmd()
br_nsvcs = []
for name, detail in xmd["mbs"]["buildrequires"].items():
br_nsvcs.append(
":".join([name, detail["stream"], detail["version"], detail["context"]]))
buildrequires_per_mmd_xmd.add(frozenset(br_nsvcs))
assert len(mmd.get_dependencies()) == 1
buildrequires = set()
dep = mmd.get_dependencies()[0]
for req_name in dep.get_buildtime_modules():
for req_stream in dep.get_buildtime_streams(req_name):
buildrequires.add(":".join([req_name, req_stream]))
buildrequires_per_mmd_buildrequires.add(frozenset(buildrequires))
assert buildrequires_per_mmd_xmd == expected_xmd
assert buildrequires_per_mmd_buildrequires == expected_buildrequires
@pytest.mark.parametrize(
"requires,build_requires,expected",
[
(
{"gtk": ["1", "2"]},
{"platform": [], "gtk": ["1", "2"]},
set([frozenset(["gtk:1"]), frozenset(["gtk:2"])]),
),
(
{"gtk": ["1", "2"]},
{"platform": [], "gtk": ["1"]},
set([frozenset(["gtk:1", "gtk:2"])]),
),
(
{"gtk": ["1"], "foo": ["1"]},
{"platform": [], "gtk": ["1"], "foo": ["1"]},
set([frozenset(["foo:1", "gtk:1"])]),
),
(
{"gtk": ["-2"], "foo": ["-2"]},
{"platform": [], "gtk": ["-2"], "foo": ["-2"]},
set([frozenset(["foo:1", "gtk:1"])]),
),
(
{"gtk": [], "foo": []},
{"platform": [], "gtk": ["1"], "foo": ["1"]},
set([frozenset([])]),
),
],
)
def test_generate_expanded_mmds_requires(self, requires, build_requires, expected):
self._generate_default_modules()
module_build = make_module("app:1:0:c1", requires, build_requires)
mmds = module_build_service.utils.generate_expanded_mmds(db.session, module_build.mmd())
requires_per_mmd = set()
for mmd in mmds:
assert len(mmd.get_dependencies()) == 1
mmd_requires = set()
dep = mmd.get_dependencies()[0]
for req_name in dep.get_runtime_modules():
for req_stream in dep.get_runtime_streams(req_name):
mmd_requires.add(":".join([req_name, req_stream]))
requires_per_mmd.add(frozenset(mmd_requires))
assert requires_per_mmd == expected
@pytest.mark.parametrize(
"requires,build_requires,expected",
[
(
{},
{"platform": [], "gtk": ["1", "2"]},
[
"platform:f29:0:c11",
"gtk:2:0:c4",
"gtk:2:0:c5",
"platform:f28:0:c10",
"gtk:1:0:c2",
"gtk:1:0:c3",
],
),
(
{},
{"platform": [], "gtk": ["1"], "foo": ["1"]},
[
"platform:f28:0:c10",
"gtk:1:0:c2",
"gtk:1:0:c3",
"foo:1:0:c2",
"foo:1:0:c3",
"platform:f29:0:c11",
],
),
(
{},
{"gtk": ["1"], "foo": ["1"], "platform": ["f28"]},
["platform:f28:0:c10", "gtk:1:0:c2", "foo:1:0:c2"],
),
(
[{}, {}],
[
{"platform": [], "gtk": ["1"], "foo": ["1"]},
{"platform": [], "gtk": ["2"], "foo": ["2"]},
],
[
"foo:1:0:c2",
"foo:1:0:c3",
"foo:2:0:c4",
"foo:2:0:c5",
"platform:f28:0:c10",
"platform:f29:0:c11",
"gtk:1:0:c2",
"gtk:1:0:c3",
"gtk:2:0:c4",
"gtk:2:0:c5",
],
),
(
{},
{"platform": [], "gtk": ["-2"], "foo": ["-2"]},
[
"foo:1:0:c2",
"foo:1:0:c3",
"platform:f29:0:c11",
"platform:f28:0:c10",
"gtk:1:0:c2",
"gtk:1:0:c3",
],
),
],
)
def test_get_required_modules_simple(self, requires, build_requires, expected):
module_build = make_module("app:1:0:c1", requires, build_requires)
self._generate_default_modules()
nsvcs = self._get_mmds_required_by_module_recursively(module_build)
assert set(nsvcs) == set(expected)
def _generate_default_modules_recursion(self):
"""
Generates the gtk:1 module requiring foo:1 module requiring bar:1
and lorem:1 modules which require base:f29 module requiring
platform:f29 module :).
"""
base_module = make_module("platform:f29:0:c11", {}, {})
make_module("gtk:1:0:c2", {"foo": ["unknown"]}, {}, base_module)
make_module("gtk:1:1:c2", {"foo": ["1"]}, {}, base_module)
make_module("foo:1:0:c2", {"bar": ["unknown"]}, {}, base_module)
make_module("foo:1:1:c2", {"bar": ["1"], "lorem": ["1"]}, {}, base_module)
make_module("bar:1:0:c2", {"base": ["unknown"]}, {}, base_module)
make_module("bar:1:1:c2", {"base": ["f29"]}, {}, base_module)
make_module("lorem:1:0:c2", {"base": ["unknown"]}, {}, base_module)
make_module("lorem:1:1:c2", {"base": ["f29"]}, {}, base_module)
make_module("base:f29:0:c3", {"platform": ["f29"]}, {}, base_module)
@pytest.mark.parametrize(
"requires,build_requires,expected",
[
(
{},
{"platform": [], "gtk": ["1"]},
[
"foo:1:1:c2",
"base:f29:0:c3",
"platform:f29:0:c11",
"bar:1:1:c2",
"gtk:1:1:c2",
"lorem:1:1:c2",
],
),
(
{},
{"platform": [], "foo": ["1"]},
["foo:1:1:c2", "base:f29:0:c3", "platform:f29:0:c11", "bar:1:1:c2", "lorem:1:1:c2"],
),
],
)
def test_get_required_modules_recursion(self, requires, build_requires, expected):
module_build = make_module("app:1:0:c1", requires, build_requires)
self._generate_default_modules_recursion()
nsvcs = self._get_mmds_required_by_module_recursively(module_build)
assert set(nsvcs) == set(expected)
def _generate_default_modules_modules_multiple_stream_versions(self):
"""
Generates the gtk:1 module requiring foo:1 module requiring bar:1
and lorem:1 modules which require base:f29 module requiring
platform:f29 module :).
"""
f290000 = make_module("platform:f29.0.0:0:c11", {}, {}, virtual_streams=["f29"])
f290100 = make_module("platform:f29.1.0:0:c11", {}, {}, virtual_streams=["f29"])
f290200 = make_module("platform:f29.2.0:0:c11", {}, {}, virtual_streams=["f29"])
make_module("gtk:1:0:c2", {"platform": ["f29"]}, {}, f290000)
make_module("gtk:1:1:c2", {"platform": ["f29"]}, {}, f290100)
make_module("gtk:1:2:c2", {"platform": ["f29"]}, {}, f290100)
make_module("gtk:1:3:c2", {"platform": ["f29"]}, {}, f290200)
@pytest.mark.parametrize(
"requires,build_requires,expected",
[
(
{},
{"platform": ["f29.1.0"], "gtk": ["1"]},
["platform:f29.0.0:0:c11", "gtk:1:0:c2", "gtk:1:2:c2", "platform:f29.1.0:0:c11"],
)
],
)
def test_get_required_modules_stream_versions(self, requires, build_requires, expected):
module_build = make_module("app:1:0:c1", requires, build_requires)
self._generate_default_modules_modules_multiple_stream_versions()
nsvcs = self._get_mmds_required_by_module_recursively(module_build)
assert set(nsvcs) == set(expected)
def test__get_base_module_mmds(self):
"""Ensure the correct results are returned without duplicates."""
init_data(data_size=1, multiple_stream_versions=True)
mmd = module_build_service.utils.load_mmd_file(
os.path.join(base_dir, "staged_data", "testmodule_v2.yaml"))
deps = mmd.get_dependencies()[0]
new_deps = Modulemd.Dependencies()
for stream in deps.get_runtime_streams("platform"):
new_deps.add_runtime_stream("platform", stream)
new_deps.add_buildtime_stream("platform", "f29.1.0")
new_deps.add_buildtime_stream("platform", "f29.2.0")
mmd.remove_dependencies(deps)
mmd.add_dependencies(new_deps)
mmds = module_build_service.utils.mse._get_base_module_mmds(mmd)
expected = set(["platform:f29.0.0", "platform:f29.1.0", "platform:f29.2.0"])
# Verify no duplicates were returned before doing set operations
assert len(mmds) == len(expected)
# Verify the expected ones were returned
actual = set()
for mmd_ in mmds:
actual.add("{}:{}".format(mmd_.get_module_name(), mmd_.get_stream_name()))
assert actual == expected
@pytest.mark.parametrize("virtual_streams", (None, ["f29"], ["lp29"]))
def test__get_base_module_mmds_virtual_streams(self, virtual_streams):
"""Ensure the correct results are returned without duplicates."""
init_data(data_size=1, multiple_stream_versions=True)
mmd = module_build_service.utils.load_mmd_file(
os.path.join(base_dir, "staged_data", "testmodule_v2.yaml"))
deps = mmd.get_dependencies()[0]
new_deps = Modulemd.Dependencies()
for stream in deps.get_runtime_streams("platform"):
new_deps.add_runtime_stream("platform", stream)
new_deps.add_buildtime_stream("platform", "f29.2.0")
mmd.remove_dependencies(deps)
mmd.add_dependencies(new_deps)
make_module("platform:lp29.1.1:12:c11", {}, {}, virtual_streams=virtual_streams)
mmds = module_build_service.utils.mse._get_base_module_mmds(mmd)
if virtual_streams == ["f29"]:
expected = set(
["platform:f29.0.0", "platform:f29.1.0", "platform:f29.2.0", "platform:lp29.1.1"])
else:
expected = set(["platform:f29.0.0", "platform:f29.1.0", "platform:f29.2.0"])
# Verify no duplicates were returned before doing set operations
assert len(mmds) == len(expected)
# Verify the expected ones were returned
actual = set()
for mmd_ in mmds:
actual.add("{}:{}".format(mmd_.get_module_name(), mmd_.get_stream_name()))
assert actual == expected