Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / tools / swarming_client / googletest / isolate_test_cases.py
1 #!/usr/bin/env python
2 # Copyright 2013 The Swarming Authors. All rights reserved.
3 # Use of this source code is governed under the Apache License, Version 2.0 that
4 # can be found in the LICENSE file.
5
6 """Traces one, multiple or all test cases of a google-test executable
7 individually and generates or updates an .isolate file.
8
9 If the trace hangs up, you can still take advantage of the traces up to the
10 points it got to by Ctrl-C'ing out, then running isolate.py merge -r
11 out/release/foo_test.isolated. the reason it works is because both isolate.py
12 and isolate_test_cases.py uses the same filename for the trace by default.
13 """
14
15 import logging
16 import os
17 import subprocess
18 import sys
19
20 ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
21 if not ROOT_DIR in sys.path:
22   sys.path.insert(0, ROOT_DIR)
23
24 import isolate
25 import trace_inputs
26 from googletest import run_test_cases
27 from googletest import trace_test_cases
28
29 from utils import tools
30
31
32 def isolate_test_cases(
33     cmd, test_cases, jobs, isolated_file, isolate_file,
34     root_dir, reldir, path_variables, config_variables, extra_variables,
35     trace_blacklist):
36   assert os.path.isabs(root_dir) and os.path.isdir(root_dir), root_dir
37
38   logname = isolated_file + '.log'
39   basename = isolated_file.rsplit('.', 1)[0]
40   cwd_dir = os.path.join(root_dir, reldir)
41   # Do the actual tracing.
42   results = trace_test_cases.trace_test_cases(
43       cmd, cwd_dir, test_cases, jobs, logname)
44   api = trace_inputs.get_api()
45   blacklist = tools.gen_blacklist(trace_blacklist)
46   logs = dict(
47       (i.pop('trace'), i) for i in api.parse_log(logname, blacklist, None))
48   exception = None
49   try:
50     inputs = []
51     for items in results:
52       item = items[-1]
53       assert item['valid']
54       # Load the results;
55       log_dict = logs[item['tracename']]
56       if log_dict.get('exception'):
57         exception = exception or log_dict['exception']
58         logging.error('Got exception: %s', exception)
59         continue
60       files = log_dict['results'].strip_root(root_dir).files
61       tracked, touched = isolate.isolate_format.split_touched(files)
62       value = isolate.generate_isolate(
63           tracked,
64           [],
65           touched,
66           root_dir,
67           path_variables,
68           config_variables,
69           extra_variables,
70           reldir,
71           blacklist)
72       # item['test_case'] could be an invalid file name.
73       out = basename + '.' + item['tracename'] + '.isolate'
74       with open(out, 'w') as f:
75         isolate.isolate_format.pretty_print(value, f)
76       inputs.append(out)
77
78     # Merges back. Note that it is possible to blow up the command line
79     # argument length here but writing the files is still useful. Convert to
80     # importing the module instead if necessary.
81     merge_cmd = [
82       sys.executable,
83       os.path.join(ROOT_DIR, 'isolate_merge.py'),
84       isolate_file,
85       '-o', isolate_file,
86     ]
87     merge_cmd.extend(inputs)
88     logging.info(merge_cmd)
89     proc = subprocess.Popen(merge_cmd)
90     proc.communicate()
91     return proc.returncode
92   finally:
93     if exception:
94       raise exception[0], exception[1], exception[2]
95
96
97 def test_xvfb(command, rel_dir):
98   """Calls back ourself if not running inside Xvfb and it's on the command line
99   to run.
100
101   Otherwise the X session will die while trying to start too many Xvfb
102   instances.
103   """
104   if os.environ.get('_CHROMIUM_INSIDE_XVFB') == '1':
105     return
106   for index, item in enumerate(command):
107     if item.endswith('xvfb.py'):
108       # Note this has inside knowledge about src/testing/xvfb.py.
109       print('Restarting itself under Xvfb')
110       prefix = command[index:index+2]
111       prefix[0] = os.path.normpath(os.path.join(rel_dir, prefix[0]))
112       prefix[1] = os.path.normpath(os.path.join(rel_dir, prefix[1]))
113       cmd = tools.fix_python_path(prefix + sys.argv)
114       sys.exit(subprocess.call(cmd))
115
116
117 def safely_load_isolated(parser, options):
118   """Loads a .isolated.state to extract the executable information.
119
120   Returns the CompleteState instance, the command and the list of test cases.
121   """
122   config = isolate.CompleteState.load_files(options.isolated)
123   logging.debug(
124       'root_dir: %s  relative_cwd: %s  isolated: %s',
125       config.root_dir, config.saved_state.relative_cwd, options.isolated)
126   reldir = os.path.join(config.root_dir, config.saved_state.relative_cwd)
127   command = config.saved_state.command
128   test_cases = []
129   if command:
130     command = tools.fix_python_path(command)
131     test_xvfb(command, reldir)
132     test_cases = parser.process_gtest_options(command, reldir, options)
133   return config, command, test_cases
134
135
136 def main():
137   """CLI frontend to validate arguments."""
138   tools.disable_buffering()
139   parser = run_test_cases.OptionParserTestCases(
140       usage='%prog <options> --isolated <.isolated>')
141   parser.format_description = lambda *_: parser.description
142   isolate.add_variable_option(parser)
143   isolate.add_trace_option(parser)
144
145   # TODO(maruel): Add support for options.timeout.
146   parser.remove_option('--timeout')
147
148   options, args = parser.parse_args()
149   if args:
150     parser.error('Unsupported arg: %s' % args)
151   isolate.parse_isolated_option(parser, options, os.getcwd(), True)
152   isolate.parse_variable_option(options)
153
154   try:
155     config, command, test_cases = safely_load_isolated(parser, options)
156     if not command:
157       parser.error('A command must be defined')
158     if not test_cases:
159       parser.error('No test case to run with command: %s' % ' '.join(command))
160
161     config.saved_state.config_variables.update(options.config_variables)
162     config.saved_state.extra_variables.update(options.extra_variables)
163     config.saved_state.path_variables.update(options.path_variables)
164     return isolate_test_cases(
165         command,
166         test_cases,
167         options.jobs,
168         config.isolated_filepath,
169         config.saved_state.isolate_filepath,
170         config.root_dir,
171         config.saved_state.relative_cwd,
172         config.saved_state.path_variables,
173         config.saved_state.config_variables,
174         config.saved_state.extra_variables,
175         options.trace_blacklist)
176   except isolate.ExecutionError, e:
177     print >> sys.stderr, str(e)
178     return 1
179
180
181 if __name__ == '__main__':
182   sys.exit(main())