Merge "[Reports] Use timestamps on X axis in trends report"
This commit is contained in:
commit
bea20ca6ec
@ -167,15 +167,15 @@ def trends(tasks_results):
|
|||||||
|
|
||||||
|
|
||||||
class Trends(object):
|
class Trends(object):
|
||||||
"""Process tasks results and make trends data.
|
"""Process workloads results and make trends data.
|
||||||
|
|
||||||
Group tasks results by their input configuration,
|
Group workloads results by their input configuration,
|
||||||
calculate statistics for these groups and prepare it
|
calculate statistics for these groups and prepare it
|
||||||
for displaying in trends HTML report.
|
for displaying in trends HTML report.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._tasks = {}
|
self._data = {}
|
||||||
|
|
||||||
def _to_str(self, obj):
|
def _to_str(self, obj):
|
||||||
"""Convert object into string."""
|
"""Convert object into string."""
|
||||||
@ -197,29 +197,39 @@ class Trends(object):
|
|||||||
|
|
||||||
def add_result(self, result):
|
def add_result(self, result):
|
||||||
key = self._make_hash(result["key"]["kw"])
|
key = self._make_hash(result["key"]["kw"])
|
||||||
if key not in self._tasks:
|
if key not in self._data:
|
||||||
name = result["key"]["name"]
|
self._data[key] = {
|
||||||
self._tasks[key] = {"seq": 1,
|
"actions": {},
|
||||||
"name": name,
|
"sla_failures": 0,
|
||||||
"cls": name.split(".")[0],
|
"name": result["key"]["name"],
|
||||||
"met": name.split(".")[1],
|
"config": json.dumps(result["key"]["kw"], indent=2)}
|
||||||
"data": {},
|
|
||||||
"total": None,
|
|
||||||
"atomic": [],
|
|
||||||
"stat": {},
|
|
||||||
"sla_failures": 0,
|
|
||||||
"config": json.dumps(result["key"]["kw"],
|
|
||||||
indent=2)}
|
|
||||||
else:
|
|
||||||
self._tasks[key]["seq"] += 1
|
|
||||||
|
|
||||||
for sla in result["sla"]:
|
for sla in result["sla"]:
|
||||||
self._tasks[key]["sla_failures"] += not sla["success"]
|
self._data[key]["sla_failures"] += not sla["success"]
|
||||||
|
|
||||||
task = {row[0]: dict(zip(result["info"]["stat"]["cols"], row))
|
stat = {row[0]: dict(zip(result["info"]["stat"]["cols"], row))
|
||||||
for row in result["info"]["stat"]["rows"]}
|
for row in result["info"]["stat"]["rows"]}
|
||||||
|
ts = int(result["info"]["tstamp_start"] * 1000)
|
||||||
|
|
||||||
|
for action in stat:
|
||||||
|
# NOTE(amaretskiy): some atomic actions can be missed due to
|
||||||
|
# failures. We can ignore that because we use NVD3 lineChart()
|
||||||
|
# for displaying trends, which is safe for missed points
|
||||||
|
if action not in self._data[key]["actions"]:
|
||||||
|
self._data[key]["actions"][action] = {
|
||||||
|
"durations": {"min": [], "median": [], "90%ile": [],
|
||||||
|
"95%ile": [], "max": [], "avg": []},
|
||||||
|
"success": []}
|
||||||
|
|
||||||
|
try:
|
||||||
|
success = float(stat[action]["Success"].rstrip("%"))
|
||||||
|
except ValueError:
|
||||||
|
# Got "n/a" for some reason
|
||||||
|
success = 0
|
||||||
|
|
||||||
|
self._data[key]["actions"][action]["success"].append(
|
||||||
|
(ts, success))
|
||||||
|
|
||||||
for k in task:
|
|
||||||
for tgt, src in (("min", "Min (sec)"),
|
for tgt, src in (("min", "Min (sec)"),
|
||||||
("median", "Median (sec)"),
|
("median", "Median (sec)"),
|
||||||
("90%ile", "90%ile (sec)"),
|
("90%ile", "90%ile (sec)"),
|
||||||
@ -227,49 +237,44 @@ class Trends(object):
|
|||||||
("max", "Max (sec)"),
|
("max", "Max (sec)"),
|
||||||
("avg", "Avg (sec)")):
|
("avg", "Avg (sec)")):
|
||||||
|
|
||||||
# NOTE(amaretskiy): some atomic actions can be
|
self._data[key]["actions"][action]["durations"][tgt].append(
|
||||||
# missed due to failures. We can ignore that
|
(ts, stat[action][src]))
|
||||||
# because we use NVD3 lineChart() for displaying
|
|
||||||
# trends, which is safe for missed points
|
|
||||||
if k not in self._tasks[key]["data"]:
|
|
||||||
self._tasks[key]["data"][k] = {"min": [],
|
|
||||||
"median": [],
|
|
||||||
"90%ile": [],
|
|
||||||
"95%ile": [],
|
|
||||||
"max": [],
|
|
||||||
"avg": [],
|
|
||||||
"success": []}
|
|
||||||
self._tasks[key]["data"][k][tgt].append(
|
|
||||||
(self._tasks[key]["seq"], task[k][src]))
|
|
||||||
|
|
||||||
try:
|
|
||||||
success = float(task[k]["Success"].rstrip("%"))
|
|
||||||
except ValueError:
|
|
||||||
# Got "n/a" for some reason
|
|
||||||
success = 0
|
|
||||||
self._tasks[key]["data"][k]["success"].append(
|
|
||||||
(self._tasks[key]["seq"], success))
|
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
for key, value in self._tasks.items():
|
trends = []
|
||||||
total = None
|
|
||||||
for k, v in value["data"].items():
|
for wload in self._data.values():
|
||||||
success = [("success", v.pop("success"))]
|
trend = {"stat": {},
|
||||||
if k == "total":
|
"name": wload["name"],
|
||||||
total = {"values": v, "success": success}
|
"cls": wload["name"].split(".")[0],
|
||||||
|
"met": wload["name"].split(".")[1],
|
||||||
|
"sla_failures": wload["sla_failures"],
|
||||||
|
"config": wload["config"],
|
||||||
|
"actions": []}
|
||||||
|
|
||||||
|
for action, data in wload["actions"].items():
|
||||||
|
action_durs = [(k, sorted(v))
|
||||||
|
for k, v in data["durations"].items()]
|
||||||
|
if action == "total":
|
||||||
|
trend.update(
|
||||||
|
{"length": len(data["success"]),
|
||||||
|
"durations": action_durs,
|
||||||
|
"success": [("success", sorted(data["success"]))]})
|
||||||
else:
|
else:
|
||||||
self._tasks[key]["atomic"].append(
|
trend["actions"].append(
|
||||||
{"name": k, "values": list(v.items()),
|
{"name": action,
|
||||||
"success": success})
|
"durations": action_durs,
|
||||||
|
"success": [("success", sorted(data["success"]))]})
|
||||||
|
|
||||||
for stat, comp in (("min", charts.streaming.MinComputation()),
|
for stat, comp in (("min", charts.streaming.MinComputation()),
|
||||||
("max", charts.streaming.MaxComputation()),
|
("max", charts.streaming.MaxComputation()),
|
||||||
("avg", charts.streaming.MeanComputation())):
|
("avg", charts.streaming.MeanComputation())):
|
||||||
for k, v in total["values"][stat]:
|
for k, v in trend["durations"]:
|
||||||
if isinstance(v, (float,) + six.integer_types):
|
for i in v:
|
||||||
comp.add(v)
|
if isinstance(i[1], (float,) + six.integer_types):
|
||||||
self._tasks[key]["stat"][stat] = comp.result()
|
comp.add(i[1])
|
||||||
del self._tasks[key]["data"]
|
trend["stat"][stat] = comp.result()
|
||||||
total["values"] = list(total["values"].items())
|
|
||||||
self._tasks[key]["total"] = total
|
trends.append(trend)
|
||||||
self._tasks[key]["single"] = self._tasks[key]["seq"] < 2
|
|
||||||
return sorted(self._tasks.values(), key=lambda s: s["name"])
|
return sorted(trends, key=lambda i: i["name"])
|
||||||
|
@ -73,9 +73,9 @@ var widgetDirective = function($compile) {
|
|||||||
.showControls(opts.controls)
|
.showControls(opts.controls)
|
||||||
.clipEdge(true);
|
.clipEdge(true);
|
||||||
chart.xAxis
|
chart.xAxis
|
||||||
.tickFormat(d3.format(opts.xformat || "d"))
|
.axisLabel(opts.xname)
|
||||||
.axisLabel(opts.xname || "")
|
.tickFormat(opts.xformat)
|
||||||
.showMaxMin(false);
|
.showMaxMin(opts.showmaxmin);
|
||||||
chart.yAxis
|
chart.yAxis
|
||||||
.orient("left")
|
.orient("left")
|
||||||
.tickFormat(d3.format(opts.yformat || ",.3f"));
|
.tickFormat(d3.format(opts.yformat || ",.3f"));
|
||||||
@ -92,9 +92,10 @@ var widgetDirective = function($compile) {
|
|||||||
.useInteractiveGuideline(opts.guide)
|
.useInteractiveGuideline(opts.guide)
|
||||||
.clipEdge(true);
|
.clipEdge(true);
|
||||||
chart.xAxis
|
chart.xAxis
|
||||||
.tickFormat(d3.format(opts.xformat || "d"))
|
.axisLabel(opts.xname)
|
||||||
.axisLabel(opts.xname || "")
|
.tickFormat(opts.xformat)
|
||||||
.showMaxMin(false);
|
.rotateLabels(opts.xrotate)
|
||||||
|
.showMaxMin(opts.showmaxmin);
|
||||||
chart.yAxis
|
chart.yAxis
|
||||||
.orient("left")
|
.orient("left")
|
||||||
.tickFormat(d3.format(opts.yformat || ",.3f"));
|
.tickFormat(d3.format(opts.yformat || ",.3f"));
|
||||||
@ -184,14 +185,20 @@ var widgetDirective = function($compile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = {
|
var opts = {
|
||||||
xname: attrs.nameX || "",
|
xname: attrs.nameX || "",
|
||||||
xformat: attrs.formatX || "d",
|
xrotate: attrs.rotateX || 0,
|
||||||
yformat: attrs.formatY || ",.3f",
|
yformat: attrs.formatY || ",.3f",
|
||||||
controls: attrs.controls === "true",
|
controls: attrs.controls === "true",
|
||||||
guide: attrs.guide === "true"
|
guide: attrs.guide === "true",
|
||||||
|
showmaxmin: attrs.showmaxmin === "true"
|
||||||
};
|
};
|
||||||
Chart.get_chart(attrs.widget)(el, data, options, do_after);
|
if (attrs.formatDateX) {
|
||||||
|
opts.xformat = function(d) { return d3.time.format(attrs.formatDateX)(new Date(d)) }
|
||||||
|
} else {
|
||||||
|
opts.xformat = d3.format(attrs.formatX || "d")
|
||||||
|
}
|
||||||
|
Chart.get_chart(attrs.widget)(el, data, opts, do_after);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attrs.nameY) {
|
if (attrs.nameY) {
|
||||||
|
@ -97,9 +97,9 @@
|
|||||||
name: "Total",
|
name: "Total",
|
||||||
visible: function(){ return true }
|
visible: function(){ return true }
|
||||||
}, {
|
}, {
|
||||||
id: "atomic",
|
id: "actions",
|
||||||
name: "Atomic actions",
|
name: "Atomic actions",
|
||||||
visible: function(){ return (! $scope.wload.single) && $scope.wload.atomic.length }
|
visible: function(){ return ($scope.wload.length !== 1) && $scope.wload.actions.length }
|
||||||
}, {
|
}, {
|
||||||
id: "config",
|
id: "config",
|
||||||
name: "Configuration",
|
name: "Configuration",
|
||||||
@ -134,6 +134,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Other helpers */
|
||||||
|
|
||||||
$scope.showError = function(message) {
|
$scope.showError = function(message) {
|
||||||
return (function (e) {
|
return (function (e) {
|
||||||
e.style.display = "block";
|
e.style.display = "block";
|
||||||
@ -173,8 +175,7 @@
|
|||||||
w.order_idx = itr > 1 ? " ["+itr+"]" : ""
|
w.order_idx = itr > 1 ? " ["+itr+"]" : ""
|
||||||
$scope.wload_map[w.ref] = w;
|
$scope.wload_map[w.ref] = w;
|
||||||
$scope.nav_map[w.ref] = cls_idx;
|
$scope.nav_map[w.ref] = cls_idx;
|
||||||
met.push({name:w.met, itr:itr, idx:idx, order_idx:w.order_idx,
|
met.push({name:w.met, itr:itr, idx:idx, order_idx:w.order_idx, ref:w.ref});
|
||||||
ref:w.ref, single:w.single});
|
|
||||||
prev_met = w.met;
|
prev_met = w.met;
|
||||||
itr += 1;
|
itr += 1;
|
||||||
}
|
}
|
||||||
@ -271,7 +272,7 @@
|
|||||||
<div class="navmet"
|
<div class="navmet"
|
||||||
title="{{m.name}}{{m.order_idx}}"
|
title="{{m.name}}{{m.order_idx}}"
|
||||||
ng-show="n.idx==nav_idx"
|
ng-show="n.idx==nav_idx"
|
||||||
ng-class="{active:wload && m.ref==wload.ref, single:m.single}"
|
ng-class="{active:wload && m.ref==wload.ref, single:m.length === 1}"
|
||||||
ng-click="location.path(m.ref)"
|
ng-click="location.path(m.ref)"
|
||||||
ng-repeat="m in n.met track by $index"
|
ng-repeat="m in n.met track by $index"
|
||||||
ng-repeat-end>{{m.name}}{{m.order_idx}}</div>
|
ng-repeat-end>{{m.name}}{{m.order_idx}}</div>
|
||||||
@ -336,18 +337,18 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="w in data | orderBy:ov_srt:ov_dir"
|
<tr ng-repeat="w in data | orderBy:ov_srt:ov_dir"
|
||||||
ng-click="location.path(w.ref)"
|
ng-click="location.path(w.ref)"
|
||||||
ng-class="{single:w.single}">
|
ng-class="{single:w.length === 1}">
|
||||||
<td>{{w.ref}}
|
<td>{{w.ref}}
|
||||||
<td>{{w.seq}}
|
<td>{{w.length}}
|
||||||
<td>
|
<td>
|
||||||
<span ng-if="w.single">-</span>
|
<span ng-if="w.length === 1">-</span>
|
||||||
<span ng-if="!w.single">{{w.stat.min | number:4}}</span>
|
<span ng-if="w.length !== 1">{{w.stat.min | number:4}}</span>
|
||||||
<td>
|
<td>
|
||||||
<span ng-if="w.single">-</span>
|
<span ng-if="w.length === 1">-</span>
|
||||||
<span ng-if="!w.single">{{w.stat.max | number:4}}</span>
|
<span ng-if="w.length !== 1">{{w.stat.max | number:4}}</span>
|
||||||
<td>
|
<td>
|
||||||
<span ng-if="w.single">-</span>
|
<span ng-if="w.length === 1">-</span>
|
||||||
<span ng-if="!w.single">{{w.stat.avg | number:4}}</span>
|
<span ng-if="w.length !== 1">{{w.stat.avg | number:4}}</span>
|
||||||
<td title="{{w.sla_failures ? 'Failures: ' + w.sla_failures : 'No failures'}}">
|
<td title="{{w.sla_failures ? 'Failures: ' + w.sla_failures : 'No failures'}}">
|
||||||
<span ng-hide="w.sla_failures" class="status-pass">✔</span>
|
<span ng-hide="w.sla_failures" class="status-pass">✔</span>
|
||||||
<span ng-show="w.sla_failures" class="status-fail">✖</span>
|
<span ng-show="w.sla_failures" class="status-fail">✖</span>
|
||||||
@ -371,46 +372,58 @@
|
|||||||
<div ng-include="tab"></div>
|
<div ng-include="tab"></div>
|
||||||
|
|
||||||
<script type="text/ng-template" id="total">
|
<script type="text/ng-template" id="total">
|
||||||
<div ng-if="wload.single">
|
<div ng-if="wload.length === 1">
|
||||||
<div style="margin:30px 0 10px; font-size:14px; color:#ff6622">
|
<div style="margin:30px 0 10px; font-size:14px; color:#ff6622">
|
||||||
This workload has single run so trends can not be displayed.<br>
|
This workload has single run so trends can not be displayed.<br>
|
||||||
There should be at least two workload results with the same configuration
|
There should be at least two workload results with the same configuration
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ng-if="!wload.single">
|
<div ng-if="wload.length !== 1">
|
||||||
<h2>Total durations</h2>
|
<h2>Total durations</h2>
|
||||||
<div widget="Lines"
|
<div widget="Lines"
|
||||||
data="wload.total.values"
|
data="wload.durations"
|
||||||
name-x="Task run sequence number"
|
|
||||||
controls="true"
|
controls="true"
|
||||||
guide="true">
|
guide="true"
|
||||||
|
showmaxmin="true"
|
||||||
|
rotate-x="-70"
|
||||||
|
format-date-x="%Y-%m-%d %H:%M:%S"
|
||||||
|
style="height:370px">
|
||||||
</div>
|
</div>
|
||||||
<h2>Total success rate</h2>
|
<h2>Total success rate</h2>
|
||||||
<div widget="Lines"
|
<div widget="Lines"
|
||||||
data="wload.total.success"
|
data="wload.success"
|
||||||
name-x="Task run sequence number"
|
|
||||||
controls="true"
|
controls="true"
|
||||||
guide="true">
|
guide="true"
|
||||||
|
showmaxmin="true"
|
||||||
|
rotate-x="-70"
|
||||||
|
format-date-x="%Y-%m-%d %H:%M:%S"
|
||||||
|
style="height:370px">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/ng-template" id="atomic">
|
<script type="text/ng-template" id="actions">
|
||||||
<h2>Atomic actions durations / success rate</h2>
|
<h2>Atomic actions durations / success rate</h2>
|
||||||
<div ng-repeat="chart in wload.atomic track by $index">
|
<div ng-repeat="chart in wload.actions track by $index">
|
||||||
<span id="{{chart.name}}"></span>
|
<span id="{{chart.name}}"></span>
|
||||||
<div class="chart-title">{{chart.name}}</div>
|
<div class="chart-title">{{chart.name}}</div>
|
||||||
<div widget="Lines"
|
<div widget="Lines"
|
||||||
data="chart.values"
|
data="chart.durations"
|
||||||
name-x="Task run sequence number"
|
|
||||||
controls="true"
|
controls="true"
|
||||||
guide="true">
|
guide="true"
|
||||||
|
showmaxmin="true"
|
||||||
|
rotate-x="-70"
|
||||||
|
format-date-x="%Y-%m-%d %H:%M:%S"
|
||||||
|
style="height:370px">
|
||||||
</div>
|
</div>
|
||||||
<div widget="Lines"
|
<div widget="Lines"
|
||||||
data="chart.success"
|
data="chart.success"
|
||||||
name-x="Task run sequence number"
|
|
||||||
controls="true"
|
controls="true"
|
||||||
guide="true">
|
guide="true"
|
||||||
|
showmaxmin="true"
|
||||||
|
rotate-x="-70"
|
||||||
|
format-date-x="%Y-%m-%d %H:%M:%S"
|
||||||
|
style="height:400px">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
@ -178,7 +178,7 @@ class TrendsTestCase(test.TestCase):
|
|||||||
|
|
||||||
def test___init__(self):
|
def test___init__(self):
|
||||||
trends = plot.Trends()
|
trends = plot.Trends()
|
||||||
self.assertEqual({}, trends._tasks)
|
self.assertEqual({}, trends._data)
|
||||||
self.assertRaises(TypeError, plot.Trends, 42)
|
self.assertRaises(TypeError, plot.Trends, 42)
|
||||||
|
|
||||||
@ddt.data({"args": [None], "result": "None"},
|
@ddt.data({"args": [None], "result": "None"},
|
||||||
@ -227,11 +227,12 @@ class TrendsTestCase(test.TestCase):
|
|||||||
atomic = {"a": 123, "b": 456}
|
atomic = {"a": 123, "b": 456}
|
||||||
stat_rows = [["a", 0.7, 0.85, 0.9, 0.87, 1.25, 0.67, "100.0%", 4],
|
stat_rows = [["a", 0.7, 0.85, 0.9, 0.87, 1.25, 0.67, "100.0%", 4],
|
||||||
["b", 0.5, 0.75, 0.85, 0.9, 1.1, 0.58, "100.0%", 4],
|
["b", 0.5, 0.75, 0.85, 0.9, 1.1, 0.58, "100.0%", 4],
|
||||||
["total", 1.2, 1.55, 1.7, 1.9, 1.5, 1.6, "100.0%", 4]]
|
["total", 1.2, 1.55, 1.7, 1.8, 1.5, 0.8, "100.0%", 4]]
|
||||||
return {
|
return {
|
||||||
"key": {"kw": salt + "_kw", "name": "Scenario.name_%s" % salt},
|
"key": {"kw": "kw_%d" % salt, "name": "Scenario.name_%d" % salt},
|
||||||
"sla": [{"success": sla_success}],
|
"sla": [{"success": sla_success}],
|
||||||
"info": {"iterations_count": 4, "atomic": atomic,
|
"info": {"iterations_count": 4, "atomic": atomic,
|
||||||
|
"tstamp_start": 123456.789 + salt,
|
||||||
"stat": {"rows": stat_rows,
|
"stat": {"rows": stat_rows,
|
||||||
"cols": ["Action", "Min (sec)", "Median (sec)",
|
"cols": ["Action", "Min (sec)", "Median (sec)",
|
||||||
"90%ile (sec)", "95%ile (sec)",
|
"90%ile (sec)", "95%ile (sec)",
|
||||||
@ -240,120 +241,151 @@ class TrendsTestCase(test.TestCase):
|
|||||||
"iterations": ["<iter-0>", "<iter-1>", "<iter-2>", "<iter-3>"]}
|
"iterations": ["<iter-0>", "<iter-1>", "<iter-2>", "<iter-3>"]}
|
||||||
|
|
||||||
def _sort_trends(self, trends_result):
|
def _sort_trends(self, trends_result):
|
||||||
for r_idx, res in enumerate(trends_result):
|
for idx in range(len(trends_result)):
|
||||||
trends_result[r_idx]["total"]["values"].sort()
|
trends_result[idx]["durations"].sort()
|
||||||
for a_idx, dummy in enumerate(res["atomic"]):
|
for a_idx in range(len(trends_result[idx]["actions"])):
|
||||||
trends_result[r_idx]["atomic"][a_idx]["values"].sort()
|
trends_result[idx]["actions"][a_idx]["durations"].sort()
|
||||||
return trends_result
|
return trends_result
|
||||||
|
|
||||||
def test_add_result_and_get_data(self):
|
def test_add_result_and_get_data(self):
|
||||||
trends = plot.Trends()
|
trends = plot.Trends()
|
||||||
for i in 0, 1:
|
for i in 0, 1:
|
||||||
trends.add_result(self._make_result(str(i)))
|
trends.add_result(self._make_result(i))
|
||||||
expected = [
|
expected = [
|
||||||
{"atomic": [
|
{"actions": [{"durations": [("90%ile", [(123456789, 0.9)]),
|
||||||
{"name": "a",
|
("95%ile", [(123456789, 0.87)]),
|
||||||
"success": [("success", [(1, 100.0)])],
|
("avg", [(123456789, 0.67)]),
|
||||||
"values": [("90%ile", [(1, 0.9)]), ("95%ile", [(1, 0.87)]),
|
("max", [(123456789, 1.25)]),
|
||||||
("avg", [(1, 0.67)]), ("max", [(1, 1.25)]),
|
("median", [(123456789, 0.85)]),
|
||||||
("median", [(1, 0.85)]), ("min", [(1, 0.7)])]},
|
("min", [(123456789, 0.7)])],
|
||||||
{"name": "b",
|
"name": "a",
|
||||||
"success": [("success", [(1, 100.0)])],
|
"success": [("success", [(123456789, 100.0)])]},
|
||||||
"values": [("90%ile", [(1, 0.85)]), ("95%ile", [(1, 0.9)]),
|
{"durations": [("90%ile", [(123456789, 0.85)]),
|
||||||
("avg", [(1, 0.58)]), ("max", [(1, 1.1)]),
|
("95%ile", [(123456789, 0.9)]),
|
||||||
("median", [(1, 0.75)]), ("min", [(1, 0.5)])]}],
|
("avg", [(123456789, 0.58)]),
|
||||||
"cls": "Scenario", "config": "\"0_kw\"", "met": "name_0",
|
("max", [(123456789, 1.1)]),
|
||||||
"name": "Scenario.name_0", "seq": 1, "single": True,
|
("median", [(123456789, 0.75)]),
|
||||||
"sla_failures": 0, "stat": {"avg": 1.6, "max": 1.5, "min": 1.2},
|
("min", [(123456789, 0.5)])],
|
||||||
"total": {"success": [("success", [(1, 100.0)])],
|
"name": "b",
|
||||||
"values": [("90%ile", [(1, 1.7)]),
|
"success": [("success", [(123456789, 100.0)])]}],
|
||||||
("95%ile", [(1, 1.9)]),
|
"cls": "Scenario",
|
||||||
("avg", [(1, 1.6)]),
|
"config": "\"kw_0\"",
|
||||||
("max", [(1, 1.5)]),
|
"durations": [("90%ile", [(123456789, 1.7)]),
|
||||||
("median", [(1, 1.55)]),
|
("95%ile", [(123456789, 1.8)]),
|
||||||
("min", [(1, 1.2)])]}},
|
("avg", [(123456789, 0.8)]),
|
||||||
{"atomic": [
|
("max", [(123456789, 1.5)]),
|
||||||
{"name": "a",
|
("median", [(123456789, 1.55)]),
|
||||||
"success": [("success", [(1, 100.0)])],
|
("min", [(123456789, 1.2)])],
|
||||||
"values": [("90%ile", [(1, 0.9)]), ("95%ile", [(1, 0.87)]),
|
"length": 1,
|
||||||
("avg", [(1, 0.67)]), ("max", [(1, 1.25)]),
|
"met": "name_0",
|
||||||
("median", [(1, 0.85)]), ("min", [(1, 0.7)])]},
|
"name": "Scenario.name_0",
|
||||||
{"name": "b",
|
"sla_failures": 0,
|
||||||
"success": [("success", [(1, 100.0)])],
|
"stat": {"avg": 1.425, "max": 1.8, "min": 0.8},
|
||||||
"values": [("90%ile", [(1, 0.85)]), ("95%ile", [(1, 0.9)]),
|
"success": [("success", [(123456789, 100.0)])]},
|
||||||
("avg", [(1, 0.58)]), ("max", [(1, 1.1)]),
|
{"actions": [{"durations": [("90%ile", [(123457789, 0.9)]),
|
||||||
("median", [(1, 0.75)]), ("min", [(1, 0.5)])]}],
|
("95%ile", [(123457789, 0.87)]),
|
||||||
"cls": "Scenario", "config": "\"1_kw\"", "met": "name_1",
|
("avg", [(123457789, 0.67)]),
|
||||||
"name": "Scenario.name_1", "seq": 1, "single": True,
|
("max", [(123457789, 1.25)]),
|
||||||
"sla_failures": 0, "stat": {"avg": 1.6, "max": 1.5, "min": 1.2},
|
("median", [(123457789, 0.85)]),
|
||||||
"total": {"success": [("success", [(1, 100.0)])],
|
("min", [(123457789, 0.7)])],
|
||||||
"values": [("90%ile", [(1, 1.7)]),
|
"name": "a",
|
||||||
("95%ile", [(1, 1.9)]),
|
"success": [("success", [(123457789, 100.0)])]},
|
||||||
("avg", [(1, 1.6)]),
|
{"durations": [("90%ile", [(123457789, 0.85)]),
|
||||||
("max", [(1, 1.5)]),
|
("95%ile", [(123457789, 0.9)]),
|
||||||
("median", [(1, 1.55)]),
|
("avg", [(123457789, 0.58)]),
|
||||||
("min", [(1, 1.2)])]}}]
|
("max", [(123457789, 1.1)]),
|
||||||
|
("median", [(123457789, 0.75)]),
|
||||||
|
("min", [(123457789, 0.5)])],
|
||||||
|
"name": "b",
|
||||||
|
"success": [("success", [(123457789, 100.0)])]}],
|
||||||
|
"cls": "Scenario",
|
||||||
|
"config": "\"kw_1\"",
|
||||||
|
"durations": [("90%ile", [(123457789, 1.7)]),
|
||||||
|
("95%ile", [(123457789, 1.8)]),
|
||||||
|
("avg", [(123457789, 0.8)]),
|
||||||
|
("max", [(123457789, 1.5)]),
|
||||||
|
("median", [(123457789, 1.55)]),
|
||||||
|
("min", [(123457789, 1.2)])],
|
||||||
|
"length": 1,
|
||||||
|
"met": "name_1",
|
||||||
|
"name": "Scenario.name_1",
|
||||||
|
"sla_failures": 0,
|
||||||
|
"stat": {"avg": 1.425, "max": 1.8, "min": 0.8},
|
||||||
|
"success": [("success", [(123457789, 100.0)])]}]
|
||||||
self.assertEqual(expected, self._sort_trends(trends.get_data()))
|
self.assertEqual(expected, self._sort_trends(trends.get_data()))
|
||||||
|
|
||||||
def test_add_result_once_and_get_data(self):
|
def test_add_result_once_and_get_data(self):
|
||||||
trends = plot.Trends()
|
trends = plot.Trends()
|
||||||
trends.add_result(self._make_result("foo", sla_success=False))
|
trends.add_result(self._make_result(42, sla_success=False))
|
||||||
expected = [
|
expected = [
|
||||||
{"atomic": [
|
{"actions": [{"durations": [("90%ile", [(123498789, 0.9)]),
|
||||||
{"name": "a",
|
("95%ile", [(123498789, 0.87)]),
|
||||||
"success": [("success", [(1, 100.0)])],
|
("avg", [(123498789, 0.67)]),
|
||||||
"values": [("90%ile", [(1, 0.9)]), ("95%ile", [(1, 0.87)]),
|
("max", [(123498789, 1.25)]),
|
||||||
("avg", [(1, 0.67)]), ("max", [(1, 1.25)]),
|
("median", [(123498789, 0.85)]),
|
||||||
("median", [(1, 0.85)]), ("min", [(1, 0.7)])]},
|
("min", [(123498789, 0.7)])],
|
||||||
{"name": "b",
|
"name": "a",
|
||||||
"success": [("success", [(1, 100.0)])],
|
"success": [("success", [(123498789, 100.0)])]},
|
||||||
"values": [("90%ile", [(1, 0.85)]), ("95%ile", [(1, 0.9)]),
|
{"durations": [("90%ile", [(123498789, 0.85)]),
|
||||||
("avg", [(1, 0.58)]), ("max", [(1, 1.1)]),
|
("95%ile", [(123498789, 0.9)]),
|
||||||
("median", [(1, 0.75)]), ("min", [(1, 0.5)])]}],
|
("avg", [(123498789, 0.58)]),
|
||||||
"cls": "Scenario", "config": "\"foo_kw\"", "met": "name_foo",
|
("max", [(123498789, 1.1)]),
|
||||||
"name": "Scenario.name_foo", "seq": 1, "single": True,
|
("median", [(123498789, 0.75)]),
|
||||||
"sla_failures": 1, "stat": {"avg": 1.6, "max": 1.5, "min": 1.2},
|
("min", [(123498789, 0.5)])],
|
||||||
"total": {"success": [("success", [(1, 100.0)])],
|
"name": "b",
|
||||||
"values": [("90%ile", [(1, 1.7)]),
|
"success": [("success", [(123498789, 100.0)])]}],
|
||||||
("95%ile", [(1, 1.9)]),
|
"cls": "Scenario",
|
||||||
("avg", [(1, 1.6)]),
|
"config": "\"kw_42\"",
|
||||||
("max", [(1, 1.5)]),
|
"durations": [("90%ile", [(123498789, 1.7)]),
|
||||||
("median", [(1, 1.55)]),
|
("95%ile", [(123498789, 1.8)]),
|
||||||
("min", [(1, 1.2)])]}}]
|
("avg", [(123498789, 0.8)]),
|
||||||
|
("max", [(123498789, 1.5)]),
|
||||||
|
("median", [(123498789, 1.55)]),
|
||||||
|
("min", [(123498789, 1.2)])],
|
||||||
|
"length": 1,
|
||||||
|
"met": "name_42",
|
||||||
|
"name": "Scenario.name_42",
|
||||||
|
"sla_failures": 1,
|
||||||
|
"stat": {"avg": 1.425, "max": 1.8, "min": 0.8},
|
||||||
|
"success": [("success", [(123498789, 100.0)])]}]
|
||||||
self.assertEqual(expected, self._sort_trends(trends.get_data()))
|
self.assertEqual(expected, self._sort_trends(trends.get_data()))
|
||||||
|
|
||||||
def test_add_result_with_na_and_get_data(self):
|
def test_add_result_with_na_and_get_data(self):
|
||||||
trends = plot.Trends()
|
trends = plot.Trends()
|
||||||
trends.add_result(self._make_result("foo",
|
trends.add_result(
|
||||||
sla_success=False, with_na=True))
|
self._make_result(42, sla_success=False, with_na=True))
|
||||||
expected = [
|
expected = [
|
||||||
{"atomic": [{"name": "a",
|
{"actions": [{"durations": [("90%ile", [(123498789, "n/a")]),
|
||||||
"success": [("success", [(1, 0)])],
|
("95%ile", [(123498789, "n/a")]),
|
||||||
"values": [("90%ile", [(1, "n/a")]),
|
("avg", [(123498789, "n/a")]),
|
||||||
("95%ile", [(1, "n/a")]),
|
("max", [(123498789, "n/a")]),
|
||||||
("avg", [(1, "n/a")]),
|
("median", [(123498789, "n/a")]),
|
||||||
("max", [(1, "n/a")]),
|
("min", [(123498789, "n/a")])],
|
||||||
("median", [(1, "n/a")]),
|
"name": "a",
|
||||||
("min", [(1, "n/a")])]},
|
"success": [("success", [(123498789, 0)])]},
|
||||||
{"name": "b",
|
{"durations": [("90%ile", [(123498789, "n/a")]),
|
||||||
"success": [("success", [(1, 0)])],
|
("95%ile", [(123498789, "n/a")]),
|
||||||
"values": [("90%ile", [(1, "n/a")]),
|
("avg", [(123498789, "n/a")]),
|
||||||
("95%ile", [(1, "n/a")]),
|
("max", [(123498789, "n/a")]),
|
||||||
("avg", [(1, "n/a")]),
|
("median", [(123498789, "n/a")]),
|
||||||
("max", [(1, "n/a")]),
|
("min", [(123498789, "n/a")])],
|
||||||
("median", [(1, "n/a")]),
|
"name": "b",
|
||||||
("min", [(1, "n/a")])]}],
|
"success": [("success", [(123498789, 0)])]}],
|
||||||
"cls": "Scenario", "config": "\"foo_kw\"", "met": "name_foo",
|
"cls": "Scenario",
|
||||||
"name": "Scenario.name_foo", "seq": 1, "single": True,
|
"config": "\"kw_42\"",
|
||||||
"sla_failures": 1, "stat": {"avg": None, "max": None,
|
"durations": [("90%ile", [(123498789, "n/a")]),
|
||||||
"min": None},
|
("95%ile", [(123498789, "n/a")]),
|
||||||
"total": {"success": [("success", [(1, 0)])],
|
("avg", [(123498789, "n/a")]),
|
||||||
"values": [("90%ile", [(1, "n/a")]),
|
("max", [(123498789, "n/a")]),
|
||||||
("95%ile", [(1, "n/a")]),
|
("median", [(123498789, "n/a")]),
|
||||||
("avg", [(1, "n/a")]),
|
("min", [(123498789, "n/a")])],
|
||||||
("max", [(1, "n/a")]),
|
"length": 1,
|
||||||
("median", [(1, "n/a")]),
|
"met": "name_42",
|
||||||
("min", [(1, "n/a")])]}}]
|
"name": "Scenario.name_42",
|
||||||
|
"sla_failures": 1,
|
||||||
|
"stat": {"avg": None, "max": None, "min": None},
|
||||||
|
"success": [("success", [(123498789, 0)])]}]
|
||||||
|
|
||||||
self.assertEqual(expected, self._sort_trends(trends.get_data()))
|
self.assertEqual(expected, self._sort_trends(trends.get_data()))
|
||||||
|
|
||||||
def test_get_data_no_results_added(self):
|
def test_get_data_no_results_added(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user