Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(677)

Side by Side Diff: tools/drmemory/scripts/pdfium_tests.py

Issue 1452373004: Merge to XFA: Add Dr. Memory tool (Closed) Base URL: https://pdfium.googlesource.com/pdfium.git@xfa
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/drmemory/scripts/pdfium_tests.bat ('k') | tools/drmemory/scripts/valgrind_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 ''' Runs various chrome tests through valgrind_test.py.'''
7
8 import glob
9 import logging
10 import optparse
11 import os
12 import subprocess
13 import sys
14
15 import logging_utils
16 import path_utils
17
18 import common
19 import valgrind_test
20
21 class TestNotFound(Exception): pass
22
23 class MultipleGTestFiltersSpecified(Exception): pass
24
25 class BuildDirNotFound(Exception): pass
26
27 class BuildDirAmbiguous(Exception): pass
28
29 class ExecutableNotFound(Exception): pass
30
31 class BadBinary(Exception): pass
32
33 class ChromeTests:
34 SLOW_TOOLS = ["drmemory"]
35
36 def __init__(self, options, args, test):
37 if ':' in test:
38 (self._test, self._gtest_filter) = test.split(':', 1)
39 else:
40 self._test = test
41 self._gtest_filter = options.gtest_filter
42
43 if self._test not in self._test_list:
44 raise TestNotFound("Unknown test: %s" % test)
45
46 if options.gtest_filter and options.gtest_filter != self._gtest_filter:
47 raise MultipleGTestFiltersSpecified("Can not specify both --gtest_filter "
48 "and --test %s" % test)
49
50 self._options = options
51 self._args = args
52
53 script_dir = path_utils.ScriptDir()
54 # Compute the top of the tree (the "source dir") from the script dir (where
55 # this script lives). We assume that the script dir is in tools/valgrind/
56 # relative to the top of the tree.
57 self._source_dir = os.path.dirname(os.path.dirname(script_dir))
58 # since this path is used for string matching, make sure it's always
59 # an absolute Unix-style path
60 self._source_dir = os.path.abspath(self._source_dir).replace('\\', '/')
61 valgrind_test_script = os.path.join(script_dir, "valgrind_test.py")
62 self._command_preamble = ["--source-dir=%s" % (self._source_dir)]
63
64 if not self._options.build_dir:
65 dirs = [
66 os.path.join(self._source_dir, "xcodebuild", "Debug"),
67 os.path.join(self._source_dir, "out", "Debug"),
68 os.path.join(self._source_dir, "build", "Debug"),
69 ]
70 build_dir = [d for d in dirs if os.path.isdir(d)]
71 if len(build_dir) > 1:
72 raise BuildDirAmbiguous("Found more than one suitable build dir:\n"
73 "%s\nPlease specify just one "
74 "using --build-dir" % ", ".join(build_dir))
75 elif build_dir:
76 self._options.build_dir = build_dir[0]
77 else:
78 self._options.build_dir = None
79
80 if self._options.build_dir:
81 build_dir = os.path.abspath(self._options.build_dir)
82 self._command_preamble += ["--build-dir=%s" % (self._options.build_dir)]
83
84 def _EnsureBuildDirFound(self):
85 if not self._options.build_dir:
86 raise BuildDirNotFound("Oops, couldn't find a build dir, please "
87 "specify it manually using --build-dir")
88
89 def _DefaultCommand(self, tool, exe=None, valgrind_test_args=None):
90 '''Generates the default command array that most tests will use.'''
91 if exe and common.IsWindows():
92 exe += '.exe'
93
94 cmd = list(self._command_preamble)
95
96 # Find all suppressions matching the following pattern:
97 # tools/valgrind/TOOL/suppressions[_PLATFORM].txt
98 # and list them with --suppressions= prefix.
99 script_dir = path_utils.ScriptDir()
100 tool_name = tool.ToolName();
101 suppression_file = os.path.join(script_dir, tool_name, "suppressions.txt")
102 if os.path.exists(suppression_file):
103 cmd.append("--suppressions=%s" % suppression_file)
104 # Platform-specific suppression
105 for platform in common.PlatformNames():
106 platform_suppression_file = \
107 os.path.join(script_dir, tool_name, 'suppressions_%s.txt' % platform)
108 if os.path.exists(platform_suppression_file):
109 cmd.append("--suppressions=%s" % platform_suppression_file)
110
111 if self._options.valgrind_tool_flags:
112 cmd += self._options.valgrind_tool_flags.split(" ")
113 if self._options.keep_logs:
114 cmd += ["--keep_logs"]
115 if valgrind_test_args != None:
116 for arg in valgrind_test_args:
117 cmd.append(arg)
118 if exe:
119 self._EnsureBuildDirFound()
120 exe_path = os.path.join(self._options.build_dir, exe)
121 if not os.path.exists(exe_path):
122 raise ExecutableNotFound("Couldn't find '%s'" % exe_path)
123
124 # Make sure we don't try to test ASan-built binaries
125 # with other dynamic instrumentation-based tools.
126 # TODO(timurrrr): also check TSan and MSan?
127 # `nm` might not be available, so use try-except.
128 try:
129 # Do not perform this check on OS X, as 'nm' on 10.6 can't handle
130 # binaries built with Clang 3.5+.
131 if not common.IsMac():
132 nm_output = subprocess.check_output(["nm", exe_path])
133 if nm_output.find("__asan_init") != -1:
134 raise BadBinary("You're trying to run an executable instrumented "
135 "with AddressSanitizer under %s. Please provide "
136 "an uninstrumented executable." % tool_name)
137 except OSError:
138 pass
139
140 cmd.append(exe_path)
141 # Valgrind runs tests slowly, so slow tests hurt more; show elapased time
142 # so we can find the slowpokes.
143 cmd.append("--gtest_print_time")
144 # Built-in test launcher for gtest-based executables runs tests using
145 # multiple process by default. Force the single-process mode back.
146 cmd.append("--single-process-tests")
147 if self._options.gtest_repeat:
148 cmd.append("--gtest_repeat=%s" % self._options.gtest_repeat)
149 if self._options.gtest_shuffle:
150 cmd.append("--gtest_shuffle")
151 if self._options.gtest_break_on_failure:
152 cmd.append("--gtest_break_on_failure")
153 if self._options.test_launcher_bot_mode:
154 cmd.append("--test-launcher-bot-mode")
155 if self._options.test_launcher_total_shards is not None:
156 cmd.append("--test-launcher-total-shards=%d" % self._options.test_launcher _total_shards)
157 if self._options.test_launcher_shard_index is not None:
158 cmd.append("--test-launcher-shard-index=%d" % self._options.test_launcher_ shard_index)
159 return cmd
160
161 def Run(self):
162 ''' Runs the test specified by command-line argument --test '''
163 logging.info("running test %s" % (self._test))
164 return self._test_list[self._test](self)
165
166 def _AppendGtestFilter(self, tool, name, cmd):
167 '''Append an appropriate --gtest_filter flag to the googletest binary
168 invocation.
169 If the user passed his own filter mentioning only one test, just use it.
170 Othewise, filter out tests listed in the appropriate gtest_exclude files.
171 '''
172 if (self._gtest_filter and
173 ":" not in self._gtest_filter and
174 "?" not in self._gtest_filter and
175 "*" not in self._gtest_filter):
176 cmd.append("--gtest_filter=%s" % self._gtest_filter)
177 return
178
179 filters = []
180 gtest_files_dir = os.path.join(path_utils.ScriptDir(), "gtest_exclude")
181
182 gtest_filter_files = [
183 os.path.join(gtest_files_dir, name + ".gtest-%s.txt" % tool.ToolName())]
184 # Use ".gtest.txt" files only for slow tools, as they now contain
185 # Valgrind- and Dr.Memory-specific filters.
186 # TODO(glider): rename the files to ".gtest_slow.txt"
187 if tool.ToolName() in ChromeTests.SLOW_TOOLS:
188 gtest_filter_files += [os.path.join(gtest_files_dir, name + ".gtest.txt")]
189 for platform_suffix in common.PlatformNames():
190 gtest_filter_files += [
191 os.path.join(gtest_files_dir, name + ".gtest_%s.txt" % platform_suffix),
192 os.path.join(gtest_files_dir, name + ".gtest-%s_%s.txt" % \
193 (tool.ToolName(), platform_suffix))]
194 logging.info("Reading gtest exclude filter files:")
195 for filename in gtest_filter_files:
196 # strip the leading absolute path (may be very long on the bot)
197 # and the following / or \.
198 readable_filename = filename.replace("\\", "/") # '\' on Windows
199 readable_filename = readable_filename.replace(self._source_dir, "")[1:]
200 if not os.path.exists(filename):
201 logging.info(" \"%s\" - not found" % readable_filename)
202 continue
203 logging.info(" \"%s\" - OK" % readable_filename)
204 f = open(filename, 'r')
205 for line in f.readlines():
206 if line.startswith("#") or line.startswith("//") or line.isspace():
207 continue
208 line = line.rstrip()
209 test_prefixes = ["FLAKY", "FAILS"]
210 for p in test_prefixes:
211 # Strip prefixes from the test names.
212 line = line.replace(".%s_" % p, ".")
213 # Exclude the original test name.
214 filters.append(line)
215 if line[-2:] != ".*":
216 # List all possible prefixes if line doesn't end with ".*".
217 for p in test_prefixes:
218 filters.append(line.replace(".", ".%s_" % p))
219 # Get rid of duplicates.
220 filters = set(filters)
221 gtest_filter = self._gtest_filter
222 if len(filters):
223 if gtest_filter:
224 gtest_filter += ":"
225 if gtest_filter.find("-") < 0:
226 gtest_filter += "-"
227 else:
228 gtest_filter = "-"
229 gtest_filter += ":".join(filters)
230 if gtest_filter:
231 cmd.append("--gtest_filter=%s" % gtest_filter)
232
233 @staticmethod
234 def ShowTests():
235 test_to_names = {}
236 for name, test_function in ChromeTests._test_list.iteritems():
237 test_to_names.setdefault(test_function, []).append(name)
238
239 name_to_aliases = {}
240 for names in test_to_names.itervalues():
241 names.sort(key=lambda name: len(name))
242 name_to_aliases[names[0]] = names[1:]
243
244 print
245 print "Available tests:"
246 print "----------------"
247 for name, aliases in sorted(name_to_aliases.iteritems()):
248 if aliases:
249 print " {} (aka {})".format(name, ', '.join(aliases))
250 else:
251 print " {}".format(name)
252
253 def SetupLdPath(self, requires_build_dir):
254 if requires_build_dir:
255 self._EnsureBuildDirFound()
256 elif not self._options.build_dir:
257 return
258
259 # Append build_dir to LD_LIBRARY_PATH so external libraries can be loaded.
260 if (os.getenv("LD_LIBRARY_PATH")):
261 os.putenv("LD_LIBRARY_PATH", "%s:%s" % (os.getenv("LD_LIBRARY_PATH"),
262 self._options.build_dir))
263 else:
264 os.putenv("LD_LIBRARY_PATH", self._options.build_dir)
265
266 def SimpleTest(self, module, name, valgrind_test_args=None, cmd_args=None):
267 tool = valgrind_test.CreateTool(self._options.valgrind_tool)
268 cmd = self._DefaultCommand(tool, name, valgrind_test_args)
269 self._AppendGtestFilter(tool, name, cmd)
270 cmd.extend(['--test-tiny-timeout=1000'])
271 if cmd_args:
272 cmd.extend(cmd_args)
273
274 self.SetupLdPath(True)
275 return tool.Run(cmd, module)
276
277 def RunCmdLine(self):
278 tool = valgrind_test.CreateTool(self._options.valgrind_tool)
279 cmd = self._DefaultCommand(tool, None, self._args)
280 self.SetupLdPath(False)
281 return tool.Run(cmd, None)
282
283 def TestPDFiumUnitTests(self):
284 return self.SimpleTest("pdfium_unittests", "pdfium_unittests")
285
286 def TestPDFiumEmbedderTests(self):
287 return self.SimpleTest("pdfium_embeddertests", "pdfium_embeddertests")
288
289 # The known list of tests.
290 _test_list = {
291 "cmdline" : RunCmdLine,
292 "pdfium_unittests": TestPDFiumUnitTests,
293 "pdfium_embeddertests": TestPDFiumEmbedderTests,
294 }
295
296
297 def _main():
298 parser = optparse.OptionParser("usage: %prog -b <dir> -t <test> "
299 "[-t <test> ...]")
300
301 parser.add_option("--help-tests", dest="help_tests", action="store_true",
302 default=False, help="List all available tests")
303 parser.add_option("-b", "--build-dir",
304 help="the location of the compiler output")
305 parser.add_option("--target", help="Debug or Release")
306 parser.add_option("-t", "--test", action="append", default=[],
307 help="which test to run, supports test:gtest_filter format "
308 "as well.")
309 parser.add_option("--gtest_filter",
310 help="additional arguments to --gtest_filter")
311 parser.add_option("--gtest_repeat", help="argument for --gtest_repeat")
312 parser.add_option("--gtest_shuffle", action="store_true", default=False,
313 help="Randomize tests' orders on every iteration.")
314 parser.add_option("--gtest_break_on_failure", action="store_true",
315 default=False,
316 help="Drop in to debugger on assertion failure. Also "
317 "useful for forcing tests to exit with a stack dump "
318 "on the first assertion failure when running with "
319 "--gtest_repeat=-1")
320 parser.add_option("-v", "--verbose", action="store_true", default=False,
321 help="verbose output - enable debug log messages")
322 parser.add_option("--tool", dest="valgrind_tool", default="drmemory_full",
323 help="specify a valgrind tool to run the tests under")
324 parser.add_option("--tool_flags", dest="valgrind_tool_flags", default="",
325 help="specify custom flags for the selected valgrind tool")
326 parser.add_option("--keep_logs", action="store_true", default=False,
327 help="store memory tool logs in the <tool>.logs directory "
328 "instead of /tmp.\nThis can be useful for tool "
329 "developers/maintainers.\nPlease note that the <tool>"
330 ".logs directory will be clobbered on tool startup.")
331 parser.add_option("--test-launcher-bot-mode", action="store_true",
332 help="run the tests with --test-launcher-bot-mode")
333 parser.add_option("--test-launcher-total-shards", type=int,
334 help="run the tests with --test-launcher-total-shards")
335 parser.add_option("--test-launcher-shard-index", type=int,
336 help="run the tests with --test-launcher-shard-index")
337
338 options, args = parser.parse_args()
339
340 # Bake target into build_dir.
341 if options.target and options.build_dir:
342 assert (options.target !=
343 os.path.basename(os.path.dirname(options.build_dir)))
344 options.build_dir = os.path.join(os.path.abspath(options.build_dir),
345 options.target)
346
347 if options.verbose:
348 logging_utils.config_root(logging.DEBUG)
349 else:
350 logging_utils.config_root()
351
352 if options.help_tests:
353 ChromeTests.ShowTests()
354 return 0
355
356 if not options.test:
357 parser.error("--test not specified")
358
359 if len(options.test) != 1 and options.gtest_filter:
360 parser.error("--gtest_filter and multiple tests don't make sense together")
361
362 for t in options.test:
363 tests = ChromeTests(options, args, t)
364 ret = tests.Run()
365 if ret: return ret
366 return 0
367
368
369 if __name__ == "__main__":
370 sys.exit(_main())
OLDNEW
« no previous file with comments | « tools/drmemory/scripts/pdfium_tests.bat ('k') | tools/drmemory/scripts/valgrind_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698