diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 79a9cebd..0ed44ccd 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -56,30 +56,21 @@ def scenario(request, test_env): def repo(scenario, test_env): """Clone the module repo to be used by the scenario - Get the module repo from the scenario configuration. + 1) Get the module repo from the scenario configuration. + 2) Clone the repo in a temporary location and switch the current working directory into it. - Clone the repo in a temporary location and switch the current working - directory into it. - - :param pytest.FixtureRequest request: request object giving access - to the requesting test context + :param pytest.fixture scenario: test scenario fixture :param pytest.fixture test_env: test environment fixture :return: repository object the tests can work with :rtype: utils.Repo """ + module = scenario["module"] + branch = scenario["branch"] with tempfile.TemporaryDirectory() as tempdir: - packaging_util = Command(test_env["packaging_utility"]).bake( - _out=sys.stdout, _err=sys.stderr, _tee=True - ) - args = [ - "--branch", - scenario["branch"], - f"modules/{scenario['module']}", - tempdir, - ] - packaging_util("clone", *args) + pkg_util = utils.PackagingUtility(test_env["packaging_utility"], None) # no need for MBS + pkg_util.clone("--branch", branch, f"modules/{module}", tempdir) with pushd(tempdir): - yield utils.Repo(scenario["module"]) + yield utils.Repo(module, branch) @pytest.fixture(scope="session") diff --git a/tests/integration/test_rest_api.py b/tests/integration/test_rest_api.py new file mode 100644 index 00000000..59e5d261 --- /dev/null +++ b/tests/integration/test_rest_api.py @@ -0,0 +1,45 @@ +import getpass + + +def test_rest_module_build(clone_and_start_build, mbs, koji, pkg_util): + """Start a module build and query MBS API for build details (?verbose=True). + Assert as many values as possible. + + * There is no need for exhaustive testing of the REST API here, + as extensive coverage of it is already implemented in tests/test_web/test_views.py. + """ + repo, builds = clone_and_start_build + assert len(builds) >= 1 + + username = getpass.getuser() + build_id = builds[0].id + giturl = pkg_util.giturl() + + # wait until 'build' state + mbs.wait_for_module_build(build_id, lambda bld: bld.get("state") == 2, timeout=200) + + build = mbs.get_module_build(build_id) + assert build.get("id") == build_id + assert build.get("owner") == username + assert build.get("rebuild_strategy") == "all" + # additional '?' in url for for branch parameter (packaging utility prints url without it) + assert build.get("scmurl").replace("?", "") == giturl + assert build.get("state_name") == "build" + assert build.get("name") == repo.module_name + assert build.get("stream") == repo.branch + assert not build.get("scratch") + + assert build.get("tasks") + if repo.modulemd["data"]["components"]: + if repo.modulemd["data"]["components"].get("rpms"): + rpms = [k for k in repo.modulemd["data"]["components"]["rpms"]] + rpms.append("module-build-macros") + assert len(rpms) == len(build.get('component_builds')) + for rpm in rpms: + assert build.get("tasks")["rpms"][rpm] + else: + assert not build.get('component_builds') + + assert type(build.get("id")) is int + assert build.get("name") + assert not build.get("time_completed") diff --git a/tests/integration/utils.py b/tests/integration/utils.py index 769bb42f..ab496d8a 100644 --- a/tests/integration/utils.py +++ b/tests/integration/utils.py @@ -112,11 +112,15 @@ class Repo: """Wrapper class to work with module git repositories :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 giturl: GIT URL of the repo/branch :attribute dict _modulemd: Modulemd file as read from the repo """ - def __init__(self, module_name): + def __init__(self, module_name, branch): self.module_name = module_name + self.branch = branch + self._modulemd = None self._version = None @@ -223,7 +227,7 @@ class PackagingUtility: def cancel(self, build): """Cancel the module build - :param list build: the Build object of the module build to be cancelled. + :param Build build: the Build object of the module build to be cancelled. :return: Standard output of the "module-build-cancel command :rtype: str """ @@ -231,6 +235,12 @@ class PackagingUtility: "utf-8") return stdout + def giturl(self): + return self._packaging_utility("giturl").stdout.decode("utf-8").strip() + + def clone(self, *args): + return self._packaging_utility("clone", *args).stdout.decode("utf-8").strip() + class Build: """Wrapper class to work with module builds @@ -521,8 +531,7 @@ class MBS: pytest.fail(response.text) 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: list of Build objects @@ -535,8 +544,7 @@ class MBS: return [Build(self._mbs_api, build["id"]) for build in r.json()["items"]] def get_module_build(self, build_id, **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_id (int): build ID :return: module build object @@ -551,7 +559,7 @@ class MBS: 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. - :param int|str build_data: build definition (either id or Build object) + :param int|Build build_data: build definition (either id or Build object) :param predicate_func: function(Build) -> bool :param int timeout: timeout in seconds :param int interval: scan interval in seconds