1#!/usr/bin/env python
2# Copyright (c) 2012 The LibYuv Project Authors. All rights reserved.
3#
4# Use of this source code is governed by a BSD-style license
5# that can be found in the LICENSE file in the root of the source
6# tree. An additional intellectual property rights grant can be found
7# in the file PATENTS.  All contributing project authors may
8# be found in the AUTHORS file in the root of the source tree.
9
10"""Runs various libyuv tests through valgrind_test.py.
11
12This script inherits the chrome_tests.py in Chrome, but allows running any test
13instead of only the hard-coded ones. It uses the -t cmdline flag to do this, and
14only supports specifying a single test for each run.
15
16Suppression files:
17The Chrome valgrind directory we use as a DEPS dependency contains the following
18suppression files:
19  valgrind/memcheck/suppressions.txt
20  valgrind/memcheck/suppressions_mac.txt
21  valgrind/tsan/suppressions.txt
22  valgrind/tsan/suppressions_mac.txt
23  valgrind/tsan/suppressions_win32.txt
24Since they're referenced from the chrome_tests.py script, we have similar files
25below the directory of this script. When executing, this script will setup both
26Chrome's suppression files and our own, so we can easily maintain libyuv
27specific suppressions in our own files.
28"""
29
30import logging
31import optparse
32import os
33import sys
34
35import logging_utils
36import path_utils
37
38import chrome_tests
39
40
41class LibyuvTest(chrome_tests.ChromeTests):
42  """Class that handles setup of suppressions for libyuv.
43
44  Everything else is inherited from chrome_tests.ChromeTests.
45  """
46
47  def _DefaultCommand(self, tool, exe=None, valgrind_test_args=None):
48    """Override command-building method so we can add more suppressions."""
49    cmd = chrome_tests.ChromeTests._DefaultCommand(self, tool, exe,
50                                                   valgrind_test_args)
51    # When ChromeTests._DefaultCommand has executed, it has setup suppression
52    # files based on what's found in the memcheck/ or tsan/ subdirectories of
53    # this script's location. If Mac or Windows is executing, additional
54    # platform specific files have also been added.
55    # Since only the ones located below this directory is added, we must also
56    # add the ones maintained by Chrome, located in ../../tools/valgrind.
57
58    # The idea is to look for --suppression arguments in the cmd list and add a
59    # modified copy of each suppression file, for the corresponding file in
60    # ../../tools/valgrind.
61    script_dir = path_utils.ScriptDir()
62    old_base, _ = os.path.split(script_dir)
63
64    checkout_src = os.path.abspath(os.path.join(script_dir, os.pardir,
65                                                os.pardir))
66    new_dir = os.path.join(checkout_src, 'tools', 'valgrind')
67    add_suppressions = []
68    for token in cmd:
69      if '--suppressions' in token:
70        add_suppressions.append(token.replace(script_dir, new_dir))
71    return add_suppressions + cmd
72
73
74def main(_):
75  parser = optparse.OptionParser('usage: %prog -b <dir> -t <test> <test args>')
76  parser.disable_interspersed_args()
77  parser.add_option('-b', '--build-dir',
78                    help=('Location of the compiler output. Can only be used '
79                          'when the test argument does not contain this path.'))
80  parser.add_option("--target", help="Debug or Release")
81  parser.add_option('-t', '--test', help='Test to run.')
82  parser.add_option('', '--baseline', action='store_true', default=False,
83                    help='Generate baseline data instead of validating')
84  parser.add_option('', '--gtest_filter',
85                    help='Additional arguments to --gtest_filter')
86  parser.add_option('', '--gtest_repeat',
87                    help='Argument for --gtest_repeat')
88  parser.add_option("--gtest_shuffle", action="store_true", default=False,
89                    help="Randomize tests' orders on every iteration.")
90  parser.add_option("--gtest_break_on_failure", action="store_true",
91                    default=False,
92                    help="Drop in to debugger on assertion failure. Also "
93                         "useful for forcing tests to exit with a stack dump "
94                         "on the first assertion failure when running with "
95                         "--gtest_repeat=-1")
96  parser.add_option('-v', '--verbose', action='store_true', default=False,
97                    help='Verbose output - enable debug log messages')
98  parser.add_option('', '--tool', dest='valgrind_tool', default='memcheck',
99                    help='Specify a valgrind tool to run the tests under')
100  parser.add_option('', '--tool_flags', dest='valgrind_tool_flags', default='',
101                    help='Specify custom flags for the selected valgrind tool')
102  parser.add_option('', '--keep_logs', action='store_true', default=False,
103                    help=('Store memory tool logs in the <tool>.logs directory '
104                          'instead of /tmp.\nThis can be useful for tool '
105                          'developers/maintainers.\nPlease note that the <tool>'
106                          '.logs directory will be clobbered on tool startup.'))
107  parser.add_option("--test-launcher-bot-mode", action="store_true",
108                    help="run the tests with --test-launcher-bot-mode")
109  parser.add_option("--test-launcher-total-shards", type=int,
110                    help="run the tests with --test-launcher-total-shards")
111  parser.add_option("--test-launcher-shard-index", type=int,
112                    help="run the tests with --test-launcher-shard-index")
113  options, args = parser.parse_args()
114
115  if options.verbose:
116    logging_utils.config_root(logging.DEBUG)
117  else:
118    logging_utils.config_root()
119
120  if not options.test:
121    parser.error('--test not specified')
122
123  # Support build dir both with and without the target.
124  if (options.target and options.build_dir and
125      not options.build_dir.endswith(options.target)):
126    options.build_dir = os.path.join(options.build_dir, options.target)
127
128  # If --build_dir is provided, prepend it to the test executable if needed.
129  test_executable = options.test
130  if options.build_dir and not test_executable.startswith(options.build_dir):
131    test_executable = os.path.join(options.build_dir, test_executable)
132  args = [test_executable] + args
133
134  test = LibyuvTest(options, args, 'cmdline')
135  return test.Run()
136
137if __name__ == '__main__':
138  return_code = main(sys.argv)
139  sys.exit(return_code)
140