author Andrew Halberstadt <>
Wed, 31 May 2017 13:52:01 -0400
changeset 363279 83081a324efb68dacb018a4ea1ef8dea91796dba
parent 352261 88e9938ce64ca0281c4f6ed2dd8ca93a0bfe5100
permissions -rwxr-xr-x
Bug 1048446 - [python-test] Create a mochitest selftest harness, r=jmaher This will create a mochitest selftest harness based on |mach python-test|. There is also a basic test that checks whether TEST-PASS and TEST-UNEXPECTED-FAIL work. MozReview-Commit-ID: Jqyhbj7nC6z

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at

# The beginning of this script is both valid shell and valid python,
# such that the script starts with the shell and is reexecuted with
# the right python.
''':' && if [ ! -z "$MSYSTEM" ] ; then exec python "$0" "$@" ; else which python2.7 > /dev/null 2> /dev/null && exec python2.7 "$0" "$@" || exec python "$0" "$@" ; fi

from __future__ import print_function, unicode_literals

import os
import sys

def main(args):
    topdir = os.path.abspath(os.path.dirname(sys.argv[0]))
    sys.path.insert(0, os.path.join(topdir, "python"))
    import mach_bootstrap
    mach = mach_bootstrap.bootstrap(topdir)

if __name__ == '__main__':
    sys.dont_write_bytecode = True
    if sys.platform == 'win32':
        # This is a complete hack to work around the fact that Windows
        # multiprocessing needs to import the original module (ie: this
        # file), but only works if it has a .py extension.
        # We do this by a sort of two-level function interposing. The first
        # level interposes forking.get_command_line() with our version defined
        # in my_get_command_line(). Our version of get_command_line will
        # replace the command string with the contents of the fork_interpose()
        # function to be used in the subprocess.
        # The subprocess then gets an interposed imp.find_module(), which we
        # hack up to find 'mach' without the .py extension, since we already
        # know where it is (it's us!). If we're not looking for 'mach', then
        # the original find_module will suffice.
        # See also:
        # And:
        import inspect
        from multiprocessing import forking
        global orig_command_line

        def fork_interpose():
            import imp
            import os
            import sys
            orig_find_module = imp.find_module
            def my_find_module(name, dirs):
                if name == 'mach':
                    path = os.path.join(dirs[0], 'mach')
                    f = open(path)
                    return (f, path, ('', 'r', imp.PY_SOURCE))
                return orig_find_module(name, dirs)

            # Don't allow writing bytecode file for mach module.
            orig_load_module = imp.load_module
            def my_load_module(name, file, path, description):
                # multiprocess.forking invokes imp.load_module manually and
                # hard-codes the name __parents_main__ as the module name.
                if name == '__parents_main__':
                    old_bytecode = sys.dont_write_bytecode
                    sys.dont_write_bytecode = True
                        return orig_load_module(name, file, path, description)
                        sys.dont_write_bytecode = old_bytecode

                return orig_load_module(name, file, path, description)

            imp.find_module = my_find_module
            imp.load_module = my_load_module
            from multiprocessing.forking import main; main()

        def my_get_command_line():
            fork_code, lineno = inspect.getsourcelines(fork_interpose)
            # Remove the first line (for 'def fork_interpose():') and the three
            # levels of indentation (12 spaces).
            fork_string = ''.join(x[12:] for x in fork_code[1:])
            cmdline = orig_command_line()
            cmdline[2] = fork_string
            return cmdline
        orig_command_line = forking.get_command_line
        forking.get_command_line = my_get_command_line