mirror of
https://pagure.io/fm-orchestrator.git
synced 2026-05-16 13:56:11 +08:00
Add test_submit_module_build
This commit is contained in:
@@ -33,7 +33,7 @@ def pkg_util(test_env):
|
|||||||
"""Fixture to interact with the packaging utility
|
"""Fixture to interact with the packaging utility
|
||||||
|
|
||||||
:return: Packaging utility configured for the tests
|
:return: Packaging utility configured for the tests
|
||||||
:rtype: object of utils.PackagingUtility
|
:rtype: utils.PackagingUtility
|
||||||
"""
|
"""
|
||||||
return utils.PackagingUtility(test_env["packaging_utility"], test_env["mbs_api"])
|
return utils.PackagingUtility(test_env["packaging_utility"], test_env["mbs_api"])
|
||||||
|
|
||||||
@@ -99,10 +99,7 @@ def clone_and_start_build(repo, pkg_util):
|
|||||||
builds = pkg_util.run("--optional", "rebuild_strategy=all")
|
builds = pkg_util.run("--optional", "rebuild_strategy=all")
|
||||||
yield repo, builds
|
yield repo, builds
|
||||||
for build in builds:
|
for build in builds:
|
||||||
try:
|
pkg_util.cancel(build, ignore_errors=True)
|
||||||
pkg_util.cancel(build)
|
|
||||||
except sh.ErrorReturnCode:
|
|
||||||
pass # we don't need to bother with clean-up errors
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
|
|||||||
@@ -136,3 +136,6 @@ testdata:
|
|||||||
static_context:
|
static_context:
|
||||||
module: testmodule
|
module: testmodule
|
||||||
branch: test-static-context
|
branch: test-static-context
|
||||||
|
rest_submit_module_build:
|
||||||
|
module: testmodule
|
||||||
|
branch: test-submit-module
|
||||||
|
|||||||
48
tests/integration/test_rest_submit_build.py
Normal file
48
tests/integration/test_rest_submit_build.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
from requests import HTTPError
|
||||||
|
|
||||||
|
|
||||||
|
def assert_build_in_build_state(mbs, build):
|
||||||
|
"""Assert build state was reached and then cancel the build using REST."""
|
||||||
|
try:
|
||||||
|
mbs.wait_for_module_build(build, lambda bld: bld.get("state") == 2, timeout=10)
|
||||||
|
finally:
|
||||||
|
mbs.cancel_module_build(build.id)
|
||||||
|
|
||||||
|
|
||||||
|
def test_rest_submit_module_build(pkg_util, scenario, repo, mbs):
|
||||||
|
"""Test module build submission. Tests only whether or not
|
||||||
|
build gets accepted and transitions successfully to the build state.
|
||||||
|
|
||||||
|
Two variants:
|
||||||
|
* submit module build with modulemd yaml (test YAMLFileHandler)
|
||||||
|
* submit module build with scmurl (test SCMHandler)
|
||||||
|
..are combined into one method to reuse 1 single test branch.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
* Submit module build using module's SCM URL (HTTP POST).
|
||||||
|
* Assert that build reaches 'build' state.
|
||||||
|
* Cancel the build (HTTP PATCH)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 1) SCMURL submission
|
||||||
|
repo.bump()
|
||||||
|
|
||||||
|
scmurl = pkg_util.giturl().replace("#", "?#")
|
||||||
|
branch = scenario["branch"]
|
||||||
|
data = {"scmurl": scmurl, "branch": branch}
|
||||||
|
|
||||||
|
builds = mbs.submit_module_build(data)
|
||||||
|
assert len(builds) == 1
|
||||||
|
assert_build_in_build_state(mbs, builds[0])
|
||||||
|
|
||||||
|
# 2) YAML submission (might not be enabled, but if it is, let's test it)
|
||||||
|
repo.bump()
|
||||||
|
|
||||||
|
data = {"modulemd": str(repo.modulemd)}
|
||||||
|
try:
|
||||||
|
builds = mbs.submit_module_build(data)
|
||||||
|
except HTTPError as e:
|
||||||
|
if "YAML submission is not enabled" not in e.response.text:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
assert_build_in_build_state(mbs, builds[0])
|
||||||
@@ -20,6 +20,13 @@ our_sh = sh(_out=sys.stdout, _err=sys.stderr, _tee=True)
|
|||||||
from our_sh import Command, git, pushd # noqa
|
from our_sh import Command, git, pushd # noqa
|
||||||
|
|
||||||
|
|
||||||
|
def get_kerberos_auth():
|
||||||
|
"""Get the 'default' Kerberos auth header field"""
|
||||||
|
# (!) User executing this request must be allowed to do so on the target MBS instance.
|
||||||
|
# MBS server does not support mutual auth, so make it optional (inspired by mbs-cli).
|
||||||
|
return requests_kerberos.HTTPKerberosAuth(mutual_authentication=requests_kerberos.OPTIONAL)
|
||||||
|
|
||||||
|
|
||||||
class Koji:
|
class Koji:
|
||||||
"""Wrapper class to work with Koji
|
"""Wrapper class to work with Koji
|
||||||
|
|
||||||
@@ -113,14 +120,12 @@ class Repo:
|
|||||||
|
|
||||||
:attribute string module_name: name of the module stored in this repo
|
:attribute string module_name: name of the module stored in this repo
|
||||||
:attribute string branch: name of the branch, the repo is checked-out
|
:attribute string branch: name of the branch, the repo is checked-out
|
||||||
:attribute string giturl: GIT URL of the repo/branch
|
|
||||||
:attribute dict _modulemd: Modulemd file as read from the repo
|
:attribute dict _modulemd: Modulemd file as read from the repo
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, module_name, branch):
|
def __init__(self, module_name, branch):
|
||||||
self.module_name = module_name
|
self.module_name = module_name
|
||||||
self.branch = branch
|
self.branch = branch
|
||||||
|
|
||||||
self._modulemd = None
|
self._modulemd = None
|
||||||
self._version = None
|
self._version = None
|
||||||
|
|
||||||
@@ -243,18 +248,23 @@ class PackagingUtility:
|
|||||||
|
|
||||||
return stdout
|
return stdout
|
||||||
|
|
||||||
def cancel(self, build):
|
def cancel(self, build, ignore_errors=False):
|
||||||
"""Cancel the module build
|
"""Cancel the module build
|
||||||
|
|
||||||
:param Build build: the Build object of the module build to be cancelled.
|
:param Build build: the Build object of the module build to be cancelled.
|
||||||
|
:param bool ignore_errors: ignore when command fails (ErrorReturnCode exception)
|
||||||
:return: Standard output of the "module-build-cancel <build id=""> command
|
:return: Standard output of the "module-build-cancel <build id=""> command
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
stdout = self._packaging_utility("module-build-cancel", build.id).stdout.decode(
|
cmd = "module-build-cancel"
|
||||||
"utf-8")
|
try:
|
||||||
return stdout
|
return self._packaging_utility(cmd, build.id).stdout.decode("utf-8")
|
||||||
|
except sh.ErrorReturnCode:
|
||||||
|
if not ignore_errors:
|
||||||
|
raise
|
||||||
|
|
||||||
def giturl(self):
|
def giturl(self):
|
||||||
|
"""Get target URL of the current repository/branch"""
|
||||||
return self._packaging_utility("giturl").stdout.decode("utf-8").strip()
|
return self._packaging_utility("giturl").stdout.decode("utf-8").strip()
|
||||||
|
|
||||||
def clone(self, *args):
|
def clone(self, *args):
|
||||||
@@ -519,9 +529,10 @@ class MBS:
|
|||||||
:param str stream: Stream name
|
:param str stream: Stream name
|
||||||
:param str order_desc_by: Optional sorting parameter e.g. "version"
|
:param str order_desc_by: Optional sorting parameter e.g. "version"
|
||||||
:return: list of Build objects
|
:return: list of Build objects
|
||||||
:rtype: list
|
:rtype: list[Build]
|
||||||
"""
|
"""
|
||||||
url = f"{self._mbs_api}module-builds/"
|
url = f"{self._mbs_api}module-builds/"
|
||||||
|
|
||||||
payload = {'name': module, "stream": stream}
|
payload = {'name': module, "stream": stream}
|
||||||
if order_desc_by:
|
if order_desc_by:
|
||||||
payload.update({"order_desc_by": order_desc_by})
|
payload.update({"order_desc_by": order_desc_by})
|
||||||
@@ -530,40 +541,25 @@ class MBS:
|
|||||||
return [Build(self._mbs_api, build["id"]) for build in r.json()["items"]]
|
return [Build(self._mbs_api, build["id"]) for build in r.json()["items"]]
|
||||||
|
|
||||||
def import_module(self, scmurl):
|
def import_module(self, scmurl):
|
||||||
"""Import module from SCM URL (modulemd).
|
"""Import module from SCM URL.
|
||||||
|
|
||||||
:param str scmurl:
|
:param str scmurl:
|
||||||
:return: requests response
|
:return: requests response
|
||||||
:rtype: requests response object
|
:rtype: requests response object
|
||||||
"""
|
"""
|
||||||
url = f"{self._mbs_api}import-module/"
|
url = f"{self._mbs_api}import-module/"
|
||||||
headers = {"Content-Type": "application/json"}
|
|
||||||
data = json.dumps({'scmurl': scmurl})
|
data = json.dumps({'scmurl': scmurl})
|
||||||
|
r = requests.post(url, auth=get_kerberos_auth(), verify=False, data=data)
|
||||||
# (!) User executing this request must be allowed to do so on the target MBS instance.
|
r.raise_for_status()
|
||||||
# MBS server does not support mutual auth, so make it optional (inspired by mbs-cli).
|
return r
|
||||||
auth = requests_kerberos.HTTPKerberosAuth(mutual_authentication=requests_kerberos.OPTIONAL)
|
|
||||||
|
|
||||||
response = requests.post(
|
|
||||||
url,
|
|
||||||
auth=auth,
|
|
||||||
headers=headers,
|
|
||||||
verify=False,
|
|
||||||
data=data
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
response.raise_for_status()
|
|
||||||
return response
|
|
||||||
except requests.exceptions.HTTPError:
|
|
||||||
# response message contains useful information, which requests module omits
|
|
||||||
pytest.fail(response.text)
|
|
||||||
|
|
||||||
def get_module_builds(self, **kwargs):
|
def get_module_builds(self, **kwargs):
|
||||||
"""Query MBS API on module-builds endpoint
|
"""Query MBS API on module-builds endpoint
|
||||||
|
|
||||||
:attribute **kwargs: options for the HTTP GET
|
:return: matched build entries
|
||||||
:return: list of Build objects
|
:rtype: list[Build]
|
||||||
:rtype: list
|
:Keyword Arguments: passed directly to the request as HTTP params.
|
||||||
"""
|
"""
|
||||||
url = f"{self._mbs_api}module-builds/"
|
url = f"{self._mbs_api}module-builds/"
|
||||||
r = requests.get(url, params=kwargs)
|
r = requests.get(url, params=kwargs)
|
||||||
@@ -574,9 +570,10 @@ class MBS:
|
|||||||
def get_module_build(self, build_data, **kwargs):
|
def get_module_build(self, build_data, **kwargs):
|
||||||
"""Query MBS API on module-builds endpoint for a specific build
|
"""Query MBS API on module-builds endpoint for a specific build
|
||||||
|
|
||||||
:attribute build_data (int|Build): build ID
|
:param int|Build build_data: build ID
|
||||||
:return: module build object
|
:return: module build object
|
||||||
:rtype: Build
|
:rtype: Build
|
||||||
|
:Keyword Arguments: passed directly to the request as HTTP params.
|
||||||
"""
|
"""
|
||||||
build_id = self._get_build_id(build_data)
|
build_id = self._get_build_id(build_data)
|
||||||
url = f"{self._mbs_api}module-builds/{build_id}"
|
url = f"{self._mbs_api}module-builds/{build_id}"
|
||||||
@@ -585,6 +582,29 @@ class MBS:
|
|||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return Build(self._mbs_api, r.json()["id"])
|
return Build(self._mbs_api, r.json()["id"])
|
||||||
|
|
||||||
|
def submit_module_build(self, data):
|
||||||
|
"""Submit a module build with arbitrary payload.
|
||||||
|
|
||||||
|
:param dict data: payload of the POST request
|
||||||
|
1) SCMURL submission: data = {scmurl, branch}
|
||||||
|
2) YAML submission: data = {modulemd: <str(modulemd as dict)>}
|
||||||
|
:return: submitted build(s)
|
||||||
|
:rtype: list[Build]
|
||||||
|
"""
|
||||||
|
url = f"{self._mbs_api}module-builds/"
|
||||||
|
|
||||||
|
r = requests.post(url, verify=False, auth=get_kerberos_auth(), data=json.dumps(data))
|
||||||
|
r.raise_for_status()
|
||||||
|
return [Build(self._mbs_api, build["id"]) for build in r.json()]
|
||||||
|
|
||||||
|
def cancel_module_build(self, build_id):
|
||||||
|
"""PATCH the state field of a module build to cancel it"""
|
||||||
|
url = f"{self._mbs_api}module-builds/{build_id}"
|
||||||
|
|
||||||
|
data = json.dumps({"state": "failed"})
|
||||||
|
response = requests.patch(url, auth=get_kerberos_auth(), verify=False, data=data)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
def wait_for_module_build(self, build_data, predicate_func, timeout=60, interval=5):
|
def wait_for_module_build(self, build_data, predicate_func, timeout=60, interval=5):
|
||||||
"""Wait for module build. Wait until the specified function returns True.
|
"""Wait for module build. Wait until the specified function returns True.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user