Remove all Django-related functionality.

Exporter functionality in `export.py` no longer uses Django to
render pages, and instead generates its own `.json` files.
Additionally, a configuration file is generated that can be
consumed by the in-progress Angular frontend.

Change-Id: I37b5be581dbd784fd009c1040422f1cadb009a3a
This commit is contained in:
Tim Buckley 2015-09-25 18:03:18 -06:00 committed by Austin Clark
parent 9aaee2b681
commit 8be1f587d7
46 changed files with 133 additions and 3203 deletions

1
.gitignore vendored
View File

@ -4,7 +4,6 @@ node_modules
build
app/js/templates.js
app/data
*.py[cod]
# C extensions
*.so

View File

@ -1,10 +0,0 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "stackviz.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

View File

@ -1,5 +1,3 @@
Django<1.8,>=1.4.2
DjangoRestless>=0.0.10
python-subunit>=0.0.18
testtools>=0.9.30
testrepository>=0.0.18

View File

@ -14,163 +14,171 @@
from __future__ import print_function
import django
import datetime
import gzip
import json
import os
import shutil
from argparse import ArgumentParser
from django.http import Http404
from django.core.urlresolvers import resolve
from django.test import RequestFactory
from functools import partial
from stackviz.parser import tempest_subunit
from stackviz import settings
EXPORT_PATHS = [
'/index.html',
'/tempest_aggregate.html'
]
_base = os.path.dirname(os.path.abspath(__file__))
_tempest_count = 0
def fake_render_view(path):
factory = RequestFactory()
request = factory.get(path)
match = resolve(path)
response = match.func(request, *match.args, **match.kwargs)
if hasattr(response, "render"):
response.render()
return response
def export_single_page(path, dest_dir, use_gzip=False):
dest_file = path
if dest_file.startswith('/'):
dest_file = dest_file[1:]
open_func = open
if use_gzip:
def open_compressed(output_dir, file_name, compress):
if compress:
file_name += ".gz"
open_func = gzip.open
dest_file += ".gz"
else:
open_func = open
try:
content = fake_render_view(path).content
with open_func(os.path.join(dest_dir, dest_file), 'wb') as f:
f.write(content)
except Http404 as ex:
print("Warning: skipping %s due to error: %s" % (path, ex.message))
return open_func(os.path.join(output_dir, file_name), 'wb'), file_name
def init_django(args):
# remove leading / from static URL to give them correct filesystem paths
settings.STATIC_URL = settings.STATIC_URL[1:]
settings.USE_GZIP = args.gzip
settings.OFFLINE = True
def json_date_handler(object):
if isinstance(object, (datetime.datetime, datetime.date)):
return object.isoformat()
if args.repository or args.stream_file or args.stdin:
settings.TEST_REPOSITORIES = []
settings.TEST_STREAMS = []
settings.TEST_STREAM_STDIN = False
return None
if args.repository:
settings.TEST_REPOSITORIES = args.repository
if args.stream_file:
settings.TEST_STREAMS = args.stream_file
def export_tempest_tree(stream, output_stream):
converted = tempest_subunit.convert_stream(stream, strip_details=True)
tree = tempest_subunit.reorganize(converted)
json.dump(tree, output_stream, default=json_date_handler)
output_stream.close()
if args.stdin:
settings.TEST_STREAM_STDIN = True
if args.dstat:
settings.DSTAT_CSV = args.dstat
def export_tempest_raw(stream, output_stream):
converted = tempest_subunit.convert_stream(stream, strip_details=True)
json.dump(converted, output_stream, default=json_date_handler)
output_stream.close()
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "stackviz.settings")
django.setup()
def export_tempest_details(stream, output_stream):
converted = tempest_subunit.convert_stream(stream, strip_details=True)
output = {}
for entry in converted:
output[entry['name']] = entry['details']
json.dump(output, output_stream, default=json_date_handler)
output_stream.close()
def export_tempest(provider, output_dir, dstat, compress):
global _tempest_count
ret = []
for i in range(provider.count):
path_base = 'tempest_%s_%d' % (provider.name, i)
if provider.count > 1:
name = '%s (%d)' % (provider.description, i)
else:
name = provider.description
open_ = partial(open_compressed,
output_dir=output_dir,
compress=compress)
stream_raw, path_raw = open_(file_name=path_base + '_raw.json')
export_tempest_raw(provider.get_stream(i), stream_raw)
stream_tree, path_tree = open_(file_name=path_base + '_tree.json')
export_tempest_tree(provider.get_stream(i), stream_tree)
stream_details, path_details = open_(
file_name=path_base + '_details.json')
export_tempest_details(provider.get_stream(i), stream_details)
entry = {
'id': _tempest_count,
'name': name,
'raw': path_raw,
'tree': path_tree,
'details': path_details
}
entry.update({'dstat': dstat} if dstat else {})
ret.append(entry)
_tempest_count += 1
return ret
def export_dstat(path, output_dir, compress):
f = open(path, 'rb')
out_stream, out_file = open_compressed(
output_dir,
'dstat_log.csv',
compress)
shutil.copyfileobj(f, out_stream)
f.close()
out_stream.close()
return out_file
def main():
parser = ArgumentParser(description="Generates a self-contained, static "
"StackViz site at the given path.")
parser = ArgumentParser(description="Generates JSON data files for a "
"StackViz site.")
parser.add_argument("path",
help="The output directory. Will be created if it "
"doesn't already exist.")
parser.add_argument("--ignore-bower",
help="Ignore missing Bower components.",
action="store_true")
parser.add_argument("-z", "--gzip",
help="Enable gzip compression for data files.",
action="store_true")
parser.add_argument("-f", "--stream-file",
action="append",
help="Include the given direct subunit stream.")
help="Include the given direct subunit stream; can be "
"used multiple times.")
parser.add_argument("-r", "--repository",
action="append",
help="A directory containing a `.testrepository` to "
"include. If not provided, the `settings.py` "
"configured values will be used.")
"include; can be used multiple times.")
parser.add_argument("-i", "--stdin",
help="Read a direct subunit stream from standard "
"input.",
action="store_true")
parser.add_argument("--dstat",
help="The path to the DStat log file (CSV-formatted) "
"to include. If not provided, the `settings.py` "
"configured value will be used.")
"to include.")
args = parser.parse_args()
if not args.ignore_bower:
if not os.listdir(os.path.join(_base, 'static', 'components')):
print("Bower components have not been installed, please run "
"`bower install`")
return 1
if os.path.exists(args.path):
if os.listdir(args.path):
print("Destination exists and is not empty, cannot continue")
return 1
else:
if not os.path.exists(args.path):
os.mkdir(args.path)
init_django(args)
dstat = None
if args.dstat:
print("Exporting DStat log")
dstat = export_dstat(args.dstat, args.path, args.gzip)
print("Copying static files ...")
shutil.copytree(os.path.join(_base, 'static'),
os.path.join(args.path, 'static'))
providers = tempest_subunit.get_providers(
args.repository,
args.stream_file,
args.stdin)
for path in EXPORT_PATHS:
print("Rendering:", path)
export_single_page(path, args.path)
tempest_config_entries = []
for provider in tempest_subunit.get_providers().values():
for i in range(provider.count):
param = (provider.name, i)
for provider in providers.values():
print("Exporting Tempest provider: %s (%d)" % (provider.description,
provider.count))
tempest_config_entries.extend(
export_tempest(provider, args.path, dstat, args.gzip)
)
print("Rendering views for tempest run %s #%d" % param)
export_single_page('/tempest_timeline_%s_%d.html' % param,
args.path)
export_single_page('/tempest_results_%s_%d.html' % param,
args.path)
print("Exporting data for tempest run %s #%d" % param)
export_single_page('/tempest_api_tree_%s_%d.json' % param,
args.path, args.gzip)
export_single_page('/tempest_api_raw_%s_%d.json' % param,
args.path, args.gzip)
export_single_page('/tempest_api_details_%s_%d.json' % param,
args.path, args.gzip)
print("Exporting DStat log: dstat_log.csv")
export_single_page('/dstat_log.csv', args.path, args.gzip)
with open(os.path.join(args.path, 'config.json'), 'w') as f:
json.dump({
'tempest': tempest_config_entries
}, f)
if __name__ == '__main__':

