| #!/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 the test with xvfb on linux. Runs the test normally on other platforms. |
| |
| For simplicity in gyp targets, this script just runs the test normal on |
| non-linux platforms. |
| """ |
| |
| import os |
| import platform |
| import signal |
| import subprocess |
| import sys |
| |
| import test_env |
| |
| |
| def kill(pid): |
| """Kills a process and traps exception if the process doesn't exist anymore. |
| """ |
| # If the process doesn't exist, it raises an exception that we can ignore. |
| try: |
| os.kill(pid, signal.SIGKILL) |
| except OSError: |
| pass |
| |
| |
| def get_xvfb_path(server_dir): |
| """Figures out which X server to use.""" |
| xvfb_path = os.path.join(server_dir, 'Xvfb.' + platform.architecture()[0]) |
| if not os.path.exists(xvfb_path): |
| xvfb_path = os.path.join(server_dir, 'Xvfb') |
| if not os.path.exists(xvfb_path): |
| print >> sys.stderr, ( |
| 'No Xvfb found in designated server path: %s' % server_dir) |
| raise Exception('No virtual server') |
| return xvfb_path |
| |
| |
| def start_xvfb(xvfb_path, display): |
| """Starts a virtual X server that we run the tests in. |
| |
| This makes it so we can run the tests even if we didn't start the tests from |
| an X session. |
| |
| Args: |
| xvfb_path: Path to Xvfb. |
| """ |
| cmd = [xvfb_path, display, '-screen', '0', '1024x768x24', '-ac', |
| '-nolisten', 'tcp'] |
| try: |
| proc = subprocess.Popen( |
| cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
| except OSError: |
| print >> sys.stderr, 'Failed to run %s' % ' '.join(cmd) |
| return |
| return proc |
| |
| |
| def wait_for_xvfb(xdisplaycheck, env): |
| """Waits for xvfb to be fully initialized by using xdisplaycheck.""" |
| try: |
| _logs = 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 properly (code %d) according to %s' % |
| (e.returncode, xdisplaycheck)) |
| return False |
| |
| return True |
| |
| |
| def run_executable(cmd, build_dir, env): |
| """Runs an executable within a xvfb buffer on linux or normally on other |
| platforms. |
| |
| Requires that both xvfb and openbox are installed on linux. |
| |
| Detects recursion with an environment variable and do not create a recursive X |
| buffer if present. |
| """ |
| # First look if we are inside a display. |
| if env.get('_CHROMIUM_INSIDE_XVFB') == '1': |
| # No need to recurse. |
| return test_env.run_executable(cmd, env) |
| |
| pid = None |
| xvfb = 'Xvfb' |
| try: |
| if sys.platform == 'linux2': |
| # Defaults to X display 9. |
| display = ':9' |
| xvfb_proc = start_xvfb(xvfb, display) |
| if not xvfb_proc or not xvfb_proc.pid: |
| return 1 |
| env['DISPLAY'] = display |
| if not wait_for_xvfb(os.path.join(build_dir, 'xdisplaycheck'), env): |
| rc = xvfb_proc.poll() |
| if rc is None: |
| print 'Xvfb still running, stopping.' |
| xvfb_proc.terminate() |
| else: |
| print 'Xvfb exited, code %d' % rc |
| |
| print 'Xvfb output:' |
| for l in xvfb_proc.communicate()[0].splitlines(): |
| print '> %s' % l |
| |
| return 3 |
| # Inhibit recursion. |
| env['_CHROMIUM_INSIDE_XVFB'] = '1' |
| # Some ChromeOS tests need a window manager. Technically, it could be |
| # another script but that would be overkill. |
| try: |
| wm_cmd = ['openbox'] |
| subprocess.Popen( |
| wm_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) |
| except OSError: |
| print >> sys.stderr, 'Failed to run %s' % ' '.join(wm_cmd) |
| return 1 |
| return test_env.run_executable(cmd, env) |
| finally: |
| if pid: |
| kill(pid) |
| |
| |
| 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()) |