Merge "[Reports] Improve HTML report and add dummy_output scenario"
This commit is contained in:
commit
eeb0b7ea2c
@ -589,6 +589,16 @@
|
|||||||
min: 20
|
min: 20
|
||||||
max: 80
|
max: 80
|
||||||
|
|
||||||
|
Dummy.dummy_output:
|
||||||
|
-
|
||||||
|
runner:
|
||||||
|
type: "constant"
|
||||||
|
times: 20
|
||||||
|
concurrency: 10
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
||||||
|
|
||||||
Dummy.dummy_with_scenario_output:
|
Dummy.dummy_with_scenario_output:
|
||||||
-
|
-
|
||||||
runner:
|
runner:
|
||||||
|
@ -80,6 +80,63 @@ class Dummy(scenario.Scenario):
|
|||||||
% exception_probability
|
% exception_probability
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@scenario.configure()
|
||||||
|
def dummy_output(self, random_range=25):
|
||||||
|
"""Generate dummy output.
|
||||||
|
|
||||||
|
This scenario generates example of output data.
|
||||||
|
:param random_range: max int limit for generated random values
|
||||||
|
"""
|
||||||
|
rand = lambda n: [n, random.randint(1, random_range)]
|
||||||
|
desc = "This is a description text for %s"
|
||||||
|
|
||||||
|
self.add_output(additive={"title": "Additive Stat Table",
|
||||||
|
"description": desc % "Additive Stat Table",
|
||||||
|
"chart": "OutputStatsTable",
|
||||||
|
"items": [rand("foo stat"), rand("bar stat"),
|
||||||
|
rand("spam stat")]})
|
||||||
|
|
||||||
|
self.add_output(additive={"title": "Additive Foo StackedArea",
|
||||||
|
"description": (
|
||||||
|
desc % "Additive Foo StackedArea"),
|
||||||
|
"chart": "OutputStackedAreaChart",
|
||||||
|
"items": [rand("foo 1"), rand("foo 2")]})
|
||||||
|
|
||||||
|
self.add_output(additive={"title": ("Additive Bar StackedArea "
|
||||||
|
"(no description)"),
|
||||||
|
"description": "",
|
||||||
|
"chart": "OutputStackedAreaChart",
|
||||||
|
"items": [rand("bar %d" % i)
|
||||||
|
for i in range(1, 7)]})
|
||||||
|
|
||||||
|
self.add_output(additive={"title": "Additive Spam Pie",
|
||||||
|
"description": desc % "Additive Spam Pie",
|
||||||
|
"chart": "OutputAvgChart",
|
||||||
|
"items": [rand("spam %d" % i)
|
||||||
|
for i in range(1, 4)]},
|
||||||
|
complete={"title": "Complete StackedArea",
|
||||||
|
"description": desc % "Complete StackedArea",
|
||||||
|
"widget": "StackedArea",
|
||||||
|
"data": [
|
||||||
|
[name, [rand(i) for i in range(30)]]
|
||||||
|
for name in ("alpha", "beta", "gamma")]})
|
||||||
|
|
||||||
|
self.add_output(
|
||||||
|
complete={"title": "Complete Pie (no description)",
|
||||||
|
"description": "",
|
||||||
|
"widget": "Pie",
|
||||||
|
"data": [rand("delta"), rand("epsilon"), rand("zeta"),
|
||||||
|
rand("theta"), rand("lambda"), rand("omega")]})
|
||||||
|
|
||||||
|
data = {"cols": ["mu column", "xi column", "pi column",
|
||||||
|
"tau column", "chi column"],
|
||||||
|
"rows": [([name + " row"] + [rand(i)[1] for i in range(4)])
|
||||||
|
for name in ("iota", "nu", "rho", "phi", "psi")]}
|
||||||
|
self.add_output(complete={"title": "Complete Table",
|
||||||
|
"description": desc % "Complete Table",
|
||||||
|
"widget": "Table",
|
||||||
|
"data": data})
|
||||||
|
|
||||||
@scenario.configure()
|
@scenario.configure()
|
||||||
def dummy_with_scenario_output(self):
|
def dummy_with_scenario_output(self):
|
||||||
"""Return a dummy scenario output.
|
"""Return a dummy scenario output.
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
p { margin:0; padding:5px 0 }
|
p { margin:0; padding:5px 0 }
|
||||||
p.thesis { padding:10px 0 }
|
p.thesis { padding:10px 0 }
|
||||||
h1 { color:#666; margin:0 0 20px; font-size:30px; font-weight:normal }
|
h1 { color:#666; margin:0 0 20px; font-size:30px; font-weight:normal }
|
||||||
h2 { color:#777; margin:20px 0 10px; font-size:25px; font-weight:normal }
|
h2, .h2 { color:#666; margin:24px 0 6px; font-size:25px; font-weight:normal }
|
||||||
h3 { color:#666; margin:13px 0 4px; font-size:18px; font-weight:normal }
|
h3, .h3 { color:#777; margin:12px 0 4px; font-size:18px; font-weight:normal }
|
||||||
table { border-collapse:collapse; border-spacing:0; width:100%; font-size:12px; margin:0 0 10px }
|
table { border-collapse:collapse; border-spacing:0; width:100%; font-size:12px; margin:0 0 10px }
|
||||||
table th { text-align:left; padding:8px; color:#000; border:2px solid #ddd; border-width:0 0 2px 0 }
|
table th { text-align:left; padding:8px; color:#000; border:2px solid #ddd; border-width:0 0 2px 0 }
|
||||||
table th.sortable { cursor:pointer }
|
table th.sortable { cursor:pointer }
|
||||||
@ -21,7 +21,6 @@
|
|||||||
table.compact td { padding:4px 8px }
|
table.compact td { padding:4px 8px }
|
||||||
table.striped tr:nth-child(odd) td { background:#f9f9f9 }
|
table.striped tr:nth-child(odd) td { background:#f9f9f9 }
|
||||||
table.linked tbody tr:hover { background:#f9f9f9; cursor:pointer }
|
table.linked tbody tr:hover { background:#f9f9f9; cursor:pointer }
|
||||||
.richcolor td { color:#036; font-weight:bold }
|
|
||||||
.rich, .rich td { font-weight:bold }
|
.rich, .rich td { font-weight:bold }
|
||||||
.code { padding:10px; font-size:13px; color:#333; background:#f6f6f6; border:1px solid #e5e5e5; border-radius:4px }
|
.code { padding:10px; font-size:13px; color:#333; background:#f6f6f6; border:1px solid #e5e5e5; border-radius:4px }
|
||||||
|
|
||||||
|
@ -23,46 +23,41 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js_before %}
|
{% block js_before %}
|
||||||
|
{% raw %}
|
||||||
"use strict";
|
"use strict";
|
||||||
if (typeof angular === "object") { angular.module("TaskApp", []).controller(
|
if (typeof angular === "object") { angular.module("TaskApp", []).controller(
|
||||||
"TaskController", ["$scope", "$location", function($scope, $location) {
|
"TaskController", ["$scope", "$location", function($scope, $location) {
|
||||||
|
{% endraw %}
|
||||||
|
$scope.source = {{ source }};
|
||||||
|
$scope.scenarios = {{ data }};
|
||||||
|
{% raw %}
|
||||||
$scope.location = {
|
$scope.location = {
|
||||||
/* This is a junior brother of angular's $location, that allows non-`#'
|
/* #/path/hash/sub/div */
|
||||||
symbol in uri, like `#/path/hash' instead of `#/path#hash' */
|
|
||||||
_splitter: "/",
|
|
||||||
normalize: function(str) {
|
normalize: function(str) {
|
||||||
/* Remove unwanted characters from string */
|
/* Remove unwanted characters from string */
|
||||||
if (typeof str !== "string") { return "" }
|
if (typeof str !== "string") { return "" }
|
||||||
return str.replace(/[^\w\-\.]/g, "")
|
return str.replace(/[^\w\-\.]/g, "")
|
||||||
},
|
},
|
||||||
_parseUri: function(uriStr) {
|
|
||||||
/* :returns: {path:string, hash:string} */
|
|
||||||
var self = this;
|
|
||||||
var obj = {path: "", hash: ""};
|
|
||||||
angular.forEach(uriStr.split(self._splitter), function(v){
|
|
||||||
var s = self.normalize(v);
|
|
||||||
if (! s) { return }
|
|
||||||
if (! this.path) { this.path = s } else if (! this.hash) { this.hash = s }
|
|
||||||
}, obj)
|
|
||||||
return obj
|
|
||||||
},
|
|
||||||
uri: function(obj) {
|
uri: function(obj) {
|
||||||
/* Getter/Setter */
|
/* Getter/Setter */
|
||||||
if (! obj) { return this._parseUri($location.url()) }
|
if (! obj) {
|
||||||
if (obj.path && obj.hash) {
|
var uri = {path: "", hash: "", sub: "", div: ""};
|
||||||
$location.url(obj.path + this._splitter + obj.hash)
|
var arr = ["div", "sub", "hash", "path"];
|
||||||
} else if (obj.path) {
|
angular.forEach($location.url().split("/"), function(value){
|
||||||
$location.url(obj.path)
|
var v = $scope.location.normalize(value);
|
||||||
} else {
|
if (v) { var k = arr.pop(); if (k) { this[k] = v }}
|
||||||
$location.url("/")
|
}, uri);
|
||||||
|
return uri
|
||||||
}
|
}
|
||||||
|
var arr = [obj.path, obj.hash, obj.sub, obj.div], res = [];
|
||||||
|
for (var i in arr) { if (! arr[i]) { break }; res.push(arr[i]) }
|
||||||
|
return $location.url("/" + res.join("/"))
|
||||||
},
|
},
|
||||||
path: function(path, hash) {
|
path: function(path, hash) {
|
||||||
/* Getter/Setter */
|
/* Getter/Setter */
|
||||||
var uri = this.uri();
|
|
||||||
if (path === "") { return this.uri({}) }
|
if (path === "") { return this.uri({}) }
|
||||||
path = this.normalize(path);
|
path = this.normalize(path);
|
||||||
|
var uri = this.uri();
|
||||||
if (! path) { return uri.path }
|
if (! path) { return uri.path }
|
||||||
uri.path = path;
|
uri.path = path;
|
||||||
var _hash = this.normalize(hash);
|
var _hash = this.normalize(hash);
|
||||||
@ -71,23 +66,27 @@
|
|||||||
},
|
},
|
||||||
hash: function(hash) {
|
hash: function(hash) {
|
||||||
/* Getter/Setter */
|
/* Getter/Setter */
|
||||||
var uri = this.uri();
|
if (hash) { this.uri({path:this.uri().path, hash:hash}) }
|
||||||
if (! hash) { return uri.hash }
|
return this.uri().hash
|
||||||
return this.uri({path:uri.path, hash:hash})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dispatch */
|
/* Dispatch */
|
||||||
|
|
||||||
$scope.route = function(uri) {
|
$scope.route = function(uri) {
|
||||||
if (! ($scope.scenarios && $scope.scenarios.length)) {
|
if (! $scope.scenarios_map) { return }
|
||||||
return
|
|
||||||
}
|
|
||||||
if (uri.path in $scope.scenarios_map) {
|
if (uri.path in $scope.scenarios_map) {
|
||||||
$scope.view = {is_scenario:true};
|
$scope.view = {is_scenario:true};
|
||||||
$scope.scenario = $scope.scenarios_map[uri.path];
|
$scope.scenario = $scope.scenarios_map[uri.path];
|
||||||
$scope.nav_idx = $scope.nav_map[uri.path];
|
$scope.nav_idx = $scope.nav_map[uri.path];
|
||||||
$scope.showTab(uri.hash);
|
if ($scope.scenario.iterations.histogram.views.length) {
|
||||||
|
$scope.mainHistogram = $scope.scenario.iterations.histogram.views[0]
|
||||||
|
}
|
||||||
|
if ($scope.scenario.atomic.histogram.views.length) {
|
||||||
|
$scope.atomicHistogram = $scope.scenario.atomic.histogram.views[0]
|
||||||
|
}
|
||||||
|
$scope.outputIteration = 0;
|
||||||
|
$scope.showTab(uri);
|
||||||
} else {
|
} else {
|
||||||
$scope.scenario = null;
|
$scope.scenario = null;
|
||||||
if (uri.path === "source") {
|
if (uri.path === "source") {
|
||||||
@ -102,11 +101,7 @@
|
|||||||
$scope.route($scope.location.uri())
|
$scope.route($scope.location.uri())
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Navigation */
|
$scope.showNav = function(nav_idx) { $scope.nav_idx = nav_idx }
|
||||||
|
|
||||||
$scope.showNav = function(nav_idx) {
|
|
||||||
$scope.nav_idx = nav_idx
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tabs */
|
/* Tabs */
|
||||||
|
|
||||||
@ -121,8 +116,8 @@
|
|||||||
visible: function(){ return !! $scope.scenario.atomic.pie.length }
|
visible: function(){ return !! $scope.scenario.atomic.pie.length }
|
||||||
},{
|
},{
|
||||||
id: "output",
|
id: "output",
|
||||||
name: "Output",
|
name: "Scenario Data",
|
||||||
visible: function(){ return !! $scope.scenario.additive_output.length }
|
visible: function(){ return $scope.scenario.output.length }
|
||||||
},{
|
},{
|
||||||
id: "failures",
|
id: "failures",
|
||||||
name: "Failures",
|
name: "Failures",
|
||||||
@ -137,19 +132,33 @@
|
|||||||
angular.forEach($scope.tabs,
|
angular.forEach($scope.tabs,
|
||||||
function(tab){ this[tab.id] = tab }, $scope.tabs_map);
|
function(tab){ this[tab.id] = tab }, $scope.tabs_map);
|
||||||
|
|
||||||
$scope.showTab = function(tab_id) {
|
$scope.showTab = function(uri) {
|
||||||
$scope.tab = tab_id in $scope.tabs_map ? tab_id : "overview"
|
$scope.tab = uri.hash in $scope.tabs_map ? uri.hash : "overview";
|
||||||
|
if (! $scope.scenario.output) {
|
||||||
|
var has_additive = !! $scope.scenario.additive_output.length;
|
||||||
|
var has_complete = !! ($scope.scenario.complete_output.length
|
||||||
|
&& $scope.scenario.complete_output[0].length);
|
||||||
|
$scope.scenario.output = {
|
||||||
|
has_additive: has_additive,
|
||||||
|
has_complete: has_complete,
|
||||||
|
length: has_additive + has_complete,
|
||||||
|
active: has_additive ? "additive" : (has_complete ? "complete" : "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uri.hash === "output") {
|
||||||
|
if (uri.sub && $scope.scenario.output["has_" + uri.sub]) {
|
||||||
|
$scope.scenario.output.active = uri.sub
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i in $scope.tabs) {
|
for (var i in $scope.tabs) {
|
||||||
if ($scope.tabs[i].id === $scope.location.hash()) {
|
if ($scope.tabs[i].id === $scope.location.hash()) {
|
||||||
$scope.tab = $scope.tabs[i].id
|
$scope.tab = $scope.tabs[i].id
|
||||||
}
|
}
|
||||||
$scope.tabs[i].isVisible = function(){
|
$scope.tabs[i].isVisible = function() {
|
||||||
if ($scope.scenario) {
|
if ($scope.scenario) {
|
||||||
if (this.visible()) {
|
if (this.visible()) { return true }
|
||||||
return true
|
|
||||||
}
|
|
||||||
/* If tab should be hidden but is selected - show another one */
|
/* If tab should be hidden but is selected - show another one */
|
||||||
if (this.id === $scope.location.hash()) {
|
if (this.id === $scope.location.hash()) {
|
||||||
for (var i in $scope.tabs) {
|
for (var i in $scope.tabs) {
|
||||||
@ -165,149 +174,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Charts */
|
|
||||||
|
|
||||||
var Charts = {
|
|
||||||
_render: function(selector, data, chart){
|
|
||||||
nv.addGraph(function() {
|
|
||||||
d3.select(selector)
|
|
||||||
.datum(data)
|
|
||||||
.transition()
|
|
||||||
.duration(0)
|
|
||||||
.call(chart);
|
|
||||||
nv.utils.windowResize(chart.update)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/* NOTE(amaretskiy): this is actually a result of
|
|
||||||
d3.scale.category20().range(), excluding red color (#d62728)
|
|
||||||
which is reserved for errors */
|
|
||||||
_colors: ["#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c",
|
|
||||||
"#98df8a", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b",
|
|
||||||
"#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7",
|
|
||||||
"#bcbd22", "#dbdb8d", "#17becf", "#9edae5"],
|
|
||||||
pie: function(selector, data){
|
|
||||||
var chart = nv.models.pieChart()
|
|
||||||
.x(function(d) { return d.key })
|
|
||||||
.y(function(d) { return d.values })
|
|
||||||
.showLabels(true)
|
|
||||||
.labelType("percent")
|
|
||||||
.donut(true)
|
|
||||||
.donutRatio(0.25)
|
|
||||||
.donutLabelsOutside(true)
|
|
||||||
.color(function(d){
|
|
||||||
if (d.data && d.data.color) {
|
|
||||||
return d.data.color
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var data_ = [],
|
|
||||||
colors = [],
|
|
||||||
colors_map = {errors: "#d62728"};
|
|
||||||
for (var i in data) {
|
|
||||||
var key = data[i][0];
|
|
||||||
if (! (key in colors_map)) {
|
|
||||||
if (! colors.length) { colors = this._colors.slice() }
|
|
||||||
colors_map[key] = colors.shift()
|
|
||||||
}
|
|
||||||
data_.push({key:key, values:data[i][1], color:colors_map[key]})
|
|
||||||
}
|
|
||||||
this._render(selector, data_, chart)
|
|
||||||
},
|
|
||||||
stack: function(selector, data, conf){
|
|
||||||
var chart = nv.models.stackedAreaChart()
|
|
||||||
.x(function(d) { return d[0] })
|
|
||||||
.y(function(d) { return d[1] })
|
|
||||||
.clipEdge(true)
|
|
||||||
.showControls(conf.controls)
|
|
||||||
.useInteractiveGuideline(conf.guide);
|
|
||||||
chart.xAxis
|
|
||||||
.axisLabel(conf.xLabel || "")
|
|
||||||
.showMaxMin(false)
|
|
||||||
.tickFormat(d3.format(conf.xFormat || "d"));
|
|
||||||
chart.yAxis
|
|
||||||
.axisLabel(conf.yLabel || "")
|
|
||||||
.tickFormat(d3.format(conf.yFormat || ",.3f"));
|
|
||||||
var data_ = [];
|
|
||||||
for (var i in data) {
|
|
||||||
var d = {key:data[i][0], values:data[i][1]};
|
|
||||||
if (d.key === "failed_duration") {
|
|
||||||
d.color = "#d62728"
|
|
||||||
}
|
|
||||||
data_.push(d)
|
|
||||||
}
|
|
||||||
this._render(selector, data_, chart)
|
|
||||||
},
|
|
||||||
histogram: function(selector, data){
|
|
||||||
var chart = nv.models.multiBarChart()
|
|
||||||
.reduceXTicks(true)
|
|
||||||
.showControls(false)
|
|
||||||
.transitionDuration(0)
|
|
||||||
.groupSpacing(0.05);
|
|
||||||
chart.legend
|
|
||||||
.radioButtonMode(true)
|
|
||||||
chart.xAxis
|
|
||||||
.axisLabel("Duration (seconds)")
|
|
||||||
.tickFormat(d3.format(",.2f"));
|
|
||||||
chart.yAxis
|
|
||||||
.axisLabel("Iterations (frequency)")
|
|
||||||
.tickFormat(d3.format("d"));
|
|
||||||
this._render(selector, data, chart)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.renderTotal = function() {
|
|
||||||
if (! $scope.scenario) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Charts.stack(
|
|
||||||
"#total-stack", $scope.scenario.iterations.iter,
|
|
||||||
{xLabel: "Iteration sequence number",
|
|
||||||
controls: true,
|
|
||||||
guide: true});
|
|
||||||
|
|
||||||
if ($scope.scenario.load_profile.length) {
|
|
||||||
Charts.stack(
|
|
||||||
"#load-profile-stack",
|
|
||||||
$scope.scenario.load_profile,
|
|
||||||
{xLabel: "Timeline (seconds)",
|
|
||||||
xFormat: ",.2f", yFormat: "d"})
|
|
||||||
}
|
|
||||||
|
|
||||||
Charts.pie("#total-pie", $scope.scenario.iterations.pie);
|
|
||||||
|
|
||||||
if ($scope.scenario.iterations.histogram.data.length) {
|
|
||||||
var idx = this.totalHistogramModel.id;
|
|
||||||
Charts.histogram("#total-histogram",
|
|
||||||
$scope.scenario.iterations.histogram.data[idx])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.renderDetails = function() {
|
|
||||||
if (! $scope.scenario) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Charts.stack(
|
|
||||||
"#atomic-stack",
|
|
||||||
$scope.scenario.atomic.iter,
|
|
||||||
{xLabel: "Iteration sequence number",
|
|
||||||
controls: true,
|
|
||||||
guide: true});
|
|
||||||
if ($scope.scenario.atomic.pie) {
|
|
||||||
Charts.pie("#atomic-pie", $scope.scenario.atomic.pie)
|
|
||||||
}
|
|
||||||
if ($scope.scenario.atomic.histogram.data.length) {
|
|
||||||
var idx = this.atomicHistogramModel.id;
|
|
||||||
Charts.histogram("#atomic-histogram", $scope.scenario.atomic.histogram.data[idx])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.renderOutput = function() {
|
|
||||||
if ($scope.scenario && $scope.scenario.additive_output.length) {
|
|
||||||
Charts.stack("#output-stack", $scope.scenario.additive_output[0].data, {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.showError = function(message) {
|
$scope.showError = function(message) {
|
||||||
return (function (e) {
|
return (function (e) {
|
||||||
e.style.display = "block";
|
e.style.display = "block";
|
||||||
@ -318,23 +184,16 @@
|
|||||||
/* Initialization */
|
/* Initialization */
|
||||||
|
|
||||||
angular.element(document).ready(function(){
|
angular.element(document).ready(function(){
|
||||||
$scope.source = {{ source }};
|
|
||||||
$scope.scenarios = {{ data }};
|
|
||||||
if (! $scope.scenarios.length) {
|
if (! $scope.scenarios.length) {
|
||||||
return $scope.showError("No data...")
|
return $scope.showError("No data...")
|
||||||
}
|
}
|
||||||
$scope.totalHistogramModel = {label:'', id:0};
|
|
||||||
$scope.atomicHistogramModel = {label:'', id:0};
|
|
||||||
|
|
||||||
/* Compose data mapping */
|
/* Compose data mapping */
|
||||||
|
|
||||||
$scope.nav = [];
|
$scope.nav = [];
|
||||||
$scope.nav_map = {};
|
$scope.nav_map = {};
|
||||||
$scope.scenarios_map = {};
|
$scope.scenarios_map = {};
|
||||||
var scenario_ref = $scope.location.path();
|
var met = [], itr = 0, cls_idx = 0;
|
||||||
var met = [];
|
|
||||||
var itr = 0;
|
|
||||||
var cls_idx = 0;
|
|
||||||
var prev_cls, prev_met;
|
var prev_cls, prev_met;
|
||||||
|
|
||||||
for (var idx in $scope.scenarios) {
|
for (var idx in $scope.scenarios) {
|
||||||
@ -350,21 +209,13 @@
|
|||||||
cls_idx += 1
|
cls_idx += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prev_met !== sc.met) {
|
if (prev_met !== sc.met) { itr = 1 };
|
||||||
itr = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
sc.ref = $scope.location.normalize(sc.cls+"."+sc.met+(itr > 1 ? "-"+itr : ""));
|
sc.ref = $scope.location.normalize(sc.cls+"."+sc.met+(itr > 1 ? "-"+itr : ""));
|
||||||
$scope.scenarios_map[sc.ref] = sc;
|
$scope.scenarios_map[sc.ref] = sc;
|
||||||
$scope.nav_map[sc.ref] = cls_idx;
|
$scope.nav_map[sc.ref] = cls_idx;
|
||||||
var current_ref = $scope.location.path();
|
|
||||||
if (sc.ref === current_ref) {
|
|
||||||
scenario_ref = sc.ref
|
|
||||||
}
|
|
||||||
|
|
||||||
met.push({name:sc.name, itr:itr, idx:idx, ref:sc.ref});
|
met.push({name:sc.name, itr:itr, idx:idx, ref:sc.ref});
|
||||||
prev_met = sc.met;
|
prev_met = sc.met;
|
||||||
itr += 1
|
itr += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (met.length) {
|
if (met.length) {
|
||||||
@ -374,11 +225,161 @@
|
|||||||
/* Start */
|
/* Start */
|
||||||
|
|
||||||
var uri = $scope.location.uri();
|
var uri = $scope.location.uri();
|
||||||
uri.path = scenario_ref;
|
uri.path = $scope.location.path();
|
||||||
$scope.route(uri);
|
$scope.route(uri);
|
||||||
$scope.$digest()
|
$scope.$digest()
|
||||||
});
|
});
|
||||||
}])}
|
}])
|
||||||
|
.directive("widget", function($compile) {
|
||||||
|
|
||||||
|
var Chart = {
|
||||||
|
_render: function(node, data, chart){
|
||||||
|
nv.addGraph(function() {
|
||||||
|
d3.select(node).datum(data).transition().duration(0).call(chart);
|
||||||
|
nv.utils.windowResize(chart.update)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/* NOTE(amaretskiy): this is actually a result of
|
||||||
|
d3.scale.category20().range(), excluding red color (#d62728)
|
||||||
|
which is reserved for errors */
|
||||||
|
_colors: ["#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c",
|
||||||
|
"#98df8a", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b",
|
||||||
|
"#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7",
|
||||||
|
"#bcbd22", "#dbdb8d", "#17becf", "#9edae5"],
|
||||||
|
_widgets: {
|
||||||
|
Pie: "pie",
|
||||||
|
StackedArea: "stack",
|
||||||
|
Histogram: "histogram"
|
||||||
|
},
|
||||||
|
get_chart: function(widget) {
|
||||||
|
if (widget in this._widgets) {
|
||||||
|
var name = this._widgets[widget];
|
||||||
|
return Chart[name]
|
||||||
|
}
|
||||||
|
return function() { console.log("Error: unexpected widget:", widget) }
|
||||||
|
},
|
||||||
|
pie: function(node, data) {
|
||||||
|
var chart = nv.models.pieChart()
|
||||||
|
.x(function(d) { return d.key })
|
||||||
|
.y(function(d) { return d.values })
|
||||||
|
.showLabels(true)
|
||||||
|
.labelType("percent")
|
||||||
|
.donut(true)
|
||||||
|
.donutRatio(0.25)
|
||||||
|
.donutLabelsOutside(true)
|
||||||
|
.color(function(d){
|
||||||
|
if (d.data && d.data.color) { return d.data.color }
|
||||||
|
});
|
||||||
|
|
||||||
|
var data_ = [], colors = [], colors_map = {errors: "#d62728"};
|
||||||
|
for (var i in data) {
|
||||||
|
var key = data[i][0];
|
||||||
|
if (! (key in colors_map)) {
|
||||||
|
if (! colors.length) { colors = Chart._colors.slice() }
|
||||||
|
colors_map[key] = colors.shift()
|
||||||
|
}
|
||||||
|
data_.push({key:key, values:data[i][1], color:colors_map[key]})
|
||||||
|
}
|
||||||
|
Chart._render(node, data_, chart)
|
||||||
|
},
|
||||||
|
stack: function(node, data, opts) {
|
||||||
|
var chart = nv.models.stackedAreaChart()
|
||||||
|
.x(function(d) { return d[0] })
|
||||||
|
.y(function(d) { return d[1] })
|
||||||
|
.useInteractiveGuideline(opts.guide)
|
||||||
|
.showControls(opts.controls)
|
||||||
|
.clipEdge(true);
|
||||||
|
chart.xAxis
|
||||||
|
.tickFormat(d3.format(opts.xformat || "d"))
|
||||||
|
.axisLabel(opts.xname || "")
|
||||||
|
.showMaxMin(false);
|
||||||
|
chart.yAxis
|
||||||
|
.tickFormat(d3.format(opts.yformat || ",.3f"))
|
||||||
|
.axisLabel(opts.yname || "");
|
||||||
|
var data_ = [];
|
||||||
|
for (var i in data) {
|
||||||
|
var d = {key:data[i][0], values:data[i][1]};
|
||||||
|
if (d.key === "failed_duration") {
|
||||||
|
d.color = "#d62728"
|
||||||
|
}
|
||||||
|
data_.push(d)
|
||||||
|
}
|
||||||
|
Chart._render(node, data_, chart)
|
||||||
|
},
|
||||||
|
histogram: function(node, data) {
|
||||||
|
var chart = nv.models.multiBarChart()
|
||||||
|
.reduceXTicks(true)
|
||||||
|
.showControls(false)
|
||||||
|
.transitionDuration(0)
|
||||||
|
.groupSpacing(0.05);
|
||||||
|
chart
|
||||||
|
.legend.radioButtonMode(true);
|
||||||
|
chart.xAxis
|
||||||
|
.axisLabel("Duration (seconds)")
|
||||||
|
.tickFormat(d3.format(",.2f"));
|
||||||
|
chart.yAxis
|
||||||
|
.axisLabel("Iterations (frequency)")
|
||||||
|
.tickFormat(d3.format("d"));
|
||||||
|
Chart._render(node, data, chart)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: "A",
|
||||||
|
scope: { data: "=" },
|
||||||
|
link: function(scope, element, attrs) {
|
||||||
|
scope.$watch("data", function(data) {
|
||||||
|
if (! data) { return console.log("Chart has no data to render!") }
|
||||||
|
if (attrs.widget === "Table") {
|
||||||
|
var ng_class = attrs.lastrowClass ? " ng-class='{"+attrs.lastrowClass+":$last}'" : "";
|
||||||
|
var template = "<table class='striped'><thead>" +
|
||||||
|
"<tr><th ng-repeat='i in data.cols track by $index'>{{i}}<tr>" +
|
||||||
|
"</thead><tbody>" +
|
||||||
|
"<tr" + ng_class + " ng-repeat='row in data.rows track by $index'>" +
|
||||||
|
"<td ng-repeat='i in row track by $index'>{{i}}" +
|
||||||
|
"<tr>" +
|
||||||
|
"</tbody></table>";
|
||||||
|
var el = element.empty().append($compile(template)(scope)).children()[0]
|
||||||
|
} else {
|
||||||
|
/* Hide widget if not enough data */
|
||||||
|
if (attrs.widget === "StackedArea") {
|
||||||
|
if ((! data.length) || (data[0].length < 1) || (data[0][1].length < 2)) {
|
||||||
|
return element.empty().css({display:"none"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (attrs.widget === "Pie") {
|
||||||
|
if (! data.length) {
|
||||||
|
return element.empty().css({display:"none"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
xname: attrs.nameX || "",
|
||||||
|
yname: attrs.nameY || "",
|
||||||
|
xformat: attrs.formatX || "d",
|
||||||
|
yformat: attrs.formatY || ",.3f",
|
||||||
|
controls: attrs.controls === "true",
|
||||||
|
guide: attrs.guide === "true"
|
||||||
|
};
|
||||||
|
var el = element.addClass("chart").css({display:"block"}).html("<svg></svg>").children()[0];
|
||||||
|
Chart.get_chart(attrs.widget)(el, data, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs.description) {
|
||||||
|
var desc_el = angular.element("<div>").addClass(attrs.descriptionClass || "h3").text(attrs.description);
|
||||||
|
angular.element(el).parent().prepend(desc_el)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs.title) {
|
||||||
|
var title_el = angular.element("<div>").addClass(attrs.titleClass || "h2").text(attrs.title);
|
||||||
|
angular.element(el).parent().prepend(title_el)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
{% endraw %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
@ -402,14 +403,15 @@
|
|||||||
.failure-mesg { color:#900 }
|
.failure-mesg { color:#900 }
|
||||||
.failure-trace { color:#333; white-space:pre; overflow:auto }
|
.failure-trace { color:#333; white-space:pre; overflow:auto }
|
||||||
|
|
||||||
.chart { height:300px }
|
.link { color:#428BCA; padding:5px 15px 5px 5px; text-decoration:underline; cursor:pointer }
|
||||||
.chart .chart-dropdown { float:right; margin:0 35px 0 }
|
.link.active { color:#333; text-decoration:none }
|
||||||
.chart.lesser { padding:0; margin:0; float:left; width:40% }
|
|
||||||
.chart.larger { padding:0; margin:0; float:left; width:59% }
|
.chart { padding:0; margin:0 }
|
||||||
|
.chart svg { height:300px; padding:0; margin:0 }
|
||||||
|
.chart.lower svg { height:180px }
|
||||||
|
|
||||||
.expandable { cursor:pointer }
|
.expandable { cursor:pointer }
|
||||||
.clearfix { clear:both }
|
.clearfix { clear:both }
|
||||||
.top-margin { margin-top:40px !important }
|
|
||||||
.sortable > .arrow { display:inline-block; width:12px; height:inherit; color:#c90 }
|
.sortable > .arrow { display:inline-block; width:12px; height:inherit; color:#c90 }
|
||||||
.content-main { margin:0 5px; display:block; float:left }
|
.content-main { margin:0 5px; display:block; float:left }
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -488,32 +490,28 @@
|
|||||||
<b ng-show="ov_srt=='full_duration' && !ov_dir">▴</b>
|
<b ng-show="ov_srt=='full_duration' && !ov_dir">▴</b>
|
||||||
<b ng-show="ov_srt=='full_duration' && ov_dir">▾</b>
|
<b ng-show="ov_srt=='full_duration' && ov_dir">▾</b>
|
||||||
</span>
|
</span>
|
||||||
<th class="sortable"
|
<th class="sortable" title="Number of iterations"
|
||||||
title="Number of iterations"
|
|
||||||
ng-click="ov_srt='iterations_count'; ov_dir=!ov_dir">
|
ng-click="ov_srt='iterations_count'; ov_dir=!ov_dir">
|
||||||
Iterations
|
Iterations
|
||||||
<span class="arrow">
|
<span class="arrow">
|
||||||
<b ng-show="ov_srt=='iterations_count' && !ov_dir">▴</b>
|
<b ng-show="ov_srt=='iterations_count' && !ov_dir">▴</b>
|
||||||
<b ng-show="ov_srt=='iterations_count' && ov_dir">▾</b>
|
<b ng-show="ov_srt=='iterations_count' && ov_dir">▾</b>
|
||||||
</span>
|
</span>
|
||||||
<th class="sortable"
|
<th class="sortable" title="Scenario runner type"
|
||||||
title="Scenario runner type"
|
|
||||||
ng-click="ov_srt='runner'; ov_dir=!ov_dir">
|
ng-click="ov_srt='runner'; ov_dir=!ov_dir">
|
||||||
Runner
|
Runner
|
||||||
<span class="arrow">
|
<span class="arrow">
|
||||||
<b ng-show="ov_srt=='runner' && !ov_dir">▴</b>
|
<b ng-show="ov_srt=='runner' && !ov_dir">▴</b>
|
||||||
<b ng-show="ov_srt=='runner' && ov_dir">▾</b>
|
<b ng-show="ov_srt=='runner' && ov_dir">▾</b>
|
||||||
</span>
|
</span>
|
||||||
<th class="sortable"
|
<th class="sortable" title="Number of errors occurred"
|
||||||
title="Number of errors occurred"
|
|
||||||
ng-click="ov_srt='errors.length'; ov_dir=!ov_dir">
|
ng-click="ov_srt='errors.length'; ov_dir=!ov_dir">
|
||||||
Errors
|
Errors
|
||||||
<span class="arrow">
|
<span class="arrow">
|
||||||
<b ng-show="ov_srt=='errors.length' && !ov_dir">▴</b>
|
<b ng-show="ov_srt=='errors.length' && !ov_dir">▴</b>
|
||||||
<b ng-show="ov_srt=='errors.length' && ov_dir">▾</b>
|
<b ng-show="ov_srt=='errors.length' && ov_dir">▾</b>
|
||||||
</span>
|
</span>
|
||||||
<th class="sortable"
|
<th class="sortable" title="Whether SLA check is successful"
|
||||||
title="Whether SLA check is successful"
|
|
||||||
ng-click="ov_srt='sla_success'; ov_dir=!ov_dir">
|
ng-click="ov_srt='sla_success'; ov_dir=!ov_dir">
|
||||||
Success (SLA)
|
Success (SLA)
|
||||||
<span class="arrow">
|
<span class="arrow">
|
||||||
@ -558,8 +556,6 @@
|
|||||||
<div ng-include="tab"></div>
|
<div ng-include="tab"></div>
|
||||||
|
|
||||||
<script type="text/ng-template" id="overview">
|
<script type="text/ng-template" id="overview">
|
||||||
{{renderTotal()}}
|
|
||||||
|
|
||||||
<p class="thesis">
|
<p class="thesis">
|
||||||
Load duration: <b>{{scenario.load_duration | number:3}} s</b>
|
Load duration: <b>{{scenario.load_duration | number:3}} s</b>
|
||||||
Full duration: <b>{{scenario.full_duration | number:3}} s</b>
|
Full duration: <b>{{scenario.full_duration | number:3}} s</b>
|
||||||
@ -589,72 +585,119 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Total durations</h2>
|
<div widget="Table"
|
||||||
<table class="striped">
|
data="scenario.table"
|
||||||
<thead>
|
lastrow-class="rich"
|
||||||
<tr>
|
title="Total durations">
|
||||||
<th ng-repeat="i in scenario.table.cols track by $index">{{i}}
|
|
||||||
<tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-class="{richcolor:$last}"
|
|
||||||
ng-repeat="row in scenario.table.rows track by $index">
|
|
||||||
<td ng-repeat="i in row track by $index">{{i}}
|
|
||||||
<tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="chart">
|
|
||||||
<svg id="total-stack"></svg>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>Load Profile</h3>
|
<div widget="StackedArea"
|
||||||
<div class="chart" style="height:180px" ng-show="scenario.load_profile[0][1].length">
|
data="scenario.iterations.iter"
|
||||||
<svg id="load-profile-stack"></svg>
|
name-x="Iteration sequence number"
|
||||||
|
controls="true"
|
||||||
|
guide="true">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>Distribution</h3>
|
<div widget="StackedArea"
|
||||||
<div class="chart lesser top-margin">
|
data="scenario.load_profile"
|
||||||
<svg id="total-pie"></svg>
|
title="Load Profile"
|
||||||
|
title-class="h3"
|
||||||
|
name-x="Timeline (seconds)"
|
||||||
|
format-x=",.2f"
|
||||||
|
class="lower">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chart larger top-margin"
|
<div widget="Pie"
|
||||||
ng-show="scenario.iterations.histogram.data.length">
|
data="scenario.iterations.pie"
|
||||||
<svg id="total-histogram"></svg>
|
title="Distribution"
|
||||||
<select class="chart-dropdown"
|
title-class="h3"
|
||||||
ng-model="totalHistogramModel"
|
style="float:left; width:40%; margin-top:15px">
|
||||||
ng-options="i.name for i in scenario.iterations.histogram.views track by i.id"></select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div widget="Histogram"
|
||||||
|
ng-if="scenario.iterations.histogram.data.length"
|
||||||
|
data="scenario.iterations.histogram.data[mainHistogram.id]"
|
||||||
|
style="float:left; width:59%; margin-top:15px; position:relative; top:40px">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<select ng-model="mainHistogram"
|
||||||
|
ng-show="scenario.iterations.histogram.data.length"
|
||||||
|
ng-options="i.name for i in scenario.iterations.histogram.views track by i.id"
|
||||||
|
style="float:right; margin:45px 35px 0">
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/ng-template" id="details">
|
<script type="text/ng-template" id="details">
|
||||||
{{renderDetails()}}
|
|
||||||
|
|
||||||
<h2>Atomic Action Durations</h2>
|
<div widget="StackedArea"
|
||||||
<div class="chart">
|
data="scenario.atomic.iter"
|
||||||
<svg id="atomic-stack"></svg>
|
title="Atomic Action Durations"
|
||||||
|
name-x="Iteration sequence number"
|
||||||
|
controls="true"
|
||||||
|
guide="true">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>Distribution</h3>
|
<div widget="Pie"
|
||||||
<div class="chart lesser top-margin">
|
data="scenario.atomic.pie"
|
||||||
<svg id="atomic-pie"></svg>
|
title="Distribution"
|
||||||
|
title-class="h3"
|
||||||
|
style="float:left; width:40%; margin-top:15px">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chart larger top-margin"
|
<div widget="Histogram" data="scenario.atomic.histogram.data[atomicHistogram.id]"
|
||||||
ng-show="scenario.atomic.histogram.data.length">
|
ng-if="scenario.atomic.histogram.data.length"
|
||||||
<svg id="atomic-histogram"></svg>
|
style="float:left; width:59%; margin-top:15px; position:relative; top:40px">
|
||||||
<select class="chart-dropdown"
|
|
||||||
ng-model="atomicHistogramModel"
|
|
||||||
ng-options="i.name for i in scenario.atomic.histogram.views track by i.id"></select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<select ng-show="scenario.atomic.histogram.data.length"
|
||||||
|
ng-model="atomicHistogram"
|
||||||
|
ng-options="i.name for i in scenario.atomic.histogram.views track by i.id"
|
||||||
|
style="float:right; margin:45px 35px 0">
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/ng-template" id="output">
|
<script type="text/ng-template" id="output">
|
||||||
{{renderOutput()}}
|
|
||||||
|
|
||||||
<h2>Scenario output</h2>
|
<div style="padding:10px 0 0">
|
||||||
<div class="chart">
|
<span class="link"
|
||||||
<svg id="output-stack"></svg>
|
ng-click="location.hash('output/additive')"
|
||||||
|
ng-class="{active:scenario.output.active === 'additive'}"
|
||||||
|
ng-if="scenario.output.has_additive">Aggregated</span>
|
||||||
|
<span class="link"
|
||||||
|
ng-click="location.hash('output/complete')"
|
||||||
|
ng-class="{active:scenario.output.active === 'complete'}"
|
||||||
|
ng-if="scenario.output.has_complete">Per iteration</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-repeat="chart in scenario.additive_output"
|
||||||
|
ng-if="scenario.output.active === 'additive'">
|
||||||
|
<div widget="{{chart.widget}}"
|
||||||
|
title="{{chart.title}}"
|
||||||
|
description="{{chart.description}}"
|
||||||
|
data="chart.data">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="scenario.output.active === 'complete'" style="padding:10px 0 0">
|
||||||
|
<select ng-model="outputIteration">
|
||||||
|
<option ng-repeat="i in scenario.complete_output track by $index"
|
||||||
|
value="{{$index}}">
|
||||||
|
Iteration {{$index}}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div ng-repeat="chart in scenario.complete_output[outputIteration]">
|
||||||
|
<div widget="{{chart.widget}}"
|
||||||
|
title="{{chart.title}}"
|
||||||
|
description="{{chart.description}}"
|
||||||
|
data="chart.data">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
20
samples/tasks/scenarios/dummy/dummy_output.json
Normal file
20
samples/tasks/scenarios/dummy/dummy_output.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"Dummy.dummy_output": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"random_range": 25
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": 50,
|
||||||
|
"concurrency": 5
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"users": {
|
||||||
|
"tenants": 1,
|
||||||
|
"users_per_tenant": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
13
samples/tasks/scenarios/dummy/dummy_output.yaml
Normal file
13
samples/tasks/scenarios/dummy/dummy_output.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
Dummy.dummy_output:
|
||||||
|
-
|
||||||
|
args:
|
||||||
|
random_range: 25
|
||||||
|
runner:
|
||||||
|
type: "constant"
|
||||||
|
times: 50
|
||||||
|
concurrency: 5
|
||||||
|
context:
|
||||||
|
users:
|
||||||
|
tenants: 1
|
||||||
|
users_per_tenant: 1
|
@ -51,6 +51,58 @@ class DummyTestCase(test.TestCase):
|
|||||||
scenario.dummy_exception_probability,
|
scenario.dummy_exception_probability,
|
||||||
exception_probability=1)
|
exception_probability=1)
|
||||||
|
|
||||||
|
@mock.patch("rally.plugins.common.scenarios.dummy.dummy.random")
|
||||||
|
def test_dummy_output(self, mock_random):
|
||||||
|
mock_random.randint.side_effect = lambda min_, max_: max_
|
||||||
|
desc = "This is a description text for %s"
|
||||||
|
for random_range, exp in (None, 25), (1, 1), (42, 42):
|
||||||
|
scenario = dummy.Dummy(test.get_test_context())
|
||||||
|
if random_range is None:
|
||||||
|
scenario.dummy_output()
|
||||||
|
else:
|
||||||
|
scenario.dummy_output(random_range=random_range)
|
||||||
|
expected = {
|
||||||
|
"additive": [
|
||||||
|
{"chart": "OutputStatsTable",
|
||||||
|
"items": [[s + " stat", exp]
|
||||||
|
for s in ("foo", "bar", "spam")],
|
||||||
|
"title": "Additive Stat Table",
|
||||||
|
"description": desc % "Additive Stat Table"},
|
||||||
|
{"chart": "OutputStackedAreaChart",
|
||||||
|
"items": [["foo 1", exp], ["foo 2", exp]],
|
||||||
|
"title": "Additive Foo StackedArea",
|
||||||
|
"description": desc % "Additive Foo StackedArea"},
|
||||||
|
{"chart": "OutputStackedAreaChart",
|
||||||
|
"items": [["bar %d" % i, exp] for i in range(1, 7)],
|
||||||
|
"title": "Additive Bar StackedArea (no description)",
|
||||||
|
"description": ""},
|
||||||
|
{"chart": "OutputAvgChart",
|
||||||
|
"items": [["spam %d" % i, exp] for i in range(1, 4)],
|
||||||
|
"title": "Additive Spam Pie",
|
||||||
|
"description": desc % "Additive Spam Pie"}],
|
||||||
|
"complete": [
|
||||||
|
{"data": [["alpha", [[i, exp] for i in range(30)]],
|
||||||
|
["beta", [[i, exp] for i in range(30)]],
|
||||||
|
["gamma", [[i, exp] for i in range(30)]]],
|
||||||
|
"title": "Complete StackedArea",
|
||||||
|
"description": desc % "Complete StackedArea",
|
||||||
|
"widget": "StackedArea"},
|
||||||
|
{"data": [["delta", exp], ["epsilon", exp], ["zeta", exp],
|
||||||
|
["theta", exp], ["lambda", exp], ["omega", exp]],
|
||||||
|
"title": "Complete Pie (no description)",
|
||||||
|
"description": "",
|
||||||
|
"widget": "Pie"},
|
||||||
|
{"data": {
|
||||||
|
"cols": ["mu column", "xi column", "pi column",
|
||||||
|
"tau column", "chi column"],
|
||||||
|
"rows": [
|
||||||
|
[r + " row", exp, exp, exp, exp]
|
||||||
|
for r in ("iota", "nu", "rho", "phi", "psi")]},
|
||||||
|
"title": "Complete Table",
|
||||||
|
"description": desc % "Complete Table",
|
||||||
|
"widget": "Table"}]}
|
||||||
|
self.assertEqual(expected, scenario._output)
|
||||||
|
|
||||||
def test_dummy_dummy_with_scenario_output(self):
|
def test_dummy_dummy_with_scenario_output(self):
|
||||||
scenario = dummy.Dummy(test.get_test_context())
|
scenario = dummy.Dummy(test.get_test_context())
|
||||||
result = scenario.dummy_with_scenario_output()
|
result = scenario.dummy_with_scenario_output()
|
||||||
|
@ -223,6 +223,9 @@ class ScenarioTestCase(test.TestCase):
|
|||||||
|
|
||||||
def test_add_output(self):
|
def test_add_output(self):
|
||||||
scenario_inst = scenario.Scenario()
|
scenario_inst = scenario.Scenario()
|
||||||
|
self.assertEqual({"additive": [], "complete": []},
|
||||||
|
scenario_inst._output)
|
||||||
|
|
||||||
additive1 = {"title": "Additive 1", "chart": "FooChart",
|
additive1 = {"title": "Additive 1", "chart": "FooChart",
|
||||||
"description": "Foo description",
|
"description": "Foo description",
|
||||||
"items": [["foo", 1], ["bar", 2]]}
|
"items": [["foo", 1], ["bar", 2]]}
|
||||||
|
Loading…
Reference in New Issue
Block a user