diff --git a/.gitignore b/.gitignore index 6323f10..5d999e7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ node_modules build app/js/templates.js app/data -*.py[cod] # C extensions *.so diff --git a/manage.py b/manage.py deleted file mode 100755 index 322ea59..0000000 --- a/manage.py +++ /dev/null @@ -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) diff --git a/requirements.txt b/requirements.txt index 4ec368e..f44e604 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 diff --git a/stackviz/export.py b/stackviz/export.py index e176f56..ebffa6f 100644 --- a/stackviz/export.py +++ b/stackviz/export.py @@ -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__': diff --git a/stackviz/global_template_injector.py b/stackviz/global_template_injector.py deleted file mode 100644 index 44a46a6..0000000 --- a/stackviz/global_template_injector.py +++ /dev/null @@ -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 diff --git a/stackviz/parser/tempest_subunit.py b/stackviz/parser/tempest_subunit.py index a825d62..868c314 100644 --- a/stackviz/parser/tempest_subunit.py +++ b/stackviz/parser/tempest_subunit.py @@ -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): diff --git a/stackviz/static/css/sb-admin-2.css b/stackviz/static/css/sb-admin-2.css deleted file mode 100644 index e8be396..0000000 --- a/stackviz/static/css/sb-admin-2.css +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/stackviz/static/css/timeline.css b/stackviz/static/css/timeline.css deleted file mode 100644 index 92161eb..0000000 --- a/stackviz/static/css/timeline.css +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/stackviz/static/css/upstream_run.css b/stackviz/static/css/upstream_run.css deleted file mode 100644 index 019a3a3..0000000 --- a/stackviz/static/css/upstream_run.css +++ /dev/null @@ -1,3 +0,0 @@ -.highlight { - font-weight: bold; -} \ No newline at end of file diff --git a/stackviz/static/js/log-dialog.js b/stackviz/static/js/log-dialog.js deleted file mode 100644 index b815ee8..0000000 --- a/stackviz/static/js/log-dialog.js +++ /dev/null @@ -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]) { - $("
").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 = $('', - { - 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" ); - } - } - ] - - }); - -} diff --git a/stackviz/static/js/sb-admin-2.js b/stackviz/static/js/sb-admin-2.js deleted file mode 100644 index 5be2c88..0000000 --- a/stackviz/static/js/sb-admin-2.js +++ /dev/null @@ -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'); - } -}); diff --git a/stackviz/static/js/summary.js b/stackviz/static/js/summary.js deleted file mode 100644 index ce387de..0000000 --- a/stackviz/static/js/summary.js +++ /dev/null @@ -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"; - -/* ---*/ - -//@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 = $("--Test Runs-- --") - .addClass('col-lg-6' ) - .appendTo($("#run-summary-div")); - - var panel = $("") - .addClass('panel panel-default') - .appendTo(container); - - var head = $("") - .addClass("panel-heading") - .appendTo(panel); - head.append($("", { - href: 'tempest_timeline_' + entry.provider + '_' + entry.run + '.html', - text: entry.providerDescription + ", run #" + entry.run - })); - - var body = $("") - .addClass("panel-body") - .appendTo(panel); - - var table = $("") - .addClass("table table-bordered table-hover table-striped") - .appendTo(body); - - var data_dict = getData(data); - for (var key in data_dict) { - $("
") - .append($(" ").text(key)) - .append($(" ").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); - }); - }) -} diff --git a/stackviz/static/js/sunburst.js b/stackviz/static/js/sunburst.js deleted file mode 100644 index 70229e3..0000000 --- a/stackviz/static/js/sunburst.js +++ /dev/null @@ -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); }; - }; - } - - -} diff --git a/stackviz/static/js/timeline.js b/stackviz/static/js/timeline.js deleted file mode 100644 index d901937..0000000 --- a/stackviz/static/js/timeline.js +++ /dev/null @@ -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; - } - - return parseInt(tags[i].split("-")[1]); - } - - return null; -}; - -var getDstatLanes = function(data, mins, maxes) { - if (!data) { - return []; - } - - var row = data[0]; - var lanes = []; - - if ('total_cpu_usage_usr' in row && 'total_cpu_usage_sys' in row) { - lanes.push([{ - scale: d3.scale.linear().domain([0, 100]), - value: function(d) { - return d.total_cpu_usage_wai; - }, - color: "rgba(224, 188, 188, 1)", - text: "CPU wait" - }, { - scale: d3.scale.linear().domain([0, 100]), - value: function(d) { - return d.total_cpu_usage_usr + d.total_cpu_usage_sys; - }, - color: "rgba(102, 140, 178, 0.75)", - text: "CPU (user+sys)" - }]); - } - - if ('memory_usage_used' in row) { - lanes.push([{ - scale: d3.scale.linear().domain([0, maxes.memory_usage_used]), - value: function(d) { return d.memory_usage_used; }, - color: "rgba(102, 140, 178, 0.75)", - text: "Memory" - }]); - } - - if ('net_total_recv' in row && 'net_total_send' in row) { - lanes.push([{ - scale: d3.scale.linear().domain([0, maxes.net_total_recv]), - value: function(d) { return d.net_total_recv; }, - color: "rgba(224, 188, 188, 1)", - text: "Net Down" - }, { - scale: d3.scale.linear().domain([0, maxes.net_total_send]), - value: function(d) { return d.net_total_send; }, - color: "rgba(102, 140, 178, 0.75)", - text: "Net Up", - type: "line" - }]); - } - - if ('dsk_total_read' in row && 'dsk_total_writ' in row) { - lanes.push([{ - scale: d3.scale.linear().domain([0, maxes.dsk_total_read]), - value: function(d) { return d.dsk_total_read; }, - color: "rgba(224, 188, 188, 1)", - text: "Disk Read", - type: "line" - }, { - scale: d3.scale.linear().domain([0, maxes.dsk_total_writ]), - value: function(d) { return d.dsk_total_writ; }, - color: "rgba(102, 140, 178, 0.75)", - text: "Disk Write", - type: "line" - }]); - } - - return lanes; -}; - -var initTimeline = function(options, data, timeExtents) { - "use strict"; - - var container = $(options.container); - - // http://bl.ocks.org/bunkat/2338034 - var margin = { top: 20, right: 10, bottom: 10, left: 80 }; - var width = container.width() - margin.left - margin.right; - var height = 550 - margin.top - margin.bottom; - - // filter dstat data immediately. if no timestamps overlap, we want to throw - // it away quickly - options.dstatData = options.dstatData.slice( - binaryMinIndex(timeExtents[0], options.dstatData, function(d) { return d.system_time; }), - binaryMaxIndex(timeExtents[1], options.dstatData, function(d) { return d.system_time; }) - ); - - var dstatLanes; - if (options.dstatData.length > 2) { - dstatLanes = getDstatLanes( - options.dstatData, - options.dstatMinimums, - options.dstatMaximums); - } else { - dstatLanes = []; - } - - var miniHeight = data.length * 12 + 30; - var dstatHeight = dstatLanes.length * 30 + 30; - var mainHeight = height - miniHeight - dstatHeight - 10; - - var x = d3.time.scale() - .range([0, width]) - .domain(timeExtents); - - var x1 = d3.scale.linear().range([0, width]); - - var y1 = d3.scale.linear() - .domain([0, data.length]) - .range([0, mainHeight]); - var y2 = d3.scale.linear() - .domain([0, data.length]) - .range([0, miniHeight]); - var y3 = d3.scale.linear() - .domain([0, dstatLanes.length]) - .range([0, dstatHeight]); - - var chart = d3.select(options.container) - .append("svg") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .attr("class", "chart"); - - var defs = chart.append("defs") - .append("clipPath") - .attr("id", "clip") - .append("rect") - .attr("width", width) - .attr("height", mainHeight); - - var main = chart.append("g") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")") - .attr("width", width) - .attr("height", mainHeight) - .attr("class", "main"); - - var laneLines = main.append("g"); - var laneLabels = main.append("g"); - - var itemGroups = main.append("g"); - - var dstatOffset = margin.top + mainHeight; - var dstatGroup = chart.append("g") - .attr("transform", "translate(" + margin.left + "," + dstatOffset + ")") - .attr("width", width) - .attr("height", dstatHeight); - - dstatLanes.forEach(function(lane, i) { - var laneGroup = dstatGroup.append("g"); - - var text = laneGroup.append("text") - .attr("y", function(d) { return y3(i + 0.5); }) - .attr("dy", ".5ex") - .attr("text-anchor", "end") - .style("font", "10px sans-serif"); - - var dy = 0; - - // precompute some known info for each lane's paths - lane.forEach(function(pathDef) { - var laneHeight = 0.8 * y3(1); - - if ('text' in pathDef) { - text.append("tspan") - .attr("x", -margin.right) - .attr("dy", dy) - .text(pathDef.text) - .attr("fill", function(d) { return pathDef.color; }); - - dy += 10; - } - - pathDef.scale.range([laneHeight, 0]); - - pathDef.path = laneGroup.append("path"); - if (pathDef.type === "line") { - pathDef.area = d3.svg.line() - .x(function(d) { return x1(d.system_time); }) - .y(function(d) { return y3(i) + pathDef.scale(pathDef.value(d)); }); - - pathDef.path - .style("stroke", pathDef.color) - .style("stroke-width", "1.5px") - .style("fill", "none"); - //.style("shape-rendering", 'crispEdges'); - } else { - pathDef.area = d3.svg.area() - .x(function(d) { return x1(d.system_time); }) - .y0(function(d) { return y3(i) + laneHeight; }) - .y1(function(d) { - return y3(i) + pathDef.scale(pathDef.value(d)); - }); - - pathDef.path.style("fill", pathDef.color); - } - }); - }); - - var cursorGroup = main.append("g") - .style("opacity", 0) - .style("pointer-events", "none"); - - var cursor = cursorGroup.append("line") - .attr("x1", 0) - .attr("x2", 0) - .attr("y1", y1(-0.1)) - .attr("stroke", "blue"); - - var cursorText = cursorGroup.append("text") - .attr("x", 0) - .attr("y", -10) - .attr("dy", "-.5ex") - .text("") - .style("text-anchor", "middle") - .style("font", "9px sans-serif"); - - var miniOffset = margin.top + mainHeight + dstatHeight; - var mini = chart.append("g") - .attr("transform", "translate(" + margin.left + "," + miniOffset + ")") - .attr("width", width) - .attr("height", mainHeight) - .attr("class", "mini"); - - var miniGroups = mini.append("g"); - - // performance hack: performance in Firefox as of 39.0 is poor due to some - // d3 bugs - // Limit the initial selection to ~1/6th of the total to make things - // bearable (user can still increase as desired) - var start = timeExtents[0]; - var end = timeExtents[1]; - var reducedEnd = new Date(start.getTime() + ((end - start) / 8)); - - var brush = d3.svg.brush() - .x(x) - .extent([start, reducedEnd]); - - chart.on("mouseout", function() { - cursorGroup.style("opacity", 0); - }); - - chart.on("mousemove", function() { - var pos = d3.mouse(this); - var px = pos[0]; - var py = pos[1]; - - if (px >= margin.left && px < (width + margin.left) && - py > margin.top && py < (mainHeight + margin.top)) { - var relX = px - margin.left; - - var currentTime = new Date(x1.invert(relX)); - - cursorGroup.style("opacity", "0.5"); - cursorGroup.attr("transform", "translate(" + relX + ", 0)"); - - cursorText.text(d3.time.format("%X")(currentTime)); - } - }); - - function updateLanes() { - var lines = laneLines.selectAll(".laneLine") - .data(data, function(d) { return d.key; }); - - lines.enter().append("line") - .attr("x1", 0) - .attr("x2", width) - .attr("stroke", "lightgray") - .attr("class", "laneLine"); - - lines.attr("y1", function(d, i) { return y1(i - 0.1); }) - .attr("y2", function(d, i) { return y1(i - 0.1); }); - - lines.exit().remove(); - - var labels = laneLabels.selectAll(".laneLabel") - .data(data, function(d) { return d.key; }); - - labels.enter().append("text") - .text(function(d) { return "Worker #" + d.key; }) - .attr("x", -margin.right) - .attr("dy", ".5ex") - .attr("text-anchor", "end") - .attr("class", "laneLabel"); - - labels.attr("y", function(d, i) { return y1(i + 0.5); }); - - labels.exit().remove(); - - cursor.attr("y2", y1(data.length - 0.1)); - } - - function updateItems() { - var minExtent = brush.extent()[0]; - var maxExtent = brush.extent()[1]; - - // filter visible items to include only those within the current extent - // additionally prune extremely small values to improve performance - var visibleItems = data.map(function(group) { - return { - key: group.key, - values: group.values.filter(function(e) { - if (x1(e.end_date) - x1(e.start_date) < 2) { - return false; - } - - if (e.start_date > maxExtent || e.end_date < minExtent) { - return false; - } - - return true; - }) - }; - }); - - var groups = itemGroups.selectAll("g") - .data(visibleItems, function(d) { return d.key; }); - - groups.enter().append("g"); - - var rects = groups.selectAll("rect") - .data(function(d) { return d.values; }, function(d) { return d.name; }); - - rects.enter().append("rect") - .attr("y", function(d) { return y1(parseWorker(d.tags)); }) - .attr("height", 0.8 * y1(1)) - .attr("stroke", 'rgba(100, 100, 100, 0.25)') - .attr("clip-path", "url(#clip)"); - - rects - .attr("x", function(d) { - return x1(d.start_date); - }) - .attr("width", function(d) { - return x1(d.end_date) - x1(d.start_date); - }) - .attr("fill", function(d) { return statusColorMap[d.status]; }) - .on("mouseover", options.onMouseover) - .on("mouseout", options.onMouseout) - .on("click", options.onClick); - - rects.exit().remove(); - groups.exit().remove(); - } - - function updateDstat() { - if (dstatLanes.length === 0) { - return; - } - - var minExtent = brush.extent()[0]; - var maxExtent = brush.extent()[1]; - - var dstat = options.dstatData; - var timeFunc = function(d) { return d.system_time; }; - - var visibleEntries = dstat.slice( - binaryMinIndex(minExtent, dstat, timeFunc), - binaryMaxIndex(maxExtent, dstat, timeFunc) - ); - - // apply the current dataset (visibleEntries) to each dstat path - // - dstatLanes.forEach(function(lane) { - lane.forEach(function(pathDef) { - pathDef.path - .datum(visibleEntries) - .attr("d", pathDef.area); - }); - }); - } - - function updateMiniItems() { - var groups = miniGroups.selectAll("g") - .data(data, function(d) { return d.key; }); - - groups.enter().append("g"); - - var rects = groups.selectAll("rect").data( - function(d) { return d.values; }, - function(d) { return d.name; }); - - rects.enter().append("rect") - .attr("y", function(d) { return y2(parseWorker(d.tags) + 0.5) - 5; }) - .attr("height", 10); - - rects.attr("x", function(d) { return x(d.start_date); }) - .attr("width", function(d) { return x(d.end_date) - x(d.start_date); }) - .attr("stroke", 'rgba(100, 100, 100, 0.25)') - .attr("fill", function(d) { return statusColorMap[d.status]; }); - - rects.exit().remove(); - groups.exit().remove(); - } - - function update() { - x1.domain(brush.extent()); - - updateLanes(); - updateItems(); - updateDstat(); - } - - brush.on("brush", update); - - mini.append("g") - .attr("class", "x brush") - .call(brush) - .selectAll("rect") - .attr("y", 1) - .attr("height", miniHeight - 1) - .attr("fill", "dodgerblue") - .attr("fill-opacity", 0.365); - - updateMiniItems(); - update(); - - $(window).resize(function() { - var brushExtent = brush.extent(); - - width = container.width() - margin.left - margin.right; - x.range([0, width]); - x1.range([0, width]); - - chart.attr("width", container.width()); - defs.attr("width", width); - main.attr("width", width); - mini.attr("width", width); - - laneLines.selectAll(".laneLine").attr("x2", width); - - brush.extent(brushExtent); - - updateMiniItems(); - update(); - }); -}; - -function fillArrayRight(array) { - // "fill" the array to the right, overwriting empty values with the next - // non-empty value to the left - // only false values will be overwritten (e.g. "", null, etc) - for (var i = 0; i < array.length - 1; i++) { - if (!array[i + 1]) { - array[i + 1] = array[i]; - } - } -} - -function mergeNames(primary, secondary) { - // "zip" together strings in the same position in each array, and do some - // basic cleanup of results - var ret = []; - for (var i = 0; i < primary.length; i++) { - ret.push((primary[i] + '_' + secondary[i]).replace(/[ /]/g, '_')); - } - return ret; -} - -function chainLoadDstat(path, yearOverride, callback) { - "use strict"; - - d3.text(path, function(error, data) { - if (error) { - callback([]); - return; - } - - var primaryNames = null; - var secondaryNames = null; - var names = null; - - var minimums = {}; - var maximums = {}; - - // assume UTC - may not necessarily be the case? - // dstat doesn't include the year in its logs, so we'll need to copy it - // from the subunit logs - var dateFormat = d3.time.format.utc("%d-%m %H:%M:%S"); - - var parsed = d3.csv.parseRows(data, function(row, i) { - if (i <= 4) { // header rows - ignore - return null; - } else if (i == 5) { // primary - primaryNames = row; - fillArrayRight(primaryNames); - return null; - } else if (i == 6) { // secondary - secondaryNames = row; - - names = mergeNames(primaryNames, secondaryNames); - return null; - } else { - var ret = {}; - - for (var col = 0; col < row.length; col++) { - var name = names[col]; - var value = row[col]; - - if (name == "system_time") { - value = dateFormat.parse(value); - value.setFullYear(1900 + yearOverride); - } else { - value = parseFloat(value); - } - - if (!(name in minimums) || value < minimums[name]) { - minimums[name] = value; - } - - if (!(name in maximums) || value > maximums[name]) { - maximums[name] = value; - } - - ret[name] = value; - } - - return ret; - } - }); - - callback(parsed, minimums, maximums); - }); -} - -function loadTimeline(path, options) { // eslint-disable-line no-unused-vars - "use strict"; - - d3.json(path, function(error, data) { - if (error) { - throw error; - } - - var minStart = null; - var maxEnd = null; - data.forEach(function(d) { - /*eslint-disable camelcase*/ - d.start_date = new Date(d.timestamps[0]); - if (minStart === null || d.start_date < minStart) { - minStart = d.start_date; - } - - d.end_date = new Date(d.timestamps[1]); - if (maxEnd === null || d.end_date > maxEnd) { - maxEnd = d.end_date; - } - /*eslint-enable camelcase*/ - }); - - data = data.filter(function (d) { return d.duration > 0; }); - - var nested = d3.nest() - .key(function(d) { return parseWorker(d.tags); }) - .sortKeys(d3.ascending) - .entries(data); - - // include dstat if available - if (options.dstatPath && !options.dstatData) { - var year = data[0].start_date.getYear(); - chainLoadDstat(options.dstatPath, year, function(data, mins, maxes) { - options.dstatData = data; - options.dstatMinimums = mins; - options.dstatMaximums = maxes; - - initTimeline(options, nested, [ minStart, maxEnd ]); - }); - } else { - initTimeline(options, nested, [ minStart, maxEnd ]); - } - }); -} diff --git a/stackviz/static/js/upstream_run.js b/stackviz/static/js/upstream_run.js deleted file mode 100644 index 2176933..0000000 --- a/stackviz/static/js/upstream_run.js +++ /dev/null @@ -1,104 +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"; - -window.addEventListener('load', function() { - - - //default panel display - $("#runs-panel").hide(); - $("#gerrit-panel").show(); - $("#run-metadata-panel").hide(); - - //dict containing all run_metadata objects, keyed by run_id - var RUN_METADATA = {}; - - //sets the run metdata of the associated run in the proper div - function show_run_metadata(id) { - $("#run-metadata-table").html(" Key Value "); - var meta = RUN_METADATA[id]; - for (var i in meta) { - var obj = meta[i]; - var row = $(""); - $("#run-metadata-table").append(row); - } - } - - //run_metadata will be queried from subunit2sql when given run_id - function get_run_metadata(request, run_id) { - $.getJSON((request),function(metadata) { - RUN_METADATA[run_id]=metadata; - }); - } - - - - //Takes a list of runs and creates a pretty div for each - function display_runs(data) { - $("#runs-panel").show(); - $("#runs-panel").append(" " + obj['key'] + " " + - "" + obj['value'] + " "); - - for (var i in data) { - var run_obj = data[i]; - //get run_metadata - var request = 'upstream_api_run_id_' + run_obj['id'] + '.json'; - get_run_metadata(request, run_obj['id']); - - var li = $(""); - //on mouseover, show the run_metadata for this run object (li) - $(li).hover( - function () { - $(this).addClass("highlight"); - show_run_metadata($(this).attr("value")); - }, - function () { - $(this).removeClass("highlight"); - } - ); - - $(li.append("" + run_obj['artifacts'] + "\n")); - $("#runs-list").append(li); - $("#runs-panel-heading").html("Displaying " + i + " Runs"); - } - $("#run-metadata-panel").show(); - } - - - $('#gerrit-id').keypress(function (e) { - if (e.which == 13) { - $( "#gerrit-id-button" ).click(); - return false; - } - }); - - - //click triggers the api call that returns the run data - $('#gerrit-id-button').click(function() { - var request = 'upstream_api_changeid_'+$("#gerrit-id").val()+'.json'; - $("#runs-panel").append("
Change ID: " + $("#gerrit-id").val() + "
"); - $("#gerrit-panel").html("Loading Test Runs..."); - - $.getJSON((request),function(data) { - $("#gerrit-panel").hide(); - display_runs(data); - }); - }); - - -}); \ No newline at end of file diff --git a/stackviz/templates/devstack/results.html b/stackviz/templates/devstack/results.html deleted file mode 100644 index ed58d23..0000000 --- a/stackviz/templates/devstack/results.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends 'template.html' %} - -{% block title %}Devstack Latest Results{% endblock %} - -{% block body %} - --- -{% endblock %} \ No newline at end of file diff --git a/stackviz/templates/index.html b/stackviz/templates/index.html deleted file mode 100644 index c2d35b3..0000000 --- a/stackviz/templates/index.html +++ /dev/null @@ -1,53 +0,0 @@ -{% extends 'template.html' %} - -{% load staticfiles %} - -{% block title %}Index{% endblock %} - -{% block head-extra %} - - -{% endblock %} - -{% block body %} - --- -Latest Results
--- ---Local Run Summary
--- - - -{% endblock %} diff --git a/stackviz/templates/menu.html b/stackviz/templates/menu.html deleted file mode 100644 index 9b6fd41..0000000 --- a/stackviz/templates/menu.html +++ /dev/null @@ -1,61 +0,0 @@ - - diff --git a/stackviz/templates/tempest/aggregate.html b/stackviz/templates/tempest/aggregate.html deleted file mode 100644 index 24d12e8..0000000 --- a/stackviz/templates/tempest/aggregate.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends 'template.html' %} - -{% block title %}Aggregate Results{% endblock %} - -{% block body %} - -----Tempest Runs-- ---- -{% endblock %} \ No newline at end of file diff --git a/stackviz/templates/tempest/results.html b/stackviz/templates/tempest/results.html deleted file mode 100644 index 71e8d20..0000000 --- a/stackviz/templates/tempest/results.html +++ /dev/null @@ -1,99 +0,0 @@ -{% extends 'template.html' %} - -{% load staticfiles %} - -{% block title %}Tempest Results{% endblock %} - -{% block head-extra %} - - -{% endblock %} - -{% block body %} - --- -Aggregate Tempest Results
--- -Details not found for test.
--- ---Results from Run #{{run_id}}
--- --- ---- Runtime Diagram ----- -- -- ---- ---Test Run Info------
--- - - - - - -{% endblock %} diff --git a/stackviz/templates/tempest/timeline.html b/stackviz/templates/tempest/timeline.html deleted file mode 100644 index 69858ee..0000000 --- a/stackviz/templates/tempest/timeline.html +++ /dev/null @@ -1,269 +0,0 @@ -{% extends 'template.html' %} -{% load staticfiles %} - -{% block title %}Tempest: Execution Timeline (run #{{run_id}}){% endblock %} - -{% block head-extra %} - -{% endblock %} - -{% block body %} ---- --------Details not found for test.
--- ---Execution Timeline ({{provider_name}}, run #{{run_id}})
--- - - -{% endblock %} diff --git a/stackviz/templates/template.html b/stackviz/templates/template.html deleted file mode 100644 index c794b9f..0000000 --- a/stackviz/templates/template.html +++ /dev/null @@ -1,114 +0,0 @@ -{% load staticfiles %} - - - - - - - - - - - ------ Timeline -- ---- -- -- ------- Info -- -- Mouse over an item to view info. --{% block title %}{% endblock %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {% block head-extra %}{% endblock %} - - - - -- - - - -- - - - - - - - - diff --git a/stackviz/templates/upstream/run.html b/stackviz/templates/upstream/run.html deleted file mode 100644 index 0ad6394..0000000 --- a/stackviz/templates/upstream/run.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends 'template.html' %} -{% load staticfiles %} - -{% block title %}Upstream Run Metadata{% endblock %} - -{% block head-extra %} - - -{% endblock %} - -{% block body %} - - - -- {% block body %}{% endblock %} -- - --- --- -Upstream Run Data
--- - - -{% endblock %} \ No newline at end of file diff --git a/stackviz/templates/upstream/test.html b/stackviz/templates/upstream/test.html deleted file mode 100644 index 89bc6c1..0000000 --- a/stackviz/templates/upstream/test.html +++ /dev/null @@ -1,30 +0,0 @@ -{% extends 'template.html' %} - -{% block title %}Upstream Test Stats{% endblock %} - -{% block body %} - -----Analyze Run---- Enter a Gerrit Change ID (six-digit): - -- -----Run Metadata------
-- --- -Upstream Test Stats
--- -{% endblock %} \ No newline at end of file diff --git a/stackviz/urls.py b/stackviz/urls.py deleted file mode 100644 index fd6af7f..0000000 --- a/stackviz/urls.py +++ /dev/null @@ -1,29 +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 django.conf.urls import include -from django.conf.urls import patterns -from django.conf.urls import url - -from stackviz.views.index import IndexView - -urlpatterns = patterns( - '', - url(r'^$', IndexView.as_view()), - url(r'^index.html$', IndexView.as_view(), name="index"), - url(r'^tempest_', include('stackviz.views.tempest.urls')), - url(r'^devstack_', include('stackviz.views.devstack.urls')), - url(r'^upstream_', include('stackviz.views.upstream.urls')), - url(r'^dstat_', include('stackviz.views.dstat.urls')) -) diff --git a/stackviz/views/__init__.py b/stackviz/views/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/stackviz/views/devstack/__init__.py b/stackviz/views/devstack/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/stackviz/views/devstack/results.py b/stackviz/views/devstack/results.py deleted file mode 100644 index ca9471e..0000000 --- a/stackviz/views/devstack/results.py +++ /dev/null @@ -1,19 +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 django.views.generic import TemplateView - - -class ResultsView(TemplateView): - template_name = 'devstack/results.html' diff --git a/stackviz/views/devstack/urls.py b/stackviz/views/devstack/urls.py deleted file mode 100644 index 059445f..0000000 --- a/stackviz/views/devstack/urls.py +++ /dev/null @@ -1,23 +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 django.conf.urls import patterns -from django.conf.urls import url - -from stackviz.views.devstack.results import ResultsView - - -urlpatterns = patterns('', - url(r'^results$', ResultsView.as_view()), - ) diff --git a/stackviz/views/dstat/__init__.py b/stackviz/views/dstat/__init__.py deleted file mode 100644 index f87606f..0000000 --- a/stackviz/views/dstat/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'tim' diff --git a/stackviz/views/dstat/api.py b/stackviz/views/dstat/api.py deleted file mode 100644 index ab6754f..0000000 --- a/stackviz/views/dstat/api.py +++ /dev/null @@ -1,47 +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 django.http import Http404 -from django.http import HttpResponse - -from django.views.generic import View - -from stackviz import settings - -_cached_csv = None - - -def _load_csv(): - global _cached_csv - - if _cached_csv: - return _cached_csv - - try: - with open(settings.DSTAT_CSV, 'r') as f: - _cached_csv = f.readlines() - return _cached_csv - except IOError: - return None - - -class DStatCSVEndpoint(View): - def get(self, request): - csv = _load_csv() - - if not csv: - raise Http404("DStat log could not be loaded at path %s" - % settings.DSTAT_CSV) - - return HttpResponse(csv, content_type="text/csv") diff --git a/stackviz/views/dstat/urls.py b/stackviz/views/dstat/urls.py deleted file mode 100644 index 3c83633..0000000 --- a/stackviz/views/dstat/urls.py +++ /dev/null @@ -1,21 +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 django.conf.urls import patterns -from django.conf.urls import url - -from api import DStatCSVEndpoint - - -urlpatterns = patterns('', url(r'^log.csv$', DStatCSVEndpoint.as_view())) diff --git a/stackviz/views/index.py b/stackviz/views/index.py deleted file mode 100644 index 316ebe5..0000000 --- a/stackviz/views/index.py +++ /dev/null @@ -1,19 +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 django.views.generic import TemplateView - - -class IndexView(TemplateView): - template_name = 'index.html' diff --git a/stackviz/views/tempest/__init__.py b/stackviz/views/tempest/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/stackviz/views/tempest/aggregate.py b/stackviz/views/tempest/aggregate.py deleted file mode 100644 index b7d1d59..0000000 --- a/stackviz/views/tempest/aggregate.py +++ /dev/null @@ -1,19 +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 django.views.generic import TemplateView - - -class AggregateResultsView(TemplateView): - template_name = 'tempest/aggregate.html' diff --git a/stackviz/views/tempest/api.py b/stackviz/views/tempest/api.py deleted file mode 100644 index 2dbd422..0000000 --- a/stackviz/views/tempest/api.py +++ /dev/null @@ -1,136 +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 django.http import Http404 -from restless.views import Endpoint - -from stackviz.parser.tempest_subunit import convert_stream -from stackviz.parser.tempest_subunit import get_providers -from stackviz.parser.tempest_subunit import reorganize - -#: Cached results from loaded subunit logs indexed by their run number -_cached_run = {} - -#: Cached results converted into tree form -_cached_tree = {} - -#: Cached results for loaded subunit logs without details stripped out. Indexed -#: initially by log number, but contains nested dicts indexed by the test name. -_cached_details = {} - - -class NoRunDataException(Http404): - pass - - -class ProviderNotFoundException(Http404): - pass - - -class RunNotFoundException(Http404): - pass - - -class TestNotFoundException(Http404): - pass - - -def _load_run(provider_name, run_id): - if (provider_name, run_id) in _cached_run: - return _cached_run[provider_name, run_id] - - providers = get_providers() - if not providers: - raise NoRunDataException("No test providers could be loaded") - - if provider_name not in providers: - raise ProviderNotFoundException("Requested subunit provider could not " - "be found") - - p = providers[provider_name] - - try: - # assume first repo for now - stream = p.get_stream(run_id) - - # strip details for now - # TODO(provide method for getting details on demand) - # (preferably for individual tests to avoid bloat) - converted_run = convert_stream(stream, strip_details=True) - _cached_run[provider_name, run_id] = converted_run - - return converted_run - except KeyError: - raise RunNotFoundException("Requested test run could not be found") - - -def _load_tree(provider, run_id): - if (provider, run_id) in _cached_tree: - return _cached_tree[provider, run_id] - - run = _load_run(provider, run_id) - tree = reorganize(run) - - _cached_tree[provider, run_id] = tree - return tree - - -def _load_details(provider_name, run_id, test_name): - if (provider_name, run_id) not in _cached_details: - providers = get_providers() - if not providers: - raise NoRunDataException("No test providers could be loaded") - - if provider_name not in providers: - raise ProviderNotFoundException("Requested subunit provider could " - "not be found: " + provider_name) - - provider = providers[provider_name] - try: - stream = provider.get_stream(run_id) - converted_run = convert_stream(stream, strip_details=False) - - # remap dict to allow direct access to details via test name - dest = {} - for entry in converted_run: - dest[entry['name']] = entry['details'] - - _cached_details[provider_name, run_id] = dest - except (KeyError, IndexError): - raise RunNotFoundException("Requested test run could not be found") - - details_map = _cached_details[provider_name, run_id] - if test_name is None: - return details_map - else: - if test_name in details_map: - return details_map[test_name] - else: - raise TestNotFoundException( - "Requested test could not be found in run") - - -class TempestRunRawEndpoint(Endpoint): - def get(self, request, provider_name, run_id): - return _load_run(provider_name, int(run_id)) - - -class TempestRunTreeEndpoint(Endpoint): - def get(self, request, provider_name, run_id): - return _load_tree(provider_name, int(run_id)) - - -class TempestRunDetailsEndpoint(Endpoint): - def get(self, request, run_id, provider_name, test_name=None): - return _load_details(provider_name, int(run_id), test_name) diff --git a/stackviz/views/tempest/results.py b/stackviz/views/tempest/results.py deleted file mode 100644 index b8bbc0f..0000000 --- a/stackviz/views/tempest/results.py +++ /dev/null @@ -1,26 +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 django.views.generic import TemplateView - - -class ResultsView(TemplateView): - template_name = 'tempest/results.html' - - def get_context_data(self, **kwargs): - context = super(ResultsView, self).get_context_data(**kwargs) - context['provider_name'] = self.kwargs['provider_name'] - context['run_id'] = self.kwargs['run_id'] - - return context diff --git a/stackviz/views/tempest/timeline.py b/stackviz/views/tempest/timeline.py deleted file mode 100644 index ac3535b..0000000 --- a/stackviz/views/tempest/timeline.py +++ /dev/null @@ -1,26 +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 django.views.generic import TemplateView - - -class TimelineView(TemplateView): - template_name = 'tempest/timeline.html' - - def get_context_data(self, **kwargs): - context = super(TimelineView, self).get_context_data(**kwargs) - context['provider_name'] = self.kwargs['provider_name'] - context['run_id'] = self.kwargs['run_id'] - - return context diff --git a/stackviz/views/tempest/urls.py b/stackviz/views/tempest/urls.py deleted file mode 100644 index b13d739..0000000 --- a/stackviz/views/tempest/urls.py +++ /dev/null @@ -1,52 +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 django.conf.urls import patterns -from django.conf.urls import url - -from aggregate import AggregateResultsView -from results import ResultsView -from timeline import TimelineView - -from api import TempestRunDetailsEndpoint -from api import TempestRunRawEndpoint -from api import TempestRunTreeEndpoint - - -urlpatterns = patterns( - '', - url(r'^results_(?P----Compare Tests-----Test---Avg-[\w_\.]+)_(?P \d+).html$', - ResultsView.as_view(), - name='tempest_results'), - url(r'^timeline_(?P [\w_\.]+)_(?P \d+).html$', - TimelineView.as_view(), - name='tempest_timeline'), - - url(r'^api_tree_(?P [\w_\.]+)_(?P \d+).json$', - TempestRunTreeEndpoint.as_view(), - name='tempest_api_tree'), - url(r'^api_raw_(?P [\w_\.]+)_(?P \d+).json$', - TempestRunRawEndpoint.as_view(), - name='tempest_api_raw'), - url(r'^api_details_(?P [\w_\.]+)_(?P \d+).json$', - TempestRunDetailsEndpoint.as_view()), - url(r'^api_details_(?P [\w_\.]+)_(?P \d+)_' - r'(?P [^/]+).json$', - TempestRunDetailsEndpoint.as_view()), - - url(r'^aggregate.html$', - AggregateResultsView.as_view(), - name='tempest_aggregate_results'), -) diff --git a/stackviz/views/upstream/__init__.py b/stackviz/views/upstream/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/stackviz/views/upstream/api.py b/stackviz/views/upstream/api.py deleted file mode 100644 index 66e2ce7..0000000 --- a/stackviz/views/upstream/api.py +++ /dev/null @@ -1,78 +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 restless.views import Endpoint - -from subunit2sql.db import api - -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker - - -def _get_runs(change_id): - """Returns the dict of run objects associated with a changeID - - When given the change_id of a Gerrit change, a connection will be made to - the upstream subunit2sql db and query all run meta having that change_id - :param change_id: the Gerrit change_id to query - :return: a json dict of run_meta objects - """ - - engine = create_engine('mysql://query:query@logstash.openstack.org' + - ':3306/subunit2sql') - Session = sessionmaker(bind=engine) - session = Session() - - list_of_runs = api.get_runs_by_key_value(key="build_change", - value=change_id, - session=session) - ret_list = [] - - for run in list_of_runs: - ret_list.append(run.to_dict()) - - return ret_list - - -def _get_metadata(run_id): - """Returns a dict of run_metadata objects associated with a run_id - - :param run_id: - :return: - """ - - engine = create_engine('mysql://query:query@logstash.openstack.org' + - ':3306/subunit2sql') - Session = sessionmaker(bind=engine) - session = Session() - - metadata = api.get_run_metadata(run_id, session=session) - ret_list = [] - - for meta in metadata: - ret_list.append(meta.to_dict()) - - return ret_list - - -class GerritURLEndpoint(Endpoint): - - def get(self, request, change_id): - return _get_runs(change_id) - - -class RunMetadataEndpoint(Endpoint): - - def get(self, request, run_id): - return _get_metadata(run_id) diff --git a/stackviz/views/upstream/run.py b/stackviz/views/upstream/run.py deleted file mode 100644 index 75d36ef..0000000 --- a/stackviz/views/upstream/run.py +++ /dev/null @@ -1,19 +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 django.views.generic import TemplateView - - -class RunView(TemplateView): - template_name = 'upstream/run.html' diff --git a/stackviz/views/upstream/test.py b/stackviz/views/upstream/test.py deleted file mode 100644 index 133f93a..0000000 --- a/stackviz/views/upstream/test.py +++ /dev/null @@ -1,23 +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 django.views.generic import TemplateView - -# TODO(Planned functionality) -# Compare one specific test against its moving average -# - - -class TestView(TemplateView): - template_name = 'upstream/test.html' diff --git a/stackviz/views/upstream/urls.py b/stackviz/views/upstream/urls.py deleted file mode 100644 index 9804de3..0000000 --- a/stackviz/views/upstream/urls.py +++ /dev/null @@ -1,41 +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 django.conf.urls import patterns -from django.conf.urls import url - -from run import RunView -from test import TestView - -from api import GerritURLEndpoint -from api import RunMetadataEndpoint - -urlpatterns = patterns('', - url(r'^run.html$', - RunView.as_view(), - name='run_metadata'), - - url(r'^test.html$', - TestView.as_view(), - name='test_data'), - - url(r'^api_changeid_(?P \d+).json$', - GerritURLEndpoint.as_view(), - name='gerrit_url'), - - url(r'^api_run_id_(?P [a-zA-Z0-9!$* ' - '\t\r\n\-]+).json$', - RunMetadataEndpoint.as_view(), - name='run_metadata_url') - ) diff --git a/stackviz/wsgi.py b/stackviz/wsgi.py deleted file mode 100644 index 37ec47a..0000000 --- a/stackviz/wsgi.py +++ /dev/null @@ -1,28 +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. - -""" -WSGI config for stackviz project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ -""" - -import os -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "stackviz.settings") - -from django.core.wsgi import get_wsgi_application -application = get_wsgi_application() diff --git a/tox.ini b/tox.ini index 73ef134..8c677f3 100644 --- a/tox.ini +++ b/tox.ini @@ -32,4 +32,4 @@ commands = oslo_debug_helper {posargs} show-source = True ignore = E123,E125 builtins = _ -exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build +exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,app,test,build,node_modules