1 # Copyright (c) 2013 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.
5 """Parses the command line, discovers the appropriate tests, and runs them.
7 Handles test configuration, but all the logic for
8 actually running the test is in Test and PageRunner."""
16 from telemetry import test
17 from telemetry.core import browser_options
18 from telemetry.core import command_line
19 from telemetry.core import discover
20 from telemetry.core import util
23 class Help(command_line.OptparseCommand):
24 """Display help information"""
26 def Run(self, options, args):
27 print >> sys.stderr, ('usage: %s <command> [<options>]' % _GetScriptName())
28 print >> sys.stderr, 'Available commands are:'
29 for command in COMMANDS:
30 print >> sys.stderr, ' %-10s %s' % (command.name, command.description)
34 class List(command_line.OptparseCommand):
35 """Lists the available tests"""
37 usage = '[test_name] [<options>]'
40 super(List, self).__init__()
43 def AddCommandLineOptions(self, parser):
44 parser.add_option('-j', '--json', action='store_true')
46 def ProcessCommandLine(self, parser, options, args):
48 self._tests = _GetTests()
50 self._tests = _MatchTestName(args[0])
52 parser.error('Must provide at most one test name.')
54 def Run(self, options, args):
57 for test_name, test_class in sorted(self._tests.items()):
60 'description': test_class.__doc__,
61 'options': test_class.options,
63 print json.dumps(test_list)
65 print >> sys.stderr, 'Available tests are:'
66 _PrintTestList(self._tests)
70 class Run(command_line.OptparseCommand):
71 """Run one or more tests"""
73 usage = 'test_name [<options>]'
76 super(Run, self).__init__()
79 def CreateParser(self):
80 options = browser_options.BrowserFinderOptions()
81 parser = options.CreateParser('%%prog %s %s' % (self.name, self.usage))
84 def AddCommandLineOptions(self, parser):
85 test.Test.AddCommandLineOptions(parser)
87 # Allow tests to add their own command line options.
89 for arg in sys.argv[1:]:
90 matching_tests.update(_MatchTestName(arg))
91 for test_class in matching_tests.itervalues():
92 test_class.AddTestCommandLineOptions(parser)
94 def ProcessCommandLine(self, parser, options, args):
96 parser.error('Must provide one test name.')
98 input_test_name = args[0]
99 matching_tests = _MatchTestName(input_test_name)
100 if not matching_tests:
101 print >> sys.stderr, 'No test named "%s".' % input_test_name
103 print >> sys.stderr, 'Available tests:'
104 _PrintTestList(_GetTests())
106 if len(matching_tests) > 1:
107 print >> sys.stderr, 'Multiple tests named "%s".' % input_test_name
109 print >> sys.stderr, 'Did you mean one of these?'
110 _PrintTestList(matching_tests)
113 self._test = matching_tests.popitem()[1]
115 def Run(self, options, args):
116 return min(255, self._test().Run(copy.copy(options)))
119 COMMANDS = [cls() for _, cls in inspect.getmembers(sys.modules[__name__])
120 if inspect.isclass(cls)
121 and cls is not command_line.OptparseCommand
122 and issubclass(cls, command_line.OptparseCommand)]
125 def _GetScriptName():
126 return os.path.basename(sys.argv[0])
130 base_dir = util.GetBaseDir()
131 tests = discover.DiscoverClasses(base_dir, base_dir, test.Test,
132 index_by_class_name=True)
133 return dict((test.GetName(), test) for test in tests.itervalues())
136 def _MatchTestName(input_test_name):
137 def _Matches(input_string, search_string):
138 if search_string.startswith(input_string):
140 for part in search_string.split('.'):
141 if part.startswith(input_string):
146 if input_test_name in test_aliases:
147 exact_match = test_aliases[input_test_name]
149 exact_match = input_test_name
150 if exact_match in _GetTests():
151 return {exact_match: _GetTests()[exact_match]}
154 return dict((test_name, test_class)
155 for test_name, test_class in _GetTests().iteritems()
156 if _Matches(input_test_name, test_name))
159 def _PrintTestList(tests):
160 for test_name, test_class in sorted(tests.items()):
161 if test_class.__doc__:
162 description = test_class.__doc__.splitlines()[0]
163 # Align the test names to the longest one.
164 format_string = ' %%-%ds %%s' % max(map(len, tests.iterkeys()))
165 print >> sys.stderr, format_string % (test_name, description)
167 print >> sys.stderr, ' %s' % test_name
174 # Get the command name from the command line.
175 if len(sys.argv) > 1 and sys.argv[1] == '--help':
179 for arg in sys.argv[1:]:
180 if not arg.startswith('-'):
184 # Validate and interpret the command name.
185 commands = [command for command in COMMANDS
186 if command.name.startswith(command_name)]
187 if len(commands) > 1:
188 print >> sys.stderr, ('"%s" is not a %s command. Did you mean one of these?'
189 % (command_name, _GetScriptName()))
190 for command in commands:
191 print >> sys.stderr, ' %-10s %s' % (command.name, command.description)
194 command = commands[0]
198 # Parse and run the command.
199 parser = command.CreateParser()
200 command.AddCommandLineOptions(parser)
201 options, args = parser.parse_args()
204 command.ProcessCommandLine(parser, options, args)
205 return command.Run(options, args)