Browse Source

Merge "Fix several issues with plugin discovery error messages"

changes/40/707940/2
Zuul 5 days ago
parent
commit
d69025e23b
17 changed files with 79 additions and 45 deletions
  1. +5
    -0
      CHANGELOG.rst
  2. +2
    -1
      rally/cli/cliutils.py
  3. +3
    -0
      rally/cli/commands/plugin.py
  4. +1
    -1
      rally/common/objects/task.py
  5. +3
    -1
      rally/common/plugin/plugin.py
  6. +2
    -3
      rally/common/validation.py
  7. +2
    -1
      rally/exceptions.py
  8. +14
    -9
      rally/task/engine.py
  9. +6
    -0
      tests/ci/playbooks/rally-install/pre.yaml
  10. +13
    -5
      tests/ci/playbooks/rally-install/run.yaml
  11. +2
    -2
      tests/functional/test_cli_deployment.py
  12. +2
    -2
      tests/functional/test_cli_env.py
  13. +2
    -2
      tests/functional/test_cli_functional.py
  14. +16
    -13
      tests/functional/test_cli_plugin.py
  15. +3
    -2
      tests/functional/test_lib_api.py
  16. +1
    -1
      tests/functional/utils.py
  17. +2
    -2
      tests/unit/common/test_validation.py

+ 5
- 0
CHANGELOG.rst View File

@@ -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
--------------------

+ 2
- 1
rally/cli/cliutils.py View File

@@ -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)

+ 3
- 0
rally/cli/commands/plugin.py View File

@@ -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,

+ 1
- 1
rally/common/objects/task.py View File

@@ -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"]}

+ 3
- 1
rally/common/plugin/plugin.py View File

@@ -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]

+ 2
- 3
rally/common/validation.py View File

@@ -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

+ 2
- 1
rally/exceptions.py View File

@@ -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):

+ 14
- 9
rally/task/engine.py View File

@@ -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):

+ 6
- 0
tests/ci/playbooks/rally-install/pre.yaml View File

@@ -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
- 5
tests/ci/playbooks/rally-install/run.yaml View File

@@ -13,15 +13,23 @@
become: yes
when: bindep_output.stdout_lines

- name: Install Rally and check
- name: Install Rally system wide
shell:
cmd: |
# install system wide
sudo pip3 install --constraint ./upper-constraints.txt ./
executable: /bin/sh
chdir: '{{ zuul.project.src_dir }}'
cmd: "sudo pip3 install --constraint ./upper-constraints.txt ./"

- name: Check Rally base commands
shell:
cmd: |
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 }}'

+ 2
- 2
tests/functional/test_cli_deployment.py View File

@@ -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(

+ 2
- 2
tests/functional/test_cli_env.py View File

@@ -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()

+ 2
- 2
tests/functional/test_cli_functional.py View File

@@ -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:

+ 16
- 13
tests/functional/test_cli_plugin.py View File

@@ -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()

+ 3
- 2
tests/functional/test_lib_api.py View File

@@ -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)

+ 1
- 1
tests/functional/utils.py View File

@@ -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:

+ 2
- 2
tests/unit/common/test_validation.py View File

@@ -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…
Cancel
Save