Merge "Port hooks to the new format"
This commit is contained in:
commit
4a7cc010b1
@ -253,28 +253,25 @@
|
||||
times: 20
|
||||
concurrency: 2
|
||||
hooks:
|
||||
- name: sys_call
|
||||
description: Run script
|
||||
args: sh rally-jobs/extra/hook_example_script.sh
|
||||
- description: Run script
|
||||
action:
|
||||
sys_call: sh rally-jobs/extra/hook_example_script.sh
|
||||
trigger:
|
||||
name: event
|
||||
args:
|
||||
event:
|
||||
unit: iteration
|
||||
at: [2, 5, 8, 13, 17]
|
||||
- name: sys_call
|
||||
description: Show time
|
||||
args: date +%Y-%m-%dT%H:%M:%S
|
||||
- description: Show time
|
||||
action:
|
||||
sys_call: date +%Y-%m-%dT%H:%M:%S
|
||||
trigger:
|
||||
name: event
|
||||
args:
|
||||
event:
|
||||
unit: time
|
||||
at: [0, 2, 5, 6, 9]
|
||||
- name: sys_call
|
||||
description: Show system name
|
||||
args: uname -a
|
||||
- description: Show system name
|
||||
action:
|
||||
sys_call: uname -a
|
||||
trigger:
|
||||
name: event
|
||||
args:
|
||||
event:
|
||||
unit: iteration
|
||||
at: [2, 3, 4, 5, 6, 8, 10, 12, 13, 15, 17, 18]
|
||||
sla:
|
||||
@ -290,12 +287,11 @@
|
||||
times: 10
|
||||
concurrency: 2
|
||||
hooks:
|
||||
- name: sys_call
|
||||
description: test hook
|
||||
args: /bin/true
|
||||
- description: test hook
|
||||
action:
|
||||
sys_call: /bin/true
|
||||
trigger:
|
||||
name: periodic
|
||||
args:
|
||||
periodic:
|
||||
unit: iteration
|
||||
step: 2
|
||||
start: 4
|
||||
@ -312,12 +308,11 @@
|
||||
serial:
|
||||
times: 10
|
||||
hooks:
|
||||
- name: sys_call
|
||||
description: Get system name
|
||||
args: uname -a
|
||||
- description: Show system name
|
||||
action:
|
||||
sys_call: uname -a
|
||||
trigger:
|
||||
name: event
|
||||
args:
|
||||
event:
|
||||
unit: time
|
||||
at: [0, 2, 4, 6, 8, 10]
|
||||
sla:
|
||||
@ -332,12 +327,11 @@
|
||||
serial:
|
||||
times: 10
|
||||
hooks:
|
||||
- name: sys_call
|
||||
description: test hook
|
||||
args: /bin/true
|
||||
- description: test hook
|
||||
action:
|
||||
sys_call: /bin/true
|
||||
trigger:
|
||||
name: periodic
|
||||
args:
|
||||
periodic:
|
||||
unit: time
|
||||
step: 2
|
||||
start: 0
|
||||
|
@ -27,7 +27,7 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@hook.configure(name="sys_call")
|
||||
class SysCallHook(hook.Hook):
|
||||
class SysCallHook(hook.HookAction):
|
||||
"""Performs system call."""
|
||||
|
||||
CONFIG_SCHEMA = {
|
||||
|
@ -14,11 +14,11 @@
|
||||
# under the License.
|
||||
|
||||
from rally import consts
|
||||
from rally.task import trigger
|
||||
from rally.task import hook
|
||||
|
||||
|
||||
@trigger.configure(name="event")
|
||||
class EventTrigger(trigger.Trigger):
|
||||
@hook.configure(name="event")
|
||||
class EventTrigger(hook.HookTrigger):
|
||||
"""Triggers hook on specified event and list of values."""
|
||||
|
||||
CONFIG_SCHEMA = {
|
@ -14,11 +14,11 @@
|
||||
# under the License.
|
||||
|
||||
from rally import consts
|
||||
from rally.task import trigger
|
||||
from rally.task import hook
|
||||
|
||||
|
||||
@trigger.configure(name="periodic")
|
||||
class PeriodicTrigger(trigger.Trigger):
|
||||
@hook.configure(name="periodic")
|
||||
class PeriodicTrigger(hook.HookTrigger):
|
||||
"""Periodically triggers hook with specified range and step."""
|
||||
|
||||
CONFIG_SCHEMA = {
|
@ -33,7 +33,6 @@ from rally.task import hook
|
||||
from rally.task import runner
|
||||
from rally.task import scenario
|
||||
from rally.task import sla
|
||||
from rally.task import trigger
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -312,19 +311,22 @@ class TaskEngine(object):
|
||||
vtype=vtype))
|
||||
|
||||
for hook_conf in workload["hooks"]:
|
||||
results.extend(hook.Hook.validate(
|
||||
name=hook_conf["config"]["name"],
|
||||
action_name, action_cfg = list(
|
||||
hook_conf["config"]["action"].items())[0]
|
||||
results.extend(hook.HookAction.validate(
|
||||
name=action_name,
|
||||
context=vcontext,
|
||||
config=None,
|
||||
plugin_cfg=hook_conf["config"]["args"],
|
||||
plugin_cfg=action_cfg,
|
||||
vtype=vtype))
|
||||
|
||||
trigger_conf = hook_conf["config"]["trigger"]
|
||||
results.extend(trigger.Trigger.validate(
|
||||
name=trigger_conf["name"],
|
||||
trigger_name, trigger_cfg = list(
|
||||
hook_conf["config"]["trigger"].items())[0]
|
||||
results.extend(hook.HookTrigger.validate(
|
||||
name=trigger_name,
|
||||
context=vcontext,
|
||||
config=None,
|
||||
plugin_cfg=trigger_conf["args"],
|
||||
plugin_cfg=trigger_cfg,
|
||||
vtype=vtype))
|
||||
|
||||
if results:
|
||||
@ -495,26 +497,6 @@ class TaskConfig(object):
|
||||
|
||||
"""
|
||||
|
||||
HOOK_CONFIG = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"description": {"type": "string"},
|
||||
"args": {},
|
||||
"trigger": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"args": {},
|
||||
},
|
||||
"required": ["name", "args"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
},
|
||||
"required": ["name", "args", "trigger"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA_V1 = {
|
||||
"type": "object",
|
||||
"$schema": consts.JSON_SCHEMA,
|
||||
@ -537,12 +519,33 @@ class TaskConfig(object):
|
||||
"sla": {"type": "object"},
|
||||
"hooks": {
|
||||
"type": "array",
|
||||
"items": HOOK_CONFIG,
|
||||
"items": {"$ref": "#/definitions/hook"},
|
||||
}
|
||||
},
|
||||
"additionalProperties": False
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"hook": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"description": {"type": "string"},
|
||||
"args": {},
|
||||
"trigger": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"args": {},
|
||||
},
|
||||
"required": ["name", "args"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
},
|
||||
"required": ["name", "args", "trigger"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,7 +598,7 @@ class TaskConfig(object):
|
||||
"sla": {"type": "object"},
|
||||
"hooks": {
|
||||
"type": "array",
|
||||
"items": HOOK_CONFIG,
|
||||
"items": {"$ref": "#/definitions/hook"},
|
||||
},
|
||||
"contexts": {"type": "object"}
|
||||
},
|
||||
@ -627,7 +630,7 @@ class TaskConfig(object):
|
||||
"sla": {"type": "object"},
|
||||
"hooks": {
|
||||
"type": "array",
|
||||
"items": HOOK_CONFIG,
|
||||
"items": {"$ref": "#/definitions/hook"},
|
||||
},
|
||||
"contexts": {"type": "object"}
|
||||
},
|
||||
@ -638,6 +641,43 @@ class TaskConfig(object):
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["title", "workloads"]
|
||||
},
|
||||
"hook": {
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"description": {"type": "string"},
|
||||
"args": {},
|
||||
"trigger": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"args": {},
|
||||
},
|
||||
"required": ["name", "args"],
|
||||
"additionalProperties": False,
|
||||
}
|
||||
},
|
||||
"required": ["name", "args", "trigger"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"maxProperties": 1,
|
||||
"patternProperties": {".*": {}}
|
||||
},
|
||||
"trigger": {"$ref": "#/definitions/singleEntity"},
|
||||
"description": {"type": "string"},
|
||||
},
|
||||
"required": ["action", "trigger"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -718,8 +758,23 @@ class TaskConfig(object):
|
||||
else:
|
||||
wconf["runner"] = {"serial": {}}
|
||||
wconf.setdefault("sla", {"failure_rate": {"max": 0}})
|
||||
wconf.setdefault("hooks", [])
|
||||
wconf["hooks"] = [{"config": h} for h in wconf["hooks"]]
|
||||
|
||||
hooks = wconf.get("hooks", [])
|
||||
wconf["hooks"] = []
|
||||
for hook_cfg in hooks:
|
||||
if "name" in hook_cfg:
|
||||
LOG.warning("The deprecated format of hook is found. "
|
||||
"Check task format documentation for more "
|
||||
"details.")
|
||||
trigger_cfg = hook_cfg["trigger"]
|
||||
wconf["hooks"].append({"config": {
|
||||
"description": hook_cfg["description"],
|
||||
"action": {hook_cfg["name"]: hook_cfg["args"]},
|
||||
"trigger": {
|
||||
trigger_cfg["name"]: trigger_cfg["args"]}}
|
||||
})
|
||||
else:
|
||||
wconf["hooks"].append({"config": hook_cfg})
|
||||
|
||||
workloads.append(wconf)
|
||||
sconf["workloads"] = workloads
|
||||
@ -757,6 +812,18 @@ class TaskConfig(object):
|
||||
if "runner" in subtask:
|
||||
runner_type = subtask["runner"].pop("type")
|
||||
subtask["runner"] = {runner_type: subtask["runner"]}
|
||||
if "hooks" in subtask:
|
||||
hooks = subtask["hooks"]
|
||||
subtask["hooks"] = []
|
||||
for hook_cfg in hooks:
|
||||
trigger_cfg = hook_cfg["trigger"]
|
||||
subtask["hooks"].append(
|
||||
{"description": hook_cfg["description"],
|
||||
"action": {
|
||||
hook_cfg["name"]: hook_cfg["args"]},
|
||||
"trigger": {
|
||||
trigger_cfg["name"]: trigger_cfg["args"]}}
|
||||
)
|
||||
subtasks.append(subtask)
|
||||
return {"title": "Task (adopted from task format v1)",
|
||||
"subtasks": subtasks}
|
||||
|
@ -27,7 +27,6 @@ from rally.common import validation
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
from rally.task.processing import charts
|
||||
from rally.task import trigger
|
||||
from rally.task import utils
|
||||
|
||||
|
||||
@ -47,9 +46,11 @@ class HookExecutor(object):
|
||||
self.triggers = collections.defaultdict(list)
|
||||
for hook in config.get("hooks", []):
|
||||
hook_cfg = hook["config"]
|
||||
hook_cls = Hook.get(hook_cfg["name"])
|
||||
trigger_obj = trigger.Trigger.get(
|
||||
hook_cfg["trigger"]["name"])(hook_cfg, self.task, hook_cls)
|
||||
action_name = list(hook_cfg["action"].keys())[0]
|
||||
trigger_name = list(hook_cfg["trigger"].keys())[0]
|
||||
action_cls = HookAction.get(action_name)
|
||||
trigger_obj = HookTrigger.get(
|
||||
trigger_name)(hook_cfg, self.task, action_cls)
|
||||
event_type = trigger_obj.get_listening_event()
|
||||
self.triggers[event_type].append(trigger_obj)
|
||||
|
||||
@ -112,7 +113,7 @@ class HookExecutor(object):
|
||||
@validation.add_default("jsonschema")
|
||||
@plugin.base()
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class Hook(plugin.Plugin, validation.ValidatablePluginMixin):
|
||||
class HookAction(plugin.Plugin, validation.ValidatablePluginMixin):
|
||||
"""Factory for hook classes."""
|
||||
|
||||
CONFIG_SCHEMA = {"type": "null"}
|
||||
@ -205,3 +206,56 @@ class Hook(plugin.Plugin, validation.ValidatablePluginMixin):
|
||||
# hook is still running, wait for result
|
||||
self._thread.join()
|
||||
return self._result
|
||||
|
||||
|
||||
@validation.add_default("jsonschema")
|
||||
@plugin.base()
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class HookTrigger(plugin.Plugin, validation.ValidatablePluginMixin):
|
||||
"""Factory for hook trigger classes."""
|
||||
|
||||
CONFIG_SCHEMA = {"type": "null"}
|
||||
|
||||
def __init__(self, hook_cfg, task, hook_cls):
|
||||
self.hook_cfg = hook_cfg
|
||||
self.config = self.hook_cfg["trigger"][self.get_name()]
|
||||
self.task = task
|
||||
self.hook_cls = hook_cls
|
||||
self._runs = []
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_listening_event(self):
|
||||
"""Returns event type to listen."""
|
||||
|
||||
def on_event(self, event_type, value=None):
|
||||
"""Launch hook on specified event."""
|
||||
LOG.info(_("Hook action %s is triggered for Task %s by %s=%s")
|
||||
% (self.hook_cls.get_name(), self.task["uuid"],
|
||||
event_type, value))
|
||||
action_cfg = list(self.hook_cfg["action"].values())[0]
|
||||
action = self.hook_cls(self.task, action_cfg,
|
||||
{"event_type": event_type, "value": value})
|
||||
action.run_async()
|
||||
self._runs.append(action)
|
||||
|
||||
def get_results(self):
|
||||
results = {"config": self.hook_cfg,
|
||||
"results": [],
|
||||
"summary": {}}
|
||||
for action in self._runs:
|
||||
action_result = action.result()
|
||||
results["results"].append(action_result)
|
||||
results["summary"].setdefault(action_result["status"], 0)
|
||||
results["summary"][action_result["status"]] += 1
|
||||
return results
|
||||
|
||||
|
||||
class Hook(HookAction):
|
||||
"""DEPRECATED! USE `rally.task.hook.HookAction` instead."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Hook, self).__init__(*args, **kwargs)
|
||||
LOG.warning("Please contact Rally plugin maintainer. The plugin '%s' "
|
||||
"inherits the deprecated base class(Hook), "
|
||||
"`rally.task.hook.HookAction` should be used instead."
|
||||
% self.get_name())
|
||||
|
@ -33,7 +33,7 @@ def _process_hooks(hooks):
|
||||
"""Prepare hooks data for report."""
|
||||
hooks_ctx = []
|
||||
for hook in hooks:
|
||||
hook_ctx = {"name": hook["config"]["name"],
|
||||
hook_ctx = {"name": list(hook["config"]["action"].keys())[0],
|
||||
"desc": hook["config"].get("description", ""),
|
||||
"additive": [], "complete": []}
|
||||
|
||||
|
@ -13,56 +13,28 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
from rally.common.i18n import _
|
||||
from rally.common import logging
|
||||
from rally.common.plugin import plugin
|
||||
from rally.common import validation
|
||||
|
||||
configure = plugin.configure
|
||||
from rally.task import hook
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@validation.add_default("jsonschema")
|
||||
@plugin.base()
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class Trigger(plugin.Plugin, validation.ValidatablePluginMixin):
|
||||
"""Factory for trigger classes."""
|
||||
class Trigger(hook.HookTrigger):
|
||||
"""DEPRECATED!!! USE `rally.task.hook.HookTrigger` instead."""
|
||||
|
||||
CONFIG_SCHEMA = {"type": "null"}
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Trigger, self).__init__(*args, **kwargs)
|
||||
LOG.warning("Please contact Rally plugin maintainer. The plugin '%s' "
|
||||
"inherits the deprecated base class(Trigger), "
|
||||
"`rally.task.hook.HookTrigger` should be used instead."
|
||||
% self.get_name())
|
||||
|
||||
def __init__(self, context, task, hook_cls):
|
||||
self.context = context
|
||||
self.config = self.context["trigger"]["args"]
|
||||
self.task = task
|
||||
self.hook_cls = hook_cls
|
||||
self._runs = []
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_listening_event(self):
|
||||
"""Returns event type to listen."""
|
||||
|
||||
def on_event(self, event_type, value=None):
|
||||
"""Launch hook on specified event."""
|
||||
LOG.info(_("Hook %s is triggered for Task %s by %s=%s")
|
||||
% (self.hook_cls.__name__, self.task["uuid"],
|
||||
event_type, value))
|
||||
hook = self.hook_cls(self.task, self.context.get("args", {}),
|
||||
{"event_type": event_type, "value": value})
|
||||
hook.run_async()
|
||||
self._runs.append(hook)
|
||||
|
||||
def get_results(self):
|
||||
results = {"config": self.context,
|
||||
"results": [],
|
||||
"summary": {}}
|
||||
for hook in self._runs:
|
||||
hook_result = hook.result()
|
||||
results["results"].append(hook_result)
|
||||
results["summary"].setdefault(hook_result["status"], 0)
|
||||
results["summary"][hook_result["status"]] += 1
|
||||
return results
|
||||
@property
|
||||
def context(self):
|
||||
action_name, action_cfg = list(self.hook_cfg["action"].items())[0]
|
||||
trigger_name, trigger_cfg = list(self.hook_cfg["trigger"].items())[0]
|
||||
return {"description": self.hook_cfg["description"],
|
||||
"name": action_name,
|
||||
"args": action_cfg,
|
||||
"trigger": {"name": trigger_name,
|
||||
"args": trigger_cfg}}
|
||||
|
@ -31,7 +31,7 @@ class SysCallHookTestCase(test.TestCase):
|
||||
@ddt.data(("ls", True), (50, False))
|
||||
@ddt.unpack
|
||||
def test_validate(self, config, valid):
|
||||
results = hook.Hook.validate(
|
||||
results = hook.HookAction.validate(
|
||||
"sys_call", None, None, config)
|
||||
if valid:
|
||||
self.assertEqual([], results)
|
||||
|
@ -16,8 +16,8 @@
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from rally.plugins.common.trigger import event
|
||||
from rally.task import trigger
|
||||
from rally.plugins.common.hook.triggers import event
|
||||
from rally.task import hook
|
||||
from tests.unit import test
|
||||
|
||||
|
||||
@ -28,8 +28,8 @@ class EventTriggerTestCase(test.TestCase):
|
||||
super(EventTriggerTestCase, self).setUp()
|
||||
self.hook_cls = mock.MagicMock(__name__="name")
|
||||
self.trigger = event.EventTrigger(
|
||||
{"trigger": {"name": "event",
|
||||
"args": {"unit": "iteration", "at": [1, 4, 5]}}},
|
||||
{"trigger": {"event": {"unit": "iteration", "at": [1, 4, 5]}},
|
||||
"action": {"foo": {}}},
|
||||
mock.MagicMock(), self.hook_cls)
|
||||
|
||||
@ddt.data((dict(unit="time", at=[0, 3, 5]), True),
|
||||
@ -51,7 +51,7 @@ class EventTriggerTestCase(test.TestCase):
|
||||
(dict(at=[1, 2, 3]), False))
|
||||
@ddt.unpack
|
||||
def test_validate(self, config, valid):
|
||||
results = trigger.Trigger.validate("event", None, None, config)
|
||||
results = hook.HookTrigger.validate("event", None, None, config)
|
||||
if valid:
|
||||
self.assertEqual([], results)
|
||||
else:
|
@ -16,8 +16,8 @@
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from rally.plugins.common.trigger import periodic
|
||||
from rally.task import trigger
|
||||
from rally.plugins.common.hook.triggers import periodic
|
||||
from rally.task import hook
|
||||
from tests.unit import test
|
||||
|
||||
|
||||
@ -28,8 +28,8 @@ class PeriodicTriggerTestCase(test.TestCase):
|
||||
super(PeriodicTriggerTestCase, self).setUp()
|
||||
self.hook_cls = mock.MagicMock(__name__="name")
|
||||
self.trigger = periodic.PeriodicTrigger(
|
||||
{"trigger": {"name": "periodic",
|
||||
"args": {"unit": "iteration", "step": 2}}},
|
||||
{"trigger": {"periodic": {"unit": "iteration", "step": 2}},
|
||||
"action": {"foo": {}}},
|
||||
mock.MagicMock(), self.hook_cls)
|
||||
|
||||
@ddt.data((dict(unit="time", step=1), True),
|
||||
@ -52,7 +52,7 @@ class PeriodicTriggerTestCase(test.TestCase):
|
||||
(dict(step=1), False))
|
||||
@ddt.unpack
|
||||
def test_validate(self, config, valid):
|
||||
results = trigger.Trigger.validate("periodic", None, None, config)
|
||||
results = hook.HookTrigger.validate("periodic", None, None, config)
|
||||
if valid:
|
||||
self.assertEqual([], results)
|
||||
else:
|
||||
@ -74,9 +74,9 @@ class PeriodicTriggerTestCase(test.TestCase):
|
||||
@ddt.unpack
|
||||
def test_on_event_start_end(self, value, should_call):
|
||||
trigger = periodic.PeriodicTrigger(
|
||||
{"trigger": {"name": "periodic",
|
||||
"args": {"unit": "time",
|
||||
"step": 3, "start": 2, "end": 9}}},
|
||||
{"trigger": {"periodic": {"unit": "time",
|
||||
"step": 3, "start": 2, "end": 9}},
|
||||
"action": {"foo": {}}},
|
||||
mock.MagicMock(), self.hook_cls)
|
||||
trigger.on_event("time", value)
|
||||
self.assertEqual(should_call, self.hook_cls.called)
|
@ -40,7 +40,8 @@ class FaultInjectionHookTestCase(test.TestCase):
|
||||
(dict(), False))
|
||||
@ddt.unpack
|
||||
def test_config_schema(self, config, valid):
|
||||
results = hook.Hook.validate("fault_injection", None, None, config)
|
||||
results = hook.HookAction.validate("fault_injection", None, None,
|
||||
config)
|
||||
if valid:
|
||||
self.assertEqual([], results)
|
||||
else:
|
||||
|
@ -87,48 +87,65 @@ class PlotTestCase(test.TestCase):
|
||||
@ddt.data(
|
||||
{"hooks": [], "expected": []},
|
||||
{"hooks": [
|
||||
{"config": {
|
||||
"trigger": {"args": {"at": [2, 5], "unit": "iteration"},
|
||||
"name": "event"},
|
||||
"args": "foo cmd", "description": "Foo", "name": "sys_call"},
|
||||
"results": [
|
||||
{"status": "success", "finished_at": 1475589987.525735,
|
||||
"triggered_by": {"event_type": "iteration", "value": 2},
|
||||
"started_at": 1475589987.433399,
|
||||
"output": {
|
||||
"additive": [
|
||||
{"chart_plugin": "StatsTable", "title": "Foo table",
|
||||
"data": [["A", 158], ["B", 177]]}],
|
||||
"complete": []}},
|
||||
{"status": "success", "finished_at": 1475589993.457818,
|
||||
"triggered_by": {"event_type": "iteration", "value": 5},
|
||||
"started_at": 1475589993.432734,
|
||||
"output": {
|
||||
"additive": [
|
||||
{"chart_plugin": "StatsTable", "title": "Foo table",
|
||||
"data": [["A", 243], ["B", 179]]}],
|
||||
"complete": []}}],
|
||||
"summary": {"success": 2}},
|
||||
{"config": {"trigger": {"args": {"at": [1, 2, 4], "unit": "time"},
|
||||
"name": "event"},
|
||||
"args": "bar cmd", "name": "sys_call"},
|
||||
"results": [
|
||||
{"status": "success", "finished_at": 1475589988.437791,
|
||||
"triggered_by": {"event_type": "time", "value": 1},
|
||||
"started_at": 1475589988.434244,
|
||||
"output": {"additive": [],
|
||||
"complete": [
|
||||
{"chart_plugin": "Pie", "title": "Bar Pie",
|
||||
"data": [["F", 4], ["G", 2]]}]}},
|
||||
{"status": "success",
|
||||
"finished_at": 1475589989.437589,
|
||||
"triggered_by": {"event_type": "time", "value": 2},
|
||||
"started_at": 1475589989.433964,
|
||||
"output": {"additive": [],
|
||||
"complete": [
|
||||
{"chart_plugin": "Pie", "title": "Bar Pie",
|
||||
"data": [["F", 42], ["G", 24]]}]}}],
|
||||
"summary": {"success": 2}}],
|
||||
{
|
||||
"config": {
|
||||
"description": "Foo",
|
||||
"action": {"sys_call": "foo cmd"},
|
||||
"trigger": {"event": {"at": [2, 5], "unit": "iteration"}}},
|
||||
"results": [
|
||||
{
|
||||
"status": "success",
|
||||
"started_at": 1475589987.433399,
|
||||
"finished_at": 1475589987.525735,
|
||||
"triggered_by": {"event_type": "iteration",
|
||||
"value": 2},
|
||||
"output": {
|
||||
"additive": [
|
||||
{"chart_plugin": "StatsTable",
|
||||
"title": "Foo table",
|
||||
"data": [["A", 158], ["B", 177]]}],
|
||||
"complete": []}},
|
||||
{
|
||||
"status": "success",
|
||||
"started_at": 1475589993.432734,
|
||||
"finished_at": 1475589993.457818,
|
||||
"triggered_by": {"event_type": "iteration",
|
||||
"value": 5},
|
||||
"output": {
|
||||
"additive": [
|
||||
{"chart_plugin": "StatsTable",
|
||||
"title": "Foo table",
|
||||
"data": [["A", 243], ["B", 179]]}],
|
||||
"complete": []}}],
|
||||
"summary": {"success": 2}},
|
||||
{
|
||||
"config": {
|
||||
"action": {"sys_call": "bar cmd"},
|
||||
"trigger": {"event": {"at": [1, 2, 4], "unit": "time"}}},
|
||||
"results": [
|
||||
{
|
||||
"status": "success",
|
||||
"started_at": 1475589988.434244,
|
||||
"finished_at": 1475589988.437791,
|
||||
"triggered_by": {"event_type": "time", "value": 1},
|
||||
"output": {
|
||||
"additive": [],
|
||||
"complete": [
|
||||
{"chart_plugin": "Pie",
|
||||
"title": "Bar Pie",
|
||||
"data": [["F", 4], ["G", 2]]}]}},
|
||||
{
|
||||
"status": "success",
|
||||
"started_at": 1475589989.433964,
|
||||
"finished_at": 1475589989.437589,
|
||||
"triggered_by": {"event_type": "time", "value": 2},
|
||||
"output": {
|
||||
"additive": [],
|
||||
"complete": [
|
||||
{"chart_plugin": "Pie",
|
||||
"title": "Bar Pie",
|
||||
"data": [["F", 42], ["G", 24]]}]}}],
|
||||
"summary": {"success": 2}}],
|
||||
"expected": [
|
||||
{"additive": [
|
||||
{"data": {"cols": ["Action", "Min (sec)", "Median (sec)",
|
||||
|
@ -128,8 +128,8 @@ class TaskEngineTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("rally.task.engine.scenario.Scenario.get")
|
||||
@mock.patch("rally.task.sla.SLA.validate")
|
||||
@mock.patch("rally.task.trigger.Trigger.validate")
|
||||
@mock.patch("rally.task.hook.Hook.validate")
|
||||
@mock.patch("rally.task.hook.HookTrigger.validate")
|
||||
@mock.patch("rally.task.hook.HookAction.validate")
|
||||
@mock.patch("rally.task.engine.TaskConfig")
|
||||
@mock.patch("rally.task.engine.runner.ScenarioRunner.validate")
|
||||
@mock.patch("rally.task.engine.context.Context.validate")
|
||||
@ -137,15 +137,15 @@ class TaskEngineTestCase(test.TestCase):
|
||||
self, mock_context_validate,
|
||||
mock_scenario_runner_validate,
|
||||
mock_task_config,
|
||||
mock_hook_validate,
|
||||
mock_trigger_validate,
|
||||
mock_hook_action_validate,
|
||||
mock_hook_trigger_validate,
|
||||
mock_sla_validate,
|
||||
mock_scenario_get):
|
||||
|
||||
mock_context_validate.return_value = []
|
||||
mock_sla_validate.return_value = []
|
||||
mock_hook_validate.return_value = []
|
||||
mock_trigger_validate.return_value = []
|
||||
mock_hook_action_validate.return_value = []
|
||||
mock_hook_trigger_validate.return_value = []
|
||||
default_context = {"foo": "foo_conf"}
|
||||
scenario_cls = mock_scenario_get.return_value
|
||||
scenario_cls.get_platform.return_value = "default"
|
||||
@ -153,9 +153,8 @@ class TaskEngineTestCase(test.TestCase):
|
||||
|
||||
scenario_name = "Foo.bar"
|
||||
runner_type = "MegaRunner"
|
||||
hook_conf = {"name": "c",
|
||||
"args": "c_args",
|
||||
"trigger": {"name": "d", "args": "d_args"}}
|
||||
hook_conf = {"action": {"c": "c_args"},
|
||||
"trigger": {"d": "d_args"}}
|
||||
workload = {"name": scenario_name,
|
||||
"runner": {"type": runner_type},
|
||||
"context": {"a": "a_conf"},
|
||||
@ -186,10 +185,10 @@ class TaskEngineTestCase(test.TestCase):
|
||||
mock_sla_validate.assert_called_once_with(
|
||||
config=None, context=None,
|
||||
name="foo_sla", plugin_cfg="sla_conf", vtype=None)
|
||||
mock_hook_validate.assert_called_once_with(
|
||||
mock_hook_action_validate.assert_called_once_with(
|
||||
config=None, context=None, name="c", plugin_cfg="c_args",
|
||||
vtype=None)
|
||||
mock_trigger_validate.assert_called_once_with(
|
||||
mock_hook_trigger_validate.assert_called_once_with(
|
||||
config=None, context=None, name="d", plugin_cfg="d_args",
|
||||
vtype=None)
|
||||
|
||||
@ -270,21 +269,21 @@ class TaskEngineTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("rally.task.engine.json.dumps")
|
||||
@mock.patch("rally.task.engine.scenario.Scenario.get")
|
||||
@mock.patch("rally.task.hook.Hook.validate")
|
||||
@mock.patch("rally.task.trigger.Trigger.validate")
|
||||
@mock.patch("rally.task.hook.HookAction.validate")
|
||||
@mock.patch("rally.task.hook.HookTrigger.validate")
|
||||
@mock.patch("rally.task.engine.TaskConfig")
|
||||
def test__validate_config_syntax__wrong_hook(
|
||||
self, mock_task_config, mock_trigger_validate, mock_hook_validate,
|
||||
self, mock_task_config, mock_hook_trigger_validate,
|
||||
mock_hook_action_validate,
|
||||
mock_scenario_get, mock_dumps):
|
||||
mock_dumps.return_value = "<JSON>"
|
||||
mock_trigger_validate.return_value = []
|
||||
mock_hook_validate.return_value = ["hook_error"]
|
||||
mock_hook_trigger_validate.return_value = []
|
||||
mock_hook_action_validate.return_value = ["hook_error"]
|
||||
scenario_cls = mock_scenario_get.return_value
|
||||
scenario_cls.get_default_context.return_value = {}
|
||||
mock_task_instance = mock.MagicMock()
|
||||
hook_conf = {"name": "c",
|
||||
"args": "c_args",
|
||||
"trigger": {"name": "d", "args": "d_args"}}
|
||||
hook_conf = {"action": {"c": "c_args"},
|
||||
"trigger": {"d": "d_args"}}
|
||||
mock_task_instance.subtasks = [{"workloads": [
|
||||
self._make_workload(name="sca"),
|
||||
self._make_workload(name="sca", position=1,
|
||||
@ -303,21 +302,21 @@ class TaskEngineTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("rally.task.engine.json.dumps")
|
||||
@mock.patch("rally.task.engine.scenario.Scenario.get")
|
||||
@mock.patch("rally.task.trigger.Trigger.validate")
|
||||
@mock.patch("rally.task.hook.Hook.validate")
|
||||
@mock.patch("rally.task.hook.HookTrigger.validate")
|
||||
@mock.patch("rally.task.hook.HookAction.validate")
|
||||
@mock.patch("rally.task.engine.TaskConfig")
|
||||
def test__validate_config_syntax__wrong_trigger(
|
||||
self, mock_task_config, mock_hook_validate, mock_trigger_validate,
|
||||
self, mock_task_config, mock_hook_action_validate,
|
||||
mock_hook_trigger_validate,
|
||||
mock_scenario_get, mock_dumps):
|
||||
mock_dumps.return_value = "<JSON>"
|
||||
mock_trigger_validate.return_value = ["trigger_error"]
|
||||
mock_hook_validate.return_value = []
|
||||
mock_hook_trigger_validate.return_value = ["trigger_error"]
|
||||
mock_hook_action_validate.return_value = []
|
||||
scenario_cls = mock_scenario_get.return_value
|
||||
scenario_cls.get_default_context.return_value = {}
|
||||
mock_task_instance = mock.MagicMock()
|
||||
hook_conf = {"name": "c",
|
||||
"args": "c_args",
|
||||
"trigger": {"name": "d", "args": "d_args"}}
|
||||
hook_conf = {"action": {"c": "c_args"},
|
||||
"trigger": {"d": "d_args"}}
|
||||
mock_task_instance.subtasks = [{"workloads": [
|
||||
self._make_workload(name="sca"),
|
||||
self._make_workload(name="sca", position=1,
|
||||
@ -954,7 +953,7 @@ class ResultConsumerTestCase(test.TestCase):
|
||||
self.assertEqual(4, mock_task_get_status.call_count)
|
||||
|
||||
|
||||
class TaskTestCase(test.TestCase):
|
||||
class TaskConfigTestCase(test.TestCase):
|
||||
@mock.patch("jsonschema.validate")
|
||||
def test_validate_json(self, mock_validate):
|
||||
config = {}
|
||||
@ -996,19 +995,75 @@ class TaskTestCase(test.TestCase):
|
||||
config = collections.OrderedDict()
|
||||
config["a.task"] = [{"s": 1, "context": {"foo": "bar"}}, {"s": 2}]
|
||||
config["b.task"] = [{"s": 3, "sla": {"key": "value"}}]
|
||||
config["c.task"] = [{"s": 5,
|
||||
"hooks": [{"name": "foo",
|
||||
"args": "bar",
|
||||
"description": "DESCR!!!",
|
||||
"trigger": {
|
||||
"name": "mega-trigger",
|
||||
"args": {"some": "thing"}
|
||||
}}]
|
||||
}]
|
||||
self.assertEqual(
|
||||
{"title": "Task (adopted from task format v1)",
|
||||
"subtasks": [{"title": "a.task",
|
||||
"scenario": {"a.task": {}},
|
||||
"s": 1,
|
||||
"contexts": {"foo": "bar"}},
|
||||
{"title": "a.task",
|
||||
"s": 2,
|
||||
"scenario": {"a.task": {}},
|
||||
"contexts": {}},
|
||||
{"title": "b.task",
|
||||
"s": 3,
|
||||
"scenario": {"b.task": {}},
|
||||
"sla": {"key": "value"},
|
||||
"contexts": {}}]},
|
||||
"subtasks": [
|
||||
{
|
||||
"title": "a.task",
|
||||
"scenario": {"a.task": {}},
|
||||
"s": 1,
|
||||
"contexts": {"foo": "bar"}
|
||||
},
|
||||
{
|
||||
"title": "a.task",
|
||||
"s": 2,
|
||||
"scenario": {"a.task": {}},
|
||||
"contexts": {}
|
||||
},
|
||||
{
|
||||
"title": "b.task",
|
||||
"s": 3,
|
||||
"scenario": {"b.task": {}},
|
||||
"sla": {"key": "value"},
|
||||
"contexts": {}
|
||||
},
|
||||
{
|
||||
"title": "c.task",
|
||||
"s": 5,
|
||||
"scenario": {"c.task": {}},
|
||||
"contexts": {},
|
||||
"hooks": [
|
||||
{"description": "DESCR!!!",
|
||||
"action": {"foo": "bar"},
|
||||
"trigger": {"mega-trigger": {"some": "thing"}}}
|
||||
]
|
||||
}]},
|
||||
TaskConfig._adopt_task_format_v1(config))
|
||||
|
||||
def test_hook_config_compatibility(self):
|
||||
cfg = {
|
||||
"title": "foo",
|
||||
"version": 2,
|
||||
"subtasks": [
|
||||
{
|
||||
"title": "foo",
|
||||
"scenario": {"xxx": {}},
|
||||
"runner": {"yyy": {}},
|
||||
"hooks": [
|
||||
{"description": "descr",
|
||||
"name": "hook_action",
|
||||
"args": {"k1": "v1"},
|
||||
"trigger": {
|
||||
"name": "hook_trigger",
|
||||
"args": {"k2": "v2"}
|
||||
}}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
task = engine.TaskConfig(cfg)
|
||||
workload = task.subtasks[0]["workloads"][0]
|
||||
self.assertEqual(
|
||||
{"description": "descr",
|
||||
"action": {"hook_action": {"k1": "v1"}},
|
||||
"trigger": {"hook_trigger": {"k2": "v2"}}},
|
||||
workload["hooks"][0]["config"])
|
||||
|
@ -25,7 +25,7 @@ from tests.unit import test
|
||||
|
||||
|
||||
@hook.configure(name="dummy_hook")
|
||||
class DummyHook(hook.Hook):
|
||||
class DummyHookAction(hook.HookAction):
|
||||
CONFIG_SCHEMA = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -56,14 +56,12 @@ class HookExecutorTestCase(test.TestCase):
|
||||
self.conf = {
|
||||
"hooks": [
|
||||
{"config": {
|
||||
"name": "dummy_hook",
|
||||
"description": "dummy_action",
|
||||
"args": {
|
||||
"status": consts.HookStatus.SUCCESS,
|
||||
"action": {
|
||||
"dummy_hook": {"status": consts.HookStatus.SUCCESS}
|
||||
},
|
||||
"trigger": {
|
||||
"name": "event",
|
||||
"args": {
|
||||
"event": {
|
||||
"unit": "iteration",
|
||||
"at": [1],
|
||||
}
|
||||
@ -92,7 +90,7 @@ class HookExecutorTestCase(test.TestCase):
|
||||
@mock.patch("rally.task.hook.HookExecutor._timer_method")
|
||||
@mock.patch("rally.common.utils.Timer", side_effect=fakes.FakeTimer)
|
||||
def test_result_optional(self, mock_timer, mock__timer_method):
|
||||
hook_args = self.conf["hooks"][0]["config"]["args"]
|
||||
hook_args = list(self.conf["hooks"][0]["config"]["action"].values())[0]
|
||||
hook_args["error"] = ["Exception", "Description", "Traceback"]
|
||||
hook_args["output"] = {"additive": None, "complete": None}
|
||||
|
||||
@ -120,9 +118,10 @@ class HookExecutorTestCase(test.TestCase):
|
||||
hook_executor.results())
|
||||
|
||||
@mock.patch("rally.task.hook.HookExecutor._timer_method")
|
||||
@mock.patch.object(DummyHook, "run", side_effect=Exception("My err msg"))
|
||||
@mock.patch.object(DummyHookAction, "run",
|
||||
side_effect=Exception("My err msg"))
|
||||
@mock.patch("rally.common.utils.Timer", side_effect=fakes.FakeTimer)
|
||||
def test_failed_result(self, mock_timer, mock_dummy_hook_run,
|
||||
def test_failed_result(self, mock_timer, mock_dummy_hook_action_run,
|
||||
mock__timer_method):
|
||||
hook_executor = hook.HookExecutor(self.conf, self.task)
|
||||
hook_executor.on_event(event_type="iteration", value=1)
|
||||
@ -141,7 +140,8 @@ class HookExecutorTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("rally.common.utils.Timer", side_effect=fakes.FakeTimer)
|
||||
def test_time_event(self, mock_timer):
|
||||
trigger_args = self.conf["hooks"][0]["config"]["trigger"]["args"]
|
||||
trigger_args = list(
|
||||
self.conf["hooks"][0]["config"]["trigger"].values())[0]
|
||||
trigger_args["unit"] = "time"
|
||||
|
||||
hook_executor = hook.HookExecutor(self.conf, self.task)
|
||||
@ -160,7 +160,7 @@ class HookExecutorTestCase(test.TestCase):
|
||||
@mock.patch("rally.common.utils.Timer", side_effect=fakes.FakeTimer)
|
||||
def test_time_periodic(self, mock_timer):
|
||||
self.conf["hooks"][0]["config"]["trigger"] = {
|
||||
"name": "periodic", "args": {"unit": "time", "step": 2}}
|
||||
"periodic": {"unit": "time", "step": 2}}
|
||||
hook_executor = hook.HookExecutor(self.conf, self.task)
|
||||
|
||||
for i in range(1, 7):
|
||||
@ -196,7 +196,8 @@ class HookExecutorTestCase(test.TestCase):
|
||||
@mock.patch("rally.common.utils.Stopwatch", autospec=True)
|
||||
@mock.patch("rally.common.utils.Timer", side_effect=fakes.FakeTimer)
|
||||
def test_timer_thread(self, mock_timer, mock_stopwatch):
|
||||
trigger_args = self.conf["hooks"][0]["config"]["trigger"]["args"]
|
||||
trigger_args = list(
|
||||
self.conf["hooks"][0]["config"]["trigger"].values())[0]
|
||||
trigger_args["unit"] = "time"
|
||||
hook_executor = hook.HookExecutor(self.conf, self.task)
|
||||
|
||||
@ -235,7 +236,7 @@ class HookTestCase(test.TestCase):
|
||||
@ddt.data(({"status": "foo"}, True), (3, False))
|
||||
@ddt.unpack
|
||||
def test_validate(self, config, valid):
|
||||
results = hook.Hook.validate(
|
||||
results = hook.HookAction.validate(
|
||||
"dummy_hook", None, None, config)
|
||||
if valid:
|
||||
self.assertEqual([], results)
|
||||
@ -246,8 +247,8 @@ class HookTestCase(test.TestCase):
|
||||
def test_result(self, mock_timer):
|
||||
task = mock.MagicMock()
|
||||
triggered_by = {"event_type": "iteration", "value": 1}
|
||||
dummy_hook = DummyHook(task, {"status": consts.HookStatus.SUCCESS},
|
||||
triggered_by)
|
||||
dummy_hook = DummyHookAction(
|
||||
task, {"status": consts.HookStatus.SUCCESS}, triggered_by)
|
||||
dummy_hook.run_sync()
|
||||
|
||||
self.assertEqual(
|
||||
@ -259,11 +260,80 @@ class HookTestCase(test.TestCase):
|
||||
def test_result_not_started(self):
|
||||
task = mock.MagicMock()
|
||||
triggered_by = {"event_type": "iteration", "value": 1}
|
||||
dummy_hook = DummyHook(task, {"status": consts.HookStatus.SUCCESS},
|
||||
triggered_by)
|
||||
dummy_hook = DummyHookAction(task,
|
||||
{"status": consts.HookStatus.SUCCESS},
|
||||
triggered_by)
|
||||
|
||||
self.assertEqual(
|
||||
{"started_at": 0.0,
|
||||
"finished_at": 0.0,
|
||||
"triggered_by": triggered_by,
|
||||
"status": consts.HookStatus.SUCCESS}, dummy_hook.result())
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TriggerTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TriggerTestCase, self).setUp()
|
||||
|
||||
@hook.configure(name="dummy_trigger")
|
||||
class DummyTrigger(hook.HookTrigger):
|
||||
CONFIG_SCHEMA = {"type": "array",
|
||||
"minItems": 1,
|
||||
"uniqueItems": True,
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
}}
|
||||
|
||||
def get_listening_event(self):
|
||||
return "dummy"
|
||||
|
||||
def on_event(self, event_type, value=None):
|
||||
if value not in self.config:
|
||||
return
|
||||
super(DummyTrigger, self).on_event(event_type, value)
|
||||
|
||||
self.DummyTrigger = DummyTrigger
|
||||
|
||||
self.addCleanup(DummyTrigger.unregister)
|
||||
|
||||
@ddt.data(([5], True), ("str", False))
|
||||
@ddt.unpack
|
||||
def test_validate(self, config, valid):
|
||||
results = hook.HookTrigger.validate(
|
||||
"dummy_trigger", None, None, config)
|
||||
if valid:
|
||||
self.assertEqual([], results)
|
||||
else:
|
||||
self.assertEqual(1, len(results))
|
||||
|
||||
def test_on_event_and_get_results(self):
|
||||
|
||||
# get_results requires launched hooks, so if we want to test it, we
|
||||
# need to duplicate all calls on_event. It is redundant, so let's merge
|
||||
# test_on_event and test_get_results in one test.
|
||||
right_values = [5, 7, 12, 13]
|
||||
|
||||
cfg = {"trigger": {self.DummyTrigger.get_name(): right_values},
|
||||
"action": {"fake": {}}}
|
||||
task = mock.MagicMock()
|
||||
hook_cls = mock.MagicMock(__name__="fake")
|
||||
dummy_trigger = self.DummyTrigger(cfg, task, hook_cls)
|
||||
for i in range(0, 20):
|
||||
dummy_trigger.on_event("fake", i)
|
||||
|
||||
self.assertEqual(
|
||||
[mock.call(task, {}, {"event_type": "fake", "value": i})
|
||||
for i in right_values],
|
||||
hook_cls.call_args_list)
|
||||
self.assertEqual(len(right_values),
|
||||
hook_cls.return_value.run_async.call_count)
|
||||
hook_status = hook_cls.return_value.result.return_value["status"]
|
||||
self.assertEqual(
|
||||
{"config": cfg,
|
||||
"results": [hook_cls.return_value.result.return_value] *
|
||||
len(right_values),
|
||||
"summary": {hook_status: len(right_values)}},
|
||||
dummy_trigger.get_results())
|
||||
|
@ -15,68 +15,50 @@
|
||||
|
||||
"""Tests for Trigger base class."""
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from rally.task import trigger
|
||||
from tests.unit import test
|
||||
|
||||
|
||||
@trigger.configure(name="dummy_trigger")
|
||||
class DummyTrigger(trigger.Trigger):
|
||||
CONFIG_SCHEMA = {"type": "array",
|
||||
"minItems": 1,
|
||||
"uniqueItems": True,
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
}}
|
||||
|
||||
def get_listening_event(self):
|
||||
return "dummy"
|
||||
|
||||
def on_event(self, event_type, value=None):
|
||||
if value not in self.config:
|
||||
return
|
||||
super(DummyTrigger, self).on_event(event_type, value)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TriggerTestCase(test.TestCase):
|
||||
|
||||
@ddt.data(([5], True), ("str", False))
|
||||
@ddt.unpack
|
||||
def test_validate(self, config, valid):
|
||||
results = trigger.Trigger.validate(
|
||||
"dummy_trigger", None, None, config)
|
||||
if valid:
|
||||
self.assertEqual([], results)
|
||||
else:
|
||||
self.assertEqual(1, len(results))
|
||||
def setUp(self):
|
||||
super(TriggerTestCase, self).setUp()
|
||||
|
||||
def test_on_event_and_get_results(self):
|
||||
# get_results requires launched hooks, so if we want to test it, we
|
||||
# need to duplicate all calls on_event. It is redundant, so let's merge
|
||||
# test_on_event and test_get_results in one test.
|
||||
right_values = [5, 7, 12, 13]
|
||||
@trigger.hook.configure(self.id())
|
||||
class DummyTrigger(trigger.Trigger):
|
||||
def get_listening_event(self):
|
||||
return "dummy"
|
||||
|
||||
cfg = {"trigger": {"args": right_values}}
|
||||
task = mock.MagicMock()
|
||||
hook_cls = mock.MagicMock(__name__="fake")
|
||||
dummy_trigger = DummyTrigger(cfg, task, hook_cls)
|
||||
for i in range(0, 20):
|
||||
dummy_trigger.on_event("fake", i)
|
||||
self.addCleanup(DummyTrigger.unregister)
|
||||
self.DummyTrigger = DummyTrigger
|
||||
|
||||
@mock.patch("rally.task.trigger.LOG.warning")
|
||||
def test_warning(self, mock_log_warning):
|
||||
self.DummyTrigger({"trigger": {self.id(): {}}}, None, None)
|
||||
|
||||
mock_log_warning.assert_called_once_with(
|
||||
"Please contact Rally plugin maintainer. The plugin '%s'"
|
||||
" inherits the deprecated base class(Trigger), "
|
||||
"`rally.task.hook.HookTrigger` should be used instead." %
|
||||
self.id())
|
||||
|
||||
def test_context(self):
|
||||
action_name = "mega_action"
|
||||
action_cfg = {"action_arg": "action_value"}
|
||||
trigger_name = self.id()
|
||||
trigger_cfg = {"trigger_arg": "trigger_value"}
|
||||
descr = "descr"
|
||||
|
||||
trigger_obj = self.DummyTrigger({
|
||||
"trigger": {trigger_name: trigger_cfg},
|
||||
"action": {action_name: action_cfg},
|
||||
"description": descr}, None, None)
|
||||
|
||||
self.assertEqual(
|
||||
[mock.call(task, {}, {"event_type": "fake", "value": i})
|
||||
for i in right_values],
|
||||
hook_cls.call_args_list)
|
||||
self.assertEqual(len(right_values),
|
||||
hook_cls.return_value.run_async.call_count)
|
||||
hook_status = hook_cls.return_value.result.return_value["status"]
|
||||
self.assertEqual(
|
||||
{"config": cfg,
|
||||
"results": [hook_cls.return_value.result.return_value] *
|
||||
len(right_values),
|
||||
"summary": {hook_status: len(right_values)}},
|
||||
dummy_trigger.get_results())
|
||||
{"name": action_name,
|
||||
"args": action_cfg,
|
||||
"trigger": {"name": trigger_name,
|
||||
"args": trigger_cfg},
|
||||
"description": descr}, trigger_obj.context)
|
||||
|
Loading…
Reference in New Issue
Block a user