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