From c9fa0fede5d3d8deff57103f1afaca9fa7b924d7 Mon Sep 17 00:00:00 2001 From: "phoglund@webrtc.org" Date: Mon, 26 Aug 2013 08:45:22 +0000 Subject: [PATCH] Removed build status tracking, refreshed front page. BUG= R=kjellander@webrtc.org Review URL: https://webrtc-codereview.appspot.com/2106004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4613 4adac7df-926f-26a2-2b94-8c16560cd09d --- tools/quality_tracking/constants.py | 5 - .../dashboard/add_build_status_data.py | 168 ----- tools/quality_tracking/dashboard/app.yaml | 11 +- tools/quality_tracking/dashboard/dashboard.py | 18 - tools/quality_tracking/dashboard/lkgr_page.py | 29 - .../dashboard/load_build_status.py | 133 ---- tools/quality_tracking/dashboard/main.py | 7 +- .../dashboard/static/index.html | 10 +- .../dashboard/static/lkgr_redirect.html | 6 + .../dashboard/static/webrtc_logo.png | Bin 0 -> 7460 bytes .../dashboard/stylesheets/stylesheet.css | 7 +- .../templates/dashboard_template.html | 53 +- tools/quality_tracking/tgrid_parser.py | 93 --- tools/quality_tracking/tgrid_parser_test.py | 601 ------------------ tools/quality_tracking/track_build_status.py | 94 --- .../track_build_status_test.py | 39 -- 16 files changed, 28 insertions(+), 1246 deletions(-) delete mode 100644 tools/quality_tracking/dashboard/add_build_status_data.py delete mode 100644 tools/quality_tracking/dashboard/lkgr_page.py delete mode 100644 tools/quality_tracking/dashboard/load_build_status.py create mode 100644 tools/quality_tracking/dashboard/static/lkgr_redirect.html create mode 100644 tools/quality_tracking/dashboard/static/webrtc_logo.png delete mode 100644 tools/quality_tracking/tgrid_parser.py delete mode 100755 tools/quality_tracking/tgrid_parser_test.py delete mode 100755 tools/quality_tracking/track_build_status.py delete mode 100755 tools/quality_tracking/track_build_status_test.py diff --git a/tools/quality_tracking/constants.py b/tools/quality_tracking/constants.py index a36b0b943a..32c8a164b4 100644 --- a/tools/quality_tracking/constants.py +++ b/tools/quality_tracking/constants.py @@ -23,13 +23,8 @@ REQUEST_TOKEN_URL = DASHBOARD_SERVER_HTTP + '/_ah/OAuthGetRequestToken' AUTHORIZE_TOKEN_URL = DASHBOARD_SERVER_HTTP + '/_ah/OAuthAuthorizeToken' ACCESS_TOKEN_URL = DASHBOARD_SERVER_HTTP + '/_ah/OAuthGetAccessToken' -# The build master URL. -BUILD_MASTER_SERVER = 'webrtc-cb-linux-master.cbf.corp.google.com:8010' -BUILD_MASTER_TRANSPOSED_GRID_URL = '/tgrid' - # Build bot constants. BUILD_BOT_COVERAGE_WWW_DIRECTORY = '/var/www/coverage' # Dashboard data input URLs. ADD_COVERAGE_DATA_URL = DASHBOARD_SERVER_HTTP + '/add_coverage_data' -ADD_BUILD_STATUS_DATA_URL = DASHBOARD_SERVER_HTTP + '/add_build_status_data' diff --git a/tools/quality_tracking/dashboard/add_build_status_data.py b/tools/quality_tracking/dashboard/add_build_status_data.py deleted file mode 100644 index 9e02c2d5d7..0000000000 --- a/tools/quality_tracking/dashboard/add_build_status_data.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- -# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -"""Implements a handler for adding build status data.""" - -import datetime -import logging - -from google.appengine.ext import db - -import oauth_post_request_handler - -VALID_STATUSES = ['OK', 'failed', 'building', 'warnings'] - - -class OrphanedBuildStatusesExistException(Exception): - pass - - -class BuildStatusRoot(db.Model): - """Exists solely to be the root parent for all build status data and to keep - track of when the last update was made. - - Since all build status data will refer to this as their parent, - we can run transactions on the build status data as a whole. - """ - last_updated_at = db.DateTimeProperty() - - -class BuildStatusData(db.Model): - """This represents one build status report from the build bot.""" - bot_name = db.StringProperty(required=True) - revision = db.IntegerProperty(required=True) - build_number = db.IntegerProperty(required=True) - status = db.StringProperty(required=True) - - -def _ensure_build_status_root_exists(): - root = db.GqlQuery('SELECT * FROM BuildStatusRoot').get() - if not root: - # Create a new root, but ensure we don't have any orphaned build statuses - # (in that case, we would not have a single entity group as we desire). - orphans = db.GqlQuery('SELECT * FROM BuildStatusData').get() - if orphans: - raise OrphanedBuildStatusesExistException('Parent is gone and there are ' - 'orphaned build statuses in ' - 'the database!') - root = BuildStatusRoot() - root.put() - - return root - - -def _filter_oauth_parameters(post_keys): - return filter(lambda post_key: not post_key.startswith('oauth_'), - post_keys) - - -def _parse_status(build_number_and_status): - parsed_status = build_number_and_status.split('--') - if len(parsed_status) != 2: - raise ValueError('Malformed status string %s.' % build_number_and_status) - - parsed_build_number = int(parsed_status[0]) - status = parsed_status[1] - - if status not in VALID_STATUSES: - raise ValueError('Invalid status in %s.' % build_number_and_status) - - return (parsed_build_number, status) - - -def _parse_name(revision_and_bot_name): - parsed_name = revision_and_bot_name.split('--') - if len(parsed_name) != 2: - raise ValueError('Malformed name string %s.' % revision_and_bot_name) - - revision = parsed_name[0] - bot_name = parsed_name[1] - if '\n' in bot_name: - raise ValueError('Bot name %s can not contain newlines.' % bot_name) - - return (int(revision), bot_name) - - -def _delete_all_with_revision(revision, build_status_root): - query_result = db.GqlQuery('SELECT * FROM BuildStatusData ' - 'WHERE revision = :1 AND ANCESTOR IS :2', - revision, build_status_root) - for entry in query_result: - entry.delete() - - -class AddBuildStatusData(oauth_post_request_handler.OAuthPostRequestHandler): - """Used to report build status data. - - Build status data is reported as a POST request. The POST request, aside - from the required oauth_* parameters should contain name-value entries that - abide by the following rules: - - 1) The name should be on the form --, for instance - 1568--Win32Release. - 2) The value should be on the form --, for instance - 553--OK, 554--building. The status is permitted to be failed, OK or - building. - - Data is keyed by revision. This handler will delete all data from a revision - if data with that revision is present in the current update, since we - assume that more recent data is always better data. We also assume that - an update always has complete information on a revision (e.g. the status - for all the bots are reported in each update). - - In particular the revision arrangement solves the problem when the latest - revision reports 'building' for a bot. Had we not deleted the old revision - we would first store a 'building' status for that bot and revision, and - later store a 'OK' or 'failed' status for that bot and revision. This is - undesirable since we don't want multiple statuses for one bot-revision - combination. Now we will effectively update the bot's status instead. - """ - def _parse_and_store_data(self): - build_status_root = _ensure_build_status_root_exists() - build_status_data = _filter_oauth_parameters(self.request.arguments()) - - db.run_in_transaction(self._parse_and_store_data_in_transaction, - build_status_root, build_status_data) - - def _parse_and_store_data_in_transaction(self, build_status_root, - build_status_data): - - encountered_revisions = set() - for revision_and_bot_name in build_status_data: - build_number_and_status = self.request.get(revision_and_bot_name) - - try: - (build_number, status) = _parse_status(build_number_and_status) - (revision, bot_name) = _parse_name(revision_and_bot_name) - except ValueError as error: - logging.warn('Invalid parameter in request: %s.' % error) - self.response.set_status(400) - return - - if revision not in encountered_revisions: - # There's new data on this revision in this update, so clear all status - # entries with that revision. Only do this once when we first encounter - # the revision. - _delete_all_with_revision(revision, build_status_root) - encountered_revisions.add(revision) - - # Finally, write the item. - item = BuildStatusData(parent=build_status_root, - bot_name=bot_name, - revision=revision, - build_number=build_number, - status=status) - item.put() - - request_posix_timestamp = float(self.request.get('oauth_timestamp')) - request_datetime = datetime.datetime.fromtimestamp(request_posix_timestamp) - build_status_root.last_updated_at = request_datetime - build_status_root.put() - diff --git a/tools/quality_tracking/dashboard/app.yaml b/tools/quality_tracking/dashboard/app.yaml index bc88559bc1..1d6169d908 100644 --- a/tools/quality_tracking/dashboard/app.yaml +++ b/tools/quality_tracking/dashboard/app.yaml @@ -5,13 +5,16 @@ api_version: 1 threadsafe: false handlers: -# Serve stylesheets statically. +# Serve stylesheets, perf dashboard, and images statically. - url: /stylesheets static_dir: stylesheets - -# Serve perf dashboard files statically. - url: /perf static_dir: static +- url: /images + static_dir: static +- url: /lkgr + static_files: static/lkgr_redirect.html + upload: static/lkgr_redirect.html # This magic file is here to prove to the Google Account Domain Management # that we own this domain. It needs to stay there so the domain management @@ -26,4 +29,4 @@ handlers: # Redirect all other requests to our dynamic handlers. - url: /.* - script: main.app \ No newline at end of file + script: main.app diff --git a/tools/quality_tracking/dashboard/dashboard.py b/tools/quality_tracking/dashboard/dashboard.py index da4d584e99..121009ccba 100644 --- a/tools/quality_tracking/dashboard/dashboard.py +++ b/tools/quality_tracking/dashboard/dashboard.py @@ -15,7 +15,6 @@ import math from google.appengine.ext.webapp import template import webapp2 -import load_build_status import load_coverage @@ -26,23 +25,6 @@ class ShowDashboard(webapp2.RequestHandler): in the App Engine database using the AddCoverageData handler. """ def get(self): - build_status_loader = load_build_status.BuildStatusLoader() - - # Split the build status data in two rows to fit them on the page. - # pylint: disable=W0612 - build_status_data = build_status_loader.load_build_status_data() - split_point = int(math.ceil(len(build_status_data) / 2.0)) - build_status_data_row_1 = build_status_data[:split_point] - build_status_data_row_2 = build_status_data[split_point:] - - last_updated_at = build_status_loader.load_last_modified_at() - if last_updated_at is None: - self._show_error_page("No data has yet been uploaded to the dashboard.") - return - - last_updated_at = last_updated_at.strftime("%Y-%m-%d %H:%M") - lkgr = build_status_loader.compute_lkgr() - coverage_loader = load_coverage.CoverageDataLoader() small_medium_coverage_json_data = ( coverage_loader.load_coverage_json_data('small_medium_tests')) diff --git a/tools/quality_tracking/dashboard/lkgr_page.py b/tools/quality_tracking/dashboard/lkgr_page.py deleted file mode 100644 index c0fa46d5d4..0000000000 --- a/tools/quality_tracking/dashboard/lkgr_page.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- -# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -"""Implements the LKGR page.""" - -import webapp2 - -import load_build_status - -class ShowLkgr(webapp2.RequestHandler): - """This handler shows the LKGR in the simplest possible way. - - The page is intended to be used by automated tools. - """ - def get(self): - build_status_loader = load_build_status.BuildStatusLoader() - - lkgr = build_status_loader.compute_lkgr() - if lkgr is None: - self.response.out.write('No data has been uploaded to the dashboard.') - else: - self.response.out.write(lkgr) diff --git a/tools/quality_tracking/dashboard/load_build_status.py b/tools/quality_tracking/dashboard/load_build_status.py deleted file mode 100644 index 5fe1de6f88..0000000000 --- a/tools/quality_tracking/dashboard/load_build_status.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- -# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -"""Loads build status data for the dashboard.""" - -from google.appengine.ext import db - - -def _status_not_ok(status): - return status not in ('OK', 'warnings') - - -def _all_ok(statuses): - return filter(_status_not_ok, statuses) == [] - - -def _get_first_entry(iterable): - if not iterable: - return None - for item in iterable: - return item - - -class BuildStatusLoader: - """ Loads various build status data from the database.""" - def __init__(self): - pass - - @staticmethod - def load_build_status_data(): - """Returns the latest conclusive build status for each bot. - - The statuses OK, failed and warnings are considered to be conclusive. - - The algorithm looks at the 100 most recent status entries, which should - give data on roughly the last five revisions if the number of bots stay - around 20 (The number 100 should be increased if the number of bots - increases significantly). This should give us enough data to get a - conclusive build status for all active bots. - - With this limit, the algorithm will adapt automatically if a bot is - decommissioned - it will eventually disappear. The limit should not be - too high either since we will perhaps remember offline bots too long, - which could be confusing. The algorithm also adapts automatically to new - bots - these show up immediately if they get a build status for a recent - revision. - - Returns: - A list of BuildStatusData entities with one entity per bot. - """ - - build_status_entries = db.GqlQuery('SELECT * ' - 'FROM BuildStatusData ' - 'ORDER BY revision DESC ' - 'LIMIT 100') - - bots_to_latest_conclusive_entry = dict() - for entry in build_status_entries: - if entry.status == 'building': - # The 'building' status it not conclusive, so discard this entry and - # pick up the entry for this bot on the next revision instead. That - # entry is guaranteed to have a status != 'building' since a bot cannot - # be building two revisions simultaneously. - continue - if bots_to_latest_conclusive_entry.has_key(entry.bot_name): - # We've already determined this bot's status. - continue - - bots_to_latest_conclusive_entry[entry.bot_name] = entry - - return bots_to_latest_conclusive_entry.values() - - @staticmethod - def load_last_modified_at(): - build_status_root = db.GqlQuery('SELECT * ' - 'FROM BuildStatusRoot').get() - if not build_status_root: - # Operating on completely empty database - return None - - return build_status_root.last_updated_at - - @staticmethod - def compute_lkgr(): - """ Finds the most recent revision for which all bots are green. - - Returns: - The last known good revision (as an integer) or None if there - is no green revision in the database. - - Implementation note: The data store fetches stuff as we go, so we won't - read in the whole status table unless the LKGR is right at the end or - we don't have a LKGR. Bots that are offline do not affect the LKGR - computation (e.g. they are not considered to be failed). - """ - build_status_entries = db.GqlQuery('SELECT * ' - 'FROM BuildStatusData ' - 'ORDER BY revision DESC ') - - first_entry = _get_first_entry(build_status_entries) - if first_entry is None: - # No entries => no LKGR - return None - - current_lkgr = first_entry.revision - statuses_for_current_lkgr = [first_entry.status] - - for entry in build_status_entries: - if current_lkgr == entry.revision: - statuses_for_current_lkgr.append(entry.status) - else: - # Starting on new revision, check previous revision. - if _all_ok(statuses_for_current_lkgr): - # All bots are green; LKGR found. - return current_lkgr - else: - # Not all bots are green, so start over on the next revision. - current_lkgr = entry.revision - statuses_for_current_lkgr = [entry.status] - - if _all_ok(statuses_for_current_lkgr): - # There was only one revision and it was OK. - return current_lkgr - - # There are no all-green revision in the database. - return None diff --git a/tools/quality_tracking/dashboard/main.py b/tools/quality_tracking/dashboard/main.py index b98465952f..8e181ac7b0 100644 --- a/tools/quality_tracking/dashboard/main.py +++ b/tools/quality_tracking/dashboard/main.py @@ -13,15 +13,10 @@ from google.appengine.ext.webapp import template import webapp2 -import add_build_status_data import add_coverage_data import dashboard -import lkgr_page app = webapp2.WSGIApplication([('/', dashboard.ShowDashboard), - ('/lkgr', lkgr_page.ShowLkgr), ('/add_coverage_data', - add_coverage_data.AddCoverageData), - ('/add_build_status_data', - add_build_status_data.AddBuildStatusData)], + add_coverage_data.AddCoverageData)], debug=True) \ No newline at end of file diff --git a/tools/quality_tracking/dashboard/static/index.html b/tools/quality_tracking/dashboard/static/index.html index 708966acd6..2b18c0eff1 100644 --- a/tools/quality_tracking/dashboard/static/index.html +++ b/tools/quality_tracking/dashboard/static/index.html @@ -1,13 +1,5 @@ - WebRTC Performance Metrics - + - -