View File

@ -1,35 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# 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.
from stackviz.parser.tempest_subunit import get_providers
from stackviz.settings import OFFLINE
from stackviz.settings import USE_GZIP
def inject_extra_context(request):
ret = {
'use_gzip': USE_GZIP,
'offline': OFFLINE
}
providers = get_providers()
if providers:
default = providers.values()[0]
ret.update({
'tempest_providers': providers.values(),
'tempest_default_provider': default,
})
return ret

View File

@ -29,16 +29,11 @@ from testtools import StreamToDict
from testrepository.repository.file import RepositoryFactory
from testrepository.repository.file import RepositoryNotFound
from stackviz import settings
NAME_SCENARIO_PATTERN = re.compile(r'^(.+) \((.+)\)$')
NAME_TAGS_PATTERN = re.compile(r'^(.+)\[(.+)\]$')
_provider_cache = None
class InvalidSubunitProvider(Exception):
pass
@ -168,39 +163,44 @@ class StandardInputProvider(SubunitProvider):
return self.buffer
def get_providers():
def get_providers(repository_paths=None, stream_paths=None, stdin=False):
"""Loads all test providers from locations configured in settings.
:param repository_paths: a list of directory paths containing
'.testrepository' folders to read
:param stream_paths: a list of paths to direct subunit streams
:param stdin: if true, read a subunit stream from standard input
:return: a dict of loaded provider names and their associated
:class:`SubunitProvider` instances
:rtype: dict[str, SubunitProvider]
"""
global _provider_cache
if repository_paths is None:
repository_paths = []
if _provider_cache is not None:
return _provider_cache
if stream_paths is None:
stream_paths = []
_provider_cache = {}
ret = {}
for path in settings.TEST_REPOSITORIES:
for path in repository_paths:
try:
p = RepositoryProvider(path)
_provider_cache[p.name] = p
ret[p.name] = p
except (ValueError, RepositoryNotFound):
continue
for path in settings.TEST_STREAMS:
for path in stream_paths:
try:
p = FileProvider(path)
_provider_cache[p.name] = p
ret[p.name] = p
except InvalidSubunitProvider:
continue
if settings.TEST_STREAM_STDIN:
if stdin:
p = StandardInputProvider()
_provider_cache[p.name] = p
ret[p.name] = p
return _provider_cache
return ret
def _clean_name(name):

