standardized output for scenario runners
We have format requests for the result of scenario runners. So, we create class ScenarioRunnerResult to check the formate. Basically, all runners should return the result with an instance of class ScenarioRunnerResult. Change-Id: Iaf62fd19e46654c7bcbd46719c7c4bea4ccaf9ad
This commit is contained in:
@@ -45,9 +45,10 @@ def _run_scenario_once(args):
|
|||||||
clients=osclients.Clients(user["endpoint"]))
|
clients=osclients.Clients(user["endpoint"]))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
scenario_output = None
|
scenario_output = {}
|
||||||
with rutils.Timer() as timer:
|
with rutils.Timer() as timer:
|
||||||
scenario_output = getattr(scenario, method_name)(**kwargs)
|
scenario_output = getattr(scenario,
|
||||||
|
method_name)(**kwargs) or {}
|
||||||
error = None
|
error = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error = utils.format_exc(e)
|
error = utils.format_exc(e)
|
||||||
@@ -64,6 +65,60 @@ def _run_scenario_once(args):
|
|||||||
"atomic_actions_time": scenario.atomic_actions_time()}
|
"atomic_actions_time": scenario.atomic_actions_time()}
|
||||||
|
|
||||||
|
|
||||||
|
class ScenarioRunnerResult(list):
|
||||||
|
"""Class for all scenario runners' result.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
RESULT_SCHEMA = {
|
||||||
|
"type": "array",
|
||||||
|
"$schema": "http://json-schema.org/draft-03/schema",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"time": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"idle_time": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"scenario_output": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "object",
|
||||||
|
"patternProperties": {
|
||||||
|
".*": {"type": "number"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
},
|
||||||
|
"atomic_actions_time": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"action": {"type": "string"},
|
||||||
|
"duration": {"type": "number"}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": {},
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, result_list):
|
||||||
|
super(ScenarioRunnerResult, self).__init__(result_list)
|
||||||
|
jsonschema.validate(result_list, self.RESULT_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
class ScenarioRunner(object):
|
class ScenarioRunner(object):
|
||||||
"""Base class for all scenario runners.
|
"""Base class for all scenario runners.
|
||||||
|
|
||||||
@@ -156,6 +211,14 @@ class ScenarioRunner(object):
|
|||||||
|
|
||||||
def run(self, name, kwargs):
|
def run(self, name, kwargs):
|
||||||
if self.admin_user:
|
if self.admin_user:
|
||||||
return self._run_as_admin(name, kwargs)
|
results = self._run_as_admin(name, kwargs)
|
||||||
else:
|
else:
|
||||||
return self._run_as_non_admin(name, kwargs)
|
results = self._run_as_non_admin(name, kwargs)
|
||||||
|
|
||||||
|
if not isinstance(results, ScenarioRunnerResult):
|
||||||
|
name = self.__execution_type__
|
||||||
|
results_type = type(results)
|
||||||
|
raise exceptions.InvalidRunnerResult(name=name,
|
||||||
|
results_type=results_type)
|
||||||
|
|
||||||
|
return results
|
||||||
|
@@ -137,11 +137,13 @@ class ContinuousScenarioRunner(base.ScenarioRunner):
|
|||||||
# amount of times.
|
# amount of times.
|
||||||
if "times" in config:
|
if "times" in config:
|
||||||
times = config["times"]
|
times = config["times"]
|
||||||
return self._run_scenario_continuously_for_times(
|
results = self._run_scenario_continuously_for_times(
|
||||||
cls, method_name, context, args, times, concurrent, timeout)
|
cls, method_name, context, args, times, concurrent, timeout)
|
||||||
# Continiously run a scenario as many times as needed
|
# Continiously run a scenario as many times as needed
|
||||||
# to fill up the given period of time.
|
# to fill up the given period of time.
|
||||||
elif "duration" in config:
|
elif "duration" in config:
|
||||||
duration = config["duration"]
|
duration = config["duration"]
|
||||||
return self._run_scenario_continuously_for_duration(
|
results = self._run_scenario_continuously_for_duration(
|
||||||
cls, method_name, context, args, duration, concurrent, timeout)
|
cls, method_name, context, args, duration, concurrent, timeout)
|
||||||
|
|
||||||
|
return base.ScenarioRunnerResult(results)
|
||||||
|
@@ -90,4 +90,4 @@ class PeriodicScenarioRunner(base.ScenarioRunner):
|
|||||||
"error": utils.format_exc(e)}
|
"error": utils.format_exc(e)}
|
||||||
results.append(result)
|
results.append(result)
|
||||||
|
|
||||||
return results
|
return base.ScenarioRunnerResult(results)
|
||||||
|
@@ -88,6 +88,11 @@ class InvalidConfigException(RallyException):
|
|||||||
msg_fmt = _("This config has invalid schema: `%(message)s`")
|
msg_fmt = _("This config has invalid schema: `%(message)s`")
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidRunnerResult(RallyException):
|
||||||
|
msg_fmt = _("Type of result of `%(name)s` runner should be"
|
||||||
|
" `base.ScenarioRunnerResult`. Got: `%(results_type)s`")
|
||||||
|
|
||||||
|
|
||||||
class InvalidTaskException(InvalidConfigException):
|
class InvalidTaskException(InvalidConfigException):
|
||||||
msg_fmt = _("This config is invalid: `%(message)s`")
|
msg_fmt = _("This config is invalid: `%(message)s`")
|
||||||
|
|
||||||
|
@@ -13,16 +13,52 @@
|
|||||||
# 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 jsonschema
|
||||||
import mock
|
import mock
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
|
||||||
from rally.benchmark.runners import base
|
from rally.benchmark.runners import base
|
||||||
from rally.benchmark.runners import continuous
|
from rally.benchmark.runners import continuous
|
||||||
from rally import consts
|
from rally import consts
|
||||||
|
from rally import exceptions
|
||||||
from tests import fakes
|
from tests import fakes
|
||||||
from tests import test
|
from tests import test
|
||||||
|
|
||||||
|
|
||||||
|
class ScenarioRunnerResultTestCase(test.TestCase):
|
||||||
|
|
||||||
|
def test_validate(self):
|
||||||
|
config = [
|
||||||
|
{
|
||||||
|
"time": 1.0,
|
||||||
|
"idle_time": 1.0,
|
||||||
|
"scenario_output": {
|
||||||
|
"data": {"test": 1.0},
|
||||||
|
"error": "test error string 1"
|
||||||
|
},
|
||||||
|
"atomic_actions_time": [{"action": "test1", "duration": 1.0}],
|
||||||
|
"error": "test1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 2.0,
|
||||||
|
"idle_time": 2.0,
|
||||||
|
"scenario_output": {
|
||||||
|
"data": {"test": 2.0},
|
||||||
|
"error": "test error string 2"
|
||||||
|
},
|
||||||
|
"atomic_actions_time": [{"action": "test2", "duration": 2.0}],
|
||||||
|
"error": "test2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertEqual(config, base.ScenarioRunnerResult(config))
|
||||||
|
|
||||||
|
def test_validate_failed(self):
|
||||||
|
config = [{"a": 10}]
|
||||||
|
self.assertRaises(jsonschema.ValidationError,
|
||||||
|
base.ScenarioRunnerResult, config)
|
||||||
|
|
||||||
|
|
||||||
class ScenarioRunnerTestCase(test.TestCase):
|
class ScenarioRunnerTestCase(test.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -68,7 +104,7 @@ class ScenarioRunnerTestCase(test.TestCase):
|
|||||||
"active_users": active_users,
|
"active_users": active_users,
|
||||||
"timeout": 2})
|
"timeout": 2})
|
||||||
expected = [{"time": 10, "idle_time": 0, "error": None,
|
expected = [{"time": 10, "idle_time": 0, "error": None,
|
||||||
"scenario_output": None, "atomic_actions_time": []}
|
"scenario_output": {}, "atomic_actions_time": []}
|
||||||
for i in range(times)]
|
for i in range(times)]
|
||||||
self.assertEqual(results, expected)
|
self.assertEqual(results, expected)
|
||||||
|
|
||||||
@@ -78,7 +114,7 @@ class ScenarioRunnerTestCase(test.TestCase):
|
|||||||
"active_users": active_users,
|
"active_users": active_users,
|
||||||
"timeout": 2})
|
"timeout": 2})
|
||||||
expected = [{"time": 10, "idle_time": 0, "error": None,
|
expected = [{"time": 10, "idle_time": 0, "error": None,
|
||||||
"scenario_output": None, "atomic_actions_time": []}
|
"scenario_output": {}, "atomic_actions_time": []}
|
||||||
for i in range(active_users)]
|
for i in range(active_users)]
|
||||||
self.assertEqual(results, expected)
|
self.assertEqual(results, expected)
|
||||||
|
|
||||||
@@ -164,3 +200,10 @@ class ScenarioRunnerTestCase(test.TestCase):
|
|||||||
self.assertEqual(r['time'], 10)
|
self.assertEqual(r['time'], 10)
|
||||||
self.assertEqual(r['error'][:2],
|
self.assertEqual(r['error'][:2],
|
||||||
[str(Exception), "Something went wrong"])
|
[str(Exception), "Something went wrong"])
|
||||||
|
|
||||||
|
@mock.patch("rally.benchmark.runners.base.ScenarioRunner._run_as_admin")
|
||||||
|
def test_run_scenario_runner_results_exception(self, mock_run_method):
|
||||||
|
runner = continuous.ContinuousScenarioRunner(mock.MagicMock(),
|
||||||
|
self.fake_endpoints)
|
||||||
|
self.assertRaises(exceptions.InvalidRunnerResult,
|
||||||
|
runner.run, mock.MagicMock(), mock.MagicMock())
|
||||||
|
@@ -122,7 +122,7 @@ class ContinuousScenarioRunnerTestCase(test.TestCase):
|
|||||||
"continuous")
|
"continuous")
|
||||||
|
|
||||||
runner._run_scenario_continuously_for_times = \
|
runner._run_scenario_continuously_for_times = \
|
||||||
mock.MagicMock(return_value="times")
|
mock.MagicMock(return_value=[{"time": 1}])
|
||||||
|
|
||||||
mock_base.Scenario.get_by_name = \
|
mock_base.Scenario.get_by_name = \
|
||||||
mock.MagicMock(return_value=FakeScenario)
|
mock.MagicMock(return_value=FakeScenario)
|
||||||
@@ -132,7 +132,7 @@ class ContinuousScenarioRunnerTestCase(test.TestCase):
|
|||||||
{"a": 1},
|
{"a": 1},
|
||||||
{"times": 2, "active_users": 3,
|
{"times": 2, "active_users": 3,
|
||||||
"timeout": 1})
|
"timeout": 1})
|
||||||
self.assertEqual(result, "times")
|
self.assertEqual(result, [{"time": 1}])
|
||||||
runner._run_scenario_continuously_for_times.assert_called_once_with(
|
runner._run_scenario_continuously_for_times.assert_called_once_with(
|
||||||
FakeScenario, "do_it", fakecontext,
|
FakeScenario, "do_it", fakecontext,
|
||||||
{"a": 1}, 2, 3, 1)
|
{"a": 1}, 2, 3, 1)
|
||||||
@@ -149,7 +149,7 @@ class ContinuousScenarioRunnerTestCase(test.TestCase):
|
|||||||
self.fake_endpoints,
|
self.fake_endpoints,
|
||||||
"continuous")
|
"continuous")
|
||||||
runner._run_scenario_continuously_for_duration = \
|
runner._run_scenario_continuously_for_duration = \
|
||||||
mock.MagicMock(return_value="duration")
|
mock.MagicMock(return_value=[{"time": 1}])
|
||||||
|
|
||||||
mock_base.Scenario.get_by_name = \
|
mock_base.Scenario.get_by_name = \
|
||||||
mock.MagicMock(return_value=FakeScenario)
|
mock.MagicMock(return_value=FakeScenario)
|
||||||
@@ -159,7 +159,7 @@ class ContinuousScenarioRunnerTestCase(test.TestCase):
|
|||||||
{"a": 1},
|
{"a": 1},
|
||||||
{"duration": 2, "active_users": 3,
|
{"duration": 2, "active_users": 3,
|
||||||
"timeout": 1})
|
"timeout": 1})
|
||||||
self.assertEqual(result, "duration")
|
self.assertEqual(result, [{"time": 1}])
|
||||||
runner._run_scenario_continuously_for_duration.\
|
runner._run_scenario_continuously_for_duration.\
|
||||||
assert_called_once_with(FakeScenario, "do_it", fakecontext,
|
assert_called_once_with(FakeScenario, "do_it", fakecontext,
|
||||||
{"a": 1}, 2, 3, 1)
|
{"a": 1}, 2, 3, 1)
|
||||||
|
@@ -52,6 +52,7 @@ class PeriodicScenarioRunnerTestCase(test.TestCase):
|
|||||||
def test_run_scenario(self, mock_osclients, mock_sleep,
|
def test_run_scenario(self, mock_osclients, mock_sleep,
|
||||||
mock_run_scenario_once):
|
mock_run_scenario_once):
|
||||||
mock_osclients.Clients.return_value = fakes.FakeClients()
|
mock_osclients.Clients.return_value = fakes.FakeClients()
|
||||||
|
mock_run_scenario_once.return_value = {}
|
||||||
runner = periodic.PeriodicScenarioRunner(mock.MagicMock(),
|
runner = periodic.PeriodicScenarioRunner(mock.MagicMock(),
|
||||||
self.fake_endpoints)
|
self.fake_endpoints)
|
||||||
times = 3
|
times = 3
|
||||||
|
Reference in New Issue
Block a user