Deprecate rally task results command
This command produces task results in old format that missis a lot of information. For backward compatibility, the new task results exporter is introduced. Change-Id: I28880642e370513c2430e8e0f67dd7a622023a92
This commit is contained in:
parent
30d5a8ed04
commit
8dbad440db
@ -42,6 +42,9 @@ Changed
|
|||||||
Deprecated
|
Deprecated
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
* Command *rally task results* is deprecated. Use *rally task report --json*
|
||||||
|
instead.
|
||||||
|
|
||||||
* Module *rally.common.sshutils* is deprecated. Use *rally.utils.sshutils*
|
* Module *rally.common.sshutils* is deprecated. Use *rally.utils.sshutils*
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"""Rally command: task"""
|
"""Rally command: task"""
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import collections
|
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import itertools
|
import itertools
|
||||||
import json
|
import json
|
||||||
@ -544,70 +543,16 @@ class TaskCommands(object):
|
|||||||
@envutils.with_default_task_id
|
@envutils.with_default_task_id
|
||||||
@cliutils.suppress_warnings
|
@cliutils.suppress_warnings
|
||||||
def results(self, api, task_id=None):
|
def results(self, api, task_id=None):
|
||||||
"""Display raw task results.
|
"""DEPRECATED since Rally 3.0.0."""
|
||||||
|
LOG.warning("CLI method `rally task results` is deprecated since "
|
||||||
This will produce a lot of output data about every iteration.
|
"Rally 3.0.0 and will be removed soon. "
|
||||||
"""
|
"Use `rally task report --json` instead.")
|
||||||
|
try:
|
||||||
task = api.task.get(task_id=task_id, detailed=True)
|
self.export(api, tasks=[task_id], output_type="old-json-results")
|
||||||
finished_statuses = (consts.TaskStatus.FINISHED,
|
except exceptions.RallyException as e:
|
||||||
consts.TaskStatus.ABORTED)
|
print(e.format_message())
|
||||||
if task["status"] not in finished_statuses:
|
|
||||||
print("Task status is %s. Results available when it is one of %s."
|
|
||||||
% (task["status"], ", ".join(finished_statuses)))
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# TODO(chenhb): Ensure `rally task results` puts out old format.
|
|
||||||
for workload in itertools.chain(
|
|
||||||
*[s["workloads"] for s in task["subtasks"]]):
|
|
||||||
for itr in workload["data"]:
|
|
||||||
itr["atomic_actions"] = collections.OrderedDict(
|
|
||||||
tutils.WrapperForAtomicActions(
|
|
||||||
itr["atomic_actions"]).items()
|
|
||||||
)
|
|
||||||
|
|
||||||
results = []
|
|
||||||
for w in itertools.chain(*[s["workloads"] for s in task["subtasks"]]):
|
|
||||||
w["runner"]["type"] = w["runner_type"]
|
|
||||||
|
|
||||||
def port_hook_cfg(h):
|
|
||||||
h["config"] = {
|
|
||||||
"name": h["config"]["action"][0],
|
|
||||||
"args": h["config"]["action"][1],
|
|
||||||
"description": h["config"].get("description", ""),
|
|
||||||
"trigger": {"name": h["config"]["trigger"][0],
|
|
||||||
"args": h["config"]["trigger"][1]}
|
|
||||||
}
|
|
||||||
return h
|
|
||||||
|
|
||||||
hooks = [port_hook_cfg(h) for h in w["hooks"]]
|
|
||||||
|
|
||||||
created_at = dt.datetime.strptime(w["created_at"],
|
|
||||||
"%Y-%m-%dT%H:%M:%S")
|
|
||||||
created_at = created_at.strftime("%Y-%d-%mT%H:%M:%S")
|
|
||||||
|
|
||||||
results.append({
|
|
||||||
"key": {
|
|
||||||
"name": w["name"],
|
|
||||||
"description": w["description"],
|
|
||||||
"pos": w["position"],
|
|
||||||
"kw": {
|
|
||||||
"args": w["args"],
|
|
||||||
"runner": w["runner"],
|
|
||||||
"context": w["contexts"],
|
|
||||||
"sla": w["sla"],
|
|
||||||
"hooks": [h["config"] for h in w["hooks"]],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"result": w["data"],
|
|
||||||
"sla": w["sla_results"].get("sla", []),
|
|
||||||
"hooks": hooks,
|
|
||||||
"load_duration": w["load_duration"],
|
|
||||||
"full_duration": w["full_duration"],
|
|
||||||
"created_at": created_at})
|
|
||||||
|
|
||||||
print(json.dumps(results, sort_keys=False, indent=4))
|
|
||||||
|
|
||||||
@cliutils.args("--deployment", dest="deployment", type=str,
|
@cliutils.args("--deployment", dest="deployment", type=str,
|
||||||
metavar="<uuid>", required=False,
|
metavar="<uuid>", required=False,
|
||||||
help="UUID or name of a deployment.")
|
help="UUID or name of a deployment.")
|
||||||
|
121
rally/plugins/task/exporters/old_json_results.py
Normal file
121
rally/plugins/task/exporters/old_json_results.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import datetime as dt
|
||||||
|
import itertools
|
||||||
|
import json
|
||||||
|
|
||||||
|
from rally import consts
|
||||||
|
from rally import exceptions
|
||||||
|
from rally.task import exporter
|
||||||
|
|
||||||
|
|
||||||
|
def _to_old_atomic_actions_format(atomic_actions):
|
||||||
|
"""Convert atomic actions to old format. """
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
@exporter.configure("old-json-results")
|
||||||
|
class OldJSONExporter(exporter.TaskExporter):
|
||||||
|
"""Generates task report in JSON format as old `rally task results`."""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(OldJSONExporter, self).__init__(*args, **kwargs)
|
||||||
|
if len(self.tasks_results) != 1:
|
||||||
|
raise exceptions.RallyException(
|
||||||
|
f"'{self.get_fullname()}' task exporter can be used only for "
|
||||||
|
f"a one task.")
|
||||||
|
self.task = self.tasks_results[0]
|
||||||
|
|
||||||
|
def _get_report(self):
|
||||||
|
results = []
|
||||||
|
for w in itertools.chain(*[s["workloads"]
|
||||||
|
for s in self.task["subtasks"]]):
|
||||||
|
for itr in w["data"]:
|
||||||
|
itr["atomic_actions"] = _to_old_atomic_actions_format(
|
||||||
|
itr["atomic_actions"]
|
||||||
|
)
|
||||||
|
|
||||||
|
w["runner"]["type"] = w["runner_type"]
|
||||||
|
|
||||||
|
def port_hook_cfg(h):
|
||||||
|
h["config"] = {
|
||||||
|
"name": h["config"]["action"][0],
|
||||||
|
"args": h["config"]["action"][1],
|
||||||
|
"description": h["config"].get("description", ""),
|
||||||
|
"trigger": {"name": h["config"]["trigger"][0],
|
||||||
|
"args": h["config"]["trigger"][1]}
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
|
||||||
|
hooks = [port_hook_cfg(h) for h in w["hooks"]]
|
||||||
|
|
||||||
|
created_at = dt.datetime.strptime(w["created_at"],
|
||||||
|
"%Y-%m-%dT%H:%M:%S")
|
||||||
|
created_at = created_at.strftime("%Y-%d-%mT%H:%M:%S")
|
||||||
|
|
||||||
|
results.append({
|
||||||
|
"key": {
|
||||||
|
"name": w["name"],
|
||||||
|
"description": w["description"],
|
||||||
|
"pos": w["position"],
|
||||||
|
"kw": {
|
||||||
|
"args": w["args"],
|
||||||
|
"runner": w["runner"],
|
||||||
|
"context": w["contexts"],
|
||||||
|
"sla": w["sla"],
|
||||||
|
"hooks": [h["config"] for h in w["hooks"]],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"result": w["data"],
|
||||||
|
"sla": w["sla_results"].get("sla", []),
|
||||||
|
"hooks": hooks,
|
||||||
|
"load_duration": w["load_duration"],
|
||||||
|
"full_duration": w["full_duration"],
|
||||||
|
"created_at": created_at})
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
if len(self.tasks_results) != 1:
|
||||||
|
raise exceptions.RallyException(
|
||||||
|
f"'{self.get_fullname()}' task exporter can be used only for "
|
||||||
|
f"a one task.")
|
||||||
|
|
||||||
|
finished_statuses = (consts.TaskStatus.FINISHED,
|
||||||
|
consts.TaskStatus.ABORTED)
|
||||||
|
if self.task["status"] not in finished_statuses:
|
||||||
|
raise exceptions.RallyException(
|
||||||
|
f"Task status is {self.task['status']}. Results available "
|
||||||
|
f"when it is one of {', '.join(finished_statuses)}."
|
||||||
|
)
|
||||||
|
|
||||||
|
results = json.dumps(self._get_report(), sort_keys=False, indent=4)
|
||||||
|
|
||||||
|
if self.output_destination:
|
||||||
|
return {"files": {self.output_destination: results},
|
||||||
|
"open": "file://" + self.output_destination}
|
||||||
|
else:
|
||||||
|
return {"print": results}
|
@ -15,7 +15,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
ALLOWED_EXTRA_MISSING=400
|
ALLOWED_EXTRA_MISSING=4
|
||||||
|
|
||||||
show_diff () {
|
show_diff () {
|
||||||
head -1 $1
|
head -1 $1
|
||||||
|
@ -365,7 +365,8 @@ class TaskTestCase(testtools.TestCase):
|
|||||||
rally("task start --task %s" % config.filename)
|
rally("task start --task %s" % config.filename)
|
||||||
task_result_file = rally.gen_report_path(suffix="results")
|
task_result_file = rally.gen_report_path(suffix="results")
|
||||||
self.addCleanup(os.remove, task_result_file)
|
self.addCleanup(os.remove, task_result_file)
|
||||||
rally("task results", report_path=task_result_file, raw=True)
|
rally("task results", report_path=task_result_file, raw=True,
|
||||||
|
getjson=True)
|
||||||
|
|
||||||
html_report = rally.gen_report_path(extension="html")
|
html_report = rally.gen_report_path(extension="html")
|
||||||
rally("task report --html-static %s --out %s"
|
rally("task report --html-static %s --out %s"
|
||||||
|
@ -573,11 +573,24 @@ class TaskCommandsTestCase(test.TestCase):
|
|||||||
"contexts": {"users": {}},
|
"contexts": {"users": {}},
|
||||||
"data": data or []}]}]}
|
"data": data or []}]}]}
|
||||||
|
|
||||||
@mock.patch("rally.cli.commands.task.json.dumps")
|
@mock.patch("rally.plugins.task.exporters.old_json_results.json.dumps")
|
||||||
def test_results(self, mock_json_dumps):
|
def test_results(self, mock_json_dumps):
|
||||||
|
|
||||||
|
mock_json_dumps.return_value = ""
|
||||||
|
|
||||||
|
def fake_export(tasks, output_type, output_dest=None):
|
||||||
|
tasks = [self.fake_api.task.get(u, detailed=True) for u in tasks]
|
||||||
|
return self.real_api.task.export(tasks, output_type, output_dest)
|
||||||
|
|
||||||
|
self.fake_api.task.export.side_effect = fake_export
|
||||||
|
|
||||||
task_id = "foo_task_id"
|
task_id = "foo_task_id"
|
||||||
|
|
||||||
task_obj = self._make_task(data=[{"atomic_actions": {"foo": 1.1}}])
|
task_obj = self._make_task(
|
||||||
|
data=[{"atomic_actions": [{"name": "foo",
|
||||||
|
"started_at": 0,
|
||||||
|
"finished_at": 1.1}]}]
|
||||||
|
)
|
||||||
task_obj["subtasks"][0]["workloads"][0]["hooks"] = [{
|
task_obj["subtasks"][0]["workloads"][0]["hooks"] = [{
|
||||||
"config": {
|
"config": {
|
||||||
"action": ("foo", "arg"),
|
"action": ("foo", "arg"),
|
||||||
@ -585,6 +598,7 @@ class TaskCommandsTestCase(test.TestCase):
|
|||||||
},
|
},
|
||||||
"summary": {"success": 1}}
|
"summary": {"success": 1}}
|
||||||
]
|
]
|
||||||
|
task_obj["uuid"] = task_id
|
||||||
|
|
||||||
def fix_r(workload):
|
def fix_r(workload):
|
||||||
cfg = workload["runner"]
|
cfg = workload["runner"]
|
||||||
@ -633,9 +647,16 @@ class TaskCommandsTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch("rally.cli.commands.task.sys.stdout")
|
@mock.patch("rally.cli.commands.task.sys.stdout")
|
||||||
def test_results_no_data(self, mock_stdout):
|
def test_results_no_data(self, mock_stdout):
|
||||||
|
def fake_export(tasks, output_type, output_dest=None):
|
||||||
|
tasks = [self.fake_api.task.get(u, detailed=True) for u in tasks]
|
||||||
|
return self.real_api.task.export(tasks, output_type, output_dest)
|
||||||
|
|
||||||
|
self.fake_api.task.export.side_effect = fake_export
|
||||||
|
|
||||||
task_id = "foo"
|
task_id = "foo"
|
||||||
self.fake_api.task.get.return_value = self._make_task(
|
task_obj = self._make_task(status=consts.TaskStatus.CRASHED)
|
||||||
status=consts.TaskStatus.CRASHED)
|
task_obj["uuid"] = task_id
|
||||||
|
self.fake_api.task.get.return_value = task_obj
|
||||||
|
|
||||||
self.assertEqual(1, self.task.results(self.fake_api, task_id))
|
self.assertEqual(1, self.task.results(self.fake_api, task_id))
|
||||||
|
|
||||||
|
120
tests/unit/plugins/task/exporters/dummy_data.py
Normal file
120
tests/unit/plugins/task/exporters/dummy_data.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
def get_tasks_results():
|
||||||
|
task_id = "2fa4f5ff-7d23-4bb0-9b1f-8ee235f7f1c8"
|
||||||
|
workload = {"uuid": "uuid",
|
||||||
|
"name": "CinderVolumes.list_volumes",
|
||||||
|
"description": "List all volumes.",
|
||||||
|
"created_at": "2017-06-04T05:14:44",
|
||||||
|
"updated_at": "2017-06-04T05:15:14",
|
||||||
|
"task_uuid": task_id,
|
||||||
|
"position": 0,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"duration": 0.2504892349243164,
|
||||||
|
"timestamp": 1584551892.7336202,
|
||||||
|
"idle_duration": 0.0,
|
||||||
|
"error": [],
|
||||||
|
"output": {
|
||||||
|
"additive": [],
|
||||||
|
"complete": []
|
||||||
|
},
|
||||||
|
"atomic_actions": [
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"children": [],
|
||||||
|
"started_at": 1584551892.733688,
|
||||||
|
"finished_at": 1584551892.984079
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"started_at": 1584551892.7336745,
|
||||||
|
"finished_at": 1584551892.9840994
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"duration": 0.25043749809265137,
|
||||||
|
"timestamp": 1584551892.7363858,
|
||||||
|
"idle_duration": 0.0,
|
||||||
|
"error": [],
|
||||||
|
"output": {
|
||||||
|
"additive": [],
|
||||||
|
"complete": []
|
||||||
|
},
|
||||||
|
"atomic_actions": [
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"children": [],
|
||||||
|
"started_at": 1584551892.7364488,
|
||||||
|
"finished_at": 1584551892.9867969
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"started_at": 1584551892.736435,
|
||||||
|
"finished_at": 1584551892.9868152
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"full_duration": 29.969523191452026,
|
||||||
|
"load_duration": 2.03029203414917,
|
||||||
|
"hooks": [],
|
||||||
|
"runner": {},
|
||||||
|
"runner_type": "runner_type",
|
||||||
|
"args": {},
|
||||||
|
"contexts": {},
|
||||||
|
"contexts_results": [],
|
||||||
|
"min_duration": 0.0,
|
||||||
|
"max_duration": 1.0,
|
||||||
|
"start_time": 0,
|
||||||
|
"statistics": {},
|
||||||
|
"failed_iteration_count": 0,
|
||||||
|
"total_iteration_count": 10,
|
||||||
|
"sla": {},
|
||||||
|
"sla_results": {"sla": []},
|
||||||
|
"pass_sla": True
|
||||||
|
}
|
||||||
|
task = {
|
||||||
|
"uuid": task_id,
|
||||||
|
"title": "task",
|
||||||
|
"description": "description",
|
||||||
|
"status": "finished",
|
||||||
|
"env_uuid": "env-uuid",
|
||||||
|
"env_name": "env-name",
|
||||||
|
"tags": [],
|
||||||
|
"created_at": "2017-06-04T05:14:44",
|
||||||
|
"updated_at": "2017-06-04T05:15:14",
|
||||||
|
"pass_sla": True,
|
||||||
|
"task_duration": 2.0,
|
||||||
|
"subtasks": [
|
||||||
|
{"uuid": "subtask_uuid",
|
||||||
|
"title": "subtask",
|
||||||
|
"description": "description",
|
||||||
|
"status": "finished",
|
||||||
|
"run_in_parallel": True,
|
||||||
|
"created_at": "2017-06-04T05:14:44",
|
||||||
|
"updated_at": "2017-06-04T05:15:14",
|
||||||
|
"sla": {},
|
||||||
|
"duration": 29.969523191452026,
|
||||||
|
"task_uuid": task_id,
|
||||||
|
"workloads": [workload]}
|
||||||
|
]}
|
||||||
|
return [task]
|
@ -16,73 +16,18 @@ import os
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from rally.plugins.task.exporters import html
|
from rally.plugins.task.exporters import html
|
||||||
|
from tests.unit.plugins.task.exporters import dummy_data
|
||||||
from tests.unit import test
|
from tests.unit import test
|
||||||
|
|
||||||
PATH = "rally.plugins.task.exporters.html"
|
PATH = "rally.plugins.task.exporters.html"
|
||||||
|
|
||||||
|
|
||||||
def get_tasks_results():
|
|
||||||
task_id = "2fa4f5ff-7d23-4bb0-9b1f-8ee235f7f1c8"
|
|
||||||
workload = {"uuid": "uuid",
|
|
||||||
"name": "CinderVolumes.list_volumes",
|
|
||||||
"description": "List all volumes.",
|
|
||||||
"created_at": "2017-06-04T05:14:44",
|
|
||||||
"updated_at": "2017-06-04T05:15:14",
|
|
||||||
"task_uuid": task_id,
|
|
||||||
"position": 0,
|
|
||||||
"data": {"raw": []},
|
|
||||||
"full_duration": 29.969523191452026,
|
|
||||||
"load_duration": 2.03029203414917,
|
|
||||||
"hooks": [],
|
|
||||||
"runner": {},
|
|
||||||
"runner_type": "runner_type",
|
|
||||||
"args": {},
|
|
||||||
"contexts": {},
|
|
||||||
"contexts_results": [],
|
|
||||||
"min_duration": 0.0,
|
|
||||||
"max_duration": 1.0,
|
|
||||||
"start_time": 0,
|
|
||||||
"statistics": {},
|
|
||||||
"failed_iteration_count": 0,
|
|
||||||
"total_iteration_count": 10,
|
|
||||||
"sla": {},
|
|
||||||
"sla_results": {"sla": []},
|
|
||||||
"pass_sla": True
|
|
||||||
}
|
|
||||||
task = {
|
|
||||||
"uuid": task_id,
|
|
||||||
"title": "task",
|
|
||||||
"description": "description",
|
|
||||||
"status": "finished",
|
|
||||||
"env_uuid": "env-uuid",
|
|
||||||
"env_name": "env-name",
|
|
||||||
"tags": [],
|
|
||||||
"created_at": "2017-06-04T05:14:44",
|
|
||||||
"updated_at": "2017-06-04T05:15:14",
|
|
||||||
"pass_sla": True,
|
|
||||||
"task_duration": 2.0,
|
|
||||||
"subtasks": [
|
|
||||||
{"uuid": "subtask_uuid",
|
|
||||||
"title": "subtask",
|
|
||||||
"description": "description",
|
|
||||||
"status": "finished",
|
|
||||||
"run_in_parallel": True,
|
|
||||||
"created_at": "2017-06-04T05:14:44",
|
|
||||||
"updated_at": "2017-06-04T05:15:14",
|
|
||||||
"sla": {},
|
|
||||||
"duration": 29.969523191452026,
|
|
||||||
"task_uuid": task_id,
|
|
||||||
"workloads": [workload]}
|
|
||||||
]}
|
|
||||||
return [task]
|
|
||||||
|
|
||||||
|
|
||||||
class HTMLExporterTestCase(test.TestCase):
|
class HTMLExporterTestCase(test.TestCase):
|
||||||
|
|
||||||
@mock.patch("%s.plot.plot" % PATH, return_value="html")
|
@mock.patch("%s.plot.plot" % PATH, return_value="html")
|
||||||
def test_generate(self, mock_plot):
|
def test_generate(self, mock_plot):
|
||||||
tasks_results = get_tasks_results()
|
tasks_results = dummy_data.get_tasks_results()
|
||||||
tasks_results.extend(get_tasks_results())
|
tasks_results.extend(dummy_data.get_tasks_results())
|
||||||
reporter = html.HTMLExporter(tasks_results, None)
|
reporter = html.HTMLExporter(tasks_results, None)
|
||||||
reporter._generate_results = mock.MagicMock()
|
reporter._generate_results = mock.MagicMock()
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ from unittest import mock
|
|||||||
|
|
||||||
from rally.common import version as rally_version
|
from rally.common import version as rally_version
|
||||||
from rally.plugins.task.exporters import json_exporter
|
from rally.plugins.task.exporters import json_exporter
|
||||||
from tests.unit.plugins.task.exporters import test_html
|
from tests.unit.plugins.task.exporters import dummy_data
|
||||||
from tests.unit import test
|
from tests.unit import test
|
||||||
|
|
||||||
PATH = "rally.plugins.task.exporters.json_exporter"
|
PATH = "rally.plugins.task.exporters.json_exporter"
|
||||||
@ -27,9 +27,11 @@ PATH = "rally.plugins.task.exporters.json_exporter"
|
|||||||
class JSONExporterTestCase(test.TestCase):
|
class JSONExporterTestCase(test.TestCase):
|
||||||
|
|
||||||
def test__generate_tasks(self):
|
def test__generate_tasks(self):
|
||||||
tasks_results = test_html.get_tasks_results()
|
tasks_results = dummy_data.get_tasks_results()
|
||||||
reporter = json_exporter.JSONExporter(tasks_results, None)
|
reporter = json_exporter.JSONExporter(tasks_results, None)
|
||||||
|
|
||||||
|
w_data = tasks_results[0]["subtasks"][0]["workloads"][0]["data"]
|
||||||
|
|
||||||
self.assertEqual([
|
self.assertEqual([
|
||||||
collections.OrderedDict([
|
collections.OrderedDict([
|
||||||
("uuid", "2fa4f5ff-7d23-4bb0-9b1f-8ee235f7f1c8"),
|
("uuid", "2fa4f5ff-7d23-4bb0-9b1f-8ee235f7f1c8"),
|
||||||
@ -65,7 +67,7 @@ class JSONExporterTestCase(test.TestCase):
|
|||||||
("load_duration", 2.03029203414917),
|
("load_duration", 2.03029203414917),
|
||||||
("full_duration", 29.969523191452026),
|
("full_duration", 29.969523191452026),
|
||||||
("statistics", {}),
|
("statistics", {}),
|
||||||
("data", {"raw": []}),
|
("data", w_data),
|
||||||
("failed_iteration_count", 0),
|
("failed_iteration_count", 0),
|
||||||
("total_iteration_count", 10),
|
("total_iteration_count", 10),
|
||||||
("created_at", "2017-06-04T05:14:44"),
|
("created_at", "2017-06-04T05:14:44"),
|
||||||
@ -86,7 +88,7 @@ class JSONExporterTestCase(test.TestCase):
|
|||||||
@mock.patch("%s.dt" % PATH)
|
@mock.patch("%s.dt" % PATH)
|
||||||
def test_generate(self, mock_dt, mock_json_dumps):
|
def test_generate(self, mock_dt, mock_json_dumps):
|
||||||
mock_dt.datetime.utcnow.return_value = dt.datetime.utcnow()
|
mock_dt.datetime.utcnow.return_value = dt.datetime.utcnow()
|
||||||
tasks_results = test_html.get_tasks_results()
|
tasks_results = dummy_data.get_tasks_results()
|
||||||
|
|
||||||
# print
|
# print
|
||||||
reporter = json_exporter.JSONExporter(tasks_results, None)
|
reporter = json_exporter.JSONExporter(tasks_results, None)
|
||||||
|
148
tests/unit/plugins/task/exporters/test_old_json_results.py
Normal file
148
tests/unit/plugins/task/exporters/test_old_json_results.py
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import collections
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from rally import exceptions
|
||||||
|
from rally.plugins.task.exporters import old_json_results
|
||||||
|
from tests.unit.plugins.task.exporters import dummy_data
|
||||||
|
from tests.unit import test
|
||||||
|
|
||||||
|
PATH = "rally.plugins.task.exporters.old_json_results"
|
||||||
|
|
||||||
|
|
||||||
|
class OldJSONResultsTestCase(test.TestCase):
|
||||||
|
|
||||||
|
def test___init__(self):
|
||||||
|
old_json_results.OldJSONExporter([1], None)
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.RallyException,
|
||||||
|
old_json_results.OldJSONExporter, [1, 2], None
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch("%s.json.dumps" % PATH, return_value="json")
|
||||||
|
def test_generate(self, mock_json_dumps):
|
||||||
|
tasks_results = dummy_data.get_tasks_results()
|
||||||
|
|
||||||
|
# print
|
||||||
|
exporter = old_json_results.OldJSONExporter(tasks_results, None)
|
||||||
|
exporter._get_report = mock.MagicMock()
|
||||||
|
|
||||||
|
self.assertEqual({"print": "json"}, exporter.generate())
|
||||||
|
|
||||||
|
exporter._get_report.assert_called_once_with()
|
||||||
|
mock_json_dumps.assert_called_once_with(
|
||||||
|
exporter._get_report.return_value, sort_keys=False, indent=4)
|
||||||
|
|
||||||
|
# export to file
|
||||||
|
exporter = old_json_results.OldJSONExporter(
|
||||||
|
tasks_results, output_destination="path")
|
||||||
|
exporter._get_report = mock.MagicMock()
|
||||||
|
self.assertEqual({"files": {"path": "json"},
|
||||||
|
"open": "file://path"}, exporter.generate())
|
||||||
|
|
||||||
|
def test__get_report(self):
|
||||||
|
tasks_results = dummy_data.get_tasks_results()
|
||||||
|
exporter = old_json_results.OldJSONExporter(tasks_results, None)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"created_at": "2017-04-06T05:14:44",
|
||||||
|
"full_duration": 29.969523191452026,
|
||||||
|
"hooks": [],
|
||||||
|
"key": {
|
||||||
|
"description": "List all volumes.",
|
||||||
|
"kw": {"args": {},
|
||||||
|
"context": {},
|
||||||
|
"hooks": [],
|
||||||
|
"runner": {"type": "runner_type"},
|
||||||
|
"sla": {}},
|
||||||
|
"name": "CinderVolumes.list_volumes",
|
||||||
|
"pos": 0
|
||||||
|
},
|
||||||
|
"load_duration": 2.03029203414917,
|
||||||
|
"result": [
|
||||||
|
{
|
||||||
|
"atomic_actions": collections.OrderedDict([
|
||||||
|
("foo", 0.250424861907959)]),
|
||||||
|
"duration": 0.2504892349243164,
|
||||||
|
"error": [],
|
||||||
|
"idle_duration": 0.0,
|
||||||
|
"output": {"additive": [], "complete": []},
|
||||||
|
"timestamp": 1584551892.7336202
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"atomic_actions": collections.OrderedDict([
|
||||||
|
("foo", 0.250380277633667)]),
|
||||||
|
"duration": 0.25043749809265137,
|
||||||
|
"error": [],
|
||||||
|
"idle_duration": 0.0,
|
||||||
|
"output": {"additive": [], "complete": []},
|
||||||
|
"timestamp": 1584551892.7363858}],
|
||||||
|
"sla": []
|
||||||
|
}
|
||||||
|
], exporter._get_report())
|
||||||
|
|
||||||
|
def test__to_old_atomic_actions_format(self):
|
||||||
|
actions = [
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"started_at": 0,
|
||||||
|
"finished_at": 1,
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"started_at": 1,
|
||||||
|
"finished_at": 2,
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"started_at": 2,
|
||||||
|
"finished_at": 3,
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bar",
|
||||||
|
"started_at": 3,
|
||||||
|
"finished_at": 5,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "xxx",
|
||||||
|
"started_at": 3,
|
||||||
|
"finished_at": 4,
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "xxx",
|
||||||
|
"started_at": 4,
|
||||||
|
"finished_at": 5,
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
actual = old_json_results._to_old_atomic_actions_format(actions)
|
||||||
|
self.assertIsInstance(actual, collections.OrderedDict)
|
||||||
|
# it is easier to compare list instead of constructing an ordered dict
|
||||||
|
actual = list(actual.items())
|
||||||
|
self.assertEqual(
|
||||||
|
[("foo", 1), ("foo (2)", 1), ("foo (3)", 1), ("bar", 2)],
|
||||||
|
actual
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user