| #!/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. |
| """ |
| |
| __author__ = 'phoglund@webrtc.org (Patrik Höglund)' |
| |
| import httplib |
| import os |
| import re |
| import sys |
| import time |
| |
| # The build-bot user which runs build bot jobs. |
| BUILD_BOT_USER = 'phoglund' |
| |
| # The server to send coverage data to. |
| # TODO(phoglund): replace with real server once we get it up. |
| DASHBOARD_SERVER = 'localhost:8080' |
| |
| |
| class FailedToParseCoverageHtml(Exception): |
| pass |
| |
| |
| class FailedToReportToDashboard(Exception): |
| pass |
| |
| |
| def _find_latest_32bit_debug_build(www_directory_contents): |
| # Build directories have the form Linux32bitDebug_<number>. There may be other |
| # directories in the list though, for instance for other build configurations. |
| # This sort ensures we will encounter the directory with the highest number |
| # first. |
| www_directory_contents.sort(reverse=True) |
| |
| for entry in www_directory_contents: |
| match = re.match('Linux32bitDBG_\d+', entry) |
| if match is not None: |
| return entry |
| |
| # Didn't find it |
| return None |
| |
| |
| 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(now, line_coverage, function_coverage): |
| request_string = ('/add_coverage_data?' |
| 'date=%d&line_coverage=%f&function_coverage=%f' % |
| (now, line_coverage, function_coverage)) |
| |
| connection = httplib.HTTPConnection(DASHBOARD_SERVER) |
| connection.request('GET', request_string) |
| response = connection.getresponse() |
| if response.status != 200: |
| message = ('Error: Failed to report to %s%s: got response %d (%s)' % |
| (DASHBOARD_SERVER, request_string, response.status, |
| response.reason)) |
| raise FailedToReportToDashboard(message) |
| |
| # The response content should be empty on success, so check that: |
| response_content = response.read() |
| if response_content: |
| message = ('Error: Dashboard reported the following error: %s.' % |
| response_content) |
| raise FailedToReportToDashboard(message) |
| |
| |
| def _main(): |
| coverage_www_dir = os.path.join('/home', BUILD_BOT_USER, 'www') |
| |
| www_dir_contents = os.listdir(coverage_www_dir) |
| latest_build_directory = _find_latest_32bit_debug_build(www_dir_contents) |
| |
| if latest_build_directory is None: |
| print 'Error: Found no 32-bit debug build in directory ' + coverage_www_dir |
| sys.exit(1) |
| |
| 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) |
| now = int(time.time()) |
| |
| _report_coverage_to_dashboard(now, line_coverage, function_coverage) |
| |
| if __name__ == '__main__': |
| _main() |
| |