Bug 1533043 - [python-test] Add ability for individual tests to have pypi dependencies, r=davehunt
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Wed, 13 Mar 2019 14:51:37 +0000
changeset 463987 203ed6d898c152b7c93c80fe52f01fa5b9141b8f
parent 463986 df7a6846edf5cb1bb85a4863cbcc117f38d381e1
child 463988 8a144ea413963941234ef747c2859875f9ad7e04
push id35705
push userrmaries@mozilla.com
push dateThu, 14 Mar 2019 21:39:47 +0000
treeherdermozilla-central@495029aae21b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1533043 - [python-test] Add ability for individual tests to have pypi dependencies, r=davehunt Sometimes tools install pypi at runtime via mach (e.g self.install_pip_package / self.install_pip_requirements). It's difficult to test these modules with pytest because we usually won't be going through mach. This gives tests the ability to depend on external pypi packages the same way they might get installed when running via mach. Note, I only added support for requirements.txt here because python/mozbuild/mozbuild/virtualenv.py's 'install_pip_package' function is completely busted with modern pip. And the pip used with |mach python-test| is more modern than the one used with the regular build venv due to pipenv. We'll need to fix this eventually, but that's another bug for another day. Differential Revision: https://phabricator.services.mozilla.com/D22784
--- a/python/mach_commands.py
+++ b/python/mach_commands.py
@@ -165,39 +165,42 @@ class MachCommands(MachCommandBase):
                 self.log(logging.INFO, 'python-test', {'line': line.rstrip()}, '{line}')
             if ret and not return_code:
                 self.log(logging.ERROR, 'python-test', {'test_path': test_path, 'ret': ret},
                          'Setting retcode to {ret} from {test_path}')
             return return_code or ret
         with ThreadPoolExecutor(max_workers=self.jobs) as executor:
-            futures = [executor.submit(self._run_python_test, test['path'])
+            futures = [executor.submit(self._run_python_test, test)
                        for test in parallel]
                 for future in as_completed(futures):
                     return_code = on_test_finished(future.result())
             except KeyboardInterrupt:
                 # Hack to force stop currently running threads.
                 # https://gist.github.com/clchiou/f2608cbe54403edb0b13
         for test in sequential:
-            return_code = on_test_finished(self._run_python_test(test['path']))
+            return_code = on_test_finished(self._run_python_test(test))
         self.log(logging.INFO, 'python-test', {'return_code': return_code},
                  'Return code from mach python-test: {return_code}')
         return return_code
-    def _run_python_test(self, test_path):
+    def _run_python_test(self, test):
         from mozprocess import ProcessHandler
+        if test.get('requirements'):
+            self.virtualenv_manager.install_pip_requirements(test['requirements'], quiet=True)
         output = []
         def _log(line):
             # Buffer messages if more than one worker to avoid interleaving
             if self.jobs > 1:
                 self.log(logging.INFO, 'python-test', {'line': line.rstrip()}, '{line}')
@@ -212,29 +215,29 @@ class MachCommands(MachCommandBase):
             # Hack to make sure treeherder highlights pytest failures
             if 'FAILED' in line.rsplit(' ', 1)[-1]:
                 line = line.replace('FAILED', 'TEST-UNEXPECTED-FAIL')
-        _log(test_path)
-        cmd = [self.virtualenv_manager.python_path, test_path]
+        _log(test['path'])
+        cmd = [self.virtualenv_manager.python_path, test['path']]
         env = os.environ.copy()
         env[b'PYTHONDONTWRITEBYTECODE'] = b'1'
         proc = ProcessHandler(cmd, env=env, processOutputLine=_line_handler, storeOutput=False)
         return_code = proc.wait()
         if not file_displayed_test:
             _log('TEST-UNEXPECTED-FAIL | No test output (missing mozunit.main() '
-                 'call?): {}'.format(test_path))
+                 'call?): {}'.format(test['path']))
         if self.verbose:
             if return_code != 0:
-                _log('Test failed: {}'.format(test_path))
+                _log('Test failed: {}'.format(test['path']))
-                _log('Test passed: {}'.format(test_path))
+                _log('Test passed: {}'.format(test['path']))
-        return output, return_code, test_path
+        return output, return_code, test['path']