Index: swarm_client/googletest/trace_test_cases.py |
=================================================================== |
--- swarm_client/googletest/trace_test_cases.py (revision 235167) |
+++ swarm_client/googletest/trace_test_cases.py (working copy) |
@@ -1,207 +0,0 @@ |
-#!/usr/bin/env python |
-# Copyright 2013 The Chromium Authors. All rights reserved. |
-# Use of this source code is governed by a BSD-style license that can be |
-# found in the LICENSE file. |
- |
-"""Traces each test cases of a google-test executable individually. |
- |
-Gives detailed information about each test case. The logs can be read afterward |
-with ./trace_inputs.py read -l /path/to/executable.logs |
-""" |
- |
-import logging |
-import multiprocessing |
-import os |
-import sys |
-import time |
- |
-ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
-if not ROOT_DIR in sys.path: |
- sys.path.insert(0, ROOT_DIR) |
- |
-import run_test_cases |
-import trace_inputs |
- |
-from utils import threading_utils |
-from utils import tools |
- |
- |
-def sanitize_test_case_name(test_case): |
- """Removes characters that are valid as test case names but invalid as file |
- names. |
- """ |
- return test_case.replace('/', '-') |
- |
- |
-class Tracer(object): |
- def __init__(self, tracer, cmd, cwd_dir, progress): |
- # Constants |
- self.tracer = tracer |
- self.cmd = cmd[:] |
- self.cwd_dir = cwd_dir |
- self.progress = progress |
- |
- def map(self, test_case): |
- """Traces a single test case and returns its output.""" |
- cmd = self.cmd[:] |
- cmd.append('--gtest_filter=%s' % test_case) |
- tracename = sanitize_test_case_name(test_case) |
- |
- out = [] |
- for retry in range(5): |
- start = time.time() |
- returncode, output = self.tracer.trace(cmd, self.cwd_dir, tracename, True) |
- duration = time.time() - start |
- # TODO(maruel): Define a way to detect if a strace log is valid. |
- valid = True |
- out.append( |
- { |
- 'test_case': test_case, |
- 'tracename': tracename, |
- 'returncode': returncode, |
- 'duration': duration, |
- 'valid': valid, |
- 'output': output, |
- }) |
- logging.debug( |
- 'Tracing %s done: %d, %.1fs' % (test_case, returncode, duration)) |
- if retry: |
- self.progress.update_item( |
- '%s - %d' % (test_case, retry), index=1, size=int(not valid)) |
- else: |
- self.progress.update_item(test_case, index=1, size=int(not valid)) |
- if valid: |
- break |
- return out |
- |
- |
-def trace_test_cases(cmd, cwd_dir, test_cases, jobs, logname): |
- """Traces each test cases individually but all in parallel.""" |
- assert os.path.isabs(cwd_dir) and os.path.isdir(cwd_dir), cwd_dir |
- |
- if not test_cases: |
- return [] |
- |
- # Resolve any symlink. |
- cwd_dir = os.path.realpath(cwd_dir) |
- assert os.path.isdir(cwd_dir) |
- |
- api = trace_inputs.get_api() |
- api.clean_trace(logname) |
- |
- jobs = jobs or multiprocessing.cpu_count() |
- # Try to do black magic here by guessing a few of the run_test_cases.py |
- # flags. It's cheezy but it works. |
- for i, v in enumerate(cmd): |
- if v.endswith('run_test_cases.py'): |
- # Found it. Process the arguments here. |
- _, options, _ = run_test_cases.process_args(cmd[i:]) |
- # Always override with the lowest value. |
- jobs = min(options.jobs, jobs) |
- break |
- |
- columns = [('index', 0), ('size', len(test_cases))] |
- progress = threading_utils.Progress(columns) |
- with threading_utils.ThreadPoolWithProgress( |
- progress, jobs, jobs, len(test_cases)) as pool: |
- with api.get_tracer(logname) as tracer: |
- function = Tracer(tracer, cmd, cwd_dir, progress).map |
- for test_case in test_cases: |
- pool.add_task(0, function, test_case) |
- |
- results = pool.join() |
- print('') |
- return results |
- |
- |
-def write_details(logname, outfile, root_dir, blacklist, results): |
- """Writes an .test_cases file with all the information about each test |
- case. |
- """ |
- api = trace_inputs.get_api() |
- logs = dict( |
- (i.pop('trace'), i) for i in api.parse_log(logname, blacklist, None)) |
- results_processed = {} |
- exception = None |
- for items in results: |
- item = items[-1] |
- assert item['valid'] |
- # Load the results; |
- log_dict = logs[item['tracename']] |
- if log_dict.get('exception'): |
- exception = exception or log_dict['exception'] |
- continue |
- trace_result = log_dict['results'] |
- if root_dir: |
- trace_result = trace_result.strip_root(root_dir) |
- results_processed[item['test_case']] = { |
- 'trace': trace_result.flatten(), |
- 'duration': item['duration'], |
- 'output': item['output'], |
- 'returncode': item['returncode'], |
- } |
- |
- # Make it dense if there is more than 20 results. |
- trace_inputs.write_json( |
- outfile, |
- results_processed, |
- len(results_processed) > 20) |
- if exception: |
- raise exception[0], exception[1], exception[2] |
- |
- |
-def main(): |
- """CLI frontend to validate arguments.""" |
- tools.disable_buffering() |
- parser = run_test_cases.OptionParserTestCases( |
- usage='%prog <options> [gtest]') |
- parser.format_description = lambda *_: parser.description |
- parser.add_option( |
- '-o', '--out', |
- help='output file, defaults to <executable>.test_cases') |
- parser.add_option( |
- '-r', '--root-dir', |
- help='Root directory under which file access should be noted') |
- parser.add_option( |
- '--trace-blacklist', action='append', default=[], |
- help='List of regexp to use as blacklist filter') |
- # TODO(maruel): Add support for options.timeout. |
- parser.remove_option('--timeout') |
- options, args = parser.parse_args() |
- |
- if not args: |
- parser.error( |
- 'Please provide the executable line to run, if you need fancy things ' |
- 'like xvfb, start this script from *inside* xvfb, it\'ll be much faster' |
- '.') |
- |
- cmd = tools.fix_python_path(args) |
- cmd[0] = os.path.abspath(cmd[0]) |
- if not os.path.isfile(cmd[0]): |
- parser.error('Tracing failed for: %s\nIt doesn\'t exit' % ' '.join(cmd)) |
- |
- if not options.out: |
- options.out = '%s.test_cases' % cmd[-1] |
- options.out = os.path.abspath(options.out) |
- if options.root_dir: |
- options.root_dir = os.path.abspath(options.root_dir) |
- logname = options.out + '.log' |
- |
- test_cases = parser.process_gtest_options(cmd, os.getcwd(), options) |
- |
- # Then run them. |
- print('Tracing...') |
- results = trace_test_cases( |
- cmd, |
- os.getcwd(), |
- test_cases, |
- options.jobs, |
- logname) |
- print('Reading trace logs...') |
- blacklist = trace_inputs.gen_blacklist(options.trace_blacklist) |
- write_details(logname, options.out, options.root_dir, blacklist, results) |
- return 0 |
- |
- |
-if __name__ == '__main__': |
- sys.exit(main()) |