forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprint-stale-test-expectations-entries
executable file
·153 lines (135 loc) · 6.26 KB
/
print-stale-test-expectations-entries
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/python
#
# Copyright (C) 2013 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Prints a list of test expectations for tests whose bugs haven't been modified recently."""
import csv
import datetime
import json
import optparse
import StringIO
import sys
import urllib2
from webkitpy.common.host import Host
from webkitpy.layout_tests.models.test_expectations import TestExpectationParser
# FIXME: Make this a direct request to Monorail.
GOOGLE_CODE_URL = 'https://www.googleapis.com/projecthosting/v2/projects/chromium/issues/%s?key=AIzaSyDgCqT1Dt5AZWLHo4QJjyMHaCjhnFacGF0'
CRBUG_PREFIX = 'crbug.com/'
CSV_ROW_HEADERS = ['crbug link', 'test file', 'days since last update', 'owner', 'status']
class BugInfo():
def __init__(self, bug_link, filename, days_since_last_update, owner, status):
self.bug_link = bug_link
self.filename = filename
self.days_since_last_update = days_since_last_update
self.owner = owner
self.status = status
class StaleTestPrinter(object):
def __init__(self, options):
self.days = options.days
self.csv_filename = options.create_csv
self.host = Host()
self.bug_info = {}
def print_stale_tests(self):
port = self.host.port_factory.get()
expectations = port.expectations_dict()
parser = TestExpectationParser(port, all_tests=(), is_lint_mode=False)
expectations_file, expectations_contents = expectations.items()[0]
expectation_lines = parser.parse(expectations_file, expectations_contents)
csv_rows = []
for line in expectation_lines:
row = self.check_expectations_line(line)
if row:
csv_rows.append(row)
if self.csv_filename:
self.write_csv(csv_rows)
def write_csv(self, rows):
out = StringIO.StringIO()
writer = csv.writer(out)
writer.writerow(CSV_ROW_HEADERS)
for row in rows:
writer.writerow(row)
self.host.filesystem.write_text_file(self.csv_filename, out.getvalue())
def check_expectations_line(self, line):
"""Checks the bugs in one test expectations line to see if they're stale.
Args:
line: A TestExpectationsLine instance.
Returns:
A CSV row (a list of strings), or None if there are no stale bugs.
"""
bug_links, test_name = line.bugs, line.name
try:
if bug_links:
# Prepopulate bug info.
for bug_link in bug_links:
self.populate_bug_info(bug_link, test_name);
# Return the stale bug's information.
if all(self.is_stale(bug_link) for bug_link in bug_links):
print line.original_string.strip()
return [bug_links[0], self.bug_info[bug_links[0]].filename,
self.bug_info[bug_links[0]].days_since_last_update,
self.bug_info[bug_links[0]].owner,
self.bug_info[bug_links[0]].status]
except urllib2.HTTPError as error:
if error.code == 404:
message = 'got 404, bug does not exist.'
elif error.code == 403:
message = 'got 403, not accessible. Not able to tell if it\'s stale.'
else:
message = str(error)
print >> sys.stderr, 'Error when checking %s: %s' % (','.join(bug_links), message)
return None
def populate_bug_info(self, bug_link, test_name):
if bug_link in self.bug_info:
return
# In case there's an error in the request, don't make the same request again.
bug_number = bug_link.strip(CRBUG_PREFIX)
url = GOOGLE_CODE_URL % bug_number
response = urllib2.urlopen(url)
parsed = json.loads(response.read())
parsed_time = datetime.datetime.strptime(parsed['updated'].split(".")[0] + "UTC", "%Y-%m-%dT%H:%M:%S%Z")
time_delta = datetime.datetime.now() - parsed_time
owner = 'none'
if 'owner' in parsed.keys():
owner = parsed['owner']['name']
self.bug_info[bug_link] = BugInfo(bug_link, test_name, time_delta.days, owner, parsed['state'])
def is_stale(self, bug_link):
return self.bug_info[bug_link].days_since_last_update > self.days
def main(argv):
option_parser = optparse.OptionParser()
option_parser.add_option(
'--days', type='int', default=90,
help='Number of days to consider a bug stale.')
option_parser.add_option(
'--create-csv', type='string', default='',
help='Filename of CSV file to write stale entries to. No file will be written if no name specified.')
options, _ = option_parser.parse_args(argv)
printer = StaleTestPrinter(options)
printer.print_stale_tests()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))