refactor atomics actions
We decided to still use atomic_actions field. First step, save new atomic actions format in database, and convert the new format to old format where the atomic actions needs to be used. Blueprint: improve-atomic-actions Co-Authored-By: chenhb-zte <chen.haibing1@zte.com.cn> Change-Id: I8aecd5bad319aa61d5f8a20a2c2fe9bacdc0e81a
This commit is contained in:
parent
b5c8d4e088
commit
8af32076d0
@ -41,12 +41,10 @@ class CalculateAtomic(scenario.Scenario, utils.RandomNameGeneratorMixin):
|
|||||||
:param number_of_atomics: int number of atomics to run
|
:param number_of_atomics: int number of atomics to run
|
||||||
"""
|
"""
|
||||||
tmp_name = "tmp_actions"
|
tmp_name = "tmp_actions"
|
||||||
|
atomic_inst = atomic.ActionTimerMixin()
|
||||||
|
|
||||||
calc_atomic_name = "calculate_%s_atomics" % number_of_atomics
|
calc_atomic_name = "calculate_%s_atomics" % number_of_atomics
|
||||||
with atomic.ActionTimer(self, calc_atomic_name):
|
with atomic.ActionTimer(self, calc_atomic_name):
|
||||||
for _ in range(number_of_atomics):
|
for _ in range(number_of_atomics):
|
||||||
with atomic.ActionTimer(self, tmp_name):
|
with atomic.ActionTimer(atomic_inst, tmp_name):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self._atomic_actions = {
|
|
||||||
calc_atomic_name: self._atomic_actions[calc_atomic_name]}
|
|
||||||
|
@ -410,9 +410,39 @@ class Task(object):
|
|||||||
def add_subtask(self, **subtask):
|
def add_subtask(self, **subtask):
|
||||||
return Subtask(self.task["uuid"], **subtask)
|
return Subtask(self.task["uuid"], **subtask)
|
||||||
|
|
||||||
def get_results(self):
|
def _get_results(self):
|
||||||
return db.task_result_get_all_by_uuid(self.task["uuid"])
|
return db.task_result_get_all_by_uuid(self.task["uuid"])
|
||||||
|
|
||||||
|
def get_results(self):
|
||||||
|
results = self._get_results()
|
||||||
|
for result in results:
|
||||||
|
for itr in result["data"]["raw"]:
|
||||||
|
itr["atomic_actions"] = self.convert_atomic_actions(
|
||||||
|
itr["atomic_actions"])
|
||||||
|
return results
|
||||||
|
|
||||||
|
"""TODO(chenhb): Remove this method after replacing old format.
|
||||||
|
Now we do not convert children actions, because our output
|
||||||
|
string and report only show one layer actions.
|
||||||
|
"""
|
||||||
|
@staticmethod
|
||||||
|
def convert_atomic_actions(atomic_actions):
|
||||||
|
"""Convert atomic actions to old format. """
|
||||||
|
if isinstance(atomic_actions, dict):
|
||||||
|
return atomic_actions
|
||||||
|
old_style = collections.OrderedDict()
|
||||||
|
for action in atomic_actions:
|
||||||
|
duration = action["finished_at"] - action["started_at"]
|
||||||
|
if action["name"] in old_style:
|
||||||
|
name_template = action["name"] + " (%i)"
|
||||||
|
i = 2
|
||||||
|
while name_template % i in old_style:
|
||||||
|
i += 1
|
||||||
|
old_style[name_template % i] = duration
|
||||||
|
else:
|
||||||
|
old_style[action["name"]] = duration
|
||||||
|
return old_style
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def extend_results(cls, results, serializable=False):
|
def extend_results(cls, results, serializable=False):
|
||||||
"""Modify and extend results with aggregated data.
|
"""Modify and extend results with aggregated data.
|
||||||
@ -461,6 +491,8 @@ class Task(object):
|
|||||||
atomic = collections.OrderedDict()
|
atomic = collections.OrderedDict()
|
||||||
|
|
||||||
for itr in scenario["data"]["raw"]:
|
for itr in scenario["data"]["raw"]:
|
||||||
|
itr["atomic_actions"] = cls.convert_atomic_actions(
|
||||||
|
itr["atomic_actions"])
|
||||||
for atomic_name, duration in itr["atomic_actions"].items():
|
for atomic_name, duration in itr["atomic_actions"].items():
|
||||||
duration = duration or 0
|
duration = duration or 0
|
||||||
if atomic_name not in atomic:
|
if atomic_name not in atomic:
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
# 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 collections
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
from rally.common import utils
|
from rally.common import utils
|
||||||
@ -22,7 +21,7 @@ from rally.common import utils
|
|||||||
class ActionTimerMixin(object):
|
class ActionTimerMixin(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._atomic_actions = collections.OrderedDict()
|
self._atomic_actions = []
|
||||||
|
|
||||||
def atomic_actions(self):
|
def atomic_actions(self):
|
||||||
"""Returns the content of each atomic action."""
|
"""Returns the content of each atomic action."""
|
||||||
@ -48,27 +47,26 @@ class ActionTimer(utils.Timer):
|
|||||||
"""
|
"""
|
||||||
super(ActionTimer, self).__init__()
|
super(ActionTimer, self).__init__()
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
self.name = self._get_atomic_action_name(instance, name)
|
self.name = name
|
||||||
self.instance._atomic_actions[self.name] = None
|
self._root = self._find_parent(self.instance._atomic_actions)
|
||||||
|
self.atomic_action = {"name": self.name,
|
||||||
|
"children": [],
|
||||||
|
"started_at": None}
|
||||||
|
self._root.append(self.atomic_action)
|
||||||
|
|
||||||
@classmethod
|
def _find_parent(self, atomic_actions):
|
||||||
def _get_atomic_action_name(cls, instance, name):
|
if atomic_actions and "finished_at" not in atomic_actions[-1]:
|
||||||
# TODO(boris-42): It was quite bad idea to store atomic actions
|
return self._find_parent(atomic_actions[-1]["children"])
|
||||||
# inside {}. We should refactor this in 0.2.0 release
|
else:
|
||||||
# and store them inside array, that will allow us to
|
return atomic_actions
|
||||||
# store atomic actions with the same name
|
|
||||||
if name not in instance._atomic_actions:
|
|
||||||
return name
|
|
||||||
|
|
||||||
name_template = name + " (%i)"
|
def __enter__(self):
|
||||||
i = 2
|
super(ActionTimer, self).__enter__()
|
||||||
while name_template % i in instance._atomic_actions:
|
self.atomic_action["started_at"] = self.start
|
||||||
i += 1
|
|
||||||
return name_template % i
|
|
||||||
|
|
||||||
def __exit__(self, type_, value, tb):
|
def __exit__(self, type_, value, tb):
|
||||||
super(ActionTimer, self).__exit__(type_, value, tb)
|
super(ActionTimer, self).__exit__(type_, value, tb)
|
||||||
self.instance._atomic_actions[self.name] = self.duration()
|
self.atomic_action["finished_at"] = self.finish
|
||||||
|
|
||||||
|
|
||||||
def action_timer(name):
|
def action_timer(name):
|
||||||
|
@ -40,7 +40,7 @@ def format_result_on_timeout(exc, timeout):
|
|||||||
"duration": timeout,
|
"duration": timeout,
|
||||||
"idle_duration": 0,
|
"idle_duration": 0,
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {},
|
"atomic_actions": [],
|
||||||
"error": utils.format_exc(exc)
|
"error": utils.format_exc(exc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +234,7 @@ class ScenarioRunner(plugin.Plugin):
|
|||||||
_RESULT_SCHEMA = {
|
_RESULT_SCHEMA = {
|
||||||
"fields": [("duration", float), ("timestamp", float),
|
"fields": [("duration", float), ("timestamp", float),
|
||||||
("idle_duration", float), ("output", dict),
|
("idle_duration", float), ("output", dict),
|
||||||
("atomic_actions", dict), ("error", list)]
|
("atomic_actions", list), ("error", list)]
|
||||||
}
|
}
|
||||||
|
|
||||||
def _result_has_valid_schema(self, result):
|
def _result_has_valid_schema(self, result):
|
||||||
@ -257,15 +257,28 @@ class ScenarioRunner(plugin.Plugin):
|
|||||||
"proper_type": proper_type.__name__})
|
"proper_type": proper_type.__name__})
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for action, value in result["atomic_actions"].items():
|
actions_list = copy.deepcopy(result["atomic_actions"])
|
||||||
if not isinstance(value, float):
|
for action in actions_list:
|
||||||
LOG.warning(
|
for key in ("name", "started_at", "finished_at", "children"):
|
||||||
"Task %(uuid)s | Atomic action %(action)s has wrong type "
|
if key not in action:
|
||||||
"'%(type)s', should be 'float'"
|
LOG.warning(
|
||||||
% {"uuid": self.task["uuid"],
|
"Task %(uuid)s | Atomic action %(action)s "
|
||||||
"action": action,
|
"missing key '%(key)s'"
|
||||||
"type": type(value)})
|
% {"uuid": self.task["uuid"],
|
||||||
return False
|
"action": action,
|
||||||
|
"key": key})
|
||||||
|
return False
|
||||||
|
for key in ("started_at", "finished_at"):
|
||||||
|
if not isinstance(action[key], float):
|
||||||
|
LOG.warning(
|
||||||
|
"Task %(uuid)s | Atomic action %(action)s has "
|
||||||
|
"wrong type '%(type)s', should be 'float'"
|
||||||
|
% {"uuid": self.task["uuid"],
|
||||||
|
"action": action,
|
||||||
|
"type": type(action[key])})
|
||||||
|
return False
|
||||||
|
if action["children"]:
|
||||||
|
actions_list.extend(action["children"])
|
||||||
|
|
||||||
for e in result["error"]:
|
for e in result["error"]:
|
||||||
if not isinstance(e, str):
|
if not isinstance(e, str):
|
||||||
|
@ -64,32 +64,6 @@ def should_be_overridden(func):
|
|||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
||||||
# TODO(andreykurilin): remove _DevNullDict and _ServiceWithoutAtomic when we
|
|
||||||
# start support inner atomics
|
|
||||||
class _DevNullDict(dict):
|
|
||||||
"""Do not keep anything."""
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class _ServiceWithoutAtomic(object):
|
|
||||||
def __init__(self, service):
|
|
||||||
self._service = service
|
|
||||||
self._atomic_actions = _DevNullDict()
|
|
||||||
|
|
||||||
def atomic_actions(self):
|
|
||||||
return self._atomic_actions
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
return getattr(self._service, name)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "'%s' without atomic actions" % self._service.__name__
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<%s>" % str(self)
|
|
||||||
|
|
||||||
|
|
||||||
def method_wrapper(func):
|
def method_wrapper(func):
|
||||||
"""Wraps service's methods with some magic
|
"""Wraps service's methods with some magic
|
||||||
|
|
||||||
@ -139,9 +113,6 @@ def method_wrapper(func):
|
|||||||
|
|
||||||
raise TypeError(message)
|
raise TypeError(message)
|
||||||
|
|
||||||
if kwargs.pop("no_atomic", False):
|
|
||||||
instance = _ServiceWithoutAtomic(instance)
|
|
||||||
|
|
||||||
return func(instance, *args, **kwargs)
|
return func(instance, *args, **kwargs)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
@ -26,6 +26,7 @@ import six
|
|||||||
|
|
||||||
from rally.common.i18n import _
|
from rally.common.i18n import _
|
||||||
from rally.common.plugin import plugin
|
from rally.common.plugin import plugin
|
||||||
|
from rally.task import utils
|
||||||
|
|
||||||
|
|
||||||
configure = plugin.configure
|
configure = plugin.configure
|
||||||
@ -58,6 +59,11 @@ class SLAChecker(object):
|
|||||||
|
|
||||||
:param iteration: iteration result object
|
:param iteration: iteration result object
|
||||||
"""
|
"""
|
||||||
|
if isinstance(iteration, dict):
|
||||||
|
atomic_actions = iteration.get("atomic_actions", None)
|
||||||
|
if isinstance(atomic_actions, list):
|
||||||
|
iteration["atomic_actions"] = utils.WrapperForAtomicActions(
|
||||||
|
atomic_actions)
|
||||||
return all([sla.add_iteration(iteration) for sla in self.sla_criteria])
|
return all([sla.add_iteration(iteration) for sla in self.sla_criteria])
|
||||||
|
|
||||||
def merge(self, other):
|
def merge(self, other):
|
||||||
|
@ -23,6 +23,7 @@ import six
|
|||||||
|
|
||||||
from rally.common.i18n import _
|
from rally.common.i18n import _
|
||||||
from rally.common import logging
|
from rally.common import logging
|
||||||
|
from rally.common import objects
|
||||||
from rally import consts
|
from rally import consts
|
||||||
from rally import exceptions
|
from rally import exceptions
|
||||||
|
|
||||||
@ -410,3 +411,38 @@ class ActionBuilder(object):
|
|||||||
self._build(binding["action"], times,
|
self._build(binding["action"], times,
|
||||||
*(binding["args"] + args), **dft_kwargs))
|
*(binding["args"] + args), **dft_kwargs))
|
||||||
return bound_actions
|
return bound_actions
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(andreykurilin): We need to implement some wrapper for atomic actions,
|
||||||
|
# we can use these wrapper to simulate new and old format.
|
||||||
|
class WrapperForAtomicActions(list):
|
||||||
|
|
||||||
|
LOG_INFO = "Atomic actions format is changed. It is a list now."
|
||||||
|
|
||||||
|
def __init__(self, atomic_actions):
|
||||||
|
super(WrapperForAtomicActions, self).__init__(atomic_actions)
|
||||||
|
self.__atomic_actions = atomic_actions
|
||||||
|
self.__old_atomic_actions = objects.Task.convert_atomic_actions(
|
||||||
|
self.__atomic_actions)
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
LOG.warning(self.LOG_INFO)
|
||||||
|
return self.__old_atomic_actions.items()
|
||||||
|
|
||||||
|
def get(self, name, default=None):
|
||||||
|
LOG.warning(self.LOG_INFO)
|
||||||
|
return self.__old_atomic_actions.get(name, default)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.__atomic_actions)
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.__atomic_actions)
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
if isinstance(item, int):
|
||||||
|
# it is a call to list:
|
||||||
|
return self.__atomic_actions[item]
|
||||||
|
else:
|
||||||
|
LOG.warning(self.LOG_INFO)
|
||||||
|
return self.__old_atomic_actions[item]
|
||||||
|
@ -229,13 +229,27 @@ class TaskTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch("rally.common.objects.task.db.task_result_get_all_by_uuid",
|
@mock.patch("rally.common.objects.task.db.task_result_get_all_by_uuid",
|
||||||
return_value="foo_results")
|
return_value="foo_results")
|
||||||
def test_get_results(self, mock_task_result_get_all_by_uuid):
|
def test__get_results(self, mock_task_result_get_all_by_uuid):
|
||||||
task = objects.Task(task=self.task)
|
task = objects.Task(task=self.task)
|
||||||
results = task.get_results()
|
results = task._get_results()
|
||||||
mock_task_result_get_all_by_uuid.assert_called_once_with(
|
mock_task_result_get_all_by_uuid.assert_called_once_with(
|
||||||
self.task["uuid"])
|
self.task["uuid"])
|
||||||
self.assertEqual(results, "foo_results")
|
self.assertEqual(results, "foo_results")
|
||||||
|
|
||||||
|
def test_get_results(self):
|
||||||
|
task = objects.Task(task=self.task)
|
||||||
|
task._get_results = mock.MagicMock()
|
||||||
|
return_value = [{"data": {"raw": [
|
||||||
|
{"atomic_actions": [
|
||||||
|
{"name": "some",
|
||||||
|
"started_at": 1.0,
|
||||||
|
"finished_at": 2.0,
|
||||||
|
"children": []}]}]}}]
|
||||||
|
task._get_results.return_value = return_value
|
||||||
|
self.assertEqual([{"data": {"raw": [
|
||||||
|
{"atomic_actions": {"some": 1.0}}]}}],
|
||||||
|
task.get_results())
|
||||||
|
|
||||||
@mock.patch("rally.common.objects.task.db.task_update")
|
@mock.patch("rally.common.objects.task.db.task_update")
|
||||||
def test_set_failed(self, mock_task_update):
|
def test_set_failed(self, mock_task_update):
|
||||||
mock_task_update.return_value = self.task
|
mock_task_update.return_value = self.task
|
||||||
@ -310,6 +324,23 @@ class TaskTestCase(test.TestCase):
|
|||||||
consts.TaskStatus.SOFT_ABORTING)
|
consts.TaskStatus.SOFT_ABORTING)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
{"atomic_actions": [{"name": "some", "started_at": 1.0,
|
||||||
|
"finished_at": 2.0, "children": []}],
|
||||||
|
"expected": {"some": 1.0}},
|
||||||
|
{"atomic_actions": [{"name": "some", "started_at": 1.0,
|
||||||
|
"finished_at": 2.0, "children": []},
|
||||||
|
{"name": "some", "started_at": 2.0,
|
||||||
|
"finished_at": 3.0, "children": []}],
|
||||||
|
"expected": {"some": 1.0, "some (2)": 1.0}},
|
||||||
|
{"atomic_actions": {"some": 1.0},
|
||||||
|
"expected": {"some": 1.0}}
|
||||||
|
)
|
||||||
|
@ddt.unpack
|
||||||
|
def test_convert_atomic_actions(self, atomic_actions, expected):
|
||||||
|
self.assertEqual(expected,
|
||||||
|
objects.Task.convert_atomic_actions(atomic_actions))
|
||||||
|
|
||||||
|
|
||||||
class SubtaskTestCase(test.TestCase):
|
class SubtaskTestCase(test.TestCase):
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class SerialScenarioRunnerTestCase(test.TestCase):
|
|||||||
times = 5
|
times = 5
|
||||||
result = {"duration": 10., "idle_duration": 0., "error": [],
|
result = {"duration": 10., "idle_duration": 0., "error": [],
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {},
|
"atomic_actions": [],
|
||||||
"timestamp": 1.}
|
"timestamp": 1.}
|
||||||
mock__run_scenario_once.return_value = result
|
mock__run_scenario_once.return_value = result
|
||||||
deque_as_queue_inst = mock_deque_as_queue.return_value
|
deque_as_queue_inst = mock_deque_as_queue.return_value
|
||||||
|
@ -58,7 +58,7 @@ class StackTestCase(test.ScenarioTestCase):
|
|||||||
@mock.patch("rally.plugins.openstack.services.heat.main.open")
|
@mock.patch("rally.plugins.openstack.services.heat.main.open")
|
||||||
@mock.patch("rally.plugins.openstack.services.heat.main.Stack._wait")
|
@mock.patch("rally.plugins.openstack.services.heat.main.Stack._wait")
|
||||||
def test_create(self, mock_stack__wait, mock_open, mock_task_atomic):
|
def test_create(self, mock_stack__wait, mock_open, mock_task_atomic):
|
||||||
mock_scenario = mock.MagicMock()
|
mock_scenario = mock.MagicMock(_atomic_actions=[])
|
||||||
mock_scenario.generate_random_name.return_value = "fake_name"
|
mock_scenario.generate_random_name.return_value = "fake_name"
|
||||||
mock_open().read.return_value = "fake_content"
|
mock_open().read.return_value = "fake_content"
|
||||||
mock_new_stack = {
|
mock_new_stack = {
|
||||||
@ -87,7 +87,8 @@ class StackTestCase(test.ScenarioTestCase):
|
|||||||
@mock.patch("rally.plugins.openstack.services.heat.main.open")
|
@mock.patch("rally.plugins.openstack.services.heat.main.open")
|
||||||
@mock.patch("rally.plugins.openstack.services.heat.main.Stack._wait")
|
@mock.patch("rally.plugins.openstack.services.heat.main.Stack._wait")
|
||||||
def test_update(self, mock_stack__wait, mock_open, mock_task_atomic):
|
def test_update(self, mock_stack__wait, mock_open, mock_task_atomic):
|
||||||
mock_scenario = mock.MagicMock(stack_id="fake_id")
|
mock_scenario = mock.MagicMock(
|
||||||
|
stack_id="fake_id", _atomic_actions=[])
|
||||||
mock_parameters = mock.Mock()
|
mock_parameters = mock.Mock()
|
||||||
mock_open().read.return_value = "fake_content"
|
mock_open().read.return_value = "fake_content"
|
||||||
stack = main.Stack(
|
stack = main.Stack(
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
# 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 collections
|
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from rally.task import atomic
|
from rally.task import atomic
|
||||||
@ -39,8 +37,17 @@ class AtomicActionTestCase(test.TestCase):
|
|||||||
with atomic.ActionTimer(inst, "some"):
|
with atomic.ActionTimer(inst, "some"):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
expected = [("test", 20), ("test (2)", 12), ("some", 4)]
|
expected = [{"name": "test",
|
||||||
self.assertEqual(collections.OrderedDict(expected),
|
"started_at": 1,
|
||||||
|
"finished_at": 21,
|
||||||
|
"children": [{"name": "test",
|
||||||
|
"started_at": 3,
|
||||||
|
"finished_at": 15,
|
||||||
|
"children": [{"name": "some",
|
||||||
|
"started_at": 6,
|
||||||
|
"finished_at": 10,
|
||||||
|
"children": []}]}]}]
|
||||||
|
self.assertEqual(expected,
|
||||||
inst.atomic_actions())
|
inst.atomic_actions())
|
||||||
|
|
||||||
@mock.patch("time.time", side_effect=[1, 3])
|
@mock.patch("time.time", side_effect=[1, 3])
|
||||||
@ -56,8 +63,8 @@ class AtomicActionTestCase(test.TestCase):
|
|||||||
except TestException:
|
except TestException:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
expected = [("test", 2)]
|
self.assertEqual([{"name": "test", "children": [],
|
||||||
self.assertEqual(collections.OrderedDict(expected),
|
"started_at": 1, "finished_at": 3}],
|
||||||
inst.atomic_actions())
|
inst.atomic_actions())
|
||||||
|
|
||||||
@mock.patch("time.time", side_effect=[1, 3])
|
@mock.patch("time.time", side_effect=[1, 3])
|
||||||
@ -71,7 +78,8 @@ class AtomicActionTestCase(test.TestCase):
|
|||||||
|
|
||||||
inst = Some()
|
inst = Some()
|
||||||
self.assertEqual(5, inst.some_func(2, 3))
|
self.assertEqual(5, inst.some_func(2, 3))
|
||||||
self.assertEqual(collections.OrderedDict({"some": 2}),
|
self.assertEqual([{"name": "some", "children": [],
|
||||||
|
"started_at": 1, "finished_at": 3}],
|
||||||
inst.atomic_actions())
|
inst.atomic_actions())
|
||||||
|
|
||||||
@mock.patch("time.time", side_effect=[1, 3])
|
@mock.patch("time.time", side_effect=[1, 3])
|
||||||
@ -88,7 +96,8 @@ class AtomicActionTestCase(test.TestCase):
|
|||||||
|
|
||||||
inst = TestTimer()
|
inst = TestTimer()
|
||||||
self.assertRaises(TestException, inst.some_func)
|
self.assertRaises(TestException, inst.some_func)
|
||||||
self.assertEqual(collections.OrderedDict({"test": 2}),
|
self.assertEqual([{"name": "test", "children": [],
|
||||||
|
"started_at": 1, "finished_at": 3}],
|
||||||
inst.atomic_actions())
|
inst.atomic_actions())
|
||||||
|
|
||||||
@mock.patch("time.time", side_effect=[1, 3, 1, 3])
|
@mock.patch("time.time", side_effect=[1, 3, 1, 3])
|
||||||
@ -107,20 +116,22 @@ class AtomicActionTestCase(test.TestCase):
|
|||||||
|
|
||||||
inst = TestAtomicTimer()
|
inst = TestAtomicTimer()
|
||||||
self.assertEqual(5, inst.some_func(2, 3))
|
self.assertEqual(5, inst.some_func(2, 3))
|
||||||
self.assertEqual(collections.OrderedDict({"some": 2}),
|
self.assertEqual([{"name": "some", "children": [],
|
||||||
|
"started_at": 1, "finished_at": 3}],
|
||||||
inst.atomic_actions())
|
inst.atomic_actions())
|
||||||
|
|
||||||
inst = TestAtomicTimer()
|
inst = TestAtomicTimer()
|
||||||
self.assertEqual(5, inst.some_func(2, 3, atomic_action=False))
|
self.assertEqual(5, inst.some_func(2, 3, atomic_action=False))
|
||||||
self.assertEqual(collections.OrderedDict(),
|
self.assertEqual([],
|
||||||
inst.atomic_actions())
|
inst.atomic_actions())
|
||||||
|
|
||||||
inst = TestAtomicTimer()
|
inst = TestAtomicTimer()
|
||||||
self.assertEqual(5, inst.other_func(2, 3))
|
self.assertEqual(5, inst.other_func(2, 3))
|
||||||
self.assertEqual(collections.OrderedDict(),
|
self.assertEqual([],
|
||||||
inst.atomic_actions())
|
inst.atomic_actions())
|
||||||
|
|
||||||
inst = TestAtomicTimer()
|
inst = TestAtomicTimer()
|
||||||
self.assertEqual(5, inst.other_func(2, 3, foo=True))
|
self.assertEqual(5, inst.other_func(2, 3, foo=True))
|
||||||
self.assertEqual(collections.OrderedDict({"some": 2}),
|
self.assertEqual([{"name": "some", "children": [],
|
||||||
|
"started_at": 1, "finished_at": 3}],
|
||||||
inst.atomic_actions())
|
inst.atomic_actions())
|
||||||
|
@ -39,7 +39,7 @@ class ScenarioRunnerHelpersTestCase(test.TestCase):
|
|||||||
"duration": 100,
|
"duration": 100,
|
||||||
"idle_duration": 0,
|
"idle_duration": 0,
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {},
|
"atomic_actions": [],
|
||||||
"error": mock_format_exc.return_value
|
"error": mock_format_exc.return_value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ class ScenarioRunnerHelpersTestCase(test.TestCase):
|
|||||||
"idle_duration": 0,
|
"idle_duration": 0,
|
||||||
"error": [],
|
"error": [],
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}
|
"atomic_actions": []
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_result, result)
|
self.assertEqual(expected_result, result)
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ class ScenarioRunnerHelpersTestCase(test.TestCase):
|
|||||||
"description": "Complete description",
|
"description": "Complete description",
|
||||||
"title": "Complete",
|
"title": "Complete",
|
||||||
"chart_plugin": "BarPlugin"}]},
|
"chart_plugin": "BarPlugin"}]},
|
||||||
"atomic_actions": {}
|
"atomic_actions": []
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_result, result)
|
self.assertEqual(expected_result, result)
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ class ScenarioRunnerHelpersTestCase(test.TestCase):
|
|||||||
"timestamp": fakes.FakeTimer().timestamp(),
|
"timestamp": fakes.FakeTimer().timestamp(),
|
||||||
"idle_duration": 0,
|
"idle_duration": 0,
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}
|
"atomic_actions": []
|
||||||
}
|
}
|
||||||
self.assertEqual(expected_result, result)
|
self.assertEqual(expected_result, result)
|
||||||
self.assertEqual(expected_error[:2],
|
self.assertEqual(expected_error[:2],
|
||||||
@ -253,67 +253,97 @@ class ScenarioRunnerTestCase(test.TestCase):
|
|||||||
@ddt.data(
|
@ddt.data(
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"error": ["err1", "err2"], "atomic_actions": {}},
|
"error": ["err1", "err2"], "atomic_actions": []},
|
||||||
"expected": True},
|
"expected": True},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"additive": [], "complete": []},
|
"error": [], "output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {"foo": 4.2}},
|
"atomic_actions": [{"name": "foo", "started_at": 1.0,
|
||||||
|
"finished_at": 5.2, "children": []}]},
|
||||||
"expected": True},
|
"expected": True},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"additive": ["a1", "a2"],
|
"error": [], "output": {"additive": ["a1", "a2"],
|
||||||
"complete": ["c1", "c2"]},
|
"complete": ["c1", "c2"]},
|
||||||
"atomic_actions": {"foo": 4.2}},
|
"atomic_actions": [{"name": "foo", "started_at": 1.0,
|
||||||
|
"finished_at": 5.2, "children": []}]},
|
||||||
"validate_output_calls": [("additive", "a1"), ("additive", "a2"),
|
"validate_output_calls": [("additive", "a1"), ("additive", "a2"),
|
||||||
("complete", "c1"), ("complete", "c2")],
|
("complete", "c1"), ("complete", "c2")],
|
||||||
"expected": True},
|
"expected": True},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"additive": ["a1", "a2"],
|
"error": [], "output": {"additive": ["a1", "a2"],
|
||||||
"complete": ["c1", "c2"]},
|
"complete": ["c1", "c2"]},
|
||||||
"atomic_actions": {"foo": 4.2}},
|
"atomic_actions": [{"name": "foo", "started_at": 1.0,
|
||||||
|
"finished_at": 5.2, "children": []}]},
|
||||||
"validate_output_return_value": "validation error message"},
|
"validate_output_return_value": "validation error message"},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [42], "output": {"additive": [], "complete": []},
|
"error": [42], "output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {"foo": 4.2}}},
|
"atomic_actions": [{"name": "foo", "started_at": 1.0,
|
||||||
|
"finished_at": 5.2, "children": []}]}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"additive": [], "complete": []},
|
"error": [], "output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {"foo": 42}}},
|
"atomic_actions": [{"name": "foo", "started_at": 10,
|
||||||
|
"finished_at": 52, "children": []}]}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"additive": [], "complete": []},
|
"error": [], "output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {"foo": "non-float"}}},
|
"atomic_actions": [{"name": "non-float", "started_at": 1.0,
|
||||||
|
"children": []}]}},
|
||||||
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
|
"error": [], "output": {"additive": [], "complete": []},
|
||||||
|
"atomic_actions": [{"name": "foo", "started_at": 1.0,
|
||||||
|
"finished_at": 4.0,
|
||||||
|
"children": [{"name": "foo1",
|
||||||
|
"started_at": 2.0,
|
||||||
|
"finished_at": 3.0,
|
||||||
|
"children": []}]}]},
|
||||||
|
"expected": True},
|
||||||
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
|
"error": [], "output": {"additive": [], "complete": []},
|
||||||
|
"atomic_actions": [{"name": "foo", "started_at": 1.0,
|
||||||
|
"finished_at": 4.0,
|
||||||
|
"children": [{"name": "foo1",
|
||||||
|
"started_at": 20,
|
||||||
|
"finished_at": 30,
|
||||||
|
"children": []}]}]}},
|
||||||
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
|
"error": [], "output": {"additive": [], "complete": []},
|
||||||
|
"atomic_actions": [{"name": "foo", "started_at": 1.0,
|
||||||
|
"finished_at": 4.0,
|
||||||
|
"children": [{"name": "foo1",
|
||||||
|
"started_at": 2.0,
|
||||||
|
"finished_at": 3.0}]}]}},
|
||||||
{"data": {"duration": 1, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"additive": [], "complete": []},
|
"error": [], "output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"additive": [], "complete": []},
|
"error": [], "output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1,
|
||||||
"error": [], "output": {"additive": [], "complete": []},
|
"error": [], "output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": "foo", "output": {"additive": [], "complete": []},
|
"error": "foo", "output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"additive": []},
|
"error": [], "output": {"additive": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"complete": []},
|
"error": [], "output": {"complete": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {}, "atomic_actions": {}}},
|
"error": [], "output": {}, "atomic_actions": []}},
|
||||||
{"data": {"timestamp": 1.0, "idle_duration": 1.0, "error": [],
|
{"data": {"timestamp": 1.0, "idle_duration": 1.0, "error": [],
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "idle_duration": 1.0, "error": [],
|
{"data": {"duration": 1.0, "idle_duration": 1.0, "error": [],
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "error": [],
|
{"data": {"duration": 1.0, "timestamp": 1.0, "error": [],
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"output": {"additive": [], "complete": []},
|
"output": {"additive": [], "complete": []},
|
||||||
"atomic_actions": {}}},
|
"atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "atomic_actions": {}}},
|
"error": [], "atomic_actions": []}},
|
||||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||||
"error": [], "output": {"additive": [], "complete": []}}},
|
"error": [], "output": {"additive": [], "complete": []}}},
|
||||||
{"data": []},
|
{"data": []},
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
import mock
|
import mock
|
||||||
|
|
||||||
from rally import exceptions
|
from rally import exceptions
|
||||||
from rally.task import atomic
|
|
||||||
from rally.task import service
|
from rally.task import service
|
||||||
from tests.unit import test
|
from tests.unit import test
|
||||||
|
|
||||||
@ -246,42 +245,3 @@ class MethodWrapperTestCase(test.TestCase):
|
|||||||
Some().foo(some=2, another=3)
|
Some().foo(some=2, another=3)
|
||||||
Some().foo(1, some=2, another=3)
|
Some().foo(1, some=2, another=3)
|
||||||
self.assertRaises(TypeError, Some().foo, 1, 2)
|
self.assertRaises(TypeError, Some().foo, 1, 2)
|
||||||
|
|
||||||
def test_disabling_atomics(self):
|
|
||||||
class Some(service.UnifiedService):
|
|
||||||
|
|
||||||
def discover_impl(self):
|
|
||||||
return mock.MagicMock, None
|
|
||||||
|
|
||||||
@atomic.action_timer("some")
|
|
||||||
def foo(slf):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def bar(slf):
|
|
||||||
pass
|
|
||||||
|
|
||||||
some = Some(mock.MagicMock(version="777"))
|
|
||||||
some.foo(no_atomic=True)
|
|
||||||
self.assertNotIn("some", some._atomic_actions)
|
|
||||||
# check that we are working with correct variable
|
|
||||||
some.foo()
|
|
||||||
self.assertIn("some", some._atomic_actions)
|
|
||||||
|
|
||||||
|
|
||||||
class ServiceWithoutAtomicTestCase(test.TestCase):
|
|
||||||
def test_access(self):
|
|
||||||
class Some(atomic.ActionTimerMixin):
|
|
||||||
def __getattr__(self, attr):
|
|
||||||
return self
|
|
||||||
|
|
||||||
some_cls = Some()
|
|
||||||
# add something to atomic actions dict to simplify comparison
|
|
||||||
# (empty fake dict != not empty _atomic_actions dict)
|
|
||||||
with atomic.ActionTimer(some_cls, "some"):
|
|
||||||
pass
|
|
||||||
wrapped_service = service._ServiceWithoutAtomic(some_cls)
|
|
||||||
self.assertNotEqual(some_cls.atomic_actions(),
|
|
||||||
wrapped_service.atomic_actions())
|
|
||||||
self.assertNotEqual(some_cls._atomic_actions,
|
|
||||||
wrapped_service._atomic_actions)
|
|
||||||
self.assertEqual(some_cls, wrapped_service.some_var)
|
|
||||||
|
@ -13,10 +13,12 @@
|
|||||||
# 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 collections
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
|
|
||||||
from jsonschema import exceptions as schema_exceptions
|
from jsonschema import exceptions as schema_exceptions
|
||||||
import mock
|
import mock
|
||||||
|
import six
|
||||||
|
|
||||||
from rally import exceptions
|
from rally import exceptions
|
||||||
from rally.task import utils
|
from rally.task import utils
|
||||||
@ -524,3 +526,38 @@ class WaitForStatusTestCase(test.TestCase):
|
|||||||
utils.wait_for_status,
|
utils.wait_for_status,
|
||||||
resource=res, ready_statuses=["ready"],
|
resource=res, ready_statuses=["ready"],
|
||||||
update_resource=upd, timeout=2, id_attr="uuid")
|
update_resource=upd, timeout=2, id_attr="uuid")
|
||||||
|
|
||||||
|
|
||||||
|
class WrapperForAtomicActionsTestCase(test.TestCase):
|
||||||
|
|
||||||
|
def test_dict_atomic(self):
|
||||||
|
atomic_actions = collections.OrderedDict(
|
||||||
|
[("action_1", 1), ("action_2", 2)])
|
||||||
|
atomic_wrapper = utils.WrapperForAtomicActions(atomic_actions)
|
||||||
|
self.assertEqual(1, atomic_wrapper["action_1"])
|
||||||
|
self.assertEqual(2, atomic_wrapper["action_2"])
|
||||||
|
self.assertEqual(atomic_actions.items(),
|
||||||
|
atomic_wrapper.items())
|
||||||
|
self.assertEqual(1, atomic_wrapper.get("action_1"))
|
||||||
|
self.assertIsNone(atomic_wrapper.get("action_3"))
|
||||||
|
self.assertEqual(2, len(atomic_wrapper))
|
||||||
|
|
||||||
|
def test_list_atomic(self):
|
||||||
|
atomic_actions = [{"name": "action_1", "started_at": 1,
|
||||||
|
"finished_at": 2, "children": []},
|
||||||
|
{"name": "action_2", "started_at": 2,
|
||||||
|
"finished_at": 4, "children": []}]
|
||||||
|
|
||||||
|
atomic_wrapper = utils.WrapperForAtomicActions(atomic_actions)
|
||||||
|
self.assertEqual(1, atomic_wrapper["action_1"])
|
||||||
|
self.assertEqual(2, atomic_wrapper["action_2"])
|
||||||
|
self.assertEqual(
|
||||||
|
collections.OrderedDict(
|
||||||
|
[("action_1", 1), ("action_2", 2)]).items(),
|
||||||
|
atomic_wrapper.items())
|
||||||
|
self.assertEqual(atomic_actions[0], atomic_wrapper[0])
|
||||||
|
self.assertEqual(atomic_actions[1], atomic_wrapper[1])
|
||||||
|
self.assertEqual(1, atomic_wrapper.get("action_1"))
|
||||||
|
self.assertIsNone(None, atomic_wrapper.get("action_3"))
|
||||||
|
self.assertEqual(2, len(atomic_wrapper))
|
||||||
|
self.assertEqual(atomic_actions[0], six.next(iter(atomic_wrapper)))
|
||||||
|
@ -22,6 +22,7 @@ from oslotest import base
|
|||||||
from oslotest import mockpatch
|
from oslotest import mockpatch
|
||||||
|
|
||||||
from rally.common import db
|
from rally.common import db
|
||||||
|
from rally.common import objects
|
||||||
from rally import plugins
|
from rally import plugins
|
||||||
from tests.unit import fakes
|
from tests.unit import fakes
|
||||||
|
|
||||||
@ -46,7 +47,9 @@ class TestCase(base.BaseTestCase):
|
|||||||
plugins.load()
|
plugins.load()
|
||||||
|
|
||||||
def _test_atomic_action_timer(self, atomic_actions, name):
|
def _test_atomic_action_timer(self, atomic_actions, name):
|
||||||
action_duration = atomic_actions.get(name)
|
_old_atomic_actions = objects.Task.convert_atomic_actions(
|
||||||
|
atomic_actions)
|
||||||
|
action_duration = _old_atomic_actions.get(name)
|
||||||
self.assertIsNotNone(action_duration)
|
self.assertIsNotNone(action_duration)
|
||||||
self.assertIsInstance(action_duration, float)
|
self.assertIsInstance(action_duration, float)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user