View File

@ -1,354 +0,0 @@
/*!
* Start Bootstrap - SB Admin 2 Bootstrap Admin Theme (http://startbootstrap.com)
* Code licensed under the Apache License v2.0.
* For details, see http://www.apache.org/licenses/LICENSE-2.0.
*/
body {
background-color: #f8f8f8;
}
#wrapper {
width: 100%;
}
#page-wrapper {
padding: 0 15px;
min-height: 568px;
background-color: #fff;
}
@media(min-width:768px) {
#page-wrapper {
position: inherit;
margin: 0 0 0 250px;
padding: 0 30px;
border-left: 1px solid #e7e7e7;
}
}
.navbar-top-links {
margin-right: 0;
}
.navbar-top-links li {
display: inline-block;
}
.navbar-top-links li:last-child {
margin-right: 15px;
}
.navbar-top-links li a {
padding: 15px;
min-height: 50px;
}
.navbar-top-links .dropdown-menu li {
display: block;
}
.navbar-top-links .dropdown-menu li:last-child {
margin-right: 0;
}
.navbar-top-links .dropdown-menu li a {
padding: 3px 20px;
min-height: 0;
}
.navbar-top-links .dropdown-menu li a div {
white-space: normal;
}
.navbar-top-links .dropdown-messages,
.navbar-top-links .dropdown-tasks,
.navbar-top-links .dropdown-alerts {
width: 310px;
min-width: 0;
}
.navbar-top-links .dropdown-messages {
margin-left: 5px;
}
.navbar-top-links .dropdown-tasks {
margin-left: -59px;
}
.navbar-top-links .dropdown-alerts {
margin-left: -123px;
}
.navbar-top-links .dropdown-user {
right: 0;
left: auto;
}
.sidebar .sidebar-nav.navbar-collapse {
padding-right: 0;
padding-left: 0;
}
.sidebar .sidebar-search {
padding: 15px;
}
.sidebar ul li {
border-bottom: 1px solid #e7e7e7;
}
.sidebar ul li a.active {
background-color: #eee;
}
.sidebar .arrow {
float: right;
}
.sidebar .fa.arrow:before {
content: "\f104";
}
.sidebar .active>a>.fa.arrow:before {
content: "\f107";
}
.sidebar .nav-second-level li,
.sidebar .nav-third-level li {
border-bottom: 0!important;
}
.sidebar .nav-second-level li a {
padding-left: 37px;
}
.sidebar .nav-third-level li a {
padding-left: 52px;
}
@media(min-width:768px) {
.sidebar {
z-index: 1;
position: absolute;
width: 250px;
margin-top: 51px;
}
.navbar-top-links .dropdown-messages,
.navbar-top-links .dropdown-tasks,
.navbar-top-links .dropdown-alerts {
margin-left: auto;
}
}
.btn-outline {
color: inherit;
background-color: transparent;
transition: all .5s;
}
.btn-primary.btn-outline {
color: #428bca;
}
.btn-success.btn-outline {
color: #5cb85c;
}
.btn-info.btn-outline {
color: #5bc0de;
}
.btn-warning.btn-outline {
color: #f0ad4e;
}
.btn-danger.btn-outline {
color: #d9534f;
}
.btn-primary.btn-outline:hover,
.btn-success.btn-outline:hover,
.btn-info.btn-outline:hover,
.btn-warning.btn-outline:hover,
.btn-danger.btn-outline:hover {
color: #fff;
}
.chat {
margin: 0;
padding: 0;
list-style: none;
}
.chat li {
margin-bottom: 10px;
padding-bottom: 5px;
border-bottom: 1px dotted #999;
}
.chat li.left .chat-body {
margin-left: 60px;
}
.chat li.right .chat-body {
margin-right: 60px;
}
.chat li .chat-body p {
margin: 0;
}
.panel .slidedown .glyphicon,
.chat .glyphicon {
margin-right: 5px;
}
.chat-panel .panel-body {
height: 350px;
overflow-y: scroll;
}
.login-panel {
margin-top: 25%;
}
.flot-chart {
display: block;
height: 400px;
}
.flot-chart-content {
width: 100%;
height: 100%;
}
.dataTables_wrapper {
position: relative;
clear: both;
}
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc,
table.dataTable thead .sorting_asc_disabled,
table.dataTable thead .sorting_desc_disabled {
background: 0 0;
}
table.dataTable thead .sorting_asc:after {
content: "\f0de";
float: right;
font-family: fontawesome;
}
table.dataTable thead .sorting_desc:after {
content: "\f0dd";
float: right;
font-family: fontawesome;
}
table.dataTable thead .sorting:after {
content: "\f0dc";
float: right;
font-family: fontawesome;
color: rgba(50,50,50,.5);
}
.btn-circle {
width: 30px;
height: 30px;
padding: 6px 0;
border-radius: 15px;
text-align: center;
font-size: 12px;
line-height: 1.428571429;
}
.btn-circle.btn-lg {
width: 50px;
height: 50px;
padding: 10px 16px;
border-radius: 25px;
font-size: 18px;
line-height: 1.33;
}
.btn-circle.btn-xl {
width: 70px;
height: 70px;
padding: 10px 16px;
border-radius: 35px;
font-size: 24px;
line-height: 1.33;
}
.show-grid [class^=col-] {
padding-top: 10px;
padding-bottom: 10px;
border: 1px solid #ddd;
background-color: #eee!important;
}
.show-grid {
margin: 15px 0;
}
.huge {
font-size: 40px;
}
.panel-green {
border-color: #5cb85c;
}
.panel-green .panel-heading {
border-color: #5cb85c;
color: #fff;
background-color: #5cb85c;
}
.panel-green a {
color: #5cb85c;
}
.panel-green a:hover {
color: #3d8b3d;
}
.panel-red {
border-color: #d9534f;
}
.panel-red .panel-heading {
border-color: #d9534f;
color: #fff;
background-color: #d9534f;
}
.panel-red a {
color: #d9534f;
}
.panel-red a:hover {
color: #b52b27;
}
.panel-yellow {
border-color: #f0ad4e;
}
.panel-yellow .panel-heading {
border-color: #f0ad4e;
color: #fff;
background-color: #f0ad4e;
}
.panel-yellow a {
color: #f0ad4e;
}
.panel-yellow a:hover {
color: #df8a13;
}

