blob: 8c063c1441657dd57b0734f40c718de2fa023317 [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
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000027import os
28import re
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +000029import sys
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000030
31import constants
32import dashboard_connection
33
34
35class FailedToParseCoverageHtml(Exception):
36 pass
37
38
39class CouldNotFindCoverageDirectory(Exception):
40 pass
41
42
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +000043def _find_latest_build_coverage(www_directory_contents, coverage_www_dir,
44 directory_prefix):
45 """Finds the most recent coverage directory in the directory listing.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000046
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +000047 We assume here that build numbers keep rising and never wrap around.
48
49 Args:
50 www_directory_contents: A list of entries in the coverage directory.
51 coverage_www_dir: The coverage directory on the bot.
52 directory_prefix: Coverage directories have the form <prefix><number>,
53 and the prefix is different on different bots. The prefix is
54 generally the builder name, such as Linux32DBG.
55
56 Returns:
57 The most recent directory name.
58
59 Raises:
60 CouldNotFindCoverageDirectory: if we failed to find coverage data.
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000061 """
62
phoglund@webrtc.org0f1a96a2012-03-01 15:50:30 +000063 found_build_numbers = []
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000064 for entry in www_directory_contents:
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +000065 match = re.match(directory_prefix + '(\d+)', entry)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000066 if match is not None:
phoglund@webrtc.org0f1a96a2012-03-01 15:50:30 +000067 found_build_numbers.append(int(match.group(1)))
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000068
phoglund@webrtc.org0f1a96a2012-03-01 15:50:30 +000069 if not found_build_numbers:
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +000070 raise CouldNotFindCoverageDirectory('Error: Found no directories %s* '
71 'in directory %s.' %
72 (directory_prefix, coverage_www_dir))
phoglund@webrtc.org0f1a96a2012-03-01 15:50:30 +000073
74 most_recent = max(found_build_numbers)
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +000075 return directory_prefix + str(most_recent)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +000076
77
78def _grab_coverage_percentage(label, index_html_contents):
79 """Extracts coverage from a LCOV coverage report.
80
81 Grabs coverage by assuming that the label in the coverage HTML report
82 is close to the actual number and that the number is followed by a space
83 and a percentage sign.
84 """
85 match = re.search('<td[^>]*>' + label + '</td>.*?(\d+\.\d) %',
86 index_html_contents, re.DOTALL)
87 if match is None:
88 raise FailedToParseCoverageHtml('Missing coverage at label "%s".' % label)
89
90 try:
91 return float(match.group(1))
92 except ValueError:
93 raise FailedToParseCoverageHtml('%s is not a float.' % match.group(1))
94
95
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +000096def _report_coverage_to_dashboard(dashboard, line_coverage, function_coverage,
97 branch_coverage, report_category):
98 parameters = {'line_coverage': '%f' % line_coverage,
99 'function_coverage': '%f' % function_coverage,
100 'branch_coverage': '%f' % branch_coverage,
101 'report_category': report_category,
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000102 }
103
phoglund@webrtc.org86ce46d2012-02-06 10:55:12 +0000104 dashboard.send_post_request(constants.ADD_COVERAGE_DATA_URL, parameters)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000105
106
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +0000107def _main(report_category, directory_prefix):
108 """Grabs coverage data from disk on a bot and publishes it.
109
110 Args:
111 report_category: The kind of coverage to report. The dashboard
112 application decides what is acceptable here (see
113 dashboard/add_coverage_data.py for more information).
114 directory_prefix: This bot's coverage directory prefix. Generally a bot's
115 coverage directories will have the form <prefix><build number>,
116 like Linux32DBG_345.
117 """
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000118 dashboard = dashboard_connection.DashboardConnection(constants.CONSUMER_KEY)
119 dashboard.read_required_files(constants.CONSUMER_SECRET_FILE,
120 constants.ACCESS_TOKEN_FILE)
121
phoglund@webrtc.org0f1a96a2012-03-01 15:50:30 +0000122 coverage_www_dir = constants.BUILD_BOT_COVERAGE_WWW_DIRECTORY
123 www_dir_contents = os.listdir(coverage_www_dir)
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +0000124 latest_build_directory = _find_latest_build_coverage(www_dir_contents,
125 coverage_www_dir,
126 directory_prefix)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000127
128 index_html_path = os.path.join(coverage_www_dir, latest_build_directory,
129 'index.html')
130 index_html_file = open(index_html_path)
131 whole_file = index_html_file.read()
132
133 line_coverage = _grab_coverage_percentage('Lines:', whole_file)
134 function_coverage = _grab_coverage_percentage('Functions:', whole_file)
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +0000135 branch_coverage = _grab_coverage_percentage('Branches:', whole_file)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000136
phoglund@webrtc.orgfc402762012-03-12 09:12:32 +0000137 _report_coverage_to_dashboard(dashboard, line_coverage, function_coverage,
138 branch_coverage, report_category)
139
140
141def _parse_args():
142 if len(sys.argv) != 3:
143 print ('Usage: %s <coverage category> <directory prefix>\n\n'
144 'The coverage category describes the kind of coverage you are '
145 'uploading. Known acceptable values are small_medium_tests and'
146 'large_tests. The directory prefix is what the directories in %s '
147 'are prefixed on this bot (such as Linux32DBG_).' %
148 (sys.argv[0], constants.BUILD_BOT_COVERAGE_WWW_DIRECTORY))
149 return (None, None)
150 return (sys.argv[1], sys.argv[2])
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000151
152
153if __name__ == '__main__':
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +0000154 category, dir_prefix = _parse_args()
155 if category:
156 _main(category, dir_prefix)
phoglund@webrtc.orgd4f0a0e2012-02-01 10:59:23 +0000157