Files
Chenxiong Qi f24cd4222f Make db_session singleton
Please note that this patch does not change the use of database session
in MBS. So, in the frontend, the database session is still managed by
Flask-SQLAlchemy, that is the db.session. And the backend, running event
handlers, has its own database session created from SQLAclehmy session
API directly.

This patch aims to reduce the number of scoped_session created when call
original function make_db_session. For technical detailed information,
please refer to SQLAlchemy documentation Contextual/Thread-local
Sessions.

As a result, a global scoped_session is accessible from the
code running inside backend, both the event handlers and functions
called from handlers. The library code shared by frontend and backend,
like resolvers, has no change.

Similarly, db.session is only used to recreate database for every test.

Signed-off-by: Chenxiong Qi <cqi@redhat.com>
2019-11-07 11:06:40 +08:00

509 lines
18 KiB
Python

# -*- coding: utf-8 -*-
# SPDX-License-Identifier: MIT
from mock import patch, PropertyMock, Mock, call
import module_build_service.resolver as mbs_resolver
import module_build_service.utils
from module_build_service.db_session import db_session
from module_build_service.utils.general import mmd_to_str
import module_build_service.models
import tests
class TestMBSModule:
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_get_module_modulemds_nsvc(self, mock_session, testmodule_mmd_9c690d0e):
""" Tests for querying a module from mbs """
mock_res = Mock()
mock_res.ok.return_value = True
mock_res.json.return_value = {
"items": [
{
"name": "testmodule",
"stream": "master",
"version": "20180205135154",
"context": "9c690d0e",
"modulemd": testmodule_mmd_9c690d0e,
}
],
"meta": {"next": None},
}
mock_session.get.return_value = mock_res
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
module_mmds = resolver.get_module_modulemds(
"testmodule", "master", "20180205135154", "9c690d0e", virtual_streams=["f28"]
)
nsvcs = set(m.get_nsvc() for m in module_mmds)
expected = {"testmodule:master:20180205135154:9c690d0e"}
mbs_url = tests.conf.mbs_url
expected_query = {
"name": "testmodule",
"stream": "master",
"version": "20180205135154",
"context": "9c690d0e",
"verbose": True,
"order_desc_by": "version",
"page": 1,
"per_page": 10,
"state": ["ready"],
"virtual_stream": ["f28"],
}
mock_session.get.assert_called_once_with(mbs_url, params=expected_query)
assert nsvcs == expected
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_get_module_modulemds_partial(
self, mock_session, testmodule_mmd_9c690d0e, testmodule_mmd_c2c572ed
):
""" Test for querying MBS without the context of a module """
version = "20180205135154"
mock_res = Mock()
mock_res.ok.return_value = True
mock_res.json.return_value = {
"items": [
{
"name": "testmodule",
"stream": "master",
"version": version,
"context": "9c690d0e",
"modulemd": testmodule_mmd_9c690d0e,
},
{
"name": "testmodule",
"stream": "master",
"version": version,
"context": "c2c572ed",
"modulemd": testmodule_mmd_c2c572ed,
},
],
"meta": {"next": None},
}
mock_session.get.return_value = mock_res
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
ret = resolver.get_module_modulemds("testmodule", "master", version)
nsvcs = set(m.get_nsvc() for m in ret)
expected = {
"testmodule:master:20180205135154:9c690d0e",
"testmodule:master:20180205135154:c2c572ed",
}
mbs_url = tests.conf.mbs_url
expected_query = {
"name": "testmodule",
"stream": "master",
"version": version,
"verbose": True,
"order_desc_by": "version",
"page": 1,
"per_page": 10,
"state": ["ready"],
}
mock_session.get.assert_called_once_with(mbs_url, params=expected_query)
assert nsvcs == expected
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_get_module_build_dependencies(
self, mock_session, platform_mmd, testmodule_mmd_9c690d0e
):
"""
Tests that we return just direct build-time dependencies of testmodule.
"""
mock_res = Mock()
mock_res.ok.return_value = True
mock_res.json.side_effect = [
{
"items": [
{
"name": "testmodule",
"stream": "master",
"version": "20180205135154",
"context": "9c690d0e",
"modulemd": testmodule_mmd_9c690d0e,
}
],
"meta": {"next": None},
},
{
"items": [
{
"name": "platform",
"stream": "f28",
"version": "3",
"context": "00000000",
"modulemd": platform_mmd,
"koji_tag": "module-f28-build",
}
],
"meta": {"next": None},
},
]
mock_session.get.return_value = mock_res
expected = {"module-f28-build"}
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
result = resolver.get_module_build_dependencies(
"testmodule", "master", "20180205135154", "9c690d0e").keys()
expected_queries = [
{
"name": "testmodule",
"stream": "master",
"version": "20180205135154",
"context": "9c690d0e",
"verbose": True,
"order_desc_by": "version",
"page": 1,
"per_page": 10,
"state": ["ready"],
},
{
"name": "platform",
"stream": "f28",
"version": "3",
"context": "00000000",
"verbose": True,
"order_desc_by": "version",
"page": 1,
"per_page": 10,
"state": ["ready"],
},
]
mbs_url = tests.conf.mbs_url
expected_calls = [
call(mbs_url, params=expected_queries[0]),
call(mbs_url, params=expected_queries[1]),
]
mock_session.get.mock_calls = expected_calls
assert mock_session.get.call_count == 2
assert set(result) == expected
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_get_module_build_dependencies_empty_buildrequires(
self, mock_session, testmodule_mmd_9c690d0e
):
mmd = module_build_service.utils.load_mmd(testmodule_mmd_9c690d0e)
# Wipe out the dependencies
for deps in mmd.get_dependencies():
mmd.remove_dependencies(deps)
xmd = mmd.get_xmd()
xmd["mbs"]["buildrequires"] = {}
mmd.set_xmd(xmd)
mock_res = Mock()
mock_res.ok.return_value = True
mock_res.json.side_effect = [
{
"items": [
{
"name": "testmodule",
"stream": "master",
"version": "20180205135154",
"context": "9c690d0e",
"modulemd": mmd_to_str(mmd),
"build_deps": [],
}
],
"meta": {"next": None},
}
]
mock_session.get.return_value = mock_res
expected = set()
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
result = resolver.get_module_build_dependencies(
"testmodule", "master", "20180205135154", "9c690d0e"
).keys()
mbs_url = tests.conf.mbs_url
expected_query = {
"name": "testmodule",
"stream": "master",
"version": "20180205135154",
"context": "9c690d0e",
"verbose": True,
"order_desc_by": "version",
"page": 1,
"per_page": 10,
"state": ["ready"],
}
mock_session.get.assert_called_once_with(mbs_url, params=expected_query)
assert set(result) == expected
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_resolve_profiles(
self, mock_session, formatted_testmodule_mmd, platform_mmd
):
mock_res = Mock()
mock_res.ok.return_value = True
mock_res.json.return_value = {
"items": [
{
"name": "platform",
"stream": "f28",
"version": "3",
"context": "00000000",
"modulemd": platform_mmd,
}
],
"meta": {"next": None},
}
mock_session.get.return_value = mock_res
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
result = resolver.resolve_profiles(
formatted_testmodule_mmd, ("buildroot", "srpm-buildroot")
)
expected = {
"buildroot": {
"unzip",
"tar",
"cpio",
"gawk",
"gcc",
"xz",
"sed",
"findutils",
"util-linux",
"bash",
"info",
"bzip2",
"grep",
"redhat-rpm-config",
"fedora-release",
"diffutils",
"make",
"patch",
"shadow-utils",
"coreutils",
"which",
"rpm-build",
"gzip",
"gcc-c++",
},
"srpm-buildroot": {
"shadow-utils",
"redhat-rpm-config",
"rpm-build",
"fedora-release",
"fedpkg-minimal",
"gnupg2",
"bash",
},
}
mbs_url = tests.conf.mbs_url
expected_query = {
"name": "platform",
"stream": "f28",
"version": "3",
"context": "00000000",
"verbose": True,
"order_desc_by": "version",
"page": 1,
"per_page": 10,
"state": ["ready"],
}
mock_session.get.assert_called_once_with(mbs_url, params=expected_query)
assert result == expected
@patch(
"module_build_service.config.Config.system", new_callable=PropertyMock, return_value="test"
)
@patch(
"module_build_service.config.Config.mock_resultsdir",
new_callable=PropertyMock,
return_value=tests.staged_data_filename("local_builds")
)
def test_resolve_profiles_local_module(
self, local_builds, conf_system, formatted_testmodule_mmd
):
tests.clean_database()
module_build_service.utils.load_local_builds(["platform"])
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
result = resolver.resolve_profiles(
formatted_testmodule_mmd, ("buildroot", "srpm-buildroot"))
expected = {"buildroot": {"foo"}, "srpm-buildroot": {"bar"}}
assert result == expected
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_get_empty_buildrequired_modulemds(self, request_session):
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
request_session.get.return_value = Mock(ok=True)
request_session.get.return_value.json.return_value = {"items": [], "meta": {"next": None}}
platform = db_session.query(module_build_service.models.ModuleBuild).filter_by(id=1).one()
result = resolver.get_buildrequired_modulemds("nodejs", "10", platform.mmd())
assert [] == result
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_get_buildrequired_modulemds(self, mock_session):
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
mock_session.get.return_value = Mock(ok=True)
mock_session.get.return_value.json.return_value = {
"items": [
{
"name": "nodejs",
"stream": "10",
"version": 1,
"context": "c1",
"modulemd": mmd_to_str(
tests.make_module("nodejs:10:1:c1"),
),
},
{
"name": "nodejs",
"stream": "10",
"version": 2,
"context": "c1",
"modulemd": mmd_to_str(
tests.make_module("nodejs:10:2:c1"),
),
},
],
"meta": {"next": None},
}
platform = db_session.query(module_build_service.models.ModuleBuild).filter_by(id=1).one()
result = resolver.get_buildrequired_modulemds("nodejs", "10", platform.mmd())
assert 1 == len(result)
mmd = result[0]
assert "nodejs" == mmd.get_module_name()
assert "10" == mmd.get_stream_name()
assert 1 == mmd.get_version()
assert "c1" == mmd.get_context()
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_get_module_count(self, mock_session):
mock_res = Mock()
mock_res.ok.return_value = True
mock_res.json.return_value = {
"items": [{"name": "platform", "stream": "f28", "version": "3", "context": "00000000"}],
"meta": {"total": 5},
}
mock_session.get.return_value = mock_res
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
count = resolver.get_module_count(name="platform", stream="f28")
assert count == 5
mock_session.get.assert_called_once_with(
"https://mbs.fedoraproject.org/module-build-service/1/module-builds/",
params={"name": "platform", "page": 1, "per_page": 1, "short": True, "stream": "f28"},
)
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_get_latest_with_virtual_stream(self, mock_session, platform_mmd):
mock_res = Mock()
mock_res.ok.return_value = True
mock_res.json.return_value = {
"items": [
{
"context": "00000000",
"modulemd": platform_mmd,
"name": "platform",
"stream": "f28",
"version": "3",
}
],
"meta": {"total": 5},
}
mock_session.get.return_value = mock_res
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
mmd = resolver.get_latest_with_virtual_stream("platform", "virtualf28")
assert mmd.get_module_name() == "platform"
mock_session.get.assert_called_once_with(
"https://mbs.fedoraproject.org/module-build-service/1/module-builds/",
params={
"name": "platform",
"order_desc_by": ["stream_version", "version"],
"page": 1,
"per_page": 1,
"verbose": True,
"virtual_stream": "virtualf28",
},
)
@patch(
"module_build_service.config.Config.system", new_callable=PropertyMock, return_value="test"
)
@patch(
"module_build_service.config.Config.mock_resultsdir",
new_callable=PropertyMock,
return_value=tests.staged_data_filename("local_builds")
)
def test_get_buildrequired_modulemds_local_builds(
self, local_builds, conf_system
):
tests.clean_database()
with tests.app.app_context():
module_build_service.utils.load_local_builds(["testmodule"])
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
result = resolver.get_buildrequired_modulemds(
"testmodule", "master", "platform:f28:1:00000000")
assert 1 == len(result)
mmd = result[0]
assert "testmodule" == mmd.get_module_name()
assert "master" == mmd.get_stream_name()
assert 20170816080816 == mmd.get_version()
assert "321" == mmd.get_context()
@patch("module_build_service.resolver.MBSResolver.requests_session")
def test_get_buildrequired_modulemds_kojiresolver(self, mock_session):
"""
Test that MBSResolver uses KojiResolver as input when KojiResolver is enabled for
the base module.
"""
mock_session.get.return_value = Mock(ok=True)
mock_session.get.return_value.json.return_value = {
"items": [
{
"name": "nodejs",
"stream": "10",
"version": 2,
"context": "c1",
"modulemd": mmd_to_str(
tests.make_module("nodejs:10:2:c1"),
),
},
],
"meta": {"next": None},
}
resolver = mbs_resolver.GenericResolver.create(db_session, tests.conf, backend="mbs")
platform = db_session.query(
module_build_service.models.ModuleBuild).filter_by(id=1).one()
platform_mmd = platform.mmd()
platform_xmd = platform_mmd.get_xmd()
platform_xmd["mbs"]["koji_tag_with_modules"] = "module-f29-build"
platform_mmd.set_xmd(platform_xmd)
with patch.object(
resolver, "get_buildrequired_koji_builds") as get_buildrequired_koji_builds:
get_buildrequired_koji_builds.return_value = [{
"build_id": 124, "name": "nodejs", "version": "10",
"release": "2.c1", "tag_name": "foo-test"}]
result = resolver.get_buildrequired_modulemds("nodejs", "10", platform_mmd)
get_buildrequired_koji_builds.assert_called_once()
assert 1 == len(result)
mmd = result[0]
assert "nodejs" == mmd.get_module_name()
assert "10" == mmd.get_stream_name()
assert 2 == mmd.get_version()
assert "c1" == mmd.get_context()