View File

@ -1,180 +0,0 @@
.timeline {
position: relative;
padding: 20px 0 20px;
list-style: none;
}
.timeline:before {
content: " ";
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 3px;
margin-left: -1.5px;
background-color: #eeeeee;
}
.timeline > li {
position: relative;
margin-bottom: 20px;
}
.timeline > li:before,
.timeline > li:after {
content: " ";
display: table;
}
.timeline > li:after {
clear: both;
}
.timeline > li:before,
.timeline > li:after {
content: " ";
display: table;
}
.timeline > li:after {
clear: both;
}
.timeline > li > .timeline-panel {
float: left;
position: relative;
width: 46%;
padding: 20px;
border: 1px solid #d4d4d4;
border-radius: 2px;
-webkit-box-shadow: 0 1px 6px rgba(0,0,0,0.175);
box-shadow: 0 1px 6px rgba(0,0,0,0.175);
}
.timeline > li > .timeline-panel:before {
content: " ";
display: inline-block;
position: absolute;
top: 26px;
right: -15px;
border-top: 15px solid transparent;
border-right: 0 solid #ccc;
border-bottom: 15px solid transparent;
border-left: 15px solid #ccc;
}
.timeline > li > .timeline-panel:after {
content: " ";
display: inline-block;
position: absolute;
top: 27px;
right: -14px;
border-top: 14px solid transparent;
border-right: 0 solid #fff;
border-bottom: 14px solid transparent;
border-left: 14px solid #fff;
}
.timeline > li > .timeline-badge {
z-index: 100;
position: absolute;
top: 16px;
left: 50%;
width: 50px;
height: 50px;
margin-left: -25px;
border-radius: 50% 50% 50% 50%;
text-align: center;
font-size: 1.4em;
line-height: 50px;
color: #fff;
background-color: #999999;
}
.timeline > li.timeline-inverted > .timeline-panel {
float: right;
}
.timeline > li.timeline-inverted > .timeline-panel:before {
right: auto;
left: -15px;
border-right-width: 15px;
border-left-width: 0;
}
.timeline > li.timeline-inverted > .timeline-panel:after {
right: auto;
left: -14px;
border-right-width: 14px;
border-left-width: 0;
}
.timeline-badge.primary {
background-color: #2e6da4 !important;
}
.timeline-badge.success {
background-color: #3f903f !important;
}
.timeline-badge.warning {
background-color: #f0ad4e !important;
}
.timeline-badge.danger {
background-color: #d9534f !important;
}
.timeline-badge.info {
background-color: #5bc0de !important;
}
.timeline-title {
margin-top: 0;
color: inherit;
}
.timeline-body > p,
.timeline-body > ul {
margin-bottom: 0;
}
.timeline-body > p + p {
margin-top: 5px;
}
@media(max-width:767px) {
ul.timeline:before {
left: 40px;
}
ul.timeline > li > .timeline-panel {
width: calc(100% - 90px);
width: -moz-calc(100% - 90px);
width: -webkit-calc(100% - 90px);
}
ul.timeline > li > .timeline-badge {
top: 16px;
left: 15px;
margin-left: 0;
}
ul.timeline > li > .timeline-panel {
float: right;
}
ul.timeline > li > .timeline-panel:before {
right: auto;
left: -15px;
border-right-width: 15px;
border-left-width: 0;
}
ul.timeline > li > .timeline-panel:after {
right: auto;
left: -14px;
border-right-width: 14px;
border-left-width: 0;
}
}

