Reuse make_module in mmd resolver tests

Signed-off-by: Chenxiong Qi <cqi@redhat.com>
This commit is contained in:
Chenxiong Qi
2020-01-19 16:34:54 +08:00
committed by mprahl
parent d068ff06c4
commit b21e130555
2 changed files with 168 additions and 145 deletions

View File

@@ -5,6 +5,7 @@ from datetime import datetime, timedelta
import functools
import hashlib
import os
import re
import time
from traceback import extract_stack
@@ -489,10 +490,18 @@ def make_module(
if arches:
assert store_to_db
name, stream, version, context = nsvc.split(":")
nsvc_regex = re.compile(r"([^:]+):([^:]+):([^:]+)(?::(.+))?")
match = nsvc_regex.match(nsvc)
if not match:
raise ValueError('Argument nsvc is not in format N:S:V or N:S:V:C')
name, stream, version, context = match.groups()
mmd = Modulemd.ModuleStreamV2.new(name, stream)
mmd.set_version(int(version))
mmd.set_context(context)
if context:
mmd.set_context(context)
mmd.set_summary("foo")
# Test unicode in mmd.
mmd.set_description(u"foo \u2019s")

View File

@@ -6,8 +6,8 @@ import collections
import pytest
import solv
from module_build_service import Modulemd
from module_build_service.web.mmd_resolver import MMDResolver
from tests import make_module
class TestMMDResolver:
@@ -17,54 +17,6 @@ class TestMMDResolver:
def teardown_method(self, test_method):
pass
@staticmethod
def _make_mmd(nsvc, requires, xmd_buildrequires=None, virtual_streams=None):
name, stream, version = nsvc.split(":", 2)
mmd = Modulemd.ModuleStreamV2.new(name, stream)
mmd.set_summary("foo")
mmd.set_description("foo")
for license_ in mmd.get_module_licenses():
mmd.remove_module_license(license_)
mmd.add_module_license("GPL")
xmd = mmd.get_xmd()
xmd["mbs"] = {}
xmd["mbs"]["buildrequires"] = {}
if xmd_buildrequires:
for ns in xmd_buildrequires:
n, s = ns.split(":")
xmd["mbs"]["buildrequires"][n] = {"stream": s}
if virtual_streams:
xmd["mbs"]["virtual_streams"] = virtual_streams
mmd.set_xmd(xmd)
if ":" in version:
version, context = version.split(":")
mmd.set_context(context)
add_requires = Modulemd.Dependencies.add_runtime_stream
add_empty_requires = Modulemd.Dependencies.set_empty_runtime_dependencies_for_module
else:
add_requires = Modulemd.Dependencies.add_buildtime_stream
add_empty_requires = Modulemd.Dependencies.set_empty_buildtime_dependencies_for_module
mmd.set_version(int(version))
if not isinstance(requires, list):
requires = [requires]
else:
requires = requires
for reqs in requires:
deps = Modulemd.Dependencies()
for req_name, req_streams in reqs.items():
if req_streams == []:
add_empty_requires(deps, req_name)
else:
for req_stream in req_streams:
add_requires(deps, req_name, req_stream)
mmd.add_dependencies(deps)
return mmd
@pytest.mark.parametrize(
"deps, expected",
(
@@ -83,12 +35,25 @@ class TestMMDResolver:
assert str(reqs) == expected
@pytest.mark.parametrize(
"buildrequires, expected",
"dependencies, expected",
(
({"platform": []}, [[["platform:f28:0:c0:x86_64"], ["platform:f29:0:c0:x86_64"]]]),
({"platform": ["f28"]}, [[["platform:f28:0:c0:x86_64"]]]),
(
{"gtk": [], "qt": []},
[{"buildrequires": {"platform": []}}],
[
[
["platform:f28:0:c0:x86_64"],
["platform:f29:0:c0:x86_64"],
]
]
),
(
[{"buildrequires": {"platform": ["f28"]}}],
[
[["platform:f28:0:c0:x86_64"]]
]
),
(
[{"buildrequires": {"gtk": [], "qt": []}}],
[
[
["gtk:3:0:c8:x86_64", "qt:4:0:c8:x86_64", "platform:f28:0:c0:x86_64"],
@@ -99,7 +64,7 @@ class TestMMDResolver:
],
),
(
{"gtk": [], "qt": [], "platform": []},
[{"buildrequires": {"gtk": [], "qt": [], "platform": []}}],
[
[
["gtk:3:0:c8:x86_64", "qt:4:0:c8:x86_64", "platform:f28:0:c0:x86_64"],
@@ -114,7 +79,10 @@ class TestMMDResolver:
],
),
(
[{"qt": [], "platform": ["f28"]}, {"gtk": [], "platform": ["f29"]}],
[
{"buildrequires": {"qt": [], "platform": ["f28"]}},
{"buildrequires": {"gtk": [], "platform": ["f29"]}}
],
[
[
["qt:4:0:c8:x86_64", "platform:f28:0:c0:x86_64"],
@@ -127,11 +95,11 @@ class TestMMDResolver:
],
),
(
{"mess": []},
[{"buildrequires": {"mess": []}}],
[[["mess:1:0:c0:x86_64", "gtk:3:0:c8:x86_64", "platform:f28:0:c0:x86_64"]]],
),
(
{"mess": [], "platform": []},
[{"buildrequires": {"mess": [], "platform": []}}],
[
[
["mess:1:0:c0:x86_64", "gtk:3:0:c8:x86_64", "platform:f28:0:c0:x86_64"],
@@ -141,27 +109,31 @@ class TestMMDResolver:
),
),
)
def test_solve(self, buildrequires, expected):
def test_solve(self, dependencies, expected):
modules = (
("platform:f28:0:c0", {}),
("platform:f29:0:c0", {}),
("gtk:3:0:c8", {"platform": ["f28"]}),
("gtk:3:0:c9", {"platform": ["f29"]}),
("gtk:4:0:c8", {"platform": ["f28"]}),
("gtk:4:0:c9", {"platform": ["f29"]}),
("qt:4:0:c8", {"platform": ["f28"]}),
("qt:4:0:c9", {"platform": ["f29"]}),
("qt:5:0:c8", {"platform": ["f28"]}),
("qt:5:0:c9", {"platform": ["f29"]}),
("platform:f28:0:c0", []),
("platform:f29:0:c0", []),
("gtk:3:0:c8", [{"requires": {"platform": ["f28"]}}]),
("gtk:3:0:c9", [{"requires": {"platform": ["f29"]}}]),
("gtk:4:0:c8", [{"requires": {"platform": ["f28"]}}]),
("gtk:4:0:c9", [{"requires": {"platform": ["f29"]}}]),
("qt:4:0:c8", [{"requires": {"platform": ["f28"]}}]),
("qt:4:0:c9", [{"requires": {"platform": ["f29"]}}]),
("qt:5:0:c8", [{"requires": {"platform": ["f28"]}}]),
("qt:5:0:c9", [{"requires": {"platform": ["f29"]}}]),
(
"mess:1:0:c0",
[{"gtk": ["3"], "platform": ["f28"]}, {"gtk": ["4"], "platform": ["f29"]}],
[
{"requires": {"gtk": ["3"], "platform": ["f28"]}},
{"requires": {"gtk": ["4"], "platform": ["f29"]}},
],
),
)
for n, req in modules:
self.mmd_resolver.add_modules(self._make_mmd(n, req))
for nsvc, deps in modules:
self.mmd_resolver.add_modules(
make_module(nsvc, dependencies=deps))
app = self._make_mmd("app:1:0", buildrequires)
app = make_module("app:1:0", dependencies=dependencies)
expanded = self.mmd_resolver.solve(app)
expected = set(
@@ -171,11 +143,11 @@ class TestMMDResolver:
assert expanded == expected
@pytest.mark.parametrize(
"buildrequires, expected",
"dependencies, expected",
(
# BR all platform streams -> build for all platform streams.
(
{"platform": []},
[{"buildrequires": {"platform": []}}],
[
[
["platform:el8.2.0.z:0:c0:x86_64"],
@@ -187,7 +159,7 @@ class TestMMDResolver:
),
# BR "el8" platform stream -> build for all el8 platform streams.
(
{"platform": ["el8"]},
[{"buildrequires": {"platform": ["el8"]}}],
[
[
["platform:el8.2.0.z:0:c0:x86_64"],
@@ -197,18 +169,21 @@ class TestMMDResolver:
],
),
# BR "el8.1.0" platform stream -> build just for el8.1.0.
({"platform": ["el8.1.0"]}, [[["platform:el8.1.0:0:c0:x86_64"]]]),
(
[{"buildrequires": {"platform": ["el8.1.0"]}}],
[[["platform:el8.1.0:0:c0:x86_64"]]]
),
# BR platform:el8.1.0 and gtk:3, which is not built against el8.1.0,
# but it is built only against el8.0.0 -> cherry-pick gtk:3 from el8.0.0
# and build once against platform:el8.1.0.
(
{"platform": ["el8.1.0"], "gtk": ["3"]},
[{"buildrequires": {"platform": ["el8.1.0"], "gtk": ["3"]}}],
[[["platform:el8.1.0:0:c0:x86_64", "gtk:3:0:c8:x86_64"]]],
),
# BR platform:el8.2.0 and gtk:3, this time gtk:3 build against el8.2.0 exists
# -> use both platform and gtk from el8.2.0 and build once.
(
{"platform": ["el8.2.0.z"], "gtk": ["3"]},
[{"buildrequires": {"platform": ["el8.2.0.z"], "gtk": ["3"]}}],
[[["platform:el8.2.0.z:0:c0:x86_64", "gtk:3:1:c8:x86_64"]]],
),
# BR platform:el8.2.0 and mess:1 which is built against platform:el8.1.0 and
@@ -217,7 +192,7 @@ class TestMMDResolver:
# -> cherry-pick mess:1 from el8.1.0 and
# -> use gtk:3:1 from el8.2.0.
(
{"platform": ["el8.2.0.z"], "mess": ["1"]},
[{"buildrequires": {"platform": ["el8.2.0.z"], "mess": ["1"]}}],
[[["platform:el8.2.0.z:0:c0:x86_64", "mess:1:0:c0:x86_64", "gtk:3:1:c8:x86_64"]]],
),
# BR platform:el8.1.0 and mess:1 which is built against platform:el8.1.0 and
@@ -226,13 +201,13 @@ class TestMMDResolver:
# -> Used mess:1 from el8.1.0 and
# -> cherry-pick gtk:3:0 from el8.0.0.
(
{"platform": ["el8.1.0"], "mess": ["1"]},
[{"buildrequires": {"platform": ["el8.1.0"], "mess": ["1"]}}],
[[["platform:el8.1.0:0:c0:x86_64", "mess:1:0:c0:x86_64", "gtk:3:0:c8:x86_64"]]],
),
# BR platform:el8.0.0 and mess:1 which is built against platform:el8.1.0 and
# requires gtk:3 which is built against platform:el8.2.0 and platform:el8.0.0
# -> No valid combination, because mess:1 is only available in el8.1.0 and later.
({"platform": ["el8.0.0"], "mess": ["1"]}, []),
([{"buildrequires": {"platform": ["el8.0.0"], "mess": ["1"]}}], []),
# This is undefined... it might build just once against latest platform or
# against all the platforms... we don't know
# ({"platform": ["el8"], "gtk": ["3"]}, {}, [
@@ -240,21 +215,40 @@ class TestMMDResolver:
# ]),
),
)
def test_solve_virtual_streams(self, buildrequires, expected):
def test_solve_virtual_streams(self, dependencies, expected):
modules = (
# (nsvc, buildrequires, expanded_buildrequires, virtual_streams)
("platform:el8.0.0:0:c0", {}, {}, ["el8"]),
("platform:el8.1.0:0:c0", {}, {}, ["el8"]),
("platform:el8.2.0.z:0:c0", {}, {}, ["el8"]),
("platform:el7.6.0:0:c0", {}, {}, ["el7"]),
("gtk:3:0:c8", {"platform": ["el8"]}, {"platform:el8.0.0"}, None),
("gtk:3:1:c8", {"platform": ["el8"]}, {"platform:el8.2.0.z"}, None),
("mess:1:0:c0", [{"gtk": ["3"], "platform": ["el8"]}], {"platform:el8.1.0"}, None),
# (nsvc, dependencies, xmd_mbs_buildrequires, virtual_streams)
("platform:el8.0.0:0:c0", [], {}, ["el8"]),
("platform:el8.1.0:0:c0", [], {}, ["el8"]),
("platform:el8.2.0.z:0:c0", [], {}, ["el8"]),
("platform:el7.6.0:0:c0", [], {}, ["el7"]),
(
"gtk:3:0:c8",
[{"requires": {"platform": ["el8"]}}],
{"platform": {"stream": "el8.0.0"}},
None
),
(
"gtk:3:1:c8",
[{"requires": {"platform": ["el8"]}}],
{"platform": {"stream": "el8.2.0.z"}},
None
),
(
"mess:1:0:c0",
[{"requires": {"gtk": ["3"], "platform": ["el8"]}}],
{"platform": {"stream": "el8.1.0"}},
None
),
)
for n, req, xmd_br, virtual_streams in modules:
self.mmd_resolver.add_modules(self._make_mmd(n, req, xmd_br, virtual_streams))
for nsvc, deps, xmd_mbs_brs, virtual_streams in modules:
xmd = {"mbs": {"buildrequires": xmd_mbs_brs}}
if virtual_streams:
xmd["mbs"]["virtual_streams"] = virtual_streams
self.mmd_resolver.add_modules(
make_module(nsvc, dependencies=deps, xmd=xmd))
app = self._make_mmd("app:1:0", buildrequires)
app = make_module("app:1:0", dependencies=dependencies)
if not expected:
with pytest.raises(RuntimeError):
self.mmd_resolver.solve(app)
@@ -268,32 +262,32 @@ class TestMMDResolver:
assert expanded == expected
@pytest.mark.parametrize(
"app_buildrequires, modules, err_msg_regex",
"dependencies, modules, err_msg_regex",
(
# app --br--> gtk:1 --req--> bar:1* ---req---> platform:f29
# \--br--> foo:1 --req--> bar:2* ---req--/
(
{"gtk": "1", "foo": "1"},
[{"buildrequires": {"gtk": ["1"], "foo": ["1"]}}],
(
("platform:f29:0:c0", {}),
("gtk:1:1:c01", {"bar": ["1"]}),
("bar:1:0:c02", {"platform": ["f29"]}),
("foo:1:1:c03", {"bar": ["2"]}),
("bar:2:0:c04", {"platform": ["f29"]}),
("platform:f29:0:c0", []),
("gtk:1:1:c01", [{"requires": {"bar": ["1"]}}]),
("bar:1:0:c02", [{"requires": {"platform": ["f29"]}}]),
("foo:1:1:c03", [{"requires": {"bar": ["2"]}}]),
("bar:2:0:c04", [{"requires": {"platform": ["f29"]}}]),
),
"bar:1:0:c02 and bar:2:0:c04",
),
# app --br--> gtk:1 --req--> bar:1* ----------req----------> platform:f29
# \--br--> foo:1 --req--> baz:1 --req--> bar:2* --req--/
(
{"gtk": "1", "foo": "1"},
[{"buildrequires": {"gtk": ["1"], "foo": ["1"]}}],
(
("platform:f29:0:c0", {}),
("gtk:1:1:c01", {"bar": ["1"]}),
("bar:1:0:c02", {"platform": ["f29"]}),
("foo:1:1:c03", {"baz": ["1"]}),
("baz:1:1:c04", {"bar": ["2"]}),
("bar:2:0:c05", {"platform": ["f29"]}),
("platform:f29:0:c0", []),
("gtk:1:1:c01", [{"requires": {"bar": ["1"]}}]),
("bar:1:0:c02", [{"requires": {"platform": ["f29"]}}]),
("foo:1:1:c03", [{"requires": {"baz": ["1"]}}]),
("baz:1:1:c04", [{"requires": {"bar": ["2"]}}]),
("bar:2:0:c05", [{"requires": {"platform": ["f29"]}}]),
),
"bar:1:0:c02 and bar:2:0:c05",
),
@@ -303,29 +297,37 @@ class TestMMDResolver:
# \--br--> pkga:1 --req--> perl:5' -------req-----------/
# \--br--> pkgb:1 --req--> perl:6' -------req-----------/
(
{"gtk": "1", "foo": "1", "pkga": "1", "pkgb": "1"},
[{
"buildrequires": {
"gtk": ["1"],
"foo": ["1"],
"pkga": ["1"],
"pkgb": ["1"],
}
}],
(
("platform:f29:0:c0", {}),
("gtk:1:1:c01", {"bar": ["1"]}),
("bar:1:0:c02", {"platform": ["f29"]}),
("foo:1:1:c03", {"baz": ["1"]}),
("baz:1:1:c04", {"bar": ["2"]}),
("bar:2:0:c05", {"platform": ["f29"]}),
("pkga:1:0:c06", {"perl": ["5"]}),
("perl:5:0:c07", {"platform": ["f29"]}),
("pkgb:1:0:c08", {"perl": ["6"]}),
("perl:6:0:c09", {"platform": ["f29"]}),
("gtk:1:1:c01", [{"requires": {"bar": ["1"]}}]),
("bar:1:0:c02", [{"requires": {"platform": ["f29"]}}]),
("foo:1:1:c03", [{"requires": {"baz": ["1"]}}]),
("baz:1:1:c04", [{"requires": {"bar": ["2"]}}]),
("bar:2:0:c05", [{"requires": {"platform": ["f29"]}}]),
("pkga:1:0:c06", [{"requires": {"perl": ["5"]}}]),
("perl:5:0:c07", [{"requires": {"platform": ["f29"]}}]),
("pkgb:1:0:c08", [{"requires": {"perl": ["6"]}}]),
("perl:6:0:c09", [{"requires": {"platform": ["f29"]}}]),
),
# MMD Resolver should still catch a conflict
"bar:1:0:c02 and bar:2:0:c05",
),
),
)
def test_solve_stream_conflicts(self, app_buildrequires, modules, err_msg_regex):
for n, req in modules:
self.mmd_resolver.add_modules(self._make_mmd(n, req))
def test_solve_stream_conflicts(self, dependencies, modules, err_msg_regex):
for nsvc, deps in modules:
self.mmd_resolver.add_modules(
make_module(nsvc, dependencies=deps))
app = self._make_mmd("app:1:0", app_buildrequires)
app = make_module("app:1:0", dependencies=dependencies)
with pytest.raises(RuntimeError, match=err_msg_regex):
self.mmd_resolver.solve(app)
@@ -338,16 +340,19 @@ class TestMMDResolver:
with all available platforms.
"""
modules = (
("platform:f28:0:c0", {}),
("platform:f29:0:c0", {}),
("platform:f30:0:c0", {}),
("gtk:3:0:c8", {"platform": ["f28"]}),
("gtk:3:0:c9", {"platform": ["f29"]}),
("platform:f28:0:c0", []),
("platform:f29:0:c0", []),
("platform:f30:0:c0", []),
("gtk:3:0:c8", [{"requires": {"platform": ["f28"]}}]),
("gtk:3:0:c9", [{"requires": {"platform": ["f29"]}}]),
)
for n, req in modules:
self.mmd_resolver.add_modules(self._make_mmd(n, req))
for nsvc, deps in modules:
self.mmd_resolver.add_modules(
make_module(nsvc, dependencies=deps))
app = self._make_mmd("app:1:0", {"platform": [], "gtk": ["3"]})
app = make_module("app:1:0", dependencies=[
{"buildrequires": {"platform": [], "gtk": ["3"]}}
])
expanded = self.mmd_resolver.solve(app)
# Build only against f28 and f29, because "gtk:3" is not built against f30.
@@ -364,15 +369,24 @@ class TestMMDResolver:
it was built on newer platform stream, but can run on any platform stream.
"""
modules = (
("platform:f28:0:c0", {}, {}),
("platform:f29:0:c0", {}, {}),
("platform:f30:0:c0", {}, {}),
("foo:1:0:c8", {"platform": []}, ["platform:f29"]),
("platform:f28:0:c0", [], {}),
("platform:f29:0:c0", [], {}),
("platform:f30:0:c0", [], {}),
(
"foo:1:0:c8",
[{"requires": {"platform": []}}],
{"platform": {"stream": "f29"}}
),
)
for n, req, xmd_req in modules:
self.mmd_resolver.add_modules(self._make_mmd(n, req, xmd_req))
for nsvc, deps, xmd_mbs_brs in modules:
mmd = make_module(nsvc, dependencies=deps, xmd={
"mbs": {"buildrequires": xmd_mbs_brs}
})
self.mmd_resolver.add_modules(mmd)
app = self._make_mmd("app:1:0", {"platform": ["f28"], "foo": ["1"]})
app = make_module("app:1:0", [
{"buildrequires": {"platform": ["f28"], "foo": ["1"]}}
])
expanded = self.mmd_resolver.solve(app)
expected = {
@@ -382,18 +396,18 @@ class TestMMDResolver:
assert expanded == expected
@pytest.mark.parametrize(
"nsvc, requires, expected",
"nsvc, dependencies, expected",
(
("platform:f28:0:c0", {}, True),
("platform:latest:5:c8", {}, False),
("gtk:3:0:c8", {"platform": ["f28"]}, False)
("platform:f28:0:c0", [], True),
("platform:latest:5:c8", [], False),
("gtk:3:0:c8", [{"requires": {"platform": ["f28"]}}], False)
),
)
def test_base_module_stream_version(self, nsvc, requires, expected):
def test_base_module_stream_version(self, nsvc, dependencies, expected):
"""
Tests that add_base_module_provides returns True for base modules with stream versions
"""
mmd = self._make_mmd(nsvc, requires)
mmd = make_module(nsvc, dependencies=dependencies)
solvable = self.mmd_resolver.available_repo.add_solvable()
solvable.name = nsvc
solvable.evr = str(mmd.get_version())
@@ -408,7 +422,7 @@ class TestMMDResolver:
),
)
def test_base_module_provides(self, nsvc, expected):
self.mmd_resolver.add_modules(self._make_mmd(nsvc, {}))
self.mmd_resolver.add_modules(make_module(nsvc))
ns = nsvc.rsplit(":", 2)[0]
provides = self.mmd_resolver.solvables[ns][0].lookup_deparray(solv.SOLVABLE_PROVIDES)
assert {str(provide) for provide in provides} == expected