Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / test_runner.py
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.
4
5 """Parses the command line, discovers the appropriate tests, and runs them.
6
7 Handles test configuration, but all the logic for
8 actually running the test is in Test and PageRunner."""
9
10 import copy
11 import inspect
12 import json
13 import os
14 import sys
15
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
21
22
23 class Help(command_line.OptparseCommand):
24   """Display help information"""
25
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)
31     return 0
32
33
34 class List(command_line.OptparseCommand):
35   """Lists the available tests"""
36
37   usage = '[test_name] [<options>]'
38
39   def __init__(self):
40     super(List, self).__init__()
41     self._tests = None
42
43   def AddCommandLineOptions(self, parser):
44     parser.add_option('-j', '--json', action='store_true')
45
46   def ProcessCommandLine(self, parser, options, args):
47     if not args:
48       self._tests = _GetTests()
49     elif len(args) == 1:
50       self._tests = _MatchTestName(args[0])
51     else:
52       parser.error('Must provide at most one test name.')
53
54   def Run(self, options, args):
55     if options.json:
56       test_list = []
57       for test_name, test_class in sorted(self._tests.items()):
58         test_list.append({
59               'name': test_name,
60               'description': test_class.__doc__,
61               'options': test_class.options,
62             })
63       print json.dumps(test_list)
64     else:
65       print >> sys.stderr, 'Available tests are:'
66       _PrintTestList(self._tests)
67     return 0
68
69
70 class Run(command_line.OptparseCommand):
71   """Run one or more tests"""
72
73   usage = 'test_name [<options>]'
74
75   def __init__(self):
76     super(Run, self).__init__()
77     self._test = None
78
79   def CreateParser(self):
80     options = browser_options.BrowserFinderOptions()
81     parser = options.CreateParser('%%prog %s %s' % (self.name, self.usage))
82     return parser
83
84   def AddCommandLineOptions(self, parser):
85     test.Test.AddCommandLineOptions(parser)
86
87     # Allow tests to add their own command line options.
88     matching_tests = {}
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)
93
94   def ProcessCommandLine(self, parser, options, args):
95     if len(args) != 1:
96       parser.error('Must provide one test name.')
97
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
102       print >> sys.stderr
103       print >> sys.stderr, 'Available tests:'
104       _PrintTestList(_GetTests())
105       sys.exit(1)
106     if len(matching_tests) > 1:
107       print >> sys.stderr, 'Multiple tests named "%s".' % input_test_name
108       print >> sys.stderr
109       print >> sys.stderr, 'Did you mean one of these?'
110       _PrintTestList(matching_tests)
111       sys.exit(1)
112
113     self._test = matching_tests.popitem()[1]
114
115   def Run(self, options, args):
116     return min(255, self._test().Run(copy.copy(options)))
117
118
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)]
123
124
125 def _GetScriptName():
126   return os.path.basename(sys.argv[0])
127
128
129 def _GetTests():
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())
134
135
136 def _MatchTestName(input_test_name):
137   def _Matches(input_string, search_string):
138     if search_string.startswith(input_string):
139       return True
140     for part in search_string.split('.'):
141       if part.startswith(input_string):
142         return True
143     return False
144
145   # Exact matching.
146   if input_test_name in test_aliases:
147     exact_match = test_aliases[input_test_name]
148   else:
149     exact_match = input_test_name
150   if exact_match in _GetTests():
151     return {exact_match: _GetTests()[exact_match]}
152
153   # Fuzzy matching.
154   return dict((test_name, test_class)
155       for test_name, test_class in _GetTests().iteritems()
156       if _Matches(input_test_name, test_name))
157
158
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)
166     else:
167       print >> sys.stderr, '  %s' % test_name
168
169
170 test_aliases = {}
171
172
173 def Main():
174   # Get the command name from the command line.
175   if len(sys.argv) > 1 and sys.argv[1] == '--help':
176     sys.argv[1] = 'help'
177
178   command_name = 'run'
179   for arg in sys.argv[1:]:
180     if not arg.startswith('-'):
181       command_name = arg
182       break
183
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)
192     return 1
193   if commands:
194     command = commands[0]
195   else:
196     command = Run()
197
198   # Parse and run the command.
199   parser = command.CreateParser()
200   command.AddCommandLineOptions(parser)
201   options, args = parser.parse_args()
202   if commands:
203     args = args[1:]
204   command.ProcessCommandLine(parser, options, args)
205   return command.Run(options, args)