| OLD | NEW |
| 1 #! /usr/bin/env python | 1 #! /usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2017 The Chromium Authors. All rights reserved. | 3 # Copyright 2017 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 import argparse | 7 import argparse |
| 8 import collections | 8 import collections |
| 9 import json | 9 import json |
| 10 import tempfile | |
| 11 import time | |
| 12 import os | 10 import os |
| 13 import subprocess | |
| 14 import sys | 11 import sys |
| 15 | 12 |
| 16 CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) | 13 CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| 17 BASE_DIR = os.path.abspath(os.path.join( | 14 BASE_DIR = os.path.abspath(os.path.join( |
| 18 CURRENT_DIR, '..', '..', '..', '..', '..')) | 15 CURRENT_DIR, '..', '..', '..', '..', '..')) |
| 19 sys.path.append(os.path.join(BASE_DIR, 'third_party')) | 16 sys.path.append(os.path.join(BASE_DIR, 'third_party')) |
| 20 import jinja2 # pylint: disable=import-error | 17 import jinja2 # pylint: disable=import-error |
| 21 JINJA_ENVIRONMENT = jinja2.Environment( | 18 JINJA_ENVIRONMENT = jinja2.Environment( |
| 22 loader=jinja2.FileSystemLoader(os.path.dirname(__file__)), | 19 loader=jinja2.FileSystemLoader(os.path.dirname(__file__)), |
| 23 autoescape=True) | 20 autoescape=True) |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 if footer_row[FAIL_COUNT_INDEX]['data'] > 0: | 225 if footer_row[FAIL_COUNT_INDEX]['data'] > 0: |
| 229 footer_row[FAIL_COUNT_INDEX]['class'] += ' failure' | 226 footer_row[FAIL_COUNT_INDEX]['class'] += ' failure' |
| 230 else: | 227 else: |
| 231 footer_row[FAIL_COUNT_INDEX]['class'] += ' success' | 228 footer_row[FAIL_COUNT_INDEX]['class'] += ' success' |
| 232 | 229 |
| 233 return (header_row, | 230 return (header_row, |
| 234 [[suite_row] for suite_row in suite_row_dict.values()], | 231 [[suite_row] for suite_row in suite_row_dict.values()], |
| 235 footer_row) | 232 footer_row) |
| 236 | 233 |
| 237 | 234 |
| 238 def results_to_html(results_dict, cs_base_url, bucket, server_url): | 235 def results_to_html(results_dict, cs_base_url, master_name): |
| 239 """Convert list of test results into html format.""" | 236 """Convert list of test results into html format.""" |
| 240 | 237 |
| 241 test_rows_header, test_rows = create_test_table(results_dict, cs_base_url) | 238 test_rows_header, test_rows = create_test_table(results_dict, cs_base_url) |
| 242 suite_rows_header, suite_rows, suite_row_footer = create_suite_table( | 239 suite_rows_header, suite_rows, suite_row_footer = create_suite_table( |
| 243 results_dict) | 240 results_dict) |
| 244 | 241 |
| 245 suite_table_values = { | 242 suite_table_values = { |
| 246 'table_id': 'suite-table', | 243 'table_id': 'suite-table', |
| 247 'table_headers': suite_rows_header, | 244 'table_headers': suite_rows_header, |
| 248 'table_row_blocks': suite_rows, | 245 'table_row_blocks': suite_rows, |
| 249 'table_footer': suite_row_footer, | 246 'table_footer': suite_row_footer, |
| 250 } | 247 } |
| 251 | 248 |
| 252 test_table_values = { | 249 test_table_values = { |
| 253 'table_id': 'test-table', | 250 'table_id': 'test-table', |
| 254 'table_headers': test_rows_header, | 251 'table_headers': test_rows_header, |
| 255 'table_row_blocks': test_rows, | 252 'table_row_blocks': test_rows, |
| 256 } | 253 } |
| 257 | 254 |
| 258 main_template = JINJA_ENVIRONMENT.get_template( | 255 main_template = JINJA_ENVIRONMENT.get_template( |
| 259 os.path.join('template', 'main.html')) | 256 os.path.join('template', 'main.html')) |
| 260 return main_template.render( # pylint: disable=no-member | 257 return main_template.render( # pylint: disable=no-member |
| 261 {'tb_values': [suite_table_values, test_table_values], | 258 {'tb_values': [suite_table_values, test_table_values], |
| 262 'bucket': bucket, 'server_url': server_url}) | 259 'master_name': master_name}) |
| 263 | 260 |
| 264 | 261 |
| 265 def result_details(json_path, cs_base_url, bucket, server_url): | 262 def result_details(json_path, cs_base_url, master_name): |
| 266 """Get result details from json path and then convert results to html.""" | 263 """Get result details from json path and then convert results to html.""" |
| 267 | 264 |
| 268 with open(json_path) as json_file: | 265 with open(json_path) as json_file: |
| 269 json_object = json.loads(json_file.read()) | 266 json_object = json.loads(json_file.read()) |
| 270 | 267 |
| 271 if not 'per_iteration_data' in json_object: | 268 if not 'per_iteration_data' in json_object: |
| 272 return 'Error: json file missing per_iteration_data.' | 269 return 'Error: json file missing per_iteration_data.' |
| 273 | 270 |
| 274 results_dict = collections.defaultdict(list) | 271 results_dict = collections.defaultdict(list) |
| 275 for testsuite_run in json_object['per_iteration_data']: | 272 for testsuite_run in json_object['per_iteration_data']: |
| 276 for test, test_runs in testsuite_run.iteritems(): | 273 for test, test_runs in testsuite_run.iteritems(): |
| 277 results_dict[test].extend(test_runs) | 274 results_dict[test].extend(test_runs) |
| 278 return results_to_html(results_dict, cs_base_url, bucket, server_url) | 275 return results_to_html(results_dict, cs_base_url, master_name) |
| 279 | 276 |
| 280 | 277 |
| 281 def upload_to_google_bucket(html, test_name, builder_name, build_number, | |
| 282 bucket, server_url, content_type): | |
| 283 with tempfile.NamedTemporaryFile(suffix='.html') as temp_file: | |
| 284 temp_file.write(html) | |
| 285 temp_file.flush() | |
| 286 dest = 'html/%s_%s_%s_%s.html' % ( | |
| 287 test_name, builder_name, build_number, | |
| 288 time.strftime('%Y_%m_%d_T%H_%M_%S')) | |
| 289 gsutil_path = os.path.join(BASE_DIR, 'third_party', 'catapult', | |
| 290 'third_party', 'gsutil', 'gsutil.py') | |
| 291 subprocess.check_call([ | |
| 292 sys.executable, gsutil_path, '-h', "Content-Type:%s" % content_type, | |
| 293 'cp', temp_file.name, 'gs://%s/%s' % (bucket, dest)]) | |
| 294 | |
| 295 return '%s/%s/%s' % (server_url, bucket, dest) | |
| 296 | |
| 297 def main(): | 278 def main(): |
| 298 parser = argparse.ArgumentParser() | 279 parser = argparse.ArgumentParser() |
| 299 parser.add_argument('--json-file', help='Path of json file.', required=True) | 280 parser.add_argument('--json-file', help='Path of json file.', required=True) |
| 300 parser.add_argument('--cs-base-url', help='Base url for code search.', | 281 parser.add_argument('--cs-base-url', help='Base url for code search.', |
| 301 default='http://cs.chromium.org') | 282 default='http://cs.chromium.org') |
| 302 parser.add_argument('--bucket', default='chromium-result-details') | 283 parser.add_argument('--master-name', help='Master name in urls.') |
| 303 parser.add_argument('--builder-name', help='Builder name.', required=True) | |
| 304 parser.add_argument('--build-number', help='Build number.', required=True) | |
| 305 parser.add_argument('--test-name', help='The name of the test.', | |
| 306 required=True) | |
| 307 parser.add_argument('--server-url', help='The url of the server.', | |
| 308 default='https://storage.googleapis.com') | |
| 309 parser.add_argument( | |
| 310 '--content-type', | |
| 311 help=('Content type, which is used to determine ' | |
| 312 'whether to download the file, or view in browser.'), | |
| 313 default='text/html', | |
| 314 choices=['text/html', 'application/octet-stream']) | |
| 315 | 284 |
| 316 args = parser.parse_args() | 285 args = parser.parse_args() |
| 317 if os.path.exists(args.json_file): | 286 if os.path.exists(args.json_file): |
| 318 result_html_string = result_details(args.json_file, args.cs_base_url, | 287 result_html_string = result_details(args.json_file, args.cs_base_url, |
| 319 args.bucket, args.server_url) | 288 args.master_name) |
| 320 print upload_to_google_bucket(result_html_string.encode('UTF-8'), | 289 print result_html_string.encode('UTF-8') |
| 321 args.test_name, args.builder_name, | |
| 322 args.build_number, args.bucket, | |
| 323 args.server_url, args.content_type) | |
| 324 else: | 290 else: |
| 325 raise IOError('--json-file %s not found.' % args.json_file) | 291 raise IOError('--json-file %s not found.' % args.json_file) |
| 326 | 292 |
| 327 | 293 |
| 328 if __name__ == '__main__': | 294 if __name__ == '__main__': |
| 329 sys.exit(main()) | 295 sys.exit(main()) |
| OLD | NEW |