Fix several issues with plugin discovery error messages
* `rally plugin show` should raise errors in case of not found or multiple match * remove dumplication of 'in' from PluginNotFound error in case of any platform search * handle Scenario plugin not found during task validation * doesn't tag 'PluginNotFound' with "Unexpected CLI error" since it is clear error Change-Id: Ibe003c26ef973b18decaa16c03b3589b4002157e
This commit is contained in:
parent
000052f67a
commit
302216c1a2
|
@ -25,6 +25,11 @@ Removed
|
|||
|
||||
* Python 2.7, Python 3.4 and Python 3.5 support
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
* *rally plugin show* command returns not-zero exit code in case of not found
|
||||
or multiple match errors
|
||||
|
||||
[2.1.0] - 2019-11-19
|
||||
--------------------
|
||||
|
|
|
@ -675,7 +675,8 @@ def run(argv, categories):
|
|||
|
||||
except (IOError, TypeError, ValueError,
|
||||
exceptions.RallyException, jsonschema.ValidationError) as e:
|
||||
if logging.is_debug():
|
||||
known_errors = (exceptions.InvalidTaskConfig,)
|
||||
if logging.is_debug() and not isinstance(e, known_errors):
|
||||
LOG.exception("Unexpected exception in CLI")
|
||||
else:
|
||||
print(e)
|
||||
|
|
|
@ -18,6 +18,7 @@ from __future__ import print_function
|
|||
from rally.cli import cliutils
|
||||
from rally.common.plugin import plugin
|
||||
from rally.common import utils
|
||||
from rally import exceptions
|
||||
from rally import plugins
|
||||
|
||||
|
||||
|
@ -58,6 +59,7 @@ class PluginCommands(object):
|
|||
)
|
||||
else:
|
||||
print("Plugin %s not found at any platform" % name)
|
||||
return exceptions.PluginNotFound.error_code
|
||||
|
||||
elif len(found) == 1 or exact_match:
|
||||
plugin_ = found[0] if len(found) == 1 else exact_match[0]
|
||||
|
@ -79,6 +81,7 @@ class PluginCommands(object):
|
|||
else:
|
||||
print("Multiple plugins found:")
|
||||
self._print_plugins_list(found)
|
||||
return exceptions.MultiplePluginsFound.error_code
|
||||
|
||||
@cliutils.args(
|
||||
"--name", dest="name", type=str,
|
||||
|
|
|
@ -560,7 +560,7 @@ class Workload(object):
|
|||
task["subtasks"] = [collections.OrderedDict()]
|
||||
subtask = task["subtasks"][0]
|
||||
subtask["title"] = workload["name"]
|
||||
subtask["description"] = workload["description"]
|
||||
subtask["description"] = workload.get("description", "")
|
||||
subtask["scenario"] = {workload["name"]: workload["args"]}
|
||||
subtask["contexts"] = workload["contexts"]
|
||||
subtask["runner"] = {workload["runner_type"]: workload["runner"]}
|
||||
|
|
|
@ -156,8 +156,10 @@ class Plugin(meta.MetaMixin, info.InfoMixin):
|
|||
allow_hidden=allow_hidden)
|
||||
|
||||
if not results:
|
||||
base = cls._get_base()
|
||||
base = "" if base == Plugin else " %s" % base.__name__
|
||||
raise exceptions.PluginNotFound(
|
||||
name=name, platform=platform or "in any")
|
||||
name=name, platform=platform or "any", base=base)
|
||||
|
||||
if len(results) == 1:
|
||||
return results[0]
|
||||
|
|
|
@ -214,9 +214,8 @@ class ValidatablePluginMixin(object):
|
|||
"""
|
||||
try:
|
||||
plugin = cls.get(name, allow_hidden=allow_hidden)
|
||||
except exceptions.PluginNotFound:
|
||||
return ["There is no %s plugin with name: '%s'" %
|
||||
(cls.__name__, name)]
|
||||
except exceptions.PluginNotFound as e:
|
||||
return [e.format_message()]
|
||||
|
||||
if vtype is None:
|
||||
semantic = True
|
||||
|
|
|
@ -140,7 +140,8 @@ class NotFoundException(RallyException):
|
|||
|
||||
class PluginNotFound(NotFoundException):
|
||||
error_code = 211
|
||||
msg_fmt = "There is no plugin `%(name)s` in %(platform)s platform."
|
||||
msg_fmt = "There is no%(base)s plugin `%(name)s` in %(platform)s " \
|
||||
"platform."
|
||||
|
||||
|
||||
class PluginWithSuchNameExists(RallyException):
|
||||
|
|
|
@ -256,7 +256,15 @@ class TaskEngine(object):
|
|||
:param vcontext: a validation context
|
||||
:param vtype: a type of validation (platform, syntax or semantic)
|
||||
"""
|
||||
scenario_cls = scenario.Scenario.get(workload["name"])
|
||||
try:
|
||||
scenario_cls = scenario.Scenario.get(workload["name"])
|
||||
except exceptions.PluginNotFound as e:
|
||||
raise exceptions.InvalidTaskConfig(
|
||||
name=workload["name"],
|
||||
pos=workload["position"],
|
||||
config=json.dumps(objects.Workload.to_task(workload)),
|
||||
reason=e.format_message()) from None
|
||||
|
||||
scenario_context = copy.deepcopy(scenario_cls.get_default_context())
|
||||
results = []
|
||||
|
||||
|
@ -318,14 +326,11 @@ class TaskEngine(object):
|
|||
vtype=vtype))
|
||||
|
||||
if results:
|
||||
msg = "\n ".join(results)
|
||||
kw = {"name": workload["name"],
|
||||
"pos": workload["position"],
|
||||
"config": json.dumps(
|
||||
objects.Workload.to_task(workload)),
|
||||
"reason": msg}
|
||||
|
||||
raise exceptions.InvalidTaskConfig(**kw)
|
||||
raise exceptions.InvalidTaskConfig(
|
||||
name=workload["name"],
|
||||
pos=workload["position"],
|
||||
config=json.dumps(objects.Workload.to_task(workload)),
|
||||
reason="\n ".join(results))
|
||||
|
||||
@logging.log_task_wrapper(LOG.info, "Task validation of syntax.")
|
||||
def _validate_config_syntax(self, config):
|
||||
|
|
|
@ -51,3 +51,9 @@
|
|||
shell:
|
||||
cmd: |
|
||||
sudo pip3 install bindep
|
||||
|
||||
- name: Prepare rally plugins stored at home dir
|
||||
shell:
|
||||
cmd: |
|
||||
mkdir --parents ~/.rally/plugins
|
||||
cp --recursive {{ zuul.project.src_dir }}/rally-jobs/plugins/* ~/.rally/plugins
|
||||
|
|
|
@ -13,15 +13,23 @@
|
|||
become: yes
|
||||
when: bindep_output.stdout_lines
|
||||
|
||||
- name: Install Rally and check
|
||||
- name: Install Rally system wide
|
||||
shell:
|
||||
executable: /bin/sh
|
||||
chdir: '{{ zuul.project.src_dir }}'
|
||||
cmd: "sudo pip3 install --constraint ./upper-constraints.txt ./"
|
||||
|
||||
- name: Check Rally base commands
|
||||
shell:
|
||||
cmd: |
|
||||
# install system wide
|
||||
sudo pip3 install --constraint ./upper-constraints.txt ./
|
||||
|
||||
rally --version
|
||||
rally db create
|
||||
rally env list
|
||||
|
||||
# should be loaded from ~/.rally/plugins
|
||||
rally plugin show --name FakePlugin.testplugin
|
||||
|
||||
# builtin plugin
|
||||
rally plugin show --name HttpRequests.check_request
|
||||
|
||||
executable: /bin/sh
|
||||
chdir: '{{ zuul.project.src_dir }}'
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
|
||||
import os
|
||||
|
||||
import unittest
|
||||
import testtools
|
||||
|
||||
from tests.functional import utils
|
||||
|
||||
|
||||
class DeploymentTestCase(unittest.TestCase):
|
||||
class DeploymentTestCase(testtools.TestCase):
|
||||
|
||||
def test_create_deployment_from_env(self):
|
||||
os.environ.update(
|
||||
|
|
|
@ -17,12 +17,12 @@ import json
|
|||
import os
|
||||
import tempfile
|
||||
|
||||
import unittest
|
||||
import testtools
|
||||
|
||||
from tests.functional import utils
|
||||
|
||||
|
||||
class EnvTestCase(unittest.TestCase):
|
||||
class EnvTestCase(testtools.TestCase):
|
||||
|
||||
def test_create_no_spec(self):
|
||||
rally = utils.Rally()
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
# under the License.
|
||||
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
import six
|
||||
import testtools
|
||||
|
||||
from rally.utils import encodeutils
|
||||
|
||||
|
||||
class CLITestCase(unittest.TestCase):
|
||||
class CLITestCase(testtools.TestCase):
|
||||
|
||||
def test_rally_cli(self):
|
||||
try:
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import unittest
|
||||
import testtools
|
||||
|
||||
from tests.functional import utils
|
||||
|
||||
|
||||
class PluginTestCase(unittest.TestCase):
|
||||
class PluginTestCase(testtools.TestCase):
|
||||
|
||||
def test_show_one(self):
|
||||
rally = utils.Rally()
|
||||
|
@ -30,29 +30,32 @@ class PluginTestCase(unittest.TestCase):
|
|||
|
||||
def test_show_multiple(self):
|
||||
rally = utils.Rally()
|
||||
result = rally("plugin show Dummy")
|
||||
self.assertIn("Multiple plugins found:", result)
|
||||
self.assertIn("Dummy.dummy", result)
|
||||
self.assertIn("Dummy.dummy_exception", result)
|
||||
self.assertIn("Dummy.dummy_random_fail_in_atomic", result)
|
||||
result = self.assertRaises(utils.RallyCliError,
|
||||
rally, "plugin show Dummy")
|
||||
self.assertIn("Multiple plugins found:", result.output)
|
||||
self.assertIn("Dummy.dummy", result.output)
|
||||
self.assertIn("Dummy.dummy_exception", result.output)
|
||||
self.assertIn("Dummy.dummy_random_fail_in_atomic", result.output)
|
||||
|
||||
def test_show_not_found(self):
|
||||
rally = utils.Rally()
|
||||
name = "Dummy666666"
|
||||
result = rally("plugin show %s" % name)
|
||||
self.assertIn("Plugin %s not found" % name, result)
|
||||
result = self.assertRaises(utils.RallyCliError,
|
||||
rally, "plugin show %s" % name)
|
||||
self.assertIn("Plugin %s not found" % name, result.output)
|
||||
|
||||
def test_show_not_found_in_specific_platform(self):
|
||||
rally = utils.Rally()
|
||||
name = "Dummy"
|
||||
platform = "non_existing"
|
||||
result = rally(
|
||||
"plugin show --name %(name)s --platform %(platform)s"
|
||||
% {"name": name, "platform": platform})
|
||||
result = self.assertRaises(
|
||||
utils.RallyCliError,
|
||||
rally, "plugin show --name %(name)s --platform %(platform)s"
|
||||
% {"name": name, "platform": platform})
|
||||
self.assertIn(
|
||||
"Plugin %(name)s@%(platform)s not found"
|
||||
% {"name": name, "platform": platform},
|
||||
result)
|
||||
result.output)
|
||||
|
||||
def test_list(self):
|
||||
rally = utils.Rally()
|
||||
|
|
|
@ -15,12 +15,13 @@
|
|||
|
||||
import os
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
import testtools
|
||||
|
||||
from tests.functional import utils
|
||||
|
||||
|
||||
class LibAPITestCase(unittest.TestCase):
|
||||
class LibAPITestCase(testtools.TestCase):
|
||||
|
||||
def test_rally_lib(self):
|
||||
rally = utils.Rally(force_new_db=True)
|
||||
|
|
|
@ -203,7 +203,7 @@ class Rally(object):
|
|||
|
||||
except subprocess.CalledProcessError as e:
|
||||
output = encodeutils.safe_decode(e.output)
|
||||
raise RallyCliError(cmd, e.returncode, output)
|
||||
raise RallyCliError(cmd, e.returncode, output) from None
|
||||
finally:
|
||||
if write_report:
|
||||
if not report_path:
|
||||
|
|
|
@ -98,8 +98,8 @@ class ValidatorTestCase(test.TestCase):
|
|||
|
||||
result = DummyPluginBase.validate("dummy_plugin", None, None, None)
|
||||
self.assertEqual(1, len(result))
|
||||
self.assertIn("There is no DummyPluginBase plugin "
|
||||
"with name: 'dummy_plugin'", result[0])
|
||||
self.assertIn("There is no DummyPluginBase plugin `dummy_plugin`",
|
||||
result[0])
|
||||
|
||||
def test_failure_includes_detailed_info(self):
|
||||
|
||||
|
|
Loading…
Reference in New Issue