Bug 1266343 - Extend the ConfigureTestSandbox to hook subprocess.Popen. r=chmanchester

This commit is contained in:
Mike Hommey 2016-04-20 13:44:03 +09:00
Родитель 11b8ab106b
Коммит 44b5cc5dc5
2 изменённых файлов: 94 добавлений и 7 удалений

Просмотреть файл

@ -4,7 +4,9 @@
from __future__ import absolute_import, print_function, unicode_literals
import errno
import os
import subprocess
from mozbuild.configure import ConfigureSandbox
from mozbuild.util import ReadOnlyNamespace
@ -12,22 +14,64 @@ from mozpack import path as mozpath
from which import WhichError
from buildconfig import (
topobjdir,
topsrcdir,
)
class ConfigureTestVFS(object):
def __init__(self, paths):
self._paths = set(mozpath.abspath(p) for p in paths)
def exists(self, path):
return mozpath.abspath(path) in self._paths
path = mozpath.abspath(path)
if path in self._paths:
return True
if mozpath.basedir(path, [topsrcdir, topobjdir]):
return os.path.exists(path)
return False
def isfile(self, path):
return mozpath.abspath(path) in self._paths
path = mozpath.abspath(path)
if path in self._paths:
return True
if mozpath.basedir(path, [topsrcdir, topobjdir]):
return os.path.isfile(path)
return False
class ConfigureTestSandbox(ConfigureSandbox):
'''Wrapper around the ConfigureSandbox for testing purposes.
Its arguments are the same as ConfigureSandbox, except for the additional
`paths` argument, which is a dict where the keys are file paths and the
values are either None or a function that will be called when the sandbox
calls an implemented function from subprocess with the key as command.
When the command is CONFIG_SHELL, the function for the path of the script
that follows will be called.
The API for those functions is:
retcode, stdout, stderr = func(stdin, args)
This class is only meant to implement the minimal things to make
moz.configure testing possible. As such, it takes shortcuts.
'''
def __init__(self, paths, config, environ, *args, **kwargs):
self._search_path = environ.get('PATH', '').split(os.pathsep)
self._subprocess_paths = {
mozpath.abspath(k): v for k, v in paths.iteritems() if v
}
paths = paths.keys()
environ = dict(environ)
if 'CONFIG_SHELL' not in environ:
environ['CONFIG_SHELL'] = mozpath.abspath('/bin/sh')
self._subprocess_paths[environ['CONFIG_SHELL']] = self.shell
paths.append(environ['CONFIG_SHELL'])
vfs = ConfigureTestVFS(paths)
self.OS = ReadOnlyNamespace(path=ReadOnlyNamespace(**{
@ -49,6 +93,17 @@ class ConfigureTestSandbox(ConfigureSandbox):
WhichError=WhichError,
)
if what == 'subprocess.Popen':
return self.Popen
if what == 'subprocess':
return ReadOnlyNamespace(
CalledProcessError=subprocess.CalledProcessError,
check_output=self.check_output,
PIPE=subprocess.PIPE,
Popen=self.Popen,
)
return super(ConfigureTestSandbox, self)._get_one_import(what)
def which(self, command):
@ -57,3 +112,35 @@ class ConfigureTestSandbox(ConfigureSandbox):
if self.OS.path.exists(path):
return path
raise WhichError()
def Popen(self, args, stdin=None, stdout=None, stderr=None, **kargs):
try:
program = self.which(args[0])
except WhichError:
raise OSError(errno.ENOENT, 'File not found')
func = self._subprocess_paths.get(program)
retcode, stdout, stderr = func(stdin, args[1:])
class Process(object):
def communicate(self, stdin=None):
return stdout, stderr
def wait(self):
return retcode
return Process()
def check_output(self, args):
proc = self.Popen(args)
stdout, stderr = proc.communicate()
retcode = proc.wait()
if retcode:
raise subprocess.CalledProcessError(retcode, args, stdout)
return stdout
def shell(self, stdin, args):
script = mozpath.abspath(args[0])
if script in self._subprocess_paths:
return self._subprocess_paths[script](stdin, args[1:])
return 127, '', 'File not found'

Просмотреть файл

@ -131,11 +131,11 @@ class TestChecksConfigure(unittest.TestCase):
prog='/bin/configure'):
config = {}
out = StringIO()
paths = (
self.KNOWN_A,
self.KNOWN_B,
self.KNOWN_C,
)
paths = {
self.KNOWN_A: None,
self.KNOWN_B: None,
self.KNOWN_C: None,
}
environ = dict(environ)
environ['PATH'] = os.pathsep.join(os.path.dirname(p) for p in paths)
sandbox = ConfigureTestSandbox(paths, config, environ, [prog] + args,