Commit 9cc81c66 authored by dnj's avatar dnj Committed by Commit bot

webkitpy: Override TEMPDIR for Xvfb.

Hard-code TEMPDIR/TMPDIR for "Xvfb" to "/tmp" in webkitpy's Linux layout
test port. The Xvfb tool's "xkb" library compiles in "/tmp" in several
places, and hard-linking expectations get violated if TEMPDIR and "/tmp"
are on different filesystems.

BUG=chromium:715848
TEST=local
  - Ran without patch and TEMPDIR/TMPDIR overrides, verified hardlink
    failure from bug.
  - Ran with patch, no more hardlink failure!

Review-Url: https://codereview.chromium.org/2859703002
Cr-Commit-Position: refs/heads/master@{#469378}
parent 66a20167
......@@ -26,6 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import collections
import logging
import os
import StringIO
......@@ -60,6 +61,9 @@ class MockProcess(object):
return
MockCall = collections.namedtuple('MockCall', ('args', 'env'))
class MockExecutive(object):
PIPE = 'MOCK PIPE'
STDOUT = 'MOCK STDOUT'
......@@ -82,7 +86,15 @@ class MockExecutive(object):
self._exception = exception
self._run_command_fn = run_command_fn
self._proc = None
self.calls = []
self.full_calls = []
def _append_call(self, args, env=None):
if env:
env = env.copy()
self.full_calls.append(MockCall(
args=args,
env=env.copy() if env is not None else None,
))
def check_running_pid(self, pid):
return pid in self._running_pids.values()
......@@ -113,7 +125,7 @@ class MockExecutive(object):
decode_output=False,
env=None,
debug_logging=False):
self.calls.append(args)
self._append_call(args, env=env)
assert isinstance(args, list) or isinstance(args, tuple)
......@@ -160,7 +172,7 @@ class MockExecutive(object):
def popen(self, args, cwd=None, env=None, **_):
assert all(isinstance(arg, basestring) for arg in args)
self.calls.append(args)
self._append_call(args, env=env)
if self._should_log:
cwd_string = ''
if cwd:
......@@ -175,21 +187,21 @@ class MockExecutive(object):
def call(self, args, **_):
assert all(isinstance(arg, basestring) for arg in args)
self.calls.append(args)
self._append_call(args)
_log.info('Mock call: %s', args)
def run_in_parallel(self, commands):
assert len(commands)
num_previous_calls = len(self.calls)
num_previous_calls = len(self.full_calls)
command_outputs = []
for cmd_line, cwd in commands:
assert all(isinstance(arg, basestring) for arg in cmd_line)
command_outputs.append([0, self.run_command(cmd_line, cwd=cwd), ''])
new_calls = self.calls[num_previous_calls:]
self.calls = self.calls[:num_previous_calls]
self.calls.append(new_calls)
new_calls = self.full_calls[num_previous_calls:]
self.full_calls = self.full_calls[:num_previous_calls]
self.full_calls.append(new_calls)
return command_outputs
def map(self, thunk, arglist, processes=None):
......@@ -198,6 +210,20 @@ class MockExecutive(object):
def process_dump(self):
return []
@property
def calls(self):
# TODO(crbug.com/718456): Make self.full_calls always be an array of
# arrays of MockCalls, rather than a union type, and possibly remove
# this property in favor of direct "full_calls" access in unit tests.
def get_args(v):
if isinstance(v, list):
return [get_args(e) for e in v]
elif isinstance(v, MockCall):
return v.args
else:
return TypeError('Unknown full_calls type: %s' % (type(v).__name__,))
return get_args(self.full_calls)
def mock_git_commands(vals, strict=False):
def run_fn(args):
......
......@@ -70,7 +70,7 @@ class TestDumpReaderWin(unittest.TestCase):
dump_reader = DumpReaderWin(host, build_dir)
self.assertTrue(dump_reader.check_is_functional())
host.executive.calls = []
host.executive.full_calls = []
self.assertEqual("MOCK output of child process", dump_reader._get_stack_from_dump(dump_file))
self.assertEqual(1, len(host.executive.calls))
cmd_line = " ".join(host.executive.calls[0])
......
......@@ -157,12 +157,22 @@ class LinuxPort(base.Port):
_log.critical('Failed to find a free display to start Xvfb.')
return
_log.info('Starting Xvfb with display "%s".', display)
# Parts of Xvfb use a hard-coded "/tmp" for its temporary directory.
# This can cause a failure when those parts expect to hardlink against
# files that were created in "TEMPDIR" / "TMPDIR".
#
# See: https://crbug.com/715848
env = self.host.environ.copy()
if env.get('TMPDIR') and env['TMPDIR'] != '/tmp':
_log.info('Overriding TMPDIR to "/tmp" for Xvfb, was: %s', env['TMPDIR'])
env['TMPDIR'] = '/tmp'
_log.debug('Starting Xvfb with display "%s".', display)
self._xvfb_stdout = tempfile.NamedTemporaryFile(delete=False)
self._xvfb_stderr = tempfile.NamedTemporaryFile(delete=False)
self._xvfb_process = self.host.executive.popen(
['Xvfb', display, '-screen', '0', '1280x800x24', '-ac', '-dpi', '96'],
stdout=self._xvfb_stdout, stderr=self._xvfb_stderr)
stdout=self._xvfb_stdout, stderr=self._xvfb_stderr, env=env)
# By setting DISPLAY here, the individual worker processes will
# get the right DISPLAY. Note, if this environment could be passed
......
......@@ -136,6 +136,30 @@ class LinuxPortTest(port_testcase.PortTestCase):
env = port.setup_environ_for_server()
self.assertEqual(env['DISPLAY'], ':99')
def test_setup_test_run_starts_xvfb_clears_tmpdir(self):
def run_command_fake(args):
if args[0] == 'xdpyinfo':
if '-display' in args:
return 1
return 0
port = self.make_port()
port.host.environ['TMPDIR'] = '/foo/bar'
port.host.executive = MockExecutive(
run_command_fn=run_command_fake)
port.setup_test_run()
self.assertEqual(
port.host.executive.calls,
[
['xdpyinfo', '-display', ':99'],
['Xvfb', ':99', '-screen', '0', '1280x800x24', '-ac', '-dpi', '96'],
['xdpyinfo'],
])
self.assertEqual(port.host.executive.full_calls[1].env.get('TMPDIR'), '/tmp')
env = port.setup_environ_for_server()
self.assertEqual(env['DISPLAY'], ':99')
def test_setup_test_runs_finds_free_display(self):
def run_command_fake(args):
if args[0] == 'xdpyinfo':
......
......@@ -223,7 +223,7 @@ crbug.com/24182 path/to/locally-changed-lined.html [ NeedsRebaseline ]
self.assertEqual(self.tool.executive.calls, [])
self.command.tree_status = lambda: 'open'
self.tool.executive.calls = []
self.tool.executive.full_calls = []
self._execute_with_mock_options()
self.assertEqual(self.tool.executive.calls, [
......@@ -322,7 +322,7 @@ Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
self.command.SECONDS_BEFORE_GIVING_UP = 0
self.command.tree_status = lambda: 'open'
self.tool.executive = MockExecutive()
self.tool.executive.calls = []
self.tool.executive.full_calls = []
self._execute_with_mock_options()
self.assertEqual(self.tool.executive.calls, [
......
......@@ -1138,9 +1138,9 @@ class MockLineRemovingExecutive(MockExecutive):
out = json.dumps({'remove-lines': [{'test': test, 'port_name': port_name}]})
command_outputs.append([0, out, ''])
new_calls = self.calls[num_previous_calls:]
self.calls = self.calls[:num_previous_calls]
self.calls.append(new_calls)
new_calls = self.full_calls[num_previous_calls:]
self.full_calls = self.full_calls[:num_previous_calls]
self.full_calls.append(new_calls)
return command_outputs
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment