Files
fm-orchestrator/tests/test_common/test_utils.py
Martin Curlej 7976b1f084 Added the support for the new libmodulemd v3 packager format.
This will enable building modules from the new libmodulemd v3 format.
This format fixes major issue with modularity which enables clear
upgrade paths for multicontext modules.

Signed-off-by: Martin Curlej <mcurlej@redhat.com>
2021-03-03 13:01:50 +01:00

290 lines
9.3 KiB
Python

# -*- coding: utf-8 -*-
# SPDX-License-Identifier: MIT
from __future__ import absolute_import
import mock
import pytest
from module_build_service.common import models
from module_build_service.common.errors import UnprocessableEntity
from module_build_service.common.utils import (import_mmd, load_mmd,
provide_module_stream_version_from_mmd,
provide_module_stream_version_from_timestamp)
from module_build_service.scheduler.db_session import db_session
from tests import read_staged_data, staged_data_filename
@pytest.mark.parametrize("context", ["c1", None])
def test_import_mmd_contexts(context):
mmd = load_mmd(read_staged_data("formatted_testmodule"))
mmd.set_context(context)
xmd = mmd.get_xmd()
xmd["mbs"]["koji_tag"] = "foo"
mmd.set_xmd(xmd)
build, msgs = import_mmd(db_session, mmd)
mmd_context = build.mmd().get_context()
if context:
assert mmd_context == context
assert build.context == context
else:
assert mmd_context == models.DEFAULT_MODULE_CONTEXT
assert build.context == models.DEFAULT_MODULE_CONTEXT
def test_import_mmd_multiple_dependencies():
mmd = load_mmd(read_staged_data("formatted_testmodule"))
mmd.add_dependencies(mmd.get_dependencies()[0].copy())
expected_error = "The imported module's dependencies list should contain just one element"
with pytest.raises(UnprocessableEntity) as e:
import_mmd(db_session, mmd)
assert str(e.value) == expected_error
def test_import_mmd_no_xmd_buildrequires():
mmd = load_mmd(read_staged_data("formatted_testmodule"))
xmd = mmd.get_xmd()
del xmd["mbs"]["buildrequires"]
mmd.set_xmd(xmd)
expected_error = (
"The imported module buildrequires other modules, but the metadata in the "
'xmd["mbs"]["buildrequires"] dictionary is missing entries'
)
with pytest.raises(UnprocessableEntity) as e:
import_mmd(db_session, mmd)
assert str(e.value) == expected_error
def test_import_mmd_minimal_xmd_from_local_repository():
mmd = load_mmd(read_staged_data("formatted_testmodule"))
xmd = mmd.get_xmd()
xmd["mbs"] = {}
xmd["mbs"]["koji_tag"] = "repofile:///etc/yum.repos.d/fedora-modular.repo"
xmd["mbs"]["mse"] = True
xmd["mbs"]["commit"] = "unknown"
mmd.set_xmd(xmd)
build, msgs = import_mmd(db_session, mmd, False)
assert build.name == mmd.get_module_name()
@pytest.mark.parametrize(
"stream, disttag_marking, error_msg",
(
("f28", None, None),
("f28", "fedora28", None),
("f-28", "f28", None),
("f-28", None, "The stream cannot contain a dash unless disttag_marking is set"),
("f28", "f-28", "The disttag_marking cannot contain a dash"),
("f-28", "fedora-28", "The disttag_marking cannot contain a dash"),
),
)
def test_import_mmd_base_module(stream, disttag_marking, error_msg, require_empty_database):
mmd = load_mmd(read_staged_data("platform"))
mmd = mmd.copy(mmd.get_module_name(), stream)
if disttag_marking:
xmd = mmd.get_xmd()
xmd["mbs"]["disttag_marking"] = disttag_marking
mmd.set_xmd(xmd)
if error_msg:
with pytest.raises(UnprocessableEntity, match=error_msg):
import_mmd(db_session, mmd)
else:
import_mmd(db_session, mmd)
def test_import_mmd_remove_dropped_virtual_streams():
mmd = load_mmd(read_staged_data("formatted_testmodule"))
# Add some virtual streams
xmd = mmd.get_xmd()
xmd["mbs"]["virtual_streams"] = ["f28", "f29", "f30"]
mmd.set_xmd(xmd)
# Import mmd into database to simulate the next step to reimport a module
import_mmd(db_session, mmd)
# Now, remove some virtual streams from module metadata
xmd = mmd.get_xmd()
xmd["mbs"]["virtual_streams"] = ["f28", "f29"] # Note that, f30 is removed
mmd.set_xmd(xmd)
# Test import modulemd again and the f30 should be removed from database.
module_build, _ = import_mmd(db_session, mmd)
db_session.refresh(module_build)
assert ["f28", "f29"] == sorted(item.name for item in module_build.virtual_streams)
assert 0 == db_session.query(models.VirtualStream).filter_by(name="f30").count()
def test_import_mmd_dont_remove_dropped_virtual_streams_associated_with_other_modules():
mmd = load_mmd(read_staged_data("formatted_testmodule"))
# Add some virtual streams to this module metadata
xmd = mmd.get_xmd()
xmd["mbs"]["virtual_streams"] = ["f28", "f29", "f30"]
mmd.set_xmd(xmd)
import_mmd(db_session, mmd)
# Import another module which has overlapping virtual streams
another_mmd = load_mmd(read_staged_data("formatted_testmodule-more-components"))
# Add some virtual streams to this module metadata
xmd = another_mmd.get_xmd()
xmd["mbs"]["virtual_streams"] = ["f29", "f30"]
another_mmd.set_xmd(xmd)
another_module_build, _ = import_mmd(
db_session, another_mmd)
# Now, remove f30 from mmd
xmd = mmd.get_xmd()
xmd["mbs"]["virtual_streams"] = ["f28", "f29"]
mmd.set_xmd(xmd)
# Reimport formatted_testmodule again
module_build, _ = import_mmd(db_session, mmd)
db_session.refresh(module_build)
assert ["f28", "f29"] == sorted(item.name for item in module_build.virtual_streams)
# The overlapped f30 should be still there.
db_session.refresh(another_module_build)
assert ["f29", "f30"] == sorted(item.name for item in another_module_build.virtual_streams)
def test_load_mmd_v2():
"""
Test to check if we can load a v2 packager file.
"""
mmd = load_mmd(read_staged_data("testmodule_v2.yaml"))
assert mmd.get_mdversion() == 2
dep = mmd.get_dependencies()
btm = dep[0].get_buildtime_modules()
rtm = dep[0].get_runtime_modules()
assert len(btm) == 1
assert len(rtm) == 1
assert btm[0] == "platform"
assert rtm[0] == "platform"
bts = dep[0].get_buildtime_streams(btm[0])
rts = dep[0].get_runtime_streams(rtm[0])
assert len(bts) == 1
assert len(rts) == 1
assert bts[0] == "f28"
assert rts[0] == "f28"
def test_load_mmd_v3():
"""
Test to check if we can load a v3 packager file.
"""
mmd = load_mmd(read_staged_data("v3/mmd_packager.yaml"))
assert mmd.get_mdversion() == 3
contexts = mmd.get_build_config_contexts_as_strv()
bc1 = mmd.get_build_config(contexts[0])
assert bc1.get_context() == "CTX1"
assert bc1.get_platform() == "f28"
btm1 = bc1.get_buildtime_modules_as_strv()
rtm1 = bc1.get_runtime_modules_as_strv()
assert len(btm1) == 0
assert len(rtm1) == 1
assert rtm1[0] == "nginx"
assert bc1.get_runtime_requirement_stream(rtm1[0]) == "1"
bc2 = mmd.get_build_config(contexts[1])
assert bc2.get_context() == "CTX2"
assert bc2.get_platform() == "f29"
assert not bc2.get_buildtime_modules_as_strv()
assert not bc2.get_runtime_modules_as_strv()
def test_provide_module_stream_version_from_timestamp():
ux_timestamp = "1613048427"
version = provide_module_stream_version_from_timestamp(ux_timestamp)
assert version == 20210211130027
@mock.patch("module_build_service.common.utils.time")
def test_provide_module_stream_version_from_timestamp_no_params(mock_time):
mock_time.time.return_value = "1613048427"
version = provide_module_stream_version_from_timestamp()
assert version == 20210211130027
def test_provide_module_stream_version_from_mmd_v2():
expected_version = 20210211130027
mmd = load_mmd(read_staged_data("testmodule_v2.yaml"))
mmd.set_version(expected_version)
version = provide_module_stream_version_from_mmd(mmd)
assert version == expected_version
@mock.patch("module_build_service.common.utils.time")
def test_provide_module_stream_version_from_mmd_v2_no_set_version(mock_time):
mock_time.time.return_value = "1613048427"
mmd = load_mmd(read_staged_data("testmodule_v2.yaml"))
version = provide_module_stream_version_from_mmd(mmd)
assert version == 20210211130027
@mock.patch("module_build_service.common.utils.time")
def test_provide_module_stream_version_from_mmd_v3(mock_time):
mock_time.time.return_value = "1613048427"
mmd = load_mmd(read_staged_data("v3/mmd_packager.yaml"))
version = provide_module_stream_version_from_mmd(mmd)
assert version == 20210211130027
def test_load_mmd_bad_mdversion_raise():
bad_mdversion_mmd = read_staged_data("v3/mmd_packager.yaml").replace("3", "4")
with pytest.raises(UnprocessableEntity) as e:
load_mmd(bad_mdversion_mmd)
err_msg = e.value.args[0]
assert "modulemd is invalid" in err_msg
assert "Invalid mdversion" in err_msg
assert "modulemd-yaml-error-quark" in err_msg
def test_load_mmd_missing_file_raise():
bad_path = "../something/something"
with pytest.raises(UnprocessableEntity) as e:
load_mmd(bad_path, is_file=True)
err_msg = e.value.args[0]
assert "file ../something/something was not found" in err_msg
def test_load_mmd_file_wrong_data_raise():
bad_file = staged_data_filename("bad.yaml")
with pytest.raises(UnprocessableEntity) as e:
load_mmd(bad_file, is_file=True)
err_msg = e.value.args[0]
assert "modulemd-yaml-error-quark" in err_msg
assert "Parse error identifying document type and version" in err_msg
assert "The modulemd bad.yaml is invalid" in err_msg