Bumping manifests a=b2g-bump
[gecko.git] / python / mach_commands.py
blobaa25787a427fcea7aad4785fd1f8cda7467895ac
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 from __future__ import print_function, unicode_literals
7 import argparse
8 import glob
9 import logging
10 import mozpack.path
11 import os
12 import sys
14 from mozbuild.base import (
15 MachCommandBase,
18 from mach.decorators import (
19 CommandArgument,
20 CommandProvider,
21 Command,
25 @CommandProvider
26 class MachCommands(MachCommandBase):
27 @Command('python', category='devenv',
28 description='Run Python.')
29 @CommandArgument('args', nargs=argparse.REMAINDER)
30 def python(self, args):
31 # Avoid logging the command
32 self.log_manager.terminal_handler.setLevel(logging.CRITICAL)
34 self._activate_virtualenv()
36 return self.run_process([self.virtualenv_manager.python_path] + args,
37 pass_thru=True, # Allow user to run Python interactively.
38 ensure_exit_code=False, # Don't throw on non-zero exit code.
39 # Note: subprocess requires native strings in os.environ on Windows
40 append_env={b'PYTHONDONTWRITEBYTECODE': str('1')})
42 @Command('python-test', category='testing',
43 description='Run Python unit tests.')
44 @CommandArgument('--verbose',
45 default=False,
46 action='store_true',
47 help='Verbose output.')
48 @CommandArgument('--stop',
49 default=False,
50 action='store_true',
51 help='Stop running tests after the first error or failure.')
52 @CommandArgument('tests', nargs='+',
53 metavar='TEST',
54 help='Tests to run. Each test can be a single file or a directory.')
55 def python_test(self, tests, verbose=False, stop=False):
56 self._activate_virtualenv()
58 # Python's unittest, and in particular discover, has problems with
59 # clashing namespaces when importing multiple test modules. What follows
60 # is a simple way to keep environments separate, at the price of
61 # launching Python multiple times. This also runs tests via mozunit,
62 # which produces output in the format Mozilla infrastructure expects.
63 return_code = 0
64 files = []
65 # We search for files in both the current directory (for people running
66 # from topsrcdir or cd'd into their test directory) and topsrcdir (to
67 # support people running mach from the objdir). The |break|s in the
68 # loop below ensure that we don't run tests twice if we're running mach
69 # from topsrcdir
70 search_dirs = ['.', self.topsrcdir]
71 last_search_dir = search_dirs[-1]
72 for t in tests:
73 for d in search_dirs:
74 test = mozpack.path.join(d, t)
75 if test.endswith('.py') and os.path.isfile(test):
76 files.append(test)
77 break
78 elif os.path.isfile(test + '.py'):
79 files.append(test + '.py')
80 break
81 elif os.path.isdir(test):
82 files += glob.glob(mozpack.path.join(test, 'test*.py'))
83 files += glob.glob(mozpack.path.join(test, 'unit*.py'))
84 break
85 elif d == last_search_dir:
86 self.log(logging.WARN, 'python-test',
87 {'test': t},
88 'TEST-UNEXPECTED-FAIL | Invalid test: {test}')
89 if stop:
90 return 1
92 for f in files:
93 file_displayed_test = [] # Used as a boolean.
94 def _line_handler(line):
95 if not file_displayed_test and line.startswith('TEST-'):
96 file_displayed_test.append(True)
98 inner_return_code = self.run_process(
99 [self.virtualenv_manager.python_path, f],
100 ensure_exit_code=False, # Don't throw on non-zero exit code.
101 log_name='python-test',
102 # subprocess requires native strings in os.environ on Windows
103 append_env={b'PYTHONDONTWRITEBYTECODE': str('1')},
104 line_handler=_line_handler)
105 return_code += inner_return_code
107 if not file_displayed_test:
108 self.log(logging.WARN, 'python-test', {'file': f},
109 'TEST-UNEXPECTED-FAIL | No test output (missing mozunit.main() call?): {file}')
111 if verbose:
112 if inner_return_code != 0:
113 self.log(logging.INFO, 'python-test', {'file': f},
114 'Test failed: {file}')
115 else:
116 self.log(logging.INFO, 'python-test', {'file': f},
117 'Test passed: {file}')
118 if stop and return_code > 0:
119 return 1
121 return 0 if return_code == 0 else 1