View File

@ -1,3 +0,0 @@
.highlight {
font-weight: bold;
}

View File

@ -1,87 +0,0 @@
"use strict";
var originalDetailsContent = null;
var detailsCache = null;
var detailsInProgress = false;
var detailsWaiting = [];
var runId = null;
var loadDetails = function(callback) {
if (detailsCache === null) {
detailsWaiting.push(callback);
if (!detailsInProgress) {
var url = "tempest_api_details_" + runId + ".json";
if ("{{use_gzip}}" === "True") {
url += ".gz";
}
detailsInProgress = true;
d3.json(url, function(error, data) {
if (error) {
throw error;
}
detailsCache = data;
detailsWaiting.forEach(function(cb) {
cb(detailsCache);
});
});
}
} else {
callback(detailsCache);
}
};
var showDetails = function(item) {
var parent = $("#details-dialog");
loadDetails(function(details) {
if (!details.hasOwnProperty(item.name_full)) {
console.log("Details not found for item:", item.name_full);
return;
}
if (originalDetailsContent === null) {
originalDetailsContent = parent.html();
}
parent.empty();
for (var prop in details[item.name_full]) {
$("<h3>").text(prop).appendTo(parent);
$("<pre>").text(details[item.name_full][prop]).appendTo(parent);
}
});
};
function addDialogButton(parentID, run_id) {
//parentID: A string contiaining the parent div id to which the button will be appended
runId=run_id;
var button = $('<button/>',
{
text: 'View Log',
click: function() {$("#details-dialog").dialog("open");}
});
$(parentID).append(button);
$("#details-dialog").dialog({
dialogClass: 'ui-dialog',
autoOpen: false,
width: 800,
height: 500,
buttons: [
{
text: "OK",
click: function() {
$( this ).dialog( "close" );
}
}
]
});
}

