BUG= Review URL: https://webrtc-codereview.appspot.com/1166004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3627 4adac7df-926f-26a2-2b94-8c16560cd09d
		
			
				
	
	
		
			158 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/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 grabs and reports coverage information.
 | 
						|
 | 
						|
   It grabs coverage information from the latest Linux 32-bit build and
 | 
						|
   pushes it to the coverage tracker, enabling us to track code coverage
 | 
						|
   over time. This script is intended to run on the 32-bit Linux slave.
 | 
						|
 | 
						|
   This script requires an access.token file in the current directory, as
 | 
						|
   generated by the request_oauth_permission.py script. It also expects a file
 | 
						|
   customer.secret with a single line containing the customer secret. The
 | 
						|
   customer secret is an OAuth concept and is received when one registers the
 | 
						|
   application with the App Engine running the dashboard.
 | 
						|
 | 
						|
   The script assumes that all coverage data is stored under
 | 
						|
   /home/<build bot user>/www.
 | 
						|
"""
 | 
						|
 | 
						|
import os
 | 
						|
import re
 | 
						|
import sys
 | 
						|
 | 
						|
import constants
 | 
						|
import dashboard_connection
 | 
						|
 | 
						|
 | 
						|
class FailedToParseCoverageHtml(Exception):
 | 
						|
  pass
 | 
						|
 | 
						|
 | 
						|
class CouldNotFindCoverageDirectory(Exception):
 | 
						|
  pass
 | 
						|
 | 
						|
 | 
						|
def _find_latest_build_coverage(www_directory_contents, coverage_www_dir,
 | 
						|
                                directory_prefix):
 | 
						|
  """Finds the most recent coverage directory in the directory listing.
 | 
						|
 | 
						|
     We assume here that build numbers keep rising and never wrap around.
 | 
						|
 | 
						|
     Args:
 | 
						|
       www_directory_contents: A list of entries in the coverage directory.
 | 
						|
       coverage_www_dir: The coverage directory on the bot.
 | 
						|
       directory_prefix: Coverage directories have the form <prefix><number>,
 | 
						|
           and the prefix is different on different bots. The prefix is
 | 
						|
           generally the builder name, such as Linux32DBG.
 | 
						|
 | 
						|
     Returns:
 | 
						|
       The most recent directory name.
 | 
						|
 | 
						|
     Raises:
 | 
						|
       CouldNotFindCoverageDirectory: if we failed to find coverage data.
 | 
						|
  """
 | 
						|
 | 
						|
  found_build_numbers = []
 | 
						|
  for entry in www_directory_contents:
 | 
						|
    match = re.match(directory_prefix + '(\d+)', entry)
 | 
						|
    if match is not None:
 | 
						|
      found_build_numbers.append(int(match.group(1)))
 | 
						|
 | 
						|
  if not found_build_numbers:
 | 
						|
    raise CouldNotFindCoverageDirectory('Error: Found no directories %s* '
 | 
						|
                                        'in directory %s.' %
 | 
						|
                                         (directory_prefix, coverage_www_dir))
 | 
						|
 | 
						|
  most_recent = max(found_build_numbers)
 | 
						|
  return directory_prefix + str(most_recent)
 | 
						|
 | 
						|
 | 
						|
def _grab_coverage_percentage(label, index_html_contents):
 | 
						|
  """Extracts coverage from a LCOV coverage report.
 | 
						|
 | 
						|
     Grabs coverage by assuming that the label in the coverage HTML report
 | 
						|
     is close to the actual number and that the number is followed by a space
 | 
						|
     and a percentage sign.
 | 
						|
  """
 | 
						|
  match = re.search('<td[^>]*>' + label + '</td>.*?(\d+\.\d) %',
 | 
						|
                    index_html_contents, re.DOTALL)
 | 
						|
  if match is None:
 | 
						|
    raise FailedToParseCoverageHtml('Missing coverage at label "%s".' % label)
 | 
						|
 | 
						|
  try:
 | 
						|
    return float(match.group(1))
 | 
						|
  except ValueError:
 | 
						|
    raise FailedToParseCoverageHtml('%s is not a float.' % match.group(1))
 | 
						|
 | 
						|
 | 
						|
def _report_coverage_to_dashboard(dashboard, line_coverage, function_coverage,
 | 
						|
                                  branch_coverage, report_category):
 | 
						|
  parameters = {'line_coverage': '%f' % line_coverage,
 | 
						|
                'function_coverage': '%f' % function_coverage,
 | 
						|
                'branch_coverage': '%f' % branch_coverage,
 | 
						|
                'report_category': report_category,
 | 
						|
               }
 | 
						|
 | 
						|
  dashboard.send_post_request(constants.ADD_COVERAGE_DATA_URL, parameters)
 | 
						|
 | 
						|
 | 
						|
def _main(report_category, directory_prefix):
 | 
						|
  """Grabs coverage data from disk on a bot and publishes it.
 | 
						|
 | 
						|
     Args:
 | 
						|
       report_category: The kind of coverage to report. The dashboard
 | 
						|
           application decides what is acceptable here (see
 | 
						|
           dashboard/add_coverage_data.py for more information).
 | 
						|
      directory_prefix: This bot's coverage directory prefix. Generally a bot's
 | 
						|
          coverage directories will have the form <prefix><build number>,
 | 
						|
          like Linux32DBG_345.
 | 
						|
  """
 | 
						|
  dashboard = dashboard_connection.DashboardConnection(constants.CONSUMER_KEY)
 | 
						|
  dashboard.read_required_files(constants.CONSUMER_SECRET_FILE,
 | 
						|
                                constants.ACCESS_TOKEN_FILE)
 | 
						|
 | 
						|
  coverage_www_dir = constants.BUILD_BOT_COVERAGE_WWW_DIRECTORY
 | 
						|
  www_dir_contents = os.listdir(coverage_www_dir)
 | 
						|
  latest_build_directory = _find_latest_build_coverage(www_dir_contents,
 | 
						|
                                                       coverage_www_dir,
 | 
						|
                                                       directory_prefix)
 | 
						|
 | 
						|
  index_html_path = os.path.join(coverage_www_dir, latest_build_directory,
 | 
						|
                                 'index.html')
 | 
						|
  index_html_file = open(index_html_path)
 | 
						|
  whole_file = index_html_file.read()
 | 
						|
 | 
						|
  line_coverage = _grab_coverage_percentage('Lines:', whole_file)
 | 
						|
  function_coverage = _grab_coverage_percentage('Functions:', whole_file)
 | 
						|
  branch_coverage = _grab_coverage_percentage('Branches:', whole_file)
 | 
						|
 | 
						|
  _report_coverage_to_dashboard(dashboard, line_coverage, function_coverage,
 | 
						|
      branch_coverage, report_category)
 | 
						|
 | 
						|
 | 
						|
def _parse_args():
 | 
						|
  if len(sys.argv) != 3:
 | 
						|
    print ('Usage: %s <coverage category> <directory prefix>\n\n'
 | 
						|
           'The coverage category describes the kind of coverage you are '
 | 
						|
           'uploading. Known acceptable values are small_medium_tests and'
 | 
						|
           'large_tests. The directory prefix is what the directories in %s '
 | 
						|
           'are prefixed on this bot (such as Linux32DBG_).' %
 | 
						|
               (sys.argv[0], constants.BUILD_BOT_COVERAGE_WWW_DIRECTORY))
 | 
						|
    return (None, None)
 | 
						|
  return (sys.argv[1], sys.argv[2])
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
  category, dir_prefix = _parse_args()
 | 
						|
  if category:
 | 
						|
    _main(category, dir_prefix)
 | 
						|
 |