Merge "Improve required_context validator to support platforms"
This commit is contained in:
commit
0740ece61a
|
@ -37,6 +37,19 @@ Added
|
|||
|
||||
* CI checks for Python 3.11 compatibility
|
||||
|
||||
* Support for specifying platform of context as a part of required_context
|
||||
validator like bellow:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from rally.task import scenario
|
||||
from rally.task import validation
|
||||
|
||||
@scenario.configure(name="Dummy.scenario")
|
||||
@validation.add("required_context", contexts=["ctx_name@platform"])
|
||||
class ElasticsearchLogInstanceName(scenario.Scenario):
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
Removed
|
||||
~~~~~~~
|
||||
|
|
|
@ -19,6 +19,8 @@ import jsonschema
|
|||
|
||||
from rally.common import logging
|
||||
from rally.common import validation
|
||||
from rally import exceptions
|
||||
from rally.task import context as context_lib
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -308,7 +310,7 @@ class RestrictedParametersValidator(validation.Validator):
|
|||
@validation.configure(name="required_contexts")
|
||||
class RequiredContextsValidator(validation.Validator):
|
||||
|
||||
def __init__(self, contexts, *args):
|
||||
def __init__(self, *args, contexts=None):
|
||||
"""Validator checks if required contexts are specified.
|
||||
|
||||
:param contexts: list of strings and tuples with context names that
|
||||
|
@ -323,25 +325,48 @@ class RequiredContextsValidator(validation.Validator):
|
|||
if args:
|
||||
LOG.warning("Positional argument is not what "
|
||||
"'required_context' decorator expects. "
|
||||
"Use `contexts` argument instead")
|
||||
"Use only `contexts` argument instead")
|
||||
else:
|
||||
# it is old way validator
|
||||
self.contexts = [contexts]
|
||||
# it is an old way validator
|
||||
self.contexts = []
|
||||
if contexts:
|
||||
self.contexts.append(contexts)
|
||||
self.contexts.extend(args)
|
||||
|
||||
@staticmethod
|
||||
def _match(requested_ctx_name, input_contexts):
|
||||
requested_ctx_name_extended = f"{requested_ctx_name}@"
|
||||
for input_ctx_name in input_contexts:
|
||||
if (requested_ctx_name == input_ctx_name
|
||||
or input_ctx_name.startswith(requested_ctx_name_extended)):
|
||||
return True
|
||||
|
||||
if "@" in requested_ctx_name:
|
||||
platform_aware_name, platform = requested_ctx_name.split("@")
|
||||
if platform_aware_name in input_contexts:
|
||||
try:
|
||||
ctx_cls = context_lib.Context.get(requested_ctx_name)
|
||||
except (exceptions.PluginNotFound,
|
||||
exceptions.MultiplePluginsFound):
|
||||
return False
|
||||
return ctx_cls.get_platform() == platform
|
||||
|
||||
return False
|
||||
|
||||
def validate(self, context, config, plugin_cls, plugin_cfg):
|
||||
missing_contexts = []
|
||||
input_context = config.get("contexts", {})
|
||||
input_contexts = config.get("contexts", {})
|
||||
|
||||
for name in self.contexts:
|
||||
if isinstance(name, tuple):
|
||||
if not set(name) & set(input_context):
|
||||
for required_ctx in self.contexts:
|
||||
if isinstance(required_ctx, tuple):
|
||||
if not any(self._match(r_ctx, input_contexts)
|
||||
for r_ctx in required_ctx):
|
||||
# formatted string like: 'foo or bar or baz'
|
||||
formatted_names = "'%s'" % " or ".join(name)
|
||||
formatted_names = "'%s'" % " or ".join(required_ctx)
|
||||
missing_contexts.append(formatted_names)
|
||||
else:
|
||||
if name not in input_context:
|
||||
missing_contexts.append(name)
|
||||
if not self._match(required_ctx, input_contexts):
|
||||
missing_contexts.append(required_ctx)
|
||||
|
||||
if missing_contexts:
|
||||
self.fail("The following context(s) are required but missing from "
|
||||
|
|
|
@ -20,6 +20,7 @@ import ddt
|
|||
from rally.common.plugin import plugin
|
||||
from rally.common import validation
|
||||
from rally.plugins.common import validators
|
||||
from rally.plugins.task.contexts import dummy as dummy_ctx
|
||||
from tests.unit import test
|
||||
|
||||
|
||||
|
@ -256,27 +257,53 @@ class RequiredContextsValidatorTestCase(test.TestCase):
|
|||
|
||||
def test_validate_failed(self):
|
||||
validator = validators.RequiredContextsValidator(
|
||||
contexts=("c1", "c2", "c3"))
|
||||
contexts=("c1@bar", "c2", "c3"))
|
||||
e = self.assertRaises(
|
||||
validation.ValidationError,
|
||||
validator.validate, self.credentials, {"contexts": {"a": 1}},
|
||||
None, None)
|
||||
self.assertEqual(
|
||||
"The following context(s) are required but missing from "
|
||||
"the input task file: c1, c2, c3", e.message)
|
||||
"the input task file: c1@bar, c2, c3", e.message)
|
||||
|
||||
@ddt.data(
|
||||
{"config": {
|
||||
"contexts": {"c1": 1, "c2": 2, "c3": 3,
|
||||
"b1": 1, "a1": 1}}},
|
||||
"contexts": {
|
||||
"a1": 1, "b1": 1, "c1@foo": 1, "c2": 2, "c3": 3
|
||||
}
|
||||
}},
|
||||
{"config": {
|
||||
"contexts": {"c1": 1, "c2": 2, "c3": 3,
|
||||
"b1": 1, "b2": 2, "a1": 1}}},
|
||||
"contexts": {
|
||||
"a1@foo": 1, "b1": 1, "c1": 1, "c2": 2, "c3": 3, "b2": 2
|
||||
}
|
||||
}},
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_validate_with_or(self, config):
|
||||
@dummy_ctx.context.configure(name="a1", platform="foo", order=0)
|
||||
class A1(dummy_ctx.DummyContext):
|
||||
pass
|
||||
|
||||
@dummy_ctx.context.configure(name="c1", platform="foo", order=0)
|
||||
class C1(dummy_ctx.DummyContext):
|
||||
pass
|
||||
|
||||
@dummy_ctx.context.configure(name="c2", platform="foo", order=0)
|
||||
class C2(dummy_ctx.DummyContext):
|
||||
pass
|
||||
|
||||
self.addCleanup(A1.unregister)
|
||||
self.addCleanup(C1.unregister)
|
||||
self.addCleanup(C2.unregister)
|
||||
|
||||
validator = validators.RequiredContextsValidator(
|
||||
contexts=[("a1", "a2"), "c1", ("b1", "b2"), "c2"])
|
||||
contexts=[("a1@foo", "a2"), "c1", ("b1", "b2"), "c2@foo"])
|
||||
validator.validate(self.credentials, config, None, None)
|
||||
|
||||
# check arg that should be ignored
|
||||
validator = validators.RequiredContextsValidator(
|
||||
"ignore@me",
|
||||
contexts=[("a1@foo", "a2"), "c1", ("b1", "b2"), "c2@foo"])
|
||||
validator.validate(self.credentials, config, None, None)
|
||||
|
||||
def test_validate_with_or_failed(self):
|
||||
|
|
Loading…
Reference in New Issue