blob: 67ef729fb7753938dcab961e9750e3f06b3380d5 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Runs tests with Xvfb and Openbox on Linux and normally on other platforms."""
import os
import platform
import signal
import subprocess
import sys
import test_env
def kill(proc):
"""Kills |proc| and ignores exceptions thrown for non-existent processes."""
try:
if proc and proc.pid:
os.kill(proc.pid, signal.SIGKILL)
except OSError:
pass
def wait_for_xvfb(xdisplaycheck, env):
"""Waits for xvfb to be fully initialized by using xdisplaycheck."""
try:
subprocess.check_output([xdisplaycheck], stderr=subprocess.STDOUT, env=env)
except OSError:
print >> sys.stderr, 'Failed to load %s with cwd=%s' % (
xdisplaycheck, os.getcwd())
return False
except subprocess.CalledProcessError as e:
print >> sys.stderr, ('Xvfb failed to load (code %d) according to %s' %
(e.returncode, xdisplaycheck))
return False
return True
def should_start_xvfb(env):
"""Xvfb is only used on Linux and shouldn't be invoked recursively."""
return sys.platform == 'linux2' and env.get('_CHROMIUM_INSIDE_XVFB') != '1'
def start_xvfb(env, build_dir, xvfb_path='Xvfb', display=':9'):
"""Start a virtual X server that can run tests without an existing X session.
Returns the Xvfb and Openbox process Popen objects, or None on failure.
The |env| dictionary is modified to set the DISPLAY and prevent re-entry.
Args:
env: The os.environ dictionary [copy] to check for re-entry.
build_dir: The path of the build directory, used for xdisplaycheck.
xvfb_path: The path to Xvfb.
display: The X display number to use.
"""
assert should_start_xvfb(env)
assert env.get('_CHROMIUM_INSIDE_XVFB') != '1'
env['_CHROMIUM_INSIDE_XVFB'] = '1'
env['DISPLAY'] = display
xvfb_proc = None
openbox_proc = None
try:
xvfb_cmd = [xvfb_path, display, '-screen', '0', '1024x768x24', '-ac',
'-nolisten', 'tcp', '-dpi', '96']
xvfb_proc = subprocess.Popen(xvfb_cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
if not wait_for_xvfb(os.path.join(build_dir, 'xdisplaycheck'), env):
rc = xvfb_proc.poll()
if rc is None:
print 'Xvfb still running after xdisplaycheck failure, stopping.'
kill(xvfb_proc)
else:
print 'Xvfb exited (code %d) after xdisplaycheck failure.' % rc
print 'Xvfb output:'
for l in xvfb_proc.communicate()[0].splitlines():
print '> %s' % l
return (None, None)
# Some ChromeOS tests need a window manager.
openbox_proc = subprocess.Popen('openbox', stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, env=env)
except OSError as e:
print >> sys.stderr, 'Failed to start Xvfb or Openbox: %s' % str(e)
kill(xvfb_proc)
kill(openbox_proc)
return (None, None)
return (xvfb_proc, openbox_proc)
def run_executable(cmd, build_dir, env):
"""Runs an executable within Xvfb on Linux or normally on other platforms.
Returns the exit code of the specified commandline, or 1 on failure.
"""
xvfb = None
openbox = None
if should_start_xvfb(env):
(xvfb, openbox) = start_xvfb(env, build_dir)
if not xvfb or not xvfb.pid or not openbox or not openbox.pid:
return 1
try:
return test_env.run_executable(cmd, env)
finally:
kill(xvfb)
kill(openbox)
def main():
if len(sys.argv) < 3:
print >> sys.stderr, (
'Usage: xvfb.py [path to build_dir] [command args...]')
return 2
return run_executable(sys.argv[2:], sys.argv[1], os.environ.copy())
if __name__ == "__main__":
sys.exit(main())