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
This commit is contained in:
		| @@ -23,13 +23,8 @@ REQUEST_TOKEN_URL = DASHBOARD_SERVER_HTTP + '/_ah/OAuthGetRequestToken' | |||||||
| AUTHORIZE_TOKEN_URL = DASHBOARD_SERVER_HTTP + '/_ah/OAuthAuthorizeToken' | AUTHORIZE_TOKEN_URL = DASHBOARD_SERVER_HTTP + '/_ah/OAuthAuthorizeToken' | ||||||
| ACCESS_TOKEN_URL = DASHBOARD_SERVER_HTTP + '/_ah/OAuthGetAccessToken' | 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 constants. | ||||||
| BUILD_BOT_COVERAGE_WWW_DIRECTORY = '/var/www/coverage' | BUILD_BOT_COVERAGE_WWW_DIRECTORY = '/var/www/coverage' | ||||||
|  |  | ||||||
| # Dashboard data input URLs. | # Dashboard data input URLs. | ||||||
| ADD_COVERAGE_DATA_URL = DASHBOARD_SERVER_HTTP + '/add_coverage_data' | ADD_COVERAGE_DATA_URL = DASHBOARD_SERVER_HTTP + '/add_coverage_data' | ||||||
| ADD_BUILD_STATUS_DATA_URL = DASHBOARD_SERVER_HTTP + '/add_build_status_data' |  | ||||||
|   | |||||||
| @@ -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 <revision>--<bot name>, for instance |  | ||||||
|         1568--Win32Release. |  | ||||||
|      2) The value should be on the form <build number>--<status>, 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() |  | ||||||
|  |  | ||||||
| @@ -5,13 +5,16 @@ api_version: 1 | |||||||
| threadsafe: false | threadsafe: false | ||||||
|  |  | ||||||
| handlers: | handlers: | ||||||
| # Serve stylesheets statically. | # Serve stylesheets, perf dashboard, and images statically. | ||||||
| - url: /stylesheets | - url: /stylesheets | ||||||
|   static_dir: stylesheets |   static_dir: stylesheets | ||||||
|  |  | ||||||
| # Serve perf dashboard files statically. |  | ||||||
| - url: /perf | - url: /perf | ||||||
|   static_dir: static |   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 | # 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 | # 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. | # Redirect all other requests to our dynamic handlers. | ||||||
| - url: /.* | - url: /.* | ||||||
|   script: main.app |   script: main.app | ||||||
|   | |||||||
| @@ -15,7 +15,6 @@ import math | |||||||
| from google.appengine.ext.webapp import template | from google.appengine.ext.webapp import template | ||||||
| import webapp2 | import webapp2 | ||||||
|  |  | ||||||
| import load_build_status |  | ||||||
| import load_coverage | import load_coverage | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -26,23 +25,6 @@ class ShowDashboard(webapp2.RequestHandler): | |||||||
|      in the App Engine database using the AddCoverageData handler. |      in the App Engine database using the AddCoverageData handler. | ||||||
|   """ |   """ | ||||||
|   def get(self): |   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() |     coverage_loader = load_coverage.CoverageDataLoader() | ||||||
|     small_medium_coverage_json_data = ( |     small_medium_coverage_json_data = ( | ||||||
|         coverage_loader.load_coverage_json_data('small_medium_tests')) |         coverage_loader.load_coverage_json_data('small_medium_tests')) | ||||||
|   | |||||||
| @@ -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) |  | ||||||
| @@ -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 |  | ||||||
| @@ -13,15 +13,10 @@ | |||||||
| from google.appengine.ext.webapp import template | from google.appengine.ext.webapp import template | ||||||
| import webapp2 | import webapp2 | ||||||
|  |  | ||||||
| import add_build_status_data |  | ||||||
| import add_coverage_data | import add_coverage_data | ||||||
| import dashboard | import dashboard | ||||||
| import lkgr_page |  | ||||||
|  |  | ||||||
| app = webapp2.WSGIApplication([('/', dashboard.ShowDashboard), | app = webapp2.WSGIApplication([('/', dashboard.ShowDashboard), | ||||||
|                                ('/lkgr', lkgr_page.ShowLkgr), |  | ||||||
|                                ('/add_coverage_data', |                                ('/add_coverage_data', | ||||||
|                                 add_coverage_data.AddCoverageData), |                                 add_coverage_data.AddCoverageData)], | ||||||
|                                ('/add_build_status_data', |  | ||||||
|                                 add_build_status_data.AddBuildStatusData)], |  | ||||||
|                               debug=True) |                               debug=True) | ||||||
| @@ -1,13 +1,5 @@ | |||||||
| <html> | <html> | ||||||
| <head> | <head> | ||||||
|   <title>WebRTC Performance Metrics</title> |   <meta HTTP-EQUIV="REFRESH" content="0; url=/"> | ||||||
|   <link rel="stylesheet" href="../stylesheets/perf.css" type="text/css"> |  | ||||||
| </head> | </head> | ||||||
| <body> |  | ||||||
|   <h1>WebRTC Performance Metrics</h1> |  | ||||||
|   <p><a href="video_perf.html">Video</a></p> |  | ||||||
|   <p><a href="audio_perf.html">Audio</a></p> |  | ||||||
|   <p><a href="audio_perf_chrome.html">Chrome Audio Path</a></p> |  | ||||||
|   <p><a href="vie_auto_test_perf.html">vie_auto_test</a></p> |  | ||||||
| </body> |  | ||||||
| </html> | </html> | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | <html> | ||||||
|  | <head> | ||||||
|  |   <meta HTTP-EQUIV="REFRESH" | ||||||
|  |       content="0; url=http://webrtc-status.appspot.com/lkgr"> | ||||||
|  | </head> | ||||||
|  | </html> | ||||||
							
								
								
									
										
											BIN
										
									
								
								tools/quality_tracking/dashboard/static/webrtc_logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tools/quality_tracking/dashboard/static/webrtc_logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 7.3 KiB | 
| @@ -30,8 +30,9 @@ | |||||||
|   background-color: #FFC343; |   background-color: #FFC343; | ||||||
| } | } | ||||||
|  |  | ||||||
| .last_known_good_revision { | .perf_links { | ||||||
|   font-size: 800%; |   margin-bottom: 50px; | ||||||
|  |   font-size: 200%; | ||||||
| } | } | ||||||
|  |  | ||||||
| .status_cell { | .status_cell { | ||||||
| @@ -42,4 +43,4 @@ | |||||||
| body { | body { | ||||||
|   margin-left: 35px; |   margin-left: 35px; | ||||||
|   margin-top: 25px; |   margin-top: 25px; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ | |||||||
|   Template file to be used to generate the WebRTC dashboard. |   Template file to be used to generate the WebRTC dashboard. | ||||||
|   --> |   --> | ||||||
|   <head> |   <head> | ||||||
|     <title>WebRTC Coverage Dashboard</title> |     <title>WebRTC Quality Dashboard</title> | ||||||
|     <meta http-equiv="refresh" content="60"> |     <meta http-equiv="refresh" content="60"> | ||||||
|     <link href="http://code.google.com/css/codesite.pack.04102009.css" |     <link href="http://code.google.com/css/codesite.pack.04102009.css" | ||||||
|           rel="stylesheet" type="text/css"> |           rel="stylesheet" type="text/css"> | ||||||
| @@ -62,49 +62,14 @@ | |||||||
|     </script> |     </script> | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
|     <h1>WebRTC Quality Dashboard</h1> |     <img src="images/webrtc_logo.png"> | ||||||
|     <h2>Current Build Status</h2> |     <h1>Performance Metrics</h1> | ||||||
|     <div>(as of {{ last_updated_at }} UTC)</div> |     <p class="perf_links"> | ||||||
|     <table> |       <a href="perf/video_perf.html">Chrome Video Quality</a> | | ||||||
|       <tr> |       <a href="perf/audio_perf.html">Chrome Audio / Voice Engine Quality</a> | | ||||||
|       {% for entry in build_status_data_row_1 %} |       <a href="perf/audio_perf_chrome.html">Chrome Audio Latency</a> | | ||||||
|         <th class="status_cell">{{ entry.bot_name }}</th> |       <a href="perf/vie_auto_test_perf.html">Video Engine</a> | ||||||
|       {% endfor %} |     </p> | ||||||
|       </tr> |  | ||||||
|       <tr> |  | ||||||
|       {% for entry in build_status_data_row_1 %} |  | ||||||
|         <td title="Last built revision {{ entry.revision }}" |  | ||||||
|             class="status_cell status_{{entry.status}}"> |  | ||||||
|           {{entry.status}} |  | ||||||
|         </td> |  | ||||||
|       {% endfor %} |  | ||||||
|       </tr> |  | ||||||
|       <tr> |  | ||||||
|       {% for entry in build_status_data_row_2 %} |  | ||||||
|         <th class="status_cell">{{ entry.bot_name }}</th> |  | ||||||
|       {% endfor %} |  | ||||||
|       </tr> |  | ||||||
|       <tr> |  | ||||||
|       {% for entry in build_status_data_row_2 %} |  | ||||||
|         <td title="Last built revision {{ entry.revision }}" |  | ||||||
|             class="status_cell status_{{entry.status}}"> |  | ||||||
|           {{entry.status}} |  | ||||||
|         </td> |  | ||||||
|       {% endfor %} |  | ||||||
|       </tr> |  | ||||||
|     </table> |  | ||||||
|     <p></p> |  | ||||||
|  |  | ||||||
|     <h2>Last Known Good Revision (LKGR)</h2> |  | ||||||
|     <div class="last_known_good_revision"> |  | ||||||
|       {% if lkgr  %} |  | ||||||
|         <a href="http://code.google.com/p/webrtc/source/detail?r={{ lkgr }}"> |  | ||||||
|           {{ lkgr }}</a> |  | ||||||
|       {% else %} |  | ||||||
|         ???? |  | ||||||
|       {% endif %} |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <h2>Code Coverage History (Small / Medium Tests)</h2> |     <h2>Code Coverage History (Small / Medium Tests)</h2> | ||||||
|     <div id="table_div_small_medium_coverage"></div> |     <div id="table_div_small_medium_coverage"></div> | ||||||
|     <h2>Code Coverage History (Large Tests)</h2> |     <h2>Code Coverage History (Large Tests)</h2> | ||||||
|   | |||||||
| @@ -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<br/>successful<br/>exception<br/>slave<br/>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 <td></td> lines. |  | ||||||
|  |  | ||||||
|      See contract for parse_tgrid_page for more information on how this function |  | ||||||
|      behaves. |  | ||||||
|  |  | ||||||
|      Example input: |  | ||||||
|      <td class="build success"><a href="builders/Android/builds/119">OK</a></td> |  | ||||||
|      The first regular expression group captures Android, second 119, third OK. |  | ||||||
|   """ |  | ||||||
|   result = {} |  | ||||||
|  |  | ||||||
|   for match in re.finditer('<td.*?>.*?<a href="builders/(.+?)/builds/(\d+)">' |  | ||||||
|                            '(OK|failed|building|warnings|exception|' + |  | ||||||
|                            BB_084_P1_BUGGY_STATUS + ')' |  | ||||||
|                            '.*?</a>.*?</td>', |  | ||||||
|                            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: |  | ||||||
|      <tr> |  | ||||||
|        <td valign="bottom" class="sourcestamp">1568</td> |  | ||||||
|        LIST OF BOTS |  | ||||||
|      </tr> |  | ||||||
|      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 <svn revision>--<bot name> mapped to |  | ||||||
|          <bot build number>--<status>, 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('<td.*?class="sourcestamp">(\d+).*?</td>(.*?)</tr>', |  | ||||||
|                            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 |  | ||||||
| @@ -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 = """ |  | ||||||
|  |  | ||||||
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |  | ||||||
|   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |  | ||||||
| <html xmlns="http://www.w3.org/1999/xhtml"> |  | ||||||
|   <head> |  | ||||||
|         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |  | ||||||
|             <title>Buildbot</title> |  | ||||||
|     <link rel="stylesheet" href="default.css" type="text/css" /> |  | ||||||
|     <link rel="alternate" type="application/rss+xml" title="RSS" href="rss"> |  | ||||||
|       </head> |  | ||||||
|   <body class="interface"> |  | ||||||
|     <div class="header"> |  | ||||||
|         <a href=".">Home</a> |  | ||||||
|         - <a href="waterfall">Waterfall</a> |  | ||||||
|         <a href="grid">Grid</a> |  | ||||||
|         <a href="tgrid">T-Grid</a> |  | ||||||
|         <a href="console">Console</a> |  | ||||||
|         <a href="builders">Builders</a> |  | ||||||
|         <a href="one_line_per_build">Recent Builds</a> |  | ||||||
|         <a href="buildslaves">Buildslaves</a> |  | ||||||
|         <a href="changes">Changesources</a> |  | ||||||
|         - <a href="json/help">JSON API</a> |  | ||||||
|         - <a href="about">About</a> |  | ||||||
|     </div> |  | ||||||
|     <hr/> |  | ||||||
|  |  | ||||||
|     <div class="content"> |  | ||||||
| <h1>Transposed Grid View</h1> |  | ||||||
|  |  | ||||||
| <table class="Grid" border="0" cellspacing="0"> |  | ||||||
|  |  | ||||||
| <tr> |  | ||||||
|  <td class="title"><a href="http://www.chromium.org">WebRTC</a> |  | ||||||
|  |  | ||||||
|  </td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/Android">Android</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/AndroidNDK">AndroidNDK</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/Chrome">Chrome</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/ChromeOS">ChromeOS</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/Linux32DBG">Linux32DBG</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/Linux32Release">Linux32Release</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/Linux64DBG">Linux64DBG</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/Linux64DBG-GCC4.6">Linux64DBG-GCC4.6</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/Linux64Release">Linux64Release</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/LinuxClang">LinuxClang</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/LinuxValgrind">LinuxValgrind</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/LinuxVideoTest">LinuxVideoTest</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/MacOS32DBG">MacOS32DBG</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder building"> |  | ||||||
|     <a href="builders/MacOS32Release">MacOS32Release</a><br/>(building)</td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder idle"> |  | ||||||
|     <a href="builders/Win32Debug">Win32Debug</a></td> |  | ||||||
|    <td valign="middle" style="text-align: center" class="builder building"> |  | ||||||
|     <a href="builders/Win32Release">Win32Release</a><br/>(building)</td> |  | ||||||
|  </tr> |  | ||||||
|  |  | ||||||
|  <tr> |  | ||||||
|  <td valign="bottom" class="sourcestamp">2006  </td> |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Android/builds/482">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/AndroidNDK/builds/70">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Chrome/builds/243">warnings</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/ChromeOS/builds/933">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32DBG/builds/936">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32Release/builds/1050">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG/builds/1038">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG-GCC4.6/builds/371">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64Release/builds/936">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxClang/builds/610">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxValgrind/builds/317">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build"> </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/MacOS32DBG/builds/1052">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build"> </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Win32Debug/builds/822">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build"> </td> |  | ||||||
|  |  | ||||||
|   </tr> |  | ||||||
|  <tr> |  | ||||||
|  <td valign="bottom" class="sourcestamp">2007  </td> |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Android/builds/483">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/AndroidNDK/builds/71">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Chrome/builds/244">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/ChromeOS/builds/934">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32DBG/builds/937">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32Release/builds/1051">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG/builds/1039">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG-GCC4.6/builds/372">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64Release/builds/937">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxClang/builds/611">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxValgrind/builds/318">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build failure"> |  | ||||||
|     <a href="builders/LinuxVideoTest/builds/731">failed<br/>voe_auto_test</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/MacOS32DBG/builds/1053">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/MacOS32Release/builds/309">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Win32Debug/builds/823">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Win32Release/builds/809">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|   </tr> |  | ||||||
|  <tr> |  | ||||||
|  <td valign="bottom" class="sourcestamp">2008  </td> |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Android/builds/484">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/AndroidNDK/builds/72">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Chrome/builds/245">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/ChromeOS/builds/935">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32DBG/builds/938">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32Release/builds/1052">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG/builds/1040">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG-GCC4.6/builds/373">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64Release/builds/938">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxClang/builds/612">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxValgrind/builds/319">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxVideoTest/builds/732">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/MacOS32DBG/builds/1054">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/MacOS32Release/builds/310">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Win32Debug/builds/824">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Win32Release/builds/810">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|   </tr> |  | ||||||
|  <tr> |  | ||||||
|  <td valign="bottom" class="sourcestamp">2010  </td> |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Android/builds/485">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/AndroidNDK/builds/73">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build"> </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/ChromeOS/builds/936">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32DBG/builds/939">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32Release/builds/1053">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG/builds/1041">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG-GCC4.6/builds/374">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64Release/builds/939">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxClang/builds/613">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxValgrind/builds/320">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxVideoTest/builds/733">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/MacOS32DBG/builds/1055">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/MacOS32Release/builds/311">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Win32Debug/builds/825">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Win32Release/builds/811">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|   </tr> |  | ||||||
|  <tr> |  | ||||||
|  <td valign="bottom" class="sourcestamp">2011  </td> |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Android/builds/486">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/AndroidNDK/builds/74">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build"> </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/ChromeOS/builds/937">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32DBG/builds/940">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux32Release/builds/1054">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG/builds/1042">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64DBG-GCC4.6/builds/375">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Linux64Release/builds/940">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxClang/builds/614">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxValgrind/builds/321">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/LinuxVideoTest/builds/734">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/MacOS32DBG/builds/1056">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build running"> |  | ||||||
|     <a href="builders/MacOS32Release/builds/313">building</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Win32Debug/builds/826">OK</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build running"> |  | ||||||
|     <a href="builders/Win32Release/builds/813">building</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|   </tr> |  | ||||||
|   <tr> |  | ||||||
|     <td valign="bottom" class="sourcestamp">latest  </td> |  | ||||||
|       <td class="build running"> |  | ||||||
|     <a href="builders/MacOS32Release/builds/313">building</a> |  | ||||||
|   </td> |  | ||||||
|  |  | ||||||
|       <td class="build success"> |  | ||||||
|     <a href="builders/Win32Debug/builds/826">OK</a> |  | ||||||
|   </td> |  | ||||||
|   </tr> |  | ||||||
| </table> |  | ||||||
|  |  | ||||||
| </div><div class="footer" style="clear:both"> |  | ||||||
|       <hr/> |  | ||||||
|       <a href="http://buildbot.net/">BuildBot</a> (0.8.4p1) |  | ||||||
|       working for the <a href="http://www.chromium.org">WebRTC |  | ||||||
|         </a> project.<br/> |  | ||||||
|       Page built: <b>Thu 12 Apr 2012 03:49:32</b> (CDT) |  | ||||||
|     </div> |  | ||||||
|     </body> |  | ||||||
| </html> |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| MINIMAL_OK = """ |  | ||||||
| <tr> |  | ||||||
| <td valign="bottom" class="sourcestamp">1570  </td> |  | ||||||
| <td class="build success"> |  | ||||||
| <a href="builders/Linux%20Clang%20%5Bstable%5D/builds/121">OK</a></td> |  | ||||||
| </tr> |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| MINIMAL_FAIL = """ |  | ||||||
| <tr> |  | ||||||
| <td valign="bottom" class="sourcestamp">1573  </td> |  | ||||||
| <td class="build failure"> |  | ||||||
|   <a href="builders/Linux%20Large%20Tests/builds/731">failed<br/>voe_auto_test |  | ||||||
|   </a> |  | ||||||
| </td> |  | ||||||
| </tr> |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| MINIMAL_BUILDING = """ |  | ||||||
| <tr> |  | ||||||
| <td valign="bottom" class="sourcestamp">1576  </td> |  | ||||||
| <td class="build running"> |  | ||||||
| <a href="builders/Win32Debug/builds/434">building</a></td> |  | ||||||
| voe_auto_test</td> |  | ||||||
| </tr> |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| MINIMAL_WARNED = """ |  | ||||||
| <tr> |  | ||||||
| <td valign="bottom" class="sourcestamp">1576  </td> |  | ||||||
| <td class="build warnings"> |  | ||||||
| <a href="builders/Chrome/builds/109">warnings</a><br /> |  | ||||||
| make chrome</td> |  | ||||||
| </tr> |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| MINIMAL_EXCEPTION = """ |  | ||||||
| <tr> |  | ||||||
| <td valign="bottom" class="sourcestamp">1576  </td> |  | ||||||
| <td class="build exception"> |  | ||||||
| <a href="builders/Chrome/builds/109">exception</a><br /> |  | ||||||
| Sync</td> |  | ||||||
| </tr> |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| MINIMAL_EXCEPTION_SLAVE_LOST = """ |  | ||||||
| <tr> |  | ||||||
| <td valign="bottom" class="sourcestamp">1576  </td> |  | ||||||
| <td class="build retry"> |  | ||||||
|   <a href="builders/LinuxValgrind/builds/324">build<br/>successful<br/>exception<br/>slave<br/>lost</a> |  | ||||||
| </td> |  | ||||||
| </tr> |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| MINIMAL_IN_TRUNK_SOURCESTAMP = """ |  | ||||||
| <tr> |  | ||||||
| <td valign="bottom" class="sourcestamp">1576 in trunk </td> |  | ||||||
| <td class="build retry"> |  | ||||||
|   <a href="builders/LinuxValgrind/builds/324">build<br/>successful<br/>exception<br/>slave<br/>lost</a> |  | ||||||
| </td> |  | ||||||
| </tr> |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| 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() |  | ||||||
| @@ -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() |  | ||||||
| @@ -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() |  | ||||||
		Reference in New Issue
	
	Block a user
	 phoglund@webrtc.org
					phoglund@webrtc.org