Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 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 | |
| 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 _DISABLED_TESTS_ANNOTATION_LIST = {'DisabledTest': None, 'FlakyTest': None} | |
| 31 _GIT_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' | |
| 32 _EXPORT_TIME_FORMAT = '%Y%m%dT%H%M%S' | |
| 33 | |
| 34 class _JSONKeyName(object): | |
|
perezju
2016/04/12 10:29:03
do we really need this?
Yoland Yan(Google)
2016/04/13 01:03:11
hmm, I thought this is good to organize global var
perezju
2016/04/13 09:53:46
I just wouldn't store these as constants at all. I
| |
| 35 TEST_MASTER_KEY = 'tests' | |
| 36 RECORD_MASTER_KEY = 'records' | |
| 37 REVISION_KEY = 'revision' | |
| 38 STATUS_KEY = 'status' | |
| 39 TEST_NAME_KEY = 'name' | |
| 40 CRBUG_KEY = 'bug_id' | |
| 41 CLASS_PATH_KEY = 'class_path' | |
| 42 CLASS_NAME_KEY = 'class_name' | |
| 43 TRACKED_TEST_COUNT_KEY = 'tracked_test_count' | |
| 44 DISABLED_TEST_COUNT_KEY = 'disabled_test_count' | |
| 45 FLAKY_TEST_COUNT_KEY = 'flaky_test_count' | |
| 46 TOTAL_TEST_COUNT_KEY = 'total_test_count' | |
| 47 UTC_BUILDTIME_KEY = 'utc_buildtime' | |
| 48 UTC_REVISIONTIME_KEY = 'utc_revisiontime' | |
| 49 PLATFORM_KEY = 'platform' | |
| 50 PLATFORM_VALUE = 'android' | |
| 51 | |
| 52 STATUS_DISABLED_TEST_VALUE = 'Disabled Test' | |
| 53 STATUS_FLAKY_TEST_VALUE = 'Flaky Test' | |
| 54 | |
| 55 def _SerializeTests(test_apks, annotations): | |
| 56 """Use GetFilteredTests to get tests info with wanted annotations""" | |
| 57 total_test_count = 0 | |
| 58 tracked_test_list = [] | |
| 59 for test_apk in test_apks: | |
| 60 logging.info('Current test apk: %s', test_apk) | |
| 61 test_jar = os.path.join( | |
| 62 constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR, | |
| 63 '%s.jar' % test_apk) | |
| 64 temp_tracked_test_list = instrumentation_test_instance.GetFilteredTests( | |
|
perezju
2016/04/12 10:29:03
could we make getting all tests, and the filtering
Yoland Yan(Google)
2016/04/13 01:03:11
Done
| |
| 65 test_jar=test_jar, | |
| 66 test_filter=None, | |
| 67 annotations=annotations, | |
| 68 exclude_annotations=None | |
| 69 ) | |
| 70 tracked_test_list.extend(temp_tracked_test_list) | |
| 71 total_test_count += instrumentation_test_instance.TotalTestCount(test_jar) | |
| 72 logging.info('Total count of tests in all test apks: %d', total_test_count) | |
| 73 result = [] | |
| 74 for test_class in tracked_test_list: | |
| 75 class_path = test_class['class'] | |
| 76 class_name = test_class['class'].split('.')[-1] | |
| 77 for test_method in test_class['methods']: | |
| 78 # getting annotation of each test case | |
| 79 bug_id = None | |
| 80 status = [] | |
| 81 test_annotations = test_method['annotations'] | |
| 82 assert len(test_annotations) != 0 | |
| 83 for annotation, content in test_annotations.iteritems(): | |
| 84 if content is not None: | |
| 85 bug_id = content['message'] | |
|
perezju
2016/04/12 10:29:03
probably a minor thing, but do we worry about mult
Yoland Yan(Google)
2016/04/13 01:03:11
hmm, that's a valid point, on one hand I can add m
perezju
2016/04/25 12:45:07
my main worry was about the bug_id, if there are t
| |
| 86 status.append(annotation) | |
| 87 # getting test method name of each test | |
| 88 test_name = test_method['method'] | |
| 89 test_dict = { | |
| 90 _JSONKeyName.CRBUG_KEY: bug_id, | |
| 91 _JSONKeyName.STATUS_KEY: status, | |
| 92 _JSONKeyName.TEST_NAME_KEY: test_name, | |
| 93 _JSONKeyName.CLASS_NAME_KEY: class_name, | |
| 94 _JSONKeyName.CLASS_PATH_KEY: class_path | |
| 95 } | |
|
perezju
2016/04/12 10:29:03
nit: The closing brace should be aligned with test
Yoland Yan(Google)
2016/04/13 01:03:11
Done.
| |
| 96 result.append(test_dict) | |
| 97 return result, total_test_count | |
| 98 | |
| 99 def _DisabledFlakyTestCount(test_list): | |
| 100 disabled_test_count = 0 | |
| 101 flaky_test_count = 0 | |
| 102 for test in test_list: | |
| 103 if _JSONKeyName.STATUS_DISABLED_TEST_VALUE in test.get( | |
| 104 _JSONKeyName.STATUS_KEY, ""): | |
| 105 disabled_test_count += 1 | |
| 106 if _JSONKeyName.STATUS_FLAKY_TEST_VALUE in test.get( | |
| 107 _JSONKeyName.STATUS_KEY, ""): | |
| 108 flaky_test_count += 1 | |
| 109 return disabled_test_count, flaky_test_count | |
| 110 | |
| 111 def _AddRecord(tracked_test_list, utc_buildtime_string, total_test_count): | |
| 112 tracked_flaky_test_count = len(tracked_test_list) | |
| 113 disabled_test_count, flaky_test_count = _DisabledFlakyTestCount( | |
| 114 tracked_test_list) | |
| 115 | |
| 116 revision = cmd_helper.GetCmdOutput(['git', 'rev-parse', 'HEAD']).strip() | |
| 117 raw_string = cmd_helper.GetCmdOutput( | |
| 118 ['git', 'log', '--pretty=format:%aI', '--max-count=1', 'HEAD']) | |
| 119 time_string_search = re.search(r'\d+-\d+-\d+T\d+:\d+:\d+', raw_string) | |
| 120 if time_string_search is None: | |
| 121 raise Exception('Time format incorrect') | |
| 122 | |
| 123 raw_string = cmd_helper.GetCmdOutput( | |
| 124 ['git', 'log', '--pretty=format:%b', '--max-count=1', 'HEAD']) | |
| 125 commit_pos_search = re.search(r'Cr-Commit-Position: (.*)', raw_string) | |
| 126 if commit_pos_search is None: | |
| 127 raise Exception('Cr commit position is not found, potentially running with ' | |
| 128 'uncommited HEAD') | |
| 129 commit_pos = commit_pos_search.group(1) | |
| 130 | |
| 131 revision_time = time.strptime(time_string_search.group(0), _GIT_TIME_FORMAT) | |
| 132 utc_revision_time = datetime.datetime.utcfromtimestamp( | |
| 133 time.mktime(revision_time)) | |
| 134 utc_revision_time = utc_revision_time.strftime(_EXPORT_TIME_FORMAT) | |
| 135 logging.info( | |
| 136 'revision is %s, revision time is %s', revision, utc_revision_time) | |
| 137 | |
| 138 record_data = [{ | |
| 139 _JSONKeyName.REVISION_KEY: revision, | |
| 140 _JSONKeyName.COMMIT_POS_KEY: commit_pos, | |
| 141 _JSONKeyName.UTC_BUILDTIME_KEY: utc_buildtime_string, | |
| 142 _JSONKeyName.UTC_REVISIONTIME_KEY: utc_revision_time, | |
| 143 _JSONKeyName.PLATFORM_KEY: _JSONKeyName.PLATFORM_VALUE, | |
| 144 _JSONKeyName.TRACKED_TEST_COUNT_KEY: tracked_flaky_test_count, | |
| 145 _JSONKeyName.DISABLED_TEST_COUNT_KEY: disabled_test_count, | |
| 146 _JSONKeyName.FLAKY_TEST_COUNT_KEY: flaky_test_count, | |
| 147 _JSONKeyName.TOTAL_TEST_COUNT_KEY: total_test_count | |
| 148 }] | |
| 149 return record_data | |
| 150 | |
| 151 def main(): | |
| 152 default_build_type = os.environ.get('BUILDTYPE', 'Debug') | |
| 153 parser = argparse.ArgumentParser() | |
| 154 parser.add_argument('-t', '--test-apks', action='append', default=[], | |
| 155 dest='test_apks', help='List all test apks file name ' + | |
| 156 'that the script uses to fetch tracked tests from') | |
| 157 parser.add_argument( | |
| 158 '--debug', action='store_const', const='Debug', dest='build_type', | |
| 159 default=default_build_type, | |
| 160 help=('If set, run test suites under out/Debug. ' | |
| 161 'Default is env var BUILDTYPE or Debug.')) | |
|
perezju
2016/04/12 10:29:03
should there be also a --release option?
Yoland Yan(Google)
2016/04/13 01:03:11
Done.
| |
| 162 parser.add_argument('-o', '--output-path', | |
| 163 help='JSON file output to be uploaded on to gcs') | |
| 164 parser.add_argument('-a', '--annotations', dest='annotations', | |
| 165 action='append', default=['DisabledTest', 'FlakyTest'], | |
| 166 help='Disabled tests annotations, seperated by ,' + | |
|
perezju
2016/04/12 10:29:04
I would rephrase as: 'Test annotations to track. T
Yoland Yan(Google)
2016/04/13 01:03:11
My bad, done
| |
| 167 'e.g. --annotation-str=DisabledTest,FlakyTest') | |
| 168 parser.add_argument('-v', '--verbose', action='store_true', default=False, | |
| 169 help='DEBUG verbosity') | |
| 170 | |
| 171 arguments = parser.parse_args(sys.argv[1:]) | |
| 172 logging.basicConfig( | |
| 173 level=logging.DEBUG if arguments.verbose else logging.WARNING) | |
| 174 annotations = dict((x, None) for x in arguments.annotations) | |
| 175 constants.SetBuildType(arguments.build_type) | |
| 176 logging.info('Use jar from build type: %s', arguments.build_type) | |
|
perezju
2016/04/12 10:29:03
nit: Use -> Using
Yoland Yan(Google)
2016/04/13 01:03:11
Done.
| |
| 177 | |
| 178 buildtime = datetime.datetime.utcnow() | |
| 179 buildtime_string = buildtime.strftime('%Y%m%dT%H%M%S') | |
|
perezju
2016/04/12 10:29:03
_EXPORT_TIME_FORMAT
Yoland Yan(Google)
2016/04/13 01:03:11
Done.
| |
| 180 logging.info('Build time is %s', buildtime_string) | |
| 181 test_data, total_test_count = _SerializeTests(arguments.test_apks, | |
| 182 annotations) | |
| 183 record_data = _AddRecord(test_data, buildtime_string, total_test_count) | |
|
perezju
2016/04/12 10:29:03
Instead of _AddRecord, I would have a single metho
Yoland Yan(Google)
2016/04/13 01:03:11
I changed record to report everywhere (will patch
perezju
2016/04/13 09:53:47
metadata? I would suggest:
report = {
"
Yoland Yan(Google)
2016/04/22 17:50:26
Got it
Done
| |
| 184 | |
| 185 if arguments.output_path is None: | |
| 186 output_path = constants.GetOutDirectory() | |
| 187 else: | |
| 188 output_path = arguments.output_path | |
| 189 json_output_path = os.path.join(output_path, | |
| 190 '%s-android-chrome.json' % buildtime_string) | |
| 191 export_data = { | |
| 192 _JSONKeyName.RECORD_MASTER_KEY: record_data, | |
| 193 _JSONKeyName.TEST_MASTER_KEY: test_data | |
| 194 } | |
| 195 with open(json_output_path, 'w') as f: | |
| 196 json.dump(export_data, f, indent=2, sort_keys=True) | |
|
perezju
2016/04/12 10:29:03
also add: separators=(': ', ',')
otherwise you en
Yoland Yan(Google)
2016/04/13 01:03:11
Woah!
Done
| |
| 197 logging.info('Saved json output file to %s', json_output_path) | |
| 198 | |
| 199 if __name__ == '__main__': | |
| 200 main() | |
| OLD | NEW |