1 # Copyright 2014 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.
11 from pylib
import constants
12 from pylib
.base
import base_test_result
13 from pylib
.base
import test_instance
15 sys
.path
.append(os
.path
.join(
16 constants
.DIR_SOURCE_ROOT
, 'build', 'util', 'lib', 'common'))
20 # Used for filtering large data deps at a finer grain than what's allowed in
21 # isolate files since pushing deps to devices is expensive.
22 # Wildcards are allowed.
23 _DEPS_EXCLUSION_LIST
= [
24 'chrome/test/data/extensions/api_test',
25 'chrome/test/data/extensions/secure_shell',
26 'chrome/test/data/firefox*',
27 'chrome/test/data/gpu',
28 'chrome/test/data/image_decoding',
29 'chrome/test/data/import',
30 'chrome/test/data/page_cycler',
31 'chrome/test/data/perf',
32 'chrome/test/data/pyauto_private',
33 'chrome/test/data/safari_import',
34 'chrome/test/data/scroll',
35 'chrome/test/data/third_party',
36 'third_party/hunspell_dictionaries/*.dic',
38 'webkit/data/bmp_decoder',
39 'webkit/data/ico_decoder',
43 # TODO(jbudorick): Remove these once we're no longer parsing stdout to generate
45 _RE_TEST_STATUS
= re
.compile(
46 r
'\[ +((?:RUN)|(?:FAILED)|(?:OK)) +\] ?([^ ]+)(?: \((\d+) ms\))?$')
47 _RE_TEST_RUN_STATUS
= re
.compile(
48 r
'\[ +(PASSED|RUNNER_FAILED|CRASHED) \] ?[^ ]+')
51 # TODO(jbudorick): Make this a class method of GtestTestInstance once
52 # test_package_apk and test_package_exe are gone.
53 def ParseGTestListTests(raw_list
):
54 """Parses a raw test list as provided by --gtest_list_tests.
57 raw_list: The raw test listing with the following format:
60 SendMessageInChannelConnected
63 DISABLED_SendWithTimeoutMixedOKAndTimeout
66 A list of all tests. For the above raw listing:
68 [IPCChannelTest.SendMessageInChannelConnected, IPCSyncChannelTest.Simple,
69 IPCSyncChannelTest.DISABLED_SendWithTimeoutMixedOKAndTimeout]
77 test_case
= test
.split()[0]
78 if test_case
.endswith('.'):
80 elif not 'YOU HAVE' in test
:
81 test_name
= test
.split()[0]
82 ret
+= [current
+ test_name
]
86 class GtestTestInstance(test_instance
.TestInstance
):
88 def __init__(self
, args
, isolate_delegate
, error_func
):
89 super(GtestTestInstance
, self
).__init
__()
90 # TODO(jbudorick): Support multiple test suites.
91 if len(args
.suite_name
) > 1:
92 raise ValueError('Platform mode currently supports only 1 gtest suite')
93 self
._suite
= args
.suite_name
[0]
95 if self
._suite
== 'content_browsertests':
96 error_func('content_browsertests are not currently supported '
98 self
._apk
_path
= os
.path
.join(
99 constants
.GetOutDirectory(), 'apks', '%s.apk' % self
._suite
)
101 self
._apk
_path
= os
.path
.join(
102 constants
.GetOutDirectory(), '%s_apk' % self
._suite
,
103 '%s-debug.apk' % self
._suite
)
104 self
._exe
_path
= os
.path
.join(constants
.GetOutDirectory(),
106 if not os
.path
.exists(self
._apk
_path
):
107 self
._apk
_path
= None
108 if not os
.path
.exists(self
._exe
_path
):
109 self
._exe
_path
= None
110 if not self
._apk
_path
and not self
._exe
_path
:
111 error_func('Could not find apk or executable for %s' % self
._suite
)
115 self
._gtest
_filter
= args
.test_filter
116 elif args
.test_filter_file
:
117 with
open(args
.test_filter_file
, 'r') as f
:
118 self
._gtest
_filter
= ':'.join(l
.strip() for l
in f
)
120 self
._gtest
_filter
= None
121 if args
.isolate_file_path
:
122 self
._isolate
_abs
_path
= os
.path
.abspath(args
.isolate_file_path
)
123 self
._isolate
_delegate
= isolate_delegate
124 self
._isolated
_abs
_path
= os
.path
.join(
125 constants
.GetOutDirectory(), '%s.isolated' % self
._suite
)
127 logging
.warning('No isolate file provided. No data deps will be pushed.');
128 self
._isolate
_delegate
= None
136 """Map data dependencies via isolate."""
137 if self
._isolate
_delegate
:
138 self
._isolate
_delegate
.Remap(
139 self
._isolate
_abs
_path
, self
._isolated
_abs
_path
)
140 self
._isolate
_delegate
.PurgeExcluded(_DEPS_EXCLUSION_LIST
)
141 self
._isolate
_delegate
.MoveOutputDeps()
143 if self
._suite
== 'breakpad_unittests':
144 dest_dir
= '/data/local/tmp/'
145 self
._data
_deps
.extend([(constants
.ISOLATE_DEPS_DIR
, dest_dir
)])
148 def GetDataDependencies(self
):
149 """Returns the test suite's data dependencies.
152 A list of (host_path, device_path) tuples to push. If device_path is
153 None, the client is responsible for determining where to push the file.
155 return self
._data
_deps
157 def FilterTests(self
, test_list
, disabled_prefixes
=None):
158 """Filters |test_list| based on prefixes and, if present, a filter string.
161 test_list: The list of tests to filter.
162 disabled_prefixes: A list of test prefixes to filter. Defaults to
163 DISABLED_, FLAKY_, FAILS_, PRE_, and MANUAL_
165 A filtered list of tests to run.
167 gtest_filter_strings
= [
168 self
._GenerateDisabledFilterString
(disabled_prefixes
)]
169 if self
._gtest
_filter
:
170 gtest_filter_strings
.append(self
._gtest
_filter
)
172 filtered_test_list
= test_list
173 for gtest_filter_string
in gtest_filter_strings
:
174 logging
.debug('Filtering tests using: %s', gtest_filter_string
)
175 filtered_test_list
= unittest_util
.FilterTestNames(
176 filtered_test_list
, gtest_filter_string
)
177 return filtered_test_list
179 def _GenerateDisabledFilterString(self
, disabled_prefixes
):
180 disabled_filter_items
= []
182 if disabled_prefixes
is None:
183 disabled_prefixes
= ['DISABLED_', 'FLAKY_', 'FAILS_', 'PRE_', 'MANUAL_']
184 disabled_filter_items
+= ['%s*' % dp
for dp
in disabled_prefixes
]
185 disabled_filter_items
+= ['*.%s*' % dp
for dp
in disabled_prefixes
]
187 disabled_tests_file_path
= os
.path
.join(
188 constants
.DIR_SOURCE_ROOT
, 'build', 'android', 'pylib', 'gtest',
189 'filter', '%s_disabled' % self
._suite
)
190 if disabled_tests_file_path
and os
.path
.exists(disabled_tests_file_path
):
191 with
open(disabled_tests_file_path
) as disabled_tests_file
:
192 disabled_filter_items
+= [
193 '%s' % l
for l
in (line
.strip() for line
in disabled_tests_file
)
194 if l
and not l
.startswith('#')]
196 return '*-%s' % ':'.join(disabled_filter_items
)
198 def ParseGTestOutput(self
, output
):
199 """Parses raw gtest output and returns a list of results.
202 output: A list of output lines.
204 A list of base_test_result.BaseTestResults.
208 matcher
= _RE_TEST_STATUS
.match(l
)
211 if matcher
.group(1) == 'OK':
212 result_type
= base_test_result
.ResultType
.PASS
213 elif matcher
.group(1) == 'FAILED':
214 result_type
= base_test_result
.ResultType
.FAIL
217 test_name
= matcher
.group(2)
218 duration
= matcher
.group(3) if matcher
.group(3) else 0
219 results
.append(base_test_result
.BaseTestResult(
220 test_name
, result_type
, duration
))
226 """Clear the mappings created by SetUp."""
227 if self
._isolate
_delegate
:
228 self
._isolate
_delegate
.Clear()
232 return self
._apk
_path
236 return self
._exe
_path