Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 from recipe_engine import recipe_api | |
| 6 | |
| 7 GS_CHROMEDRIVER_DATA_BUCKET = 'chromedriver-data' | |
| 8 GS_PREBUILTS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/prebuilts' | |
| 9 GS_SERVER_LOGS_URL = GS_CHROMEDRIVER_DATA_BUCKET + '/server_logs' | |
| 10 | |
| 11 TEST_LOG_FORMAT = '%s_log.json' | |
| 12 TEST_LOG_MAX_LENGTH = 500 | |
| 13 | |
| 14 class ChromedriverApi(recipe_api.RecipeApi): | |
| 15 | |
| 16 def __init__(self, *args, **kwargs): | |
| 17 super(ChromedriverApi, self).__init__(*args, **kwargs) | |
| 18 self._chromedriver_log_dir = None | |
| 19 | |
| 20 def get_chromedriver_platform(self, is_android): | |
| 21 """Gets the platform name for Chromedriver.""" | |
| 22 if is_android: | |
| 23 return 'android' | |
| 24 else: # pragma: no cover | |
| 25 raise NotImplementedError('Only Android is currently supported for ' | |
| 26 'Chromedriver recipes.') | |
| 27 | |
| 28 def download_prebuilts(self): | |
| 29 """Downloads the most recent prebuilts from Google storage.""" | |
| 30 with self.m.step.nest('Download Prebuilts'): | |
| 31 prebuilt_dir = self.m.path.mkdtemp('prebuilt') | |
| 32 zipfile = prebuilt_dir.join('build.zip') | |
| 33 unzip_dir = prebuilt_dir.join('unzipped') | |
| 34 try: | |
| 35 self.m.gsutil.download_latest_file(base_url=GS_PREBUILTS_URL, | |
| 36 partial_name=GS_PREBUILTS_URL + '/r', | |
| 37 destination=zipfile, | |
| 38 name='download latest prebuilt') | |
| 39 self.m.zip.unzip(step_name='unzip prebuilt', | |
| 40 zip_file=zipfile, | |
| 41 output=unzip_dir) | |
| 42 self.m.file.move(name='move prebuilt', | |
| 43 source=unzip_dir.join('chromedriver'), | |
| 44 dest=self.m.chromium.output_dir, | |
| 45 infra_step=False) | |
| 46 finally: | |
| 47 self.m.file.rmtree(name='remove temp dir', path=prebuilt_dir) | |
| 48 | |
|
jbudorick
2016/06/22 10:17:01
nit: -1 blank line
mikecase (-- gone --)
2016/06/23 19:14:34
Done
| |
| 49 | |
| 50 def archive_server_logs(self, chromedriver_log_dir): | |
| 51 """Uploads chromedriver server logs to Google storage. | |
| 52 | |
| 53 Args: | |
| 54 chromedriver_log_dir: Directory containing the Chromedriver server logs. | |
| 55 """ | |
| 56 with self.m.step.nest('Upload Chromedriver Server Logs'): | |
| 57 server_logs = self.m.file.glob( | |
| 58 name='glob search for server logs', | |
| 59 pattern=chromedriver_log_dir.join('*'), | |
| 60 test_data=[chromedriver_log_dir.join('chromedriver_123'), | |
| 61 chromedriver_log_dir.join('chromedriver_456'), | |
| 62 chromedriver_log_dir.join('chromedriver_789')]) | |
| 63 for server_log in server_logs: | |
| 64 self.m.gsutil.upload(name='uploading %s' % server_log, | |
| 65 source=server_log, | |
| 66 bucket=GS_SERVER_LOGS_URL, | |
| 67 dest=self.m.path.basename(server_log), | |
| 68 link_name='server log %s' % server_log) | |
| 69 | |
| 70 def download_test_results_log(self, chromedriver_platform): | |
| 71 """Downloads the test results log for the given Chromedriver platform. | |
| 72 | |
| 73 Args: | |
| 74 chromedriver_platform: The platform of the test results log. | |
| 75 | |
| 76 Returns: | |
| 77 A dictionary where the keys are commit positions and the values are | |
| 78 booleans indicating whether the tests passed. | |
| 79 """ | |
| 80 with self.m.step.nest('Download Test Results Log'): | |
| 81 log_name = TEST_LOG_FORMAT % chromedriver_platform | |
| 82 temp_log_dir = self.m.path.mkdtemp('results_log') | |
| 83 temp_log_file = temp_log_dir.join(log_name) | |
| 84 try: | |
| 85 self.m.gsutil.download(name='download results log', | |
| 86 source=log_name, | |
| 87 bucket=GS_CHROMEDRIVER_DATA_BUCKET, | |
| 88 dest=temp_log_file) | |
| 89 json_data = self.m.file.read(name='read results log file', | |
| 90 path=temp_log_file, | |
| 91 test_data='{}') | |
| 92 json_dict = self.m.json.loads(json_data) | |
| 93 except self.m.step.StepFailure: | |
| 94 json_dict = {} | |
| 95 finally: | |
| 96 self.m.file.rmtree(name='remove temp dir', path=temp_log_dir) | |
| 97 return {int(k): v for k, v in json_dict.items()} | |
|
jbudorick
2016/06/22 10:17:01
nit: iteritems
mikecase (-- gone --)
2016/06/23 19:14:34
Done
| |
| 98 | |
| 99 def upload_test_results_log(self, chromedriver_platform, test_results_log): | |
| 100 """Uploads the given test results log to Google storage.""" | |
| 101 with self.m.step.nest('Upload Test Results Log'): | |
| 102 log_name = TEST_LOG_FORMAT % chromedriver_platform | |
| 103 temp_log_dir = self.m.path.mkdtemp('results_log') | |
| 104 temp_log_file = temp_log_dir.join(log_name) | |
| 105 try: | |
| 106 self.m.file.write(name='write results log to file %s' % log_name, | |
| 107 path=temp_log_file, | |
| 108 data=self.m.json.dumps(test_results_log)) | |
| 109 self.m.gsutil.upload(name='upload results log %s' % log_name, | |
| 110 source=temp_log_file, | |
| 111 bucket=GS_CHROMEDRIVER_DATA_BUCKET, | |
| 112 dest=log_name, | |
| 113 link_name='results log') | |
| 114 finally: | |
| 115 self.m.file.rmtree(name='remove temp dir', path=temp_log_dir) | |
| 116 | |
| 117 def update_test_results_log(self, chromedriver_platform, | |
| 118 commit_position, passed): | |
| 119 """Updates the test results log stored in GS for the given platform. | |
| 120 | |
| 121 Args: | |
| 122 chromedriver_platform: The platform name. | |
| 123 commit_position: The commit position number. | |
| 124 passed: Boolean indicating whether the tests passed at this | |
| 125 commit position. | |
| 126 """ | |
| 127 log = self.download_test_results_log(chromedriver_platform) | |
| 128 while len(log) > TEST_LOG_MAX_LENGTH: # pragma: no cover | |
| 129 del log[min(log.keys())] | |
| 130 if commit_position not in log: | |
| 131 log[commit_position] = bool(passed) | |
| 132 self.upload_test_results_log(chromedriver_platform, log) | |
| 133 else: | |
| 134 raise self.m.step.StepFailure( | |
| 135 'Results already exist for commit position %s' % commit_position) | |
| 136 | |
| 137 def _generate_test_command(self, script, chromedriver, test_log_dir, | |
| 138 ref_chromedriver=None, android_package=None, | |
| 139 build_type=None, verbose=None): | |
| 140 cmd = [ | |
| 141 script, | |
| 142 '--chromedriver', chromedriver, | |
| 143 '--log-dir', str(test_log_dir) | |
| 144 ] | |
| 145 if ref_chromedriver: | |
| 146 cmd.extend(['--reference-chromedriver', ref_chromedriver]) | |
| 147 if build_type: | |
| 148 cmd.extend(['--build-type', build_type]) | |
| 149 if verbose: | |
| 150 cmd.extend(['--verbose']) | |
| 151 if android_package: | |
| 152 cmd = ['xvfb-run', '-a'] + cmd | |
| 153 cmd.extend(['--android-package', android_package]) | |
| 154 return cmd | |
| 155 | |
| 156 def run_python_tests(self, chromedriver, test_log_dir, ref_chromedriver, | |
| 157 chrome=None, chrome_version_name=None, | |
| 158 android_package=None, build_type=None, **kwargs): | |
| 159 """Run the Chromedriver Python tests.""" | |
| 160 version_info = '' | |
| 161 if chrome_version_name: | |
| 162 version_info = '(%s)' % chrome_version_name | |
| 163 self.m.step('python_tests%s' % version_info, | |
| 164 self._generate_test_command('run_py_tests.py', chromedriver, | |
| 165 test_log_dir, | |
| 166 ref_chromedriver=ref_chromedriver, | |
| 167 android_package=android_package, | |
| 168 build_type=build_type), | |
| 169 **kwargs) | |
| 170 | |
| 171 def run_java_tests(self, chromedriver, test_log_dir, chrome=None, | |
| 172 chrome_version_name=None, | |
| 173 android_package=None, build_type=None, verbose=False, | |
| 174 **kwargs): | |
| 175 """Run the Chromedriver Java tests.""" | |
| 176 version_info = '' | |
| 177 if chrome_version_name: | |
| 178 version_info = '(%s)' % chrome_version_name | |
| 179 self.m.step('java_tests%s' % version_info, | |
| 180 self._generate_test_command('run_java_tests.py', chromedriver, | |
| 181 test_log_dir, | |
| 182 ref_chromedriver=None, | |
| 183 android_package=android_package, | |
| 184 build_type=build_type, | |
| 185 verbose=verbose), | |
| 186 **kwargs) | |
| 187 | |
| 188 def run_all_tests(self, android_packages=None, archive_logs=True): | |
| 189 """Run all Chromedriver tests.""" | |
| 190 server_name = 'chromedriver' | |
| 191 chromedriver = self.m.chromium.output_dir.join(server_name) | |
| 192 build_type = self.m.path.basename(self.m.chromium.output_dir) | |
| 193 | |
| 194 platform_name = self.m.platform.name | |
| 195 if self.m.platform.is_linux and self.m.platform.bits == 64: | |
| 196 platform_name = 'linux64' | |
| 197 ref_chromedriver = self.m.path.join( | |
| 198 self.m.path['checkout'], | |
| 199 'chrome', 'test', 'chromedriver', 'third_party', 'java_tests', | |
| 200 'reference_builds', 'chromedriver_%s' % platform_name) | |
| 201 | |
| 202 test_env = {'PATH': '%(PATH)s'} | |
| 203 failure = False | |
| 204 if android_packages: | |
|
jbudorick
2016/06/22 10:17:01
So this does nothing w/o android_packages and isn'
mikecase (-- gone --)
2016/06/23 19:14:35
eh, I mean, it was intentional, but removing for n
jbudorick
2016/06/24 13:31:09
That's fine. I'm of the opinion that, while we sho
| |
| 205 test_env['PATH'] = self.m.path.pathsep.join([ | |
| 206 test_env['PATH'], | |
| 207 str(self.m.path['checkout'].join( | |
| 208 'chrome', 'test', 'chromedriver', 'chrome'))]) | |
| 209 try: | |
|
jbudorick
2016/06/22 10:17:01
nit: you're creating temp_log_dir inside the with
mikecase (-- gone --)
2016/06/23 19:14:34
Done
| |
| 210 with self.m.step.defer_results(): | |
| 211 temp_log_dir = self.m.path.mkdtemp('results_log') | |
| 212 for package in android_packages: | |
| 213 self.run_python_tests(chromedriver, | |
| 214 temp_log_dir, | |
| 215 ref_chromedriver, | |
| 216 chrome_version_name=package, | |
| 217 android_package=package, | |
| 218 build_type=build_type, | |
| 219 env=test_env) | |
| 220 self.run_java_tests(chromedriver, | |
| 221 temp_log_dir, | |
| 222 chrome_version_name=package, | |
| 223 android_package=package, | |
| 224 build_type=build_type, | |
| 225 verbose=True, | |
| 226 env=test_env) | |
| 227 if archive_logs: | |
| 228 self.archive_server_logs(temp_log_dir) | |
| 229 except recipe_api.AggregatedStepFailure: | |
|
jbudorick
2016/06/22 10:17:01
Why is this returning True/False and circumventing
mikecase (-- gone --)
2016/06/23 19:14:34
Its how the buildbot scripts did this. The result
jbudorick
2016/06/24 13:31:09
SG. I think it's fine for individual recipes.
| |
| 230 failure = True | |
| 231 finally: | |
| 232 self.m.file.rmtree(name='Remove Temp Log Dir', path=temp_log_dir) | |
| 233 return not failure | |
| OLD | NEW |