From c3221a3f96ccd5f00023d495b0d0dd626c606285 Mon Sep 17 00:00:00 2001 From: Jakub Kadlcik Date: Jun 08 2020 11:43:22 +0000 Subject: frontend: return a user friendly error when modulemd is not ok Fix #1382 Instead of a typical last-resort exception message Error: Request wasn't successful, there is probably a bug in the API code Print something more user-frinedly, e.g. Error: Unsupported or malformed modulemd yaml - Missing required option data.summary Error: Invalid modulemd yaml - Provided YAML did not begin with a module document Error: Invalid modulemd yaml - Parser error Merges: #1384 --- diff --git a/beaker-tests/Sanity/copr-cli-basic-operations/runtest-modules.sh b/beaker-tests/Sanity/copr-cli-basic-operations/runtest-modules.sh index 4a987c0..77c0aa2 100755 --- a/beaker-tests/Sanity/copr-cli-basic-operations/runtest-modules.sh +++ b/beaker-tests/Sanity/copr-cli-basic-operations/runtest-modules.sh @@ -102,6 +102,12 @@ rlJournalStart sed -i "s/\$PLATFORM/$BRANCH/g" /tmp/testmodule.yaml rlRun "copr-cli build-module --yaml /tmp/testmodule.yaml $PROJECT" + # Test submitting a wrong modulemd + OUTPUT=`mktemp` + touch "/tmp/emptyfile.yaml" + rlRun "copr-cli build-module --yaml /tmp/emptyfile.yaml $PROJECT &> $OUTPUT" 1 + rlAssertEquals "Module in wrong format" `cat $OUTPUT | grep "Invalid modulemd yaml" |wc -l` 1 + # Test module duplicity # @FIXME the request sometimes hangs for some obscure reason OUTPUT=`mktemp` diff --git a/frontend/coprs_frontend/coprs/logic/modules_logic.py b/frontend/coprs_frontend/coprs/logic/modules_logic.py index 5b95d72..2624b06 100644 --- a/frontend/coprs_frontend/coprs/logic/modules_logic.py +++ b/frontend/coprs_frontend/coprs/logic/modules_logic.py @@ -14,7 +14,7 @@ from wtforms import ValidationError import gi gi.require_version('Modulemd', '1.0') -from gi.repository import Modulemd +from gi.repository import Modulemd, GLib class ModulesLogic(object): @@ -51,15 +51,24 @@ class ModulesLogic(object): @classmethod def yaml2modulemd(cls, yaml): - mmd = Modulemd.ModuleStream() - mmd.import_from_string(yaml) - return mmd + try: + mmd = Modulemd.ModuleStream() + mmd.import_from_string(yaml) + return mmd + except GLib.GError as ex: + # pylint: disable=no-member + raise exceptions.BadRequest("Invalid modulemd yaml - {0}" .format(ex.message)) @classmethod def from_modulemd(cls, mmd): - yaml_b64 = base64.b64encode(mmd.dumps().encode("utf-8")).decode("utf-8") - return models.Module(name=mmd.get_name(), stream=mmd.get_stream(), version=mmd.get_version(), - summary=mmd.get_summary(), description=mmd.get_description(), yaml_b64=yaml_b64) + try: + yaml_b64 = base64.b64encode(mmd.dumps().encode("utf-8")).decode("utf-8") + return models.Module(name=mmd.get_name(), stream=mmd.get_stream(), + version=mmd.get_version(), summary=mmd.get_summary(), + description=mmd.get_description(), yaml_b64=yaml_b64) + except GLib.GError as ex: + raise exceptions.BadRequest("Unsupported or malformed modulemd yaml - {0}" + .format(ex.message)) # pylint: disable=no-member @classmethod def validate(cls, mmd): diff --git a/frontend/coprs_frontend/tests/test_logic/test_modules_logic.py b/frontend/coprs_frontend/tests/test_logic/test_modules_logic.py index d5ecc63..7f386e7 100644 --- a/frontend/coprs_frontend/tests/test_logic/test_modules_logic.py +++ b/frontend/coprs_frontend/tests/test_logic/test_modules_logic.py @@ -66,6 +66,48 @@ class TestModulesLogic(CoprsTestCase): ModulesLogic.get_by_nsv_str(self.c1, "notenough-dashes").one() assert "not a valid NSV" in str(ex) + def test_yaml2modulemd(self): + # Test that valid yaml can be sucessfully converted to modulemd object + generator = ModulemdGenerator(name="testmodule", stream="master", + version=123, summary="some summary") + valid_yaml = generator.generate() + modulemd = ModulesLogic.yaml2modulemd(valid_yaml) + assert isinstance(modulemd, Modulemd.ModuleStream) + + # Test a yaml with syntax error + invalid_yaml = valid_yaml.replace("name:", "name") + with pytest.raises(BadRequest) as ex: + ModulesLogic.yaml2modulemd(invalid_yaml) + assert "Invalid modulemd yaml - Parser error" in ex.value.message + + # There is no validation in the yaml2modulemd method, therefore even yaml that + # doesn't contain all the necessary fields can be converted to the modulemd object + incomplete_yaml = valid_yaml.replace(" summary: some summary\n", "") + modulemd2 = ModulesLogic.yaml2modulemd(incomplete_yaml) + assert isinstance(modulemd2, Modulemd.ModuleStream) + + # Test an empty string + with pytest.raises(BadRequest) as ex: + ModulesLogic.yaml2modulemd("") + assert ("Invalid modulemd yaml - " + "Provided YAML did not begin with a module document") in ex.value.message + + def test_from_modulemd(self): + # Test that valid yaml can be sucessfully converted to modulemd object + generator = ModulemdGenerator(name="testmodule", stream="master", + version=123, summary="some summary") + valid_yaml = generator.generate() + modulemd = ModulesLogic.yaml2modulemd(valid_yaml) + mod1 = ModulesLogic.from_modulemd(modulemd) + assert isinstance(mod1, models.Module) + + # Test a modulemd that is missing some required parameters + modulemd.set_summary(None) + with pytest.raises(BadRequest) as ex: + ModulesLogic.from_modulemd(modulemd) + assert ("Unsupported or malformed modulemd yaml - " + "Missing required option data.summary") in ex.value.message + class TestModuleBuildFacade(CoprsTestCase): def test_get_build_batches(self):