WebRTC Performance Metrics

-

Video

-

Audio

-

Chrome Audio Path

-

vie_auto_test

- \ No newline at end of file diff --git a/tools/quality_tracking/dashboard/static/lkgr_redirect.html b/tools/quality_tracking/dashboard/static/lkgr_redirect.html new file mode 100644 index 0000000000..49a4733902 --- /dev/null +++ b/tools/quality_tracking/dashboard/static/lkgr_redirect.html @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/tools/quality_tracking/dashboard/static/webrtc_logo.png b/tools/quality_tracking/dashboard/static/webrtc_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ce5ece0774047bd5a093d469ddf850c611225e7c GIT binary patch literal 7460 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 iui{m_idXR};`nEp%u7#({p%9|0000 - WebRTC Coverage Dashboard + WebRTC Quality Dashboard @@ -62,49 +62,14 @@ -

WebRTC Quality Dashboard

-

Current Build Status

-
(as of {{ last_updated_at }} UTC)
- - - {% for entry in build_status_data_row_1 %} - - {% endfor %} - - - {% for entry in build_status_data_row_1 %} - - {% endfor %} - - - {% for entry in build_status_data_row_2 %} - - {% endfor %} - - - {% for entry in build_status_data_row_2 %} - - {% endfor %} - -
{{ entry.bot_name }}
- {{entry.status}} -
{{ entry.bot_name }}
- {{entry.status}} -
-

- -

Last Known Good Revision (LKGR)

-
- {% if lkgr %} - - {{ lkgr }} - {% else %} - ???? - {% endif %} -
- + +

Performance Metrics

+

Code Coverage History (Small / Medium Tests)

Code Coverage History (Large Tests)

diff --git a/tools/quality_tracking/tgrid_parser.py b/tools/quality_tracking/tgrid_parser.py deleted file mode 100644 index 63cc0b97bd..0000000000 --- a/tools/quality_tracking/tgrid_parser.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- -# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -"""Contains functions for parsing the build master's transposed grid page. - - Compatible with build bot 0.8.4 P1. -""" - -import re -import urllib - - -# This is here to work around a buggy build bot status message which makes no -# sense, but which means the build failed when the slave was lost. -BB_084_P1_BUGGY_STATUS = 'build
successful
exception
slave
lost' - - -class FailedToParseBuildStatus(Exception): - pass - - -def _map_status(status): - if status == 'exception' or status == BB_084_P1_BUGGY_STATUS: - return 'failed' - return status - - -def _parse_builds(revision, html): - """Parses the bot list, which is a sequence of lines. - - See contract for parse_tgrid_page for more information on how this function - behaves. - - Example input: - OK - The first regular expression group captures Android, second 119, third OK. - """ - result = {} - - for match in re.finditer('.*?' - '(OK|failed|building|warnings|exception|' + - BB_084_P1_BUGGY_STATUS + ')' - '.*?.*?', - html, re.DOTALL): - revision_and_bot_name = revision + "--" + urllib.unquote(match.group(1)) - build_number_and_status = match.group(2) + "--" + _map_status( - match.group(3)) - - result[revision_and_bot_name] = build_number_and_status - - return result - - -def parse_tgrid_page(html): - """Parses the build master's tgrid page. - - Example input: - - 1568 - LIST OF BOTS - - The first regular expression group captures 1568, second group captures - everything in LIST OF BOTS. The list of bots is then passed into a - separate function for parsing. - - Args: - html: The raw HTML from the tgrid page. - - Returns: A dictionary with -- mapped to - --, where status is either OK, failed, - building or warnings. The status may be 'exception' in the input, but - we simply map that to failed. - """ - result = {} - - for match in re.finditer('(\d+).*?(.*?)', - html, re.DOTALL): - revision = match.group(1) - builds_for_revision_html = match.group(2) - result.update(_parse_builds(revision, builds_for_revision_html)) - - if not result: - raise FailedToParseBuildStatus('Could not find any build statuses in %s.' % - html) - - return result diff --git a/tools/quality_tracking/tgrid_parser_test.py b/tools/quality_tracking/tgrid_parser_test.py deleted file mode 100755 index 98de03a3cb..0000000000 --- a/tools/quality_tracking/tgrid_parser_test.py +++ /dev/null @@ -1,601 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- -# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -"""Test the tgrid parser. - - Compatible with build bot 0.8.4 P1. -""" - -import unittest - -import tgrid_parser - - -SAMPLE_FILE = """ - - - - - - Buildbot - - - - - -
- -
-

Transposed Grid View

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
WebRTC - - - Android - AndroidNDK - Chrome - ChromeOS - Linux32DBG - Linux32Release - Linux64DBG - Linux64DBG-GCC4.6 - Linux64Release - LinuxClang - LinuxValgrind - LinuxVideoTest - MacOS32DBG - MacOS32Release
(building)
- Win32Debug - Win32Release
(building)
2006 - OK - - OK - - warnings - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK -   - OK -   - OK -  
2007 - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - failed
voe_auto_test
-
- OK - - OK - - OK - - OK -
2008 - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK -
2010 - OK - - OK -   - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK -
2011 - OK - - OK -   - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - OK - - building - - OK - - building -
latest - building - - OK -
- -
- - -""" - -MINIMAL_OK = """ - -1570 - -OK - -""" - -MINIMAL_FAIL = """ - -1573 - - failed
voe_auto_test -
- - -""" - -MINIMAL_BUILDING = """ - -1576 - -building -voe_auto_test - -""" - -MINIMAL_WARNED = """ - -1576 - -warnings
-make chrome - -""" - -MINIMAL_EXCEPTION = """ - -1576 - -exception
-Sync - -""" - -MINIMAL_EXCEPTION_SLAVE_LOST = """ - -1576 - - build
successful
exception
slave
lost
- - -""" - -MINIMAL_IN_TRUNK_SOURCESTAMP = """ - -1576 in trunk - - build
successful
exception
slave
lost
- - -""" - -class TGridParserTest(unittest.TestCase): - def test_parser_throws_exception_on_empty_html(self): - self.assertRaises(tgrid_parser.FailedToParseBuildStatus, - tgrid_parser.parse_tgrid_page, '') - - def test_parser_finds_successful_bot(self): - result = tgrid_parser.parse_tgrid_page(MINIMAL_OK) - - self.assertEqual(1, len(result), 'There is only one bot in the sample.') - first_mapping = result.items()[0] - - # Note: the parser should unescape % quotations, like %20 for space. - self.assertEqual('1570--Linux Clang [stable]', first_mapping[0]) - self.assertEqual('121--OK', first_mapping[1]) - - def test_parser_finds_failed_bot(self): - result = tgrid_parser.parse_tgrid_page(MINIMAL_FAIL) - - self.assertEqual(1, len(result), 'There is only one bot in the sample.') - first_mapping = result.items()[0] - - self.assertEqual('1573--Linux Large Tests', first_mapping[0]) - self.assertEqual('731--failed', first_mapping[1]) - - def test_parser_finds_building_bot(self): - result = tgrid_parser.parse_tgrid_page(MINIMAL_BUILDING) - - self.assertEqual(1, len(result), 'There is only one bot in the sample.') - first_mapping = result.items()[0] - - self.assertEqual('1576--Win32Debug', first_mapping[0]) - self.assertEqual('434--building', first_mapping[1]) - - def test_parser_finds_warnings(self): - result = tgrid_parser.parse_tgrid_page(MINIMAL_WARNED) - - self.assertEqual(1, len(result), 'There is only one bot in the sample.') - first_mapping = result.items()[0] - - self.assertEqual('1576--Chrome', first_mapping[0]) - self.assertEqual('109--warnings', first_mapping[1]) - - def test_parser_finds_exception_and_maps_to_failed(self): - result = tgrid_parser.parse_tgrid_page(MINIMAL_EXCEPTION) - - self.assertEqual(1, len(result), 'There is only one bot in the sample.') - first_mapping = result.items()[0] - - self.assertEqual('1576--Chrome', first_mapping[0]) - self.assertEqual('109--failed', first_mapping[1]) - - def test_parser_finds_exception_slave_lost_and_maps_to_failed(self): - # This is to work around a bug in build bot 0.8.4p1 where it may say that - # the build was successful AND the slave was lost. In this case the build - # is not actually successful, so treat it as such. - result = tgrid_parser.parse_tgrid_page(MINIMAL_EXCEPTION_SLAVE_LOST) - - self.assertEqual(1, len(result), 'There is only one bot in the sample.') - first_mapping = result.items()[0] - - self.assertEqual('1576--LinuxValgrind', first_mapping[0]) - self.assertEqual('324--failed', first_mapping[1]) - - def test_parser_finds_all_bots_and_revisions_except_forced_builds(self): - result = tgrid_parser.parse_tgrid_page(SAMPLE_FILE) - - # 5*16 = 80 bots in sample. There's also five empty results because some - # bots did not run for some revisions, so 80 - 5 = 75 results. There are - # two additional statuses under an explicit 'latest' revision, which should - # be ignored since that means the build was forced. - self.assertEqual(75, len(result)) - - # Make some samples - self.assertTrue(result.has_key('2006--ChromeOS')) - self.assertEquals('933--OK', result['2006--ChromeOS']) - - self.assertTrue(result.has_key('2006--Chrome')) - self.assertEquals('243--warnings', result['2006--Chrome']) - - self.assertTrue(result.has_key('2006--LinuxClang')) - self.assertEquals('610--OK', result['2006--LinuxClang']) - - # This one happened to not get reported in revision 2006, but it should be - # there in the next revision: - self.assertFalse(result.has_key('2006--Win32Release')) - self.assertTrue(result.has_key('2007--Win32Release')) - self.assertEquals('809--OK', result['2007--Win32Release']) - - self.assertTrue(result.has_key('2007--ChromeOS')) - self.assertEquals('934--OK', result['2007--ChromeOS']) - - self.assertTrue(result.has_key('2007--LinuxVideoTest')) - self.assertEquals('731--failed', result['2007--LinuxVideoTest']) - - self.assertTrue(result.has_key('2011--Win32Release')) - self.assertEquals('813--building', result['2011--Win32Release']) - - -if __name__ == '__main__': - unittest.main() diff --git a/tools/quality_tracking/track_build_status.py b/tools/quality_tracking/track_build_status.py deleted file mode 100755 index 3bc158a7c1..0000000000 --- a/tools/quality_tracking/track_build_status.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- -# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -"""This script checks the current build status on the master and submits - it to the dashboard. It is adapted to build bot version 0.7.12. -""" - -import httplib - -import constants -import dashboard_connection -import tgrid_parser - -# Bots that must be green in order to increment the LKGR revision. -# TODO(kjellander): Remake this entirely as we have now switched to Chrome infra -# bots. This is just to get the LGKR moving forward for now. -BOTS = ['Linux32 Debug Coverage', - 'Win Large Tests', - 'Mac Large Tests', - 'Linux Large Tests', - 'Android Platform', - 'Android NDK', - ] - - -class FailedToGetStatusFromMaster(Exception): - pass - - -def _download_and_parse_build_status(): - connection = httplib.HTTPConnection(constants.BUILD_MASTER_SERVER) - connection.request('GET', constants.BUILD_MASTER_TRANSPOSED_GRID_URL) - response = connection.getresponse() - - if response.status != 200: - raise FailedToGetStatusFromMaster(('Failed to get build status from master:' - ' got status %d, reason %s.' % - (response.status, response.reason))) - - full_response = response.read() - connection.close() - - return tgrid_parser.parse_tgrid_page(full_response) - - -def _is_chrome_only_build(revision_to_bot_name): - """Figures out if a revision-to-bot-name mapping represents a Chrome build. - - We assume here that Chrome revisions are always > 100000, whereas WebRTC - revisions will not reach that number in the foreseeable future. - """ - revision = int(revision_to_bot_name.split('--')[0]) - bot_name = revision_to_bot_name.split('--')[1] - return 'Chrome' in bot_name and revision > 100000 - - -def _filter_undesired_bots(bot_to_status_mapping, desired_bot_names): - """Returns the desired bots for the builds status from the dictionary. - - Args: - bot_to_status_mapping: Dictionary mapping bot name with revision to status. - desired_bot_names: List of bot names that will be the only bots returned in - the resulting dictionary. - Returns: A dictionary only containing the desired bots. - """ - result = {} - for revision_to_bot_name, status in bot_to_status_mapping.iteritems(): - bot_name = revision_to_bot_name.split('--')[1] - if bot_name in desired_bot_names: - result[revision_to_bot_name] = status - return result - - -def _main(): - dashboard = dashboard_connection.DashboardConnection(constants.CONSUMER_KEY) - dashboard.read_required_files(constants.CONSUMER_SECRET_FILE, - constants.ACCESS_TOKEN_FILE) - - bot_to_status_mapping = _download_and_parse_build_status() - bot_to_status_mapping = _filter_undesired_bots(bot_to_status_mapping, BOTS) - - dashboard.send_post_request(constants.ADD_BUILD_STATUS_DATA_URL, - bot_to_status_mapping) - - -if __name__ == '__main__': - _main() diff --git a/tools/quality_tracking/track_build_status_test.py b/tools/quality_tracking/track_build_status_test.py deleted file mode 100755 index 9a9844ce9d..0000000000 --- a/tools/quality_tracking/track_build_status_test.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- -# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. -# -# Use of this source code is governed by a BSD-style license -# that can be found in the LICENSE file in the root of the source -# tree. An additional intellectual property rights grant can be found -# in the file PATENTS. All contributing project authors may -# be found in the AUTHORS file in the root of the source tree. - -"""Unit test for the build status tracker script.""" - - -import copy -import unittest - -import track_build_status - - -NORMAL_BOT_TO_STATUS_MAPPING = { - '1455--Win 64 Release': '455--OK', - '1455--CrOS': '900--failed', - '1455--Linux32 Debug': '344--OK', - '1456--Win Large Tests': '456--OK'} - - -class TrackBuildStatusTest(unittest.TestCase): - - def test_get_desired_bots(self): - bot_to_status_mapping = copy.deepcopy(NORMAL_BOT_TO_STATUS_MAPPING) - desired_bot_names = ['Linux32 Debug'] - # pylint: disable=W0212 - result = track_build_status._filter_undesired_bots(bot_to_status_mapping, - desired_bot_names) - self.assertEquals(1, len(result)) - self.assertTrue(desired_bot_names[0] in result.keys()[0]) - -if __name__ == '__main__': - unittest.main()