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
|
||||
"""
|
||||
tmp_name = "tmp_actions"
|
||||
atomic_inst = atomic.ActionTimerMixin()
|
||||
|
||||
calc_atomic_name = "calculate_%s_atomics" % number_of_atomics
|
||||
with atomic.ActionTimer(self, calc_atomic_name):
|
||||
for _ in range(number_of_atomics):
|
||||
with atomic.ActionTimer(self, tmp_name):
|
||||
with atomic.ActionTimer(atomic_inst, tmp_name):
|
||||
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):
|
||||
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"])
|
||||
|
||||
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
|
||||
def extend_results(cls, results, serializable=False):
|
||||
"""Modify and extend results with aggregated data.
|
||||
@ -461,6 +491,8 @@ class Task(object):
|
||||
atomic = collections.OrderedDict()
|
||||
|
||||
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():
|
||||
duration = duration or 0
|
||||
if atomic_name not in atomic:
|
||||
|
@ -13,7 +13,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import functools
|
||||
|
||||
from rally.common import utils
|
||||
@ -22,7 +21,7 @@ from rally.common import utils
|
||||
class ActionTimerMixin(object):
|
||||
|
||||
def __init__(self):
|
||||
self._atomic_actions = collections.OrderedDict()
|
||||
self._atomic_actions = []
|
||||
|
||||
def atomic_actions(self):
|
||||
"""Returns the content of each atomic action."""
|
||||
@ -48,27 +47,26 @@ class ActionTimer(utils.Timer):
|
||||
"""
|
||||
super(ActionTimer, self).__init__()
|
||||
self.instance = instance
|
||||
self.name = self._get_atomic_action_name(instance, name)
|
||||
self.instance._atomic_actions[self.name] = None
|
||||
self.name = name
|
||||
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 _get_atomic_action_name(cls, instance, name):
|
||||
# TODO(boris-42): It was quite bad idea to store atomic actions
|
||||
# inside {}. We should refactor this in 0.2.0 release
|
||||
# and store them inside array, that will allow us to
|
||||
# store atomic actions with the same name
|
||||
if name not in instance._atomic_actions:
|
||||
return name
|
||||
def _find_parent(self, atomic_actions):
|
||||
if atomic_actions and "finished_at" not in atomic_actions[-1]:
|
||||
return self._find_parent(atomic_actions[-1]["children"])
|
||||
else:
|
||||
return atomic_actions
|
||||
|
||||
name_template = name + " (%i)"
|
||||
i = 2
|
||||
while name_template % i in instance._atomic_actions:
|
||||
i += 1
|
||||
return name_template % i
|
||||
def __enter__(self):
|
||||
super(ActionTimer, self).__enter__()
|
||||
self.atomic_action["started_at"] = self.start
|
||||
|
||||
def __exit__(self, 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):
|
||||
|
@ -40,7 +40,7 @@ def format_result_on_timeout(exc, timeout):
|
||||
"duration": timeout,
|
||||
"idle_duration": 0,
|
||||
"output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {},
|
||||
"atomic_actions": [],
|
||||
"error": utils.format_exc(exc)
|
||||
}
|
||||
|
||||
@ -234,7 +234,7 @@ class ScenarioRunner(plugin.Plugin):
|
||||
_RESULT_SCHEMA = {
|
||||
"fields": [("duration", float), ("timestamp", float),
|
||||
("idle_duration", float), ("output", dict),
|
||||
("atomic_actions", dict), ("error", list)]
|
||||
("atomic_actions", list), ("error", list)]
|
||||
}
|
||||
|
||||
def _result_has_valid_schema(self, result):
|
||||
@ -257,15 +257,28 @@ class ScenarioRunner(plugin.Plugin):
|
||||
"proper_type": proper_type.__name__})
|
||||
return False
|
||||
|
||||
for action, value in result["atomic_actions"].items():
|
||||
if not isinstance(value, 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(value)})
|
||||
return False
|
||||
actions_list = copy.deepcopy(result["atomic_actions"])
|
||||
for action in actions_list:
|
||||
for key in ("name", "started_at", "finished_at", "children"):
|
||||
if key not in action:
|
||||
LOG.warning(
|
||||
"Task %(uuid)s | Atomic action %(action)s "
|
||||
"missing key '%(key)s'"
|
||||
% {"uuid": self.task["uuid"],
|
||||
"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"]:
|
||||
if not isinstance(e, str):
|
||||
|
@ -64,32 +64,6 @@ def should_be_overridden(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):
|
||||
"""Wraps service's methods with some magic
|
||||
|
||||
@ -139,9 +113,6 @@ def method_wrapper(func):
|
||||
|
||||
raise TypeError(message)
|
||||
|
||||
if kwargs.pop("no_atomic", False):
|
||||
instance = _ServiceWithoutAtomic(instance)
|
||||
|
||||
return func(instance, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
@ -26,6 +26,7 @@ import six
|
||||
|
||||
from rally.common.i18n import _
|
||||
from rally.common.plugin import plugin
|
||||
from rally.task import utils
|
||||
|
||||
|
||||
configure = plugin.configure
|
||||
@ -58,6 +59,11 @@ class SLAChecker(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])
|
||||
|
||||
def merge(self, other):
|
||||
|
@ -23,6 +23,7 @@ import six
|
||||
|
||||
from rally.common.i18n import _
|
||||
from rally.common import logging
|
||||
from rally.common import objects
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
|
||||
@ -410,3 +411,38 @@ class ActionBuilder(object):
|
||||
self._build(binding["action"], times,
|
||||
*(binding["args"] + args), **dft_kwargs))
|
||||
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",
|
||||
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)
|
||||
results = task.get_results()
|
||||
results = task._get_results()
|
||||
mock_task_result_get_all_by_uuid.assert_called_once_with(
|
||||
self.task["uuid"])
|
||||
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")
|
||||
def test_set_failed(self, mock_task_update):
|
||||
mock_task_update.return_value = self.task
|
||||
@ -310,6 +324,23 @@ class TaskTestCase(test.TestCase):
|
||||
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):
|
||||
|
||||
|
@ -28,7 +28,7 @@ class SerialScenarioRunnerTestCase(test.TestCase):
|
||||
times = 5
|
||||
result = {"duration": 10., "idle_duration": 0., "error": [],
|
||||
"output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {},
|
||||
"atomic_actions": [],
|
||||
"timestamp": 1.}
|
||||
mock__run_scenario_once.return_value = result
|
||||
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.Stack._wait")
|
||||
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_open().read.return_value = "fake_content"
|
||||
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.Stack._wait")
|
||||
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_open().read.return_value = "fake_content"
|
||||
stack = main.Stack(
|
||||
|
@ -13,8 +13,6 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
|
||||
import mock
|
||||
|
||||
from rally.task import atomic
|
||||
@ -39,8 +37,17 @@ class AtomicActionTestCase(test.TestCase):
|
||||
with atomic.ActionTimer(inst, "some"):
|
||||
pass
|
||||
|
||||
expected = [("test", 20), ("test (2)", 12), ("some", 4)]
|
||||
self.assertEqual(collections.OrderedDict(expected),
|
||||
expected = [{"name": "test",
|
||||
"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())
|
||||
|
||||
@mock.patch("time.time", side_effect=[1, 3])
|
||||
@ -56,8 +63,8 @@ class AtomicActionTestCase(test.TestCase):
|
||||
except TestException:
|
||||
pass
|
||||
|
||||
expected = [("test", 2)]
|
||||
self.assertEqual(collections.OrderedDict(expected),
|
||||
self.assertEqual([{"name": "test", "children": [],
|
||||
"started_at": 1, "finished_at": 3}],
|
||||
inst.atomic_actions())
|
||||
|
||||
@mock.patch("time.time", side_effect=[1, 3])
|
||||
@ -71,7 +78,8 @@ class AtomicActionTestCase(test.TestCase):
|
||||
|
||||
inst = Some()
|
||||
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())
|
||||
|
||||
@mock.patch("time.time", side_effect=[1, 3])
|
||||
@ -88,7 +96,8 @@ class AtomicActionTestCase(test.TestCase):
|
||||
|
||||
inst = TestTimer()
|
||||
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())
|
||||
|
||||
@mock.patch("time.time", side_effect=[1, 3, 1, 3])
|
||||
@ -107,20 +116,22 @@ class AtomicActionTestCase(test.TestCase):
|
||||
|
||||
inst = TestAtomicTimer()
|
||||
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 = TestAtomicTimer()
|
||||
self.assertEqual(5, inst.some_func(2, 3, atomic_action=False))
|
||||
self.assertEqual(collections.OrderedDict(),
|
||||
self.assertEqual([],
|
||||
inst.atomic_actions())
|
||||
|
||||
inst = TestAtomicTimer()
|
||||
self.assertEqual(5, inst.other_func(2, 3))
|
||||
self.assertEqual(collections.OrderedDict(),
|
||||
self.assertEqual([],
|
||||
inst.atomic_actions())
|
||||
|
||||
inst = TestAtomicTimer()
|
||||
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())
|
||||
|
@ -39,7 +39,7 @@ class ScenarioRunnerHelpersTestCase(test.TestCase):
|
||||
"duration": 100,
|
||||
"idle_duration": 0,
|
||||
"output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {},
|
||||
"atomic_actions": [],
|
||||
"error": mock_format_exc.return_value
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ class ScenarioRunnerHelpersTestCase(test.TestCase):
|
||||
"idle_duration": 0,
|
||||
"error": [],
|
||||
"output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}
|
||||
"atomic_actions": []
|
||||
}
|
||||
self.assertEqual(expected_result, result)
|
||||
|
||||
@ -108,7 +108,7 @@ class ScenarioRunnerHelpersTestCase(test.TestCase):
|
||||
"description": "Complete description",
|
||||
"title": "Complete",
|
||||
"chart_plugin": "BarPlugin"}]},
|
||||
"atomic_actions": {}
|
||||
"atomic_actions": []
|
||||
}
|
||||
self.assertEqual(expected_result, result)
|
||||
|
||||
@ -123,7 +123,7 @@ class ScenarioRunnerHelpersTestCase(test.TestCase):
|
||||
"timestamp": fakes.FakeTimer().timestamp(),
|
||||
"idle_duration": 0,
|
||||
"output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}
|
||||
"atomic_actions": []
|
||||
}
|
||||
self.assertEqual(expected_result, result)
|
||||
self.assertEqual(expected_error[:2],
|
||||
@ -253,67 +253,97 @@ class ScenarioRunnerTestCase(test.TestCase):
|
||||
@ddt.data(
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||
"output": {"additive": [], "complete": []},
|
||||
"error": ["err1", "err2"], "atomic_actions": {}},
|
||||
"error": ["err1", "err2"], "atomic_actions": []},
|
||||
"expected": True},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||
"error": [], "output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {"foo": 4.2}},
|
||||
"atomic_actions": [{"name": "foo", "started_at": 1.0,
|
||||
"finished_at": 5.2, "children": []}]},
|
||||
"expected": True},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||
"error": [], "output": {"additive": ["a1", "a2"],
|
||||
"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"),
|
||||
("complete", "c1"), ("complete", "c2")],
|
||||
"expected": True},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||
"error": [], "output": {"additive": ["a1", "a2"],
|
||||
"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"},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||
"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,
|
||||
"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,
|
||||
"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,
|
||||
"error": [], "output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"data": {"duration": 1.0, "timestamp": 1, "idle_duration": 1.0,
|
||||
"error": [], "output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1,
|
||||
"error": [], "output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||
"error": "foo", "output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||
"error": [], "output": {"additive": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||
"error": [], "output": {"complete": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"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": [],
|
||||
"output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"data": {"duration": 1.0, "idle_duration": 1.0, "error": [],
|
||||
"output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "error": [],
|
||||
"output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"data": {"duration": 1.0, "timestamp": 1.0, "idle_duration": 1.0,
|
||||
"output": {"additive": [], "complete": []},
|
||||
"atomic_actions": {}}},
|
||||
"atomic_actions": []}},
|
||||
{"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,
|
||||
"error": [], "output": {"additive": [], "complete": []}}},
|
||||
{"data": []},
|
||||
|
@ -14,7 +14,6 @@
|
||||
import mock
|
||||
|
||||
from rally import exceptions
|
||||
from rally.task import atomic
|
||||
from rally.task import service
|
||||
from tests.unit import test
|
||||
|
||||
@ -246,42 +245,3 @@ class MethodWrapperTestCase(test.TestCase):
|
||||
Some().foo(some=2, another=3)
|
||||
Some().foo(1, some=2, another=3)
|
||||
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
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import datetime as dt
|
||||
|
||||
from jsonschema import exceptions as schema_exceptions
|
||||
import mock
|
||||
import six
|
||||
|
||||
from rally import exceptions
|
||||
from rally.task import utils
|
||||
@ -524,3 +526,38 @@ class WaitForStatusTestCase(test.TestCase):
|
||||
utils.wait_for_status,
|
||||
resource=res, ready_statuses=["ready"],
|
||||
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 rally.common import db
|
||||
from rally.common import objects
|
||||
from rally import plugins
|
||||
from tests.unit import fakes
|
||||
|
||||
@ -46,7 +47,9 @@ class TestCase(base.BaseTestCase):
|
||||
plugins.load()
|
||||
|
||||
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.assertIsInstance(action_duration, float)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user