mirror of
https://pagure.io/fm-orchestrator.git
synced 2026-04-03 02:37:48 +08:00
Merge #1567 Module Stream Expansion integration test
This commit is contained in:
@@ -28,6 +28,16 @@ def test_env():
|
||||
return env
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def pkg_util(test_env):
|
||||
"""Fixture to interact with the packaging utility
|
||||
|
||||
:return: Packaging utility configured for the tests
|
||||
:rtype: object of utils.PackagingUtility
|
||||
"""
|
||||
return utils.PackagingUtility(test_env["packaging_utility"], test_env["mbs_api"])
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def scenario(request, test_env):
|
||||
"""Configuration data for the scenario
|
||||
|
||||
@@ -64,3 +64,9 @@ testdata:
|
||||
no_components:
|
||||
module: testmodule
|
||||
branch: test-no-components-branch
|
||||
stream_expansion:
|
||||
# testmodule2 buildrequires and requires 2 streams from testmodule.
|
||||
# These are expected to be built already.
|
||||
# For this scenario reusing former builds doesn't make sense.
|
||||
module: testmodule2
|
||||
branch: test-stream-expans-branch
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import utils
|
||||
|
||||
|
||||
def test_failed_build(test_env, scenario, repo, koji):
|
||||
def test_failed_build(pkg_util, scenario, repo, koji):
|
||||
"""
|
||||
Run the build with "rebuild_strategy=all".
|
||||
|
||||
@@ -13,14 +11,15 @@ def test_failed_build(test_env, scenario, repo, koji):
|
||||
* Check that any other components in the same batch as the failed component are
|
||||
cancelled, if not completed.
|
||||
"""
|
||||
build = utils.Build(test_env["packaging_utility"], test_env["mbs_api"])
|
||||
repo.bump()
|
||||
build.run(
|
||||
builds = pkg_util.run(
|
||||
"--optional",
|
||||
"rebuild_strategy=all",
|
||||
reuse=scenario.get("build_id"),
|
||||
)
|
||||
build.watch()
|
||||
assert len(builds) == 1
|
||||
build = builds[0]
|
||||
pkg_util.watch(builds)
|
||||
|
||||
assert build.state_name == "failed"
|
||||
batch = scenario["batch"]
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import utils
|
||||
|
||||
|
||||
def test_no_components(test_env, scenario, repo, koji):
|
||||
def test_no_components(pkg_util, scenario, repo, koji):
|
||||
"""
|
||||
Submit the testmodule build with `fedpkg module-build`
|
||||
|
||||
@@ -13,10 +11,12 @@ def test_no_components(test_env, scenario, repo, koji):
|
||||
* Verify that the testmodule build succeeds
|
||||
|
||||
"""
|
||||
build = utils.Build(test_env["packaging_utility"], test_env["mbs_api"])
|
||||
repo.bump()
|
||||
build.run(reuse=scenario.get("build_id"))
|
||||
build.watch()
|
||||
builds = pkg_util.run(reuse=scenario.get("build_id"))
|
||||
assert len(builds) == 1
|
||||
|
||||
pkg_util.watch(builds)
|
||||
build = builds[0]
|
||||
|
||||
assert build.state_name == "ready"
|
||||
assert not build.data["component_builds"]
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import utils
|
||||
|
||||
|
||||
def test_normal_build(test_env, scenario, repo, koji):
|
||||
def test_normal_build(pkg_util, scenario, repo, koji):
|
||||
"""
|
||||
Run build with `rhpkg-stage module-build --optional rebuild_strategy=all`
|
||||
|
||||
@@ -17,14 +15,15 @@ def test_normal_build(test_env, scenario, repo, koji):
|
||||
* Check that MBS changed the buildrequired platform to have a suffix of “z”
|
||||
if a Platform stream is representing a GA RHEL release.
|
||||
"""
|
||||
build = utils.Build(test_env["packaging_utility"], test_env["mbs_api"])
|
||||
repo.bump()
|
||||
build_id = build.run(
|
||||
builds = pkg_util.run(
|
||||
"--optional",
|
||||
"rebuild_strategy=all",
|
||||
reuse=scenario.get("build_id"),
|
||||
)
|
||||
build.watch()
|
||||
assert len(builds) == 1
|
||||
pkg_util.watch(builds)
|
||||
build = builds[0]
|
||||
|
||||
assert sorted(build.component_names()) == sorted(repo.components + ["module-build-macros"])
|
||||
|
||||
@@ -36,7 +35,7 @@ def test_normal_build(test_env, scenario, repo, koji):
|
||||
cg_build = koji.get_build(build.nvr())
|
||||
cg_devel_build = koji.get_build(build.nvr(name_suffix="-devel"))
|
||||
assert cg_build and cg_devel_build
|
||||
assert cg_devel_build['extra']['typeinfo']['module']['module_build_service_id'] == int(build_id)
|
||||
assert cg_devel_build['extra']['typeinfo']['module']['module_build_service_id'] == int(build.id)
|
||||
|
||||
modulemd = koji.get_modulemd(cg_build)
|
||||
actual_platforms = modulemd["data"]["dependencies"][0]["buildrequires"]["platform"]
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import utils
|
||||
import time
|
||||
|
||||
|
||||
def test_resume_cancelled_build(test_env, scenario, repo, koji):
|
||||
def test_resume_cancelled_build(pkg_util, scenario, repo, koji):
|
||||
"""
|
||||
Run the build with "rebuild_strategy=all".
|
||||
Wait until the module-build-macros build is submitted to Koji.
|
||||
@@ -17,17 +16,20 @@ def test_resume_cancelled_build(test_env, scenario, repo, koji):
|
||||
* Check that the testmodule build succeeded
|
||||
|
||||
"""
|
||||
build = utils.Build(test_env["packaging_utility"], test_env["mbs_api"])
|
||||
repo.bump()
|
||||
build.run(
|
||||
builds = pkg_util.run(
|
||||
"--optional",
|
||||
"rebuild_strategy=all",
|
||||
)
|
||||
|
||||
assert len(builds) == 1
|
||||
build = builds[0]
|
||||
build.wait_for_koji_task_id(package="module-build-macros", batch=1)
|
||||
build.cancel()
|
||||
pkg_util.cancel(build)
|
||||
# Behave like a human: restarting the build too quickly would lead to an error.
|
||||
time.sleep(10)
|
||||
build.run("--watch")
|
||||
|
||||
builds = pkg_util.run("--watch")
|
||||
assert len(builds) == 1
|
||||
build = builds[0]
|
||||
assert build.state_name == "ready"
|
||||
assert build.was_cancelled()
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import utils
|
||||
|
||||
|
||||
def test_reuse_all_components(test_env, scenario, repo, koji):
|
||||
def test_reuse_all_components(pkg_util, scenario, repo, koji):
|
||||
"""Rebuild the test module again, without changing any of the components with:
|
||||
|
||||
`fedpkg module-build -w --optional rebuild_strategy=only-changed`
|
||||
@@ -13,23 +11,28 @@ def test_reuse_all_components(test_env, scenario, repo, koji):
|
||||
* Verify that all the components are reused from the first build.
|
||||
* Verify that module-build-macros is not built in the second build.
|
||||
"""
|
||||
build = utils.Build(test_env["packaging_utility"], test_env["mbs_api"])
|
||||
repo.bump()
|
||||
build.run(
|
||||
builds = pkg_util.run(
|
||||
"--watch",
|
||||
"--optional",
|
||||
"rebuild_strategy=all",
|
||||
reuse=scenario.get("build_id"),
|
||||
)
|
||||
assert len(builds) == 1
|
||||
|
||||
build = builds[0]
|
||||
task_ids = build.component_task_ids()
|
||||
task_ids.pop("module-build-macros")
|
||||
|
||||
repo.bump()
|
||||
build.run(
|
||||
builds = pkg_util.run(
|
||||
"-w",
|
||||
"--optional",
|
||||
"rebuild_strategy=only-changed",
|
||||
reuse=scenario.get("build_id_reused"))
|
||||
|
||||
assert len(builds) == 1
|
||||
build = builds[0]
|
||||
reused_task_ids = build.component_task_ids()
|
||||
|
||||
assert not build.components(package="module-build-macros")
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import utils
|
||||
|
||||
|
||||
def test_reuse_components(test_env, scenario, repo, koji):
|
||||
def test_reuse_components(pkg_util, test_env, scenario, repo, koji):
|
||||
"""
|
||||
Bump the commit of one of the components that MBS uses.
|
||||
Bump the commit of the same testmodule that was mentioned in the preconditions.
|
||||
@@ -16,14 +16,15 @@ def test_reuse_components(test_env, scenario, repo, koji):
|
||||
* Verify that the component with the changed commit was rebuilt.
|
||||
"""
|
||||
repo.bump()
|
||||
baseline_build = utils.Build(test_env["packaging_utility"], test_env["mbs_api"])
|
||||
baseline_build.run(
|
||||
baseline_builds = pkg_util.run(
|
||||
"--watch",
|
||||
"--optional",
|
||||
"rebuild_strategy=all",
|
||||
reuse=scenario.get("baseline_build_id"),
|
||||
)
|
||||
assert len(baseline_builds) == 1
|
||||
|
||||
baseline_build = baseline_builds[0]
|
||||
package = scenario.get("package")
|
||||
component = utils.Component(
|
||||
package,
|
||||
@@ -33,14 +34,14 @@ def test_reuse_components(test_env, scenario, repo, koji):
|
||||
component.bump()
|
||||
|
||||
repo.bump()
|
||||
build = utils.Build(test_env["packaging_utility"], test_env["mbs_api"])
|
||||
build.run(
|
||||
builds = pkg_util.run(
|
||||
"--watch",
|
||||
"--optional",
|
||||
"rebuild_strategy=only-changed",
|
||||
reuse=scenario.get("build_id"),
|
||||
)
|
||||
|
||||
assert len(builds) == 1
|
||||
build = builds[0]
|
||||
comp_task_ids_base = baseline_build.component_task_ids()
|
||||
comp_task_ids = build.component_task_ids()
|
||||
comp_task_ids_base.pop('module-build-macros')
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import utils
|
||||
|
||||
|
||||
def test_scratch_build(test_env, scenario, repo, koji):
|
||||
def test_scratch_build(pkg_util, scenario, repo, koji):
|
||||
"""
|
||||
Run a scratch build with "rebuild_strategy=all".
|
||||
|
||||
@@ -14,14 +12,16 @@ def test_scratch_build(test_env, scenario, repo, koji):
|
||||
(as opposed to the "ready" state)
|
||||
* no content generator builds are created in Koji
|
||||
"""
|
||||
build = utils.Build(test_env["packaging_utility"], test_env["mbs_api"])
|
||||
build.run(
|
||||
builds = pkg_util.run(
|
||||
"--scratch",
|
||||
"--optional",
|
||||
"rebuild_strategy=all",
|
||||
reuse=scenario.get("build_id"),
|
||||
)
|
||||
build.watch()
|
||||
|
||||
assert len(builds) == 1
|
||||
pkg_util.watch(builds)
|
||||
build = builds[0]
|
||||
|
||||
assert build.state_name == "done"
|
||||
assert sorted(build.component_names(state="COMPLETE")) == sorted(
|
||||
|
||||
21
tests/integration/test_stream_expansion.py
Normal file
21
tests/integration/test_stream_expansion.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
def test_stream_expansion(pkg_util, scenario, repo, koji):
|
||||
"""
|
||||
|
||||
Submit the testmodule2 build with `rhpkg-stage module-build`
|
||||
The produced builds can be cancelled after the test cases have been verified to save on
|
||||
resources and time
|
||||
|
||||
Checks:
|
||||
* Verify two module builds were generated from this build submission
|
||||
|
||||
"""
|
||||
repo.bump()
|
||||
builds = pkg_util.run()
|
||||
|
||||
assert len(builds) == 2
|
||||
for build in builds:
|
||||
pkg_util.cancel(build)
|
||||
@@ -114,15 +114,12 @@ class Repo:
|
||||
git("push")
|
||||
|
||||
|
||||
class Build:
|
||||
"""Wrapper class to work with module builds
|
||||
class PackagingUtility:
|
||||
"""Wrapper class to work with the packaging utility configured for the tests
|
||||
|
||||
:attribute sh.Command _packaging_utility: packaging utility command used to
|
||||
kick off this build
|
||||
:attribute string _mbs_api: URL of the MBS API (including trailing '/')
|
||||
:attribute string _url: URL of this MBS module build
|
||||
:attribute string _data: Module build data cache for this build fetched from MBS
|
||||
:attribute string _module_build_data: Verbose module build data cache for this build
|
||||
"""
|
||||
|
||||
def __init__(self, packaging_utility, mbs_api):
|
||||
@@ -130,54 +127,76 @@ class Build:
|
||||
_out=sys.stdout, _err=sys.stderr, _tee=True
|
||||
)
|
||||
self._mbs_api = mbs_api
|
||||
self._data = None
|
||||
self._component_data = None
|
||||
self._build_id = None
|
||||
self._module_build_data = None
|
||||
|
||||
def run(self, *args, reuse=None):
|
||||
"""Run a module build
|
||||
"""Run one or more module builds
|
||||
|
||||
:param args: Options and arguments for the build command
|
||||
:param int reuse: Optional MBS build id to be reused for this run.
|
||||
When specified, the corresponding module build will be used,
|
||||
instead of triggering and waiting for a new one to finish.
|
||||
:param int reuse: An optional MBS build id or a list of MBS build
|
||||
ids to be reused for this run.
|
||||
When specified, the corresponding module build(s) will be used,
|
||||
instead of triggering and waiting for new one(s) to finish.
|
||||
Intended to be used while developing the tests.
|
||||
:return: MBS build id of the build created
|
||||
:rtype: int
|
||||
:return: list of Build objects for the MBS builds created
|
||||
:rtype: list of Build objects
|
||||
"""
|
||||
current_build_id = self._build_id
|
||||
build_ids = []
|
||||
|
||||
if reuse is not None:
|
||||
self._build_id = int(reuse)
|
||||
if isinstance(reuse, list):
|
||||
build_ids = reuse
|
||||
else:
|
||||
build_ids = [reuse]
|
||||
else:
|
||||
stdout = self._packaging_utility("module-build", *args).stdout.decode("utf-8")
|
||||
self._build_id = int(re.search(self._mbs_api + r"module-builds/(\d+)", stdout).group(1))
|
||||
# Clear cached data
|
||||
if current_build_id != self._build_id:
|
||||
self._component_data = None
|
||||
return self._build_id
|
||||
build_ids = re.findall(self._mbs_api + r"module-builds/(\d+)", stdout)
|
||||
return [Build(self._mbs_api, int(build_id)) for build_id in build_ids]
|
||||
|
||||
def watch(self):
|
||||
"""Watch the build till the finish"""
|
||||
if self._build_id is None:
|
||||
raise RuntimeError("Build was not started. Cannot watch.")
|
||||
def watch(self, builds):
|
||||
"""Watch one or more builds till the finish
|
||||
|
||||
:param list builds: list of Build objects of the builds to be watched.
|
||||
:return: Stdout of the watch command
|
||||
:rtype: string
|
||||
"""
|
||||
stdout = self._packaging_utility(
|
||||
"module-build-watch", str(self._build_id)
|
||||
"module-build-watch", [str(build.id) for build in builds]
|
||||
).stdout.decode("utf-8")
|
||||
|
||||
return stdout
|
||||
|
||||
def cancel(self):
|
||||
def cancel(self, build):
|
||||
"""Cancel the module build
|
||||
|
||||
:param list build: the Build object of the module build to be cancelled.
|
||||
:return: Standard output of the "module-build-cancel <build id=""> command
|
||||
:rtype: str
|
||||
"""
|
||||
stdout = self._packaging_utility("module-build-cancel", self._build_id).stdout.decode(
|
||||
stdout = self._packaging_utility("module-build-cancel", build.id).stdout.decode(
|
||||
"utf-8")
|
||||
return stdout
|
||||
|
||||
|
||||
class Build:
|
||||
"""Wrapper class to work with module builds
|
||||
|
||||
:attribute string _mbs_api: URL of the MBS API (including trailing '/')
|
||||
:attribute int _build_id: id of this MBS module build
|
||||
:attribute string _data: Module build data cache for this build fetched from MBS
|
||||
:attribute string _module_build_data: Verbose module build data cache for this build
|
||||
"""
|
||||
|
||||
def __init__(self, mbs_api, build_id):
|
||||
self._mbs_api = mbs_api
|
||||
self._data = None
|
||||
self._component_data = None
|
||||
self._build_id = build_id
|
||||
self._module_build_data = None
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._build_id
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
"""Module build data cache for this build fetched from MBS"""
|
||||
|
||||
Reference in New Issue
Block a user