1#!/usr/bin/env python
2# Copyright (c) 2012 The WebRTC 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 WebRTC 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
21Since they're referenced from the chrome_tests.py script, we have similar files
22below the directory of this script. When executing, this script will setup both
23Chrome's suppression files and our own, so we can easily maintain WebRTC
24specific suppressions in our own files.
25"""
26
27import logging
28import optparse
29import os
30import sys
31
32import logging_utils
33import path_utils
34
35import chrome_tests
36
37
38class WebRTCTest(chrome_tests.ChromeTests):
39  """Class that handles setup of suppressions for WebRTC.
40
41  Everything else is inherited from chrome_tests.ChromeTests.
42  """
43
44  def __init__(self, test_name, options, args, test_in_chrome_tests):
45    """Create a WebRTC test.
46    Args:
47      test_name: Short name for the test executable (no path).
48      options: options to pass to ChromeTests.
49      args: args to pass to ChromeTests.
50      test_in_chrome_tests: The name of the test configuration in ChromeTests.
51    """
52    self._test_name = test_name
53    chrome_tests.ChromeTests.__init__(self, options, args, test_in_chrome_tests)
54
55  def _DefaultCommand(self, tool, exe=None, valgrind_test_args=None):
56    """Override command-building method so we can add more suppressions."""
57    cmd = chrome_tests.ChromeTests._DefaultCommand(self, tool, exe,
58                                                   valgrind_test_args)
59
60    # Add gtest filters, if found.
61    chrome_tests.ChromeTests._AppendGtestFilter(self, tool, self._test_name,
62                                                cmd)
63
64    # When ChromeTests._DefaultCommand has executed, it has setup suppression
65    # files based on what's found in the memcheck/ subdirectory of
66    # this script's location. If Mac or Windows is executing, additional
67    # platform specific files have also been added.
68    # Since only the ones located below this directory are added, we must also
69    # add the ones maintained by Chrome, located in ../valgrind.
70
71    # The idea is to look for --suppression arguments in the cmd list and add a
72    # modified copy of each suppression file, for the corresponding file in
73    # ../valgrind. If we would simply replace 'valgrind-webrtc' with 'valgrind'
74    # we may produce invalid paths if other parts of the path contain that
75    # string. That's why the code below only replaces the end of the path.
76    script_dir = path_utils.ScriptDir()
77    old_base, _ = os.path.split(script_dir)
78    new_dir = os.path.join(old_base, 'valgrind')
79    add_suppressions = []
80    for token in cmd:
81      if '--suppressions' in token:
82        add_suppressions.append(token.replace(script_dir, new_dir))
83    return add_suppressions + cmd
84
85
86def main(_):
87  parser = optparse.OptionParser(
88      'usage: %prog -b <dir> -t <test> -- <test args>')
89  parser.disable_interspersed_args()
90  parser.add_option('-b', '--build-dir',
91                    help=('Location of the compiler output. Can only be used '
92                          'when the test argument does not contain this path.'))
93  parser.add_option("--target", help="Debug or Release")
94  parser.add_option('-t', '--test', help='Test to run.')
95  parser.add_option('', '--baseline', action='store_true', default=False,
96                    help='Generate baseline data instead of validating')
97  parser.add_option('', '--gtest_filter',
98                    help='Additional arguments to --gtest_filter')
99  parser.add_option('', '--gtest_repeat',
100                    help='Argument for --gtest_repeat')
101  parser.add_option("--gtest_shuffle", action="store_true", default=False,
102                    help="Randomize tests' orders on every iteration.")
103  parser.add_option("--gtest_break_on_failure", action="store_true",
104                    default=False,
105                    help="Drop in to debugger on assertion failure. Also "
106                         "useful for forcing tests to exit with a stack dump "
107                         "on the first assertion failure when running with "
108                         "--gtest_repeat=-1")
109  parser.add_option('-v', '--verbose', action='store_true', default=False,
110                    help='Verbose output - enable debug log messages')
111  parser.add_option('', '--tool', dest='valgrind_tool', default='memcheck',
112                    help='Specify a valgrind tool to run the tests under')
113  parser.add_option('', '--tool_flags', dest='valgrind_tool_flags', default='',
114                    help='Specify custom flags for the selected valgrind tool')
115  parser.add_option('', '--keep_logs', action='store_true', default=False,
116                    help=('Store memory tool logs in the <tool>.logs directory '
117                          'instead of /tmp.\nThis can be useful for tool '
118                          'developers/maintainers.\nPlease note that the <tool>'
119                          '.logs directory will be clobbered on tool startup.'))
120  parser.add_option("--test-launcher-bot-mode", action="store_true",
121                    help="run the tests with --test-launcher-bot-mode")
122  parser.add_option("--test-launcher-total-shards", type=int,
123                    help="run the tests with --test-launcher-total-shards")
124  parser.add_option("--test-launcher-shard-index", type=int,
125                    help="run the tests with --test-launcher-shard-index")
126  options, args = parser.parse_args()
127
128  if options.verbose:
129    logging_utils.config_root(logging.DEBUG)
130  else:
131    logging_utils.config_root()
132
133  if not options.test:
134    parser.error('--test not specified')
135
136  # Support build dir both with and without the target.
137  if (options.target and options.build_dir and
138      not options.build_dir.endswith(options.target)):
139    options.build_dir = os.path.join(options.build_dir, options.target)
140
141  # If --build_dir is provided, prepend it to the test executable if needed.
142  test_executable = options.test
143  if options.build_dir and not test_executable.startswith(options.build_dir):
144    test_executable = os.path.join(options.build_dir, test_executable)
145  args = [test_executable] + args
146
147  test = WebRTCTest(options.test, options, args, 'cmdline')
148  return test.Run()
149
150if __name__ == '__main__':
151  return_code = main(sys.argv)
152  sys.exit(return_code)
153