View File

@ -1,36 +0,0 @@
$(function() {
$('#side-menu').metisMenu();
});
//Loads the correct sidebar on window load,
//collapses the sidebar on window resize.
// Sets the min-height of #page-wrapper to window size
$(function() {
$(window).bind("load resize", function() {
topOffset = 50;
width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width;
if (width < 768) {
$('div.navbar-collapse').addClass('collapse');
topOffset = 100; // 2-row-menu
} else {
$('div.navbar-collapse').removeClass('collapse');
}
height = ((this.window.innerHeight > 0) ? this.window.innerHeight : this.screen.height) - 1;
height = height - topOffset;
if (height < 1) height = 1;
if (height > topOffset) {
$("#page-wrapper").css("min-height", (height) + "px");
}
});
var url = window.location;
var element = $('ul.nav a').filter(function() {
return this.href == url || url.href.indexOf(this.href) == 0;
}).addClass('active').parent().parent().addClass('in').parent();
if (element.is('li')) {
element.addClass('active');
}
});

View File

@ -1,118 +0,0 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
"use strict";
/*
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">Test Runs</div>
<div class="panel-body" id="run-summary-div">
</div>
</div>
</div>
*/
//@param data: JSON data of the test run
function getData(data) {
var num_successes = 0;
var num_failures = 0;
var num_skipped = 0
var total_time = 0;
var longest_test={duration: 0};
function calculateChildrenTime(i) {
var dur = 0;
if (typeof i.duration !== "undefined") {
if (i.status=="success") num_successes++;
else if (i.status=="fail") num_failures++;
else if (i.status=="skip") num_skipped++;
if (longest_test.duration < i.duration)
longest_test = i;
dur = i.duration;
}
else {
for (var k in i.children) {
dur += calculateChildrenTime(i.children[k]);
}
}
return dur;
}
total_time=calculateChildrenTime(data);
var data_dict= { "Successes": num_successes,
"Failures": num_failures,
"Skipped": num_skipped,
"Total Time": total_time.toFixed(2),
"Longest Test": longest_test.name + " ("+longest_test.duration+")"};
return data_dict;
}
function createTable(data, entry) {
var container = $("<div>")
.addClass('col-lg-6' )
.appendTo($("#run-summary-div"));
var panel = $("<div>")
.addClass('panel panel-default')
.appendTo(container);
var head = $("<div>")
.addClass("panel-heading")
.appendTo(panel);
head.append($("<a>", {
href: 'tempest_timeline_' + entry.provider + '_' + entry.run + '.html',
text: entry.providerDescription + ", run #" + entry.run
}));
var body = $("<div>")
.addClass("panel-body")
.appendTo(panel);
var table = $("<table>")
.addClass("table table-bordered table-hover table-striped")
.appendTo(body);
var data_dict = getData(data);
for (var key in data_dict) {
$("<tr>")
.append($("<td>").text(key))
.append($("<td>").text(data_dict[key]))
.appendTo(table);
}
}
//@param run_id: The method is passed the latest run_id so it can populate the tables moving backwards
function createTables(entries) {
entries.forEach(function(entry) {
//TODO: Sort tables when inserting so they appear in correct order
d3.json(entry.url, function(error, data) {
if (error) throw error;
//create a table for the info
// TODO: entry now has provider description, etc which should be
// shown (categorized?)
createTable(data, entry);
});
})
}

View File

@ -1,177 +0,0 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
"use strict";
var runId = null;
var providerName = null;
function populateTable(d, textColor) {
var oldtbl = document.getElementById("result-table-div");
oldtbl.innerHTML = "";
var tbl = document.createElement('table');
tbl.setAttribute("id","test-table");
tbl.setAttribute("class","table table-bordered table-hover table-striped");
if (typeof d.children == "undefined") {
for (var key in d) {
if (key=="status" || key=="name_full" || key=="name" || key=="duration" || key=="tags" || key=="timestamps") {
var row = tbl.insertRow();
var td1 = row.insertCell();
var td2 = row.insertCell();
td1.innerHTML = key;
td2.innerHTML = d[key];
}
}
document.getElementById("result-table-div").appendChild(tbl);
document.getElementById("table-heading").innerHTML=d.name;
addDialogButton("#result-table-div",providerName + "_" + runId);
showDetails(d);
}
else {
for (var j in d.children) {
var row = tbl.insertRow();
var td1 = row.insertCell();
var td2 = row.insertCell();
td1.innerHTML = d.children[j].name;
td2.innerHTML = calculateChildrenTime(d.children[j]).toFixed(2);
td1.style.color = textColor(d.children[j]);
document.getElementById("result-table-div").appendChild(tbl);
document.getElementById("table-heading").innerHTML=d.name +
": " + calculateChildrenTime(d).toFixed(2) + " seconds"
$( "table-test" ).DataTable();
}
}
}
function calculateChildrenTime(i) {
var dur = 0;
if (typeof i.duration !== "undefined") {
dur = i.duration;
}
else {
for (var k in i.children) {
dur += calculateChildrenTime(i.children[k]);
}
}
return dur;
}
function displayFailingTests(d) {
document.getElementById("failure-table-div").innerHTML="";
var tbl = document.createElement('table');
tbl.setAttribute("id","failure-table");
tbl.setAttribute("class","table table-bordered table-hover table-striped");
function findFailingTests(i,result) {
if (i.status == "fail") {
result.push(i);
}
else {
for (var k in i.children) {
findFailingTests(i.children[k],result);
}
}
return;
}
var failureList=[];
findFailingTests(d,failureList);
for (var row in failureList) {
var newRow = tbl.insertRow();
newRow.setAttribute("class","failure-row");
var td1 = newRow.insertCell();
var td2 = newRow.insertCell();
td1.innerHTML = failureList[row].name_full;
td2.innerHTML = parseFloat(failureList[row].duration).toFixed(2);
}
document.getElementById("failure-table-div").appendChild(tbl);
$( "#failure-table-div" ).hide();
}
function createSunburst(url, provider_name, run_id) {
runId = run_id;
providerName = provider_name;
var width = 700,
height = 500,
radius = Math.min(width, height) / 2;
var x = d3.scale.linear()
.range([0, 2 * Math.PI]);
var y = d3.scale.sqrt()
.range([0, radius]);
var color = d3.scale.category20c();
var svg = d3.select("#sunburst").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + 10) + ")");
var partition = d3.layout.partition()
.value(function(d) { return d.duration; });
var arc = d3.svg.arc()
.startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
.endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
.innerRadius(function(d) { return Math.max(0, y(d.y)); })
.outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });
d3.json(url, function(error, root) {
if (error) throw error;
displayFailingTests(root);
var path = svg.selectAll("path")
.data(partition.nodes(root))
.enter().append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.name); })
.on("click", click);
function click(d) {
path.transition()
.duration(750)
.attrTween("d", arcTween(d));
populateTable(d,mouse);
}
function mouse(d) { return color(d.name); }
});
d3.select(self.frameElement).style("height", height + "px");
// Interpolate the scales!
function arcTween(d) {
var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
yd = d3.interpolate(y.domain(), [d.y, 1]),
yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
return function(d, i) {
return i
? function(t) { return arc(d); }
: function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };
};
}
}

View File

@ -1,661 +0,0 @@
/*
* (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
*
* 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.
*/
/*global d3:false*/
var statusColorMap = {
"success": "LightGreen",
"fail": "Crimson",
"skip": "DodgerBlue"
};
var binaryMinIndex = function(min, array, func) {
"use strict";
var left = 0;
var right = array.length - 1;
while (left < right) {
var mid = Math.floor((left + right) / 2);
if (min < func(array[mid])) {
right = mid - 1;
} else if (min > func(array[mid])) {
left = mid + 1;
} else {
right = mid;
}
}
if (left >= array.length) {
return array.length - 1;
} else if (func(array[left]) <= min) {
return left;
} else {
return left - 1;
}
};
var binaryMaxIndex = function(max, array, func) {
"use strict";
var left = 0;
var right = array.length - 1;
while (left < right) {
var mid = Math.floor((left + right) / 2);
if (max < func(array[mid])) {
right = mid - 1;
} else if (max > func(array[mid])) {
left = mid + 1;
} else {
right = mid;
}
}
if (right < 0) {
return 0;
} else if (func(array[right]) <= max) {
return right + 1; // exclusive index
} else {
return right;
}
};
var parseWorker = function(tags) {
"use strict";
for (var i = 0; i < tags.length; i++) {
if (!tags[i].startsWith("worker")) {
continue;
}