blob: 6f9754a693f5335192d0df2af29faef81105b82a [file] [log] [blame]
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +00001#!/usr/bin/env python
2#-*- coding: utf-8 -*-
3# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
4#
5# Use of this source code is governed by a BSD-style license
6# that can be found in the LICENSE file in the root of the source
7# tree. An additional intellectual property rights grant can be found
8# in the file PATENTS. All contributing project authors may
9# be found in the AUTHORS file in the root of the source tree.
10
11"""This script grabs and reports coverage information.
12
13 It grabs coverage information from the latest Linux 32-bit build and
14 pushes it to the coverage tracker, enabling us to track code coverage
15 over time. This script is intended to run on the 32-bit Linux slave.
16
17 This script requires an access.token file in the current directory, as
18 generated by the request_oauth_permission.py script. It also expects a file
19 customer.secret with a single line containing the customer secret. The
20 customer secret is an OAuth concept and is received when one registers the
21 application with the App Engine running the dashboard.
22
23 The script assumes that all coverage data is stored under
24 /home/<build bot user>/www.
25"""
26
27__author__ = 'phoglund@webrtc.org (Patrik Höglund)'
28
29import os
30import re
31import sys
32import time
33
34import constants
35import dashboard_connection
36
37
38class FailedToParseCoverageHtml(Exception):
39 pass
40
41
42class CouldNotFindCoverageDirectory(Exception):
43 pass
44
45
46def _find_latest_32bit_debug_build(www_directory_contents, coverage_www_dir):
47 """Finds the latest 32-bit coverage directory in the directory listing.
48
49 Coverage directories have the form Linux32bitDBG_<number>. There may be
50 other directories in the list though, for instance for other build
51 configurations.
52 """
53
54 # This sort ensures we will encounter the directory with the highest number
55 # first.
56 www_directory_contents.sort(reverse=True)
57
58 for entry in www_directory_contents:
59 match = re.match('Linux32bitDBG_\d+', entry)
60 if match is not None:
61 return entry
62
63 raise CouldNotFindCoverageDirectory('Error: Found no 32-bit '
64 'debug build in directory %s.' %
65 coverage_www_dir)
66
67
68def _grab_coverage_percentage(label, index_html_contents):
69 """Extracts coverage from a LCOV coverage report.
70
71 Grabs coverage by assuming that the label in the coverage HTML report
72 is close to the actual number and that the number is followed by a space
73 and a percentage sign.
74 """
75 match = re.search('<td[^>]*>' + label + '</td>.*?(\d+\.\d) %',
76 index_html_contents, re.DOTALL)
77 if match is None:
78 raise FailedToParseCoverageHtml('Missing coverage at label "%s".' % label)
79
80 try:
81 return float(match.group(1))
82 except ValueError:
83 raise FailedToParseCoverageHtml('%s is not a float.' % match.group(1))
84
85
86def _report_coverage_to_dashboard(dashboard, now, line_coverage,
87 function_coverage):
88 parameters = {'date': '%d' % now,
89 'line_coverage': '%f' % line_coverage,
90 'function_coverage': '%f' % function_coverage
91 }
92
93 response = dashboard.send_post_request(constants.ADD_COVERAGE_DATA_URL,
94 parameters)
95
96 # The response content should be empty on success, so check that:
97 response_content = response.read()
98 if response_content:
99 message = ('Error: Dashboard reported the following error: %s.' %
100 response_content)
101 raise dashboard_connection.FailedToReportToDashboard(message)
102
103
104def _main():
105 dashboard = dashboard_connection.DashboardConnection(constants.CONSUMER_KEY)
106 dashboard.read_required_files(constants.CONSUMER_SECRET_FILE,
107 constants.ACCESS_TOKEN_FILE)
108
109 coverage_www_dir = os.path.join('/home', constants.BUILD_BOT_USER, 'www')
110
111 www_dir_contents = os.listdir(coverage_www_dir)
112 latest_build_directory = _find_latest_32bit_debug_build(www_dir_contents,
113 coverage_www_dir)
114
115 index_html_path = os.path.join(coverage_www_dir, latest_build_directory,
116 'index.html')
117 index_html_file = open(index_html_path)
118 whole_file = index_html_file.read()
119
120 line_coverage = _grab_coverage_percentage('Lines:', whole_file)
121 function_coverage = _grab_coverage_percentage('Functions:', whole_file)
122 now = int(time.time())
123
124 _report_coverage_to_dashboard(dashboard, now, line_coverage,
125 function_coverage)
126
127
128if __name__ == '__main__':
129 _main()
130