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