OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
jbudorick
2016/04/28 14:17:14
Can you move this to a subdirectory of tools/andro
Yoland Yan(Google)
2016/04/29 19:51:43
Will move to tools/android/find_annotated_tests/fi
| |
2 # Copyright (c) 2016 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 """Finds all the tracked(disabled/flaky) tests from proguard dump""" | |
7 | |
8 import argparse | |
9 import datetime | |
10 import json | |
11 import linecache | |
12 import logging | |
13 import os | |
14 import pprint | |
15 import re | |
16 import sys | |
17 import time | |
18 | |
19 _SRC_DIR = os.path.abspath(os.path.join( | |
20 os.path.dirname(__file__), '..', '..')) | |
21 | |
22 sys.path.append(os.path.join(_SRC_DIR, 'build', 'android')) | |
23 | |
jbudorick
2016/04/28 14:17:15
nit: no blank line here
Yoland Yan(Google)
2016/04/29 19:51:42
Done.
| |
24 from pylib import constants | |
25 from pylib.instrumentation import instrumentation_test_instance | |
26 | |
27 sys.path.append(os.path.join(_SRC_DIR, 'third_party', 'catapult', 'devil')) | |
28 from devil.utils import cmd_helper | |
29 | |
30 _GIT_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' | |
31 _EXPORT_TIME_FORMAT = '%Y%m%dT%H%M%S' | |
32 | |
33 class _JSONKeyName(object): | |
jbudorick
2016/04/28 14:17:14
I didn't read the earlier reviews, so perhaps this
perezju
2016/04/28 14:33:58
I've been saying the same thing for several review
Yoland Yan(Google)
2016/04/29 19:51:43
wow, what a bunch of bullies
lol
Done
| |
34 TEST_MASTER_KEY = 'tests' | |
35 REPORT_MASTER_KEY = 'metadata' | |
36 REVISION_KEY = 'revision' | |
37 COMMIT_POS_KEY = 'commit_pos' | |
38 ANNOTATIONS_KEY = 'annotations' | |
39 TEST_NAME_KEY = 'test_name' | |
40 TEST_APK_KEY = 'test_apk_name' | |
41 CRBUG_KEY = 'bug_id' | |
42 CLASS_PATH_KEY = 'class_path' | |
43 CLASS_NAME_KEY = 'class_name' | |
44 TRACKED_TEST_COUNT_KEY = 'tracked_test_count' | |
45 DISABLED_TEST_COUNT_KEY = 'disabled_test_count' | |
46 FLAKY_TEST_COUNT_KEY = 'flaky_test_count' | |
47 TOTAL_TEST_COUNT_KEY = 'total_test_count' | |
48 UTC_BUILDTIME_KEY = 'build_time' | |
49 UTC_REVISIONTIME_KEY = 'revision_time' | |
50 PLATFORM_KEY = 'platform' | |
51 PLATFORM_VALUE = 'android' | |
52 | |
53 | |
54 def _GetBugId(message): | |
55 """Validate bug message format and get bug id""" | |
56 result = re.search(r'crbug(?:.com)?/(\d+)', message) | |
jbudorick
2016/04/28 14:17:15
compile this into a module-scope constant
Yoland Yan(Google)
2016/04/29 19:51:42
Done.
| |
57 if result: | |
58 return int(result.group(1)) | |
59 else: | |
60 return None | |
61 | |
jbudorick
2016/04/28 14:17:14
nit: two lines
Yoland Yan(Google)
2016/04/29 19:51:43
Done.
| |
62 def _GetAnnotations(test_annotations): | |
63 """Store annotations in the existing anntation_dict and return bug id""" | |
64 bug_id = None | |
65 annotations_dict = {} | |
66 for annotation, content in test_annotations.iteritems(): | |
67 if content is not None and content.get('message') is not None: | |
68 bug_id = _GetBugId(content.get('message')) | |
69 annotations_dict.update({annotation: content}) | |
70 return bug_id, annotations_dict | |
71 | |
72 | |
73 def _GetTests(test_apks): | |
74 """All the all the tests""" | |
jbudorick
2016/04/28 14:17:14
nit: "All the all the tests"?
Yoland Yan(Google)
2016/04/29 19:51:43
got it s/All the all the tests/All the all the all
| |
75 result = [] | |
76 total_test_count = 0 | |
77 for test_apk in test_apks: | |
78 logging.info('Current test apk: %s', test_apk) | |
79 test_jar = os.path.join( | |
80 constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR, | |
81 '%s.jar' % test_apk) | |
82 all_tests = instrumentation_test_instance.GetAllTests(test_jar=test_jar) | |
83 for test_class in all_tests: | |
84 class_path = test_class['class'] | |
85 class_name = test_class['class'].split('.')[-1] | |
86 | |
87 bug_id, class_annotation = _GetAnnotations(test_class['annotations']) | |
perezju
2016/04/27 09:29:15
hmm.. looks like you always end up throwing away t
Yoland Yan(Google)
2016/04/29 19:51:43
Done.
Yoland Yan(Google)
2016/04/29 19:51:43
Changed to class_bug_id and test_bug_id for cases
| |
88 for test_method in test_class['methods']: | |
89 total_test_count += 1 | |
90 # getting annotation of each test case | |
91 bug_id, test_annotations = _GetAnnotations(test_method['annotations']) | |
92 test_annotations.update(class_annotation) | |
93 # getting test method name of each test | |
94 test_name = test_method['method'] | |
95 test_dict = { | |
96 _JSONKeyName.CRBUG_KEY: bug_id, | |
jbudorick
2016/04/28 14:17:15
nit: 2 space indent
Yoland Yan(Google)
2016/04/29 19:51:43
Keep it as 4 after a serious discussion
| |
97 _JSONKeyName.ANNOTATIONS_KEY: test_annotations, | |
98 _JSONKeyName.TEST_NAME_KEY: test_name, | |
99 _JSONKeyName.TEST_APK_KEY: test_apk, | |
100 _JSONKeyName.CLASS_NAME_KEY: class_name, | |
101 _JSONKeyName.CLASS_PATH_KEY: class_path | |
102 } | |
103 result.append(test_dict) | |
104 logging.info('Total count of tests in all test apks: %d', total_test_count) | |
105 return result, total_test_count | |
106 | |
107 | |
108 def _GetReportMeta(utc_buildtime_string, total_test_count): | |
109 """Returns a dictionary of the report's metadata""" | |
110 revision = cmd_helper.GetCmdOutput(['git', 'rev-parse', 'HEAD']).strip() | |
111 raw_string = cmd_helper.GetCmdOutput( | |
112 ['git', 'log', '--pretty=format:%aI', '--max-count=1', 'HEAD']) | |
perezju
2016/04/27 09:29:15
hmm, when I run this locally I get:
2016-04-22T
Yoland Yan(Google)
2016/04/29 19:51:42
Done.
| |
113 git_log_time_pattern = r'\d+-\d+-\d+T\d+:\d+:\d+' | |
perezju
2016/04/27 09:29:15
nit: a module level constant :)
you could also pr
jbudorick
2016/04/28 14:17:15
+1.
Yoland Yan(Google)
2016/04/29 19:51:43
Done.
| |
114 time_string_search = re.search(git_log_time_pattern, raw_string) | |
115 if time_string_search is None: | |
116 raise Exception('Time format incorrect') | |
jbudorick
2016/04/28 14:17:15
This error should be a little more verbose -- _why
Yoland Yan(Google)
2016/04/29 19:51:42
Done.
| |
117 | |
118 raw_string = cmd_helper.GetCmdOutput( | |
119 ['git', 'log', '--pretty=format:%b', '--max-count=1', 'HEAD']) | |
120 git_log_message_pattern = r'Cr-Commit-Position: (.*)' | |
perezju
2016/04/27 09:29:15
strip away the "refs/heads/master" blurb, and cast
jbudorick
2016/04/28 14:17:15
note that this should also be compiled into a modu
Yoland Yan(Google)
2016/04/29 19:51:43
Done.
| |
121 commit_pos_search = re.search(git_log_message_pattern, raw_string) | |
122 if commit_pos_search is None: | |
123 raise Exception('Cr commit position is not found, potentially running with ' | |
jbudorick
2016/04/28 14:17:14
nit: this should say "Cr-Commit-Position ..." rath
Yoland Yan(Google)
2016/04/29 19:51:42
Done.
| |
124 'uncommited HEAD') | |
125 commit_pos = commit_pos_search.group(1) | |
126 | |
127 revision_time = time.strptime(time_string_search.group(0), _GIT_TIME_FORMAT) | |
128 utc_revision_time = datetime.datetime.utcfromtimestamp( | |
129 time.mktime(revision_time)) | |
130 utc_revision_time = utc_revision_time.strftime(_EXPORT_TIME_FORMAT) | |
131 logging.info( | |
132 'revision is %s, revision time is %s', revision, utc_revision_time) | |
133 | |
134 return { | |
135 _JSONKeyName.REVISION_KEY: revision, | |
jbudorick
2016/04/28 14:17:14
nit: 2 space indent
Yoland Yan(Google)
2016/04/29 19:51:43
Keep as 4 space indent after serious discussion wi
| |
136 _JSONKeyName.COMMIT_POS_KEY: commit_pos, | |
137 _JSONKeyName.UTC_BUILDTIME_KEY: utc_buildtime_string, | |
138 _JSONKeyName.UTC_REVISIONTIME_KEY: utc_revision_time, | |
139 _JSONKeyName.PLATFORM_KEY: _JSONKeyName.PLATFORM_VALUE, | |
140 _JSONKeyName.TOTAL_TEST_COUNT_KEY: total_test_count} | |
jbudorick
2016/04/28 14:17:14
nit: drop the trailing } onto the next line
Yoland Yan(Google)
2016/04/29 19:51:43
Done.
| |
141 | |
142 | |
143 def _GetReport(test_apks, buildtime_string): | |
144 """Generate the dictionary of report data | |
145 | |
146 Args: | |
147 test_apks: a list of apks for search for tests | |
148 buildtime_string: the time when the script is run at | |
149 format: '%Y%m%dT%H%M%S' | |
150 """ | |
151 | |
152 test_data, total_test_count = _GetTests(test_apks) | |
153 report_meta = _GetReportMeta(buildtime_string, total_test_count) | |
154 report_data = { | |
155 _JSONKeyName.REPORT_MASTER_KEY: report_meta, | |
156 _JSONKeyName.TEST_MASTER_KEY: test_data} | |
157 return report_data | |
158 | |
159 | |
160 def main(): | |
161 default_build_type = os.environ.get('BUILDTYPE', 'Debug') | |
jbudorick
2016/04/28 14:17:14
please no
Yoland Yan(Google)
2016/04/29 19:51:43
but...lol (Explain: all this was added when the sc
| |
162 parser = argparse.ArgumentParser() | |
jbudorick
2016/04/28 14:17:15
Which of these are required?
Yoland Yan(Google)
2016/04/29 19:51:43
--test-apks, --json-output-dir
Done
| |
163 parser.add_argument('-t', '--test-apks', nargs='+', dest='test_apks', | |
jbudorick
2016/04/28 14:17:15
Why should this handle multiple APKs at once? Why
Yoland Yan(Google)
2016/04/29 19:51:42
Because the that would produce multiple JSON file
| |
164 help='List all test apks file name that the script uses ' | |
165 'to fetch tracked tests from') | |
166 parser.add_argument( | |
jbudorick
2016/04/28 14:17:14
nix both --debug and --release and instead support
Yoland Yan(Google)
2016/04/29 19:51:42
Done
| |
167 '--debug', action='store_const', const='Debug', dest='build_type', | |
168 default=default_build_type, | |
169 help=('If set, run test suites under out/Debug. ' | |
170 'Default is env var BUILDTYPE or Debug.')) | |
171 parser.add_argument( | |
172 '--release', action='store_const', const='Release', dest='build_type', | |
173 help=('If set, run test suites under out/Release. ' | |
174 'Default is env var BUILDTYPE or Debug.')) | |
175 parser.add_argument('-o', '--output-path', | |
176 help='JSON file output to be uploaded on to gcs') | |
jbudorick
2016/04/28 14:17:14
This description is wrong; this is now the output
Yoland Yan(Google)
2016/04/29 19:51:42
Done.
| |
177 parser.add_argument('-v', '--verbose', action='store_true', default=False, | |
jbudorick
2016/04/28 14:17:14
-v = INFO, -vv = DEBUG plz
Yoland Yan(Google)
2016/04/29 19:51:43
Done.
| |
178 help='DEBUG verbosity') | |
179 | |
180 arguments = parser.parse_args(sys.argv[1:]) | |
181 logging.basicConfig( | |
182 level=logging.DEBUG if arguments.verbose else logging.WARNING) | |
183 constants.SetBuildType(arguments.build_type) | |
jbudorick
2016/04/28 14:17:14
Get rid of these two lines.
Yoland Yan(Google)
2016/04/29 19:51:43
Done
| |
184 logging.info('Using jar from build type: %s', arguments.build_type) | |
185 | |
186 buildtime = datetime.datetime.utcnow() | |
jbudorick
2016/04/28 14:17:15
nit: buildtime is a bad name because this isn't wh
Yoland Yan(Google)
2016/04/29 19:51:42
Changed to script_run_time
(I was considering chan
| |
187 buildtime_string = buildtime.strftime(_EXPORT_TIME_FORMAT) | |
188 logging.info('Build time is %s', buildtime_string) | |
189 report_data = _GetReport(arguments.test_apks, buildtime_string) | |
190 | |
191 if arguments.output_path is None: | |
192 output_path = constants.GetOutDirectory() | |
193 else: | |
194 output_path = arguments.output_path | |
195 json_output_path = os.path.join(output_path, | |
196 '%s-android-chrome.json' % buildtime_string) | |
197 with open(json_output_path, 'w') as f: | |
198 json.dump(report_data, f, indent=2, sort_keys=True, separators=(',',': ')) | |
jbudorick
2016/04/28 14:17:14
This shouldn't be using indent
Yoland Yan(Google)
2016/04/29 19:51:43
Done.
| |
199 logging.info('Saved json output file to %s', json_output_path) | |
200 | |
201 if __name__ == '__main__': | |
202 main() | |
OLD | NEW |