1 #!/usr/bin/env python 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 """Runs the test with xvfb on linux. Runs the test normally on other platforms. 7 8 For simplicity in gyp targets, this script just runs the test normal on 9 non-linux platforms. 10 """ 11 12 import os 13 import platform 14 import signal 15 import subprocess 16 import sys 17 18 import test_env 19 20 21 def kill(pid): 22 """Kills a process and traps exception if the process doesn't exist anymore. 23 """ 24 # If the process doesn't exist, it raises an exception that we can ignore. 25 try: 26 os.kill(pid, signal.SIGKILL) 27 except OSError: 28 pass 29 30 31 def get_xvfb_path(server_dir): 32 """Figures out which X server to use.""" 33 xvfb_path = os.path.join(server_dir, 'Xvfb.' + platform.architecture()[0]) 34 if not os.path.exists(xvfb_path): 35 xvfb_path = os.path.join(server_dir, 'Xvfb') 36 if not os.path.exists(xvfb_path): 37 print >> sys.stderr, ( 38 'No Xvfb found in designated server path: %s' % server_dir) 39 raise Exception('No virtual server') 40 return xvfb_path 41 42 43 def start_xvfb(xvfb_path, display): 44 """Starts a virtual X server that we run the tests in. 45 46 This makes it so we can run the tests even if we didn't start the tests from 47 an X session. 48 49 Args: 50 xvfb_path: Path to Xvfb. 51 """ 52 cmd = [xvfb_path, display, '-screen', '0', '1024x768x24', '-ac'] 53 try: 54 proc = subprocess.Popen( 55 cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 56 except OSError: 57 print >> sys.stderr, 'Failed to run %s' % ' '.join(cmd) 58 return 0 59 return proc.pid 60 61 62 def wait_for_xvfb(xdisplaycheck, env): 63 """Waits for xvfb to be fully initialized by using xdisplaycheck.""" 64 try: 65 subprocess.check_call( 66 [xdisplaycheck], 67 stdout=subprocess.PIPE, 68 stderr=subprocess.STDOUT, 69 env=env) 70 except OSError: 71 print >> sys.stderr, 'Failed to load %s with cwd=%s' % ( 72 xdisplaycheck, os.getcwd()) 73 return False 74 except subprocess.CalledProcessError: 75 print >> sys.stderr, ( 76 'Xvfb failed to load properly while trying to run %s' % xdisplaycheck) 77 return False 78 return True 79 80 81 def run_executable(cmd, build_dir, env): 82 """Runs an executable within a xvfb buffer on linux or normally on other 83 platforms. 84 85 Requires that both xvfb and openbox are installed on linux. 86 87 Detects recursion with an environment variable and do not create a recursive X 88 buffer if present. 89 """ 90 # First look if we are inside a display. 91 if env.get('_CHROMIUM_INSIDE_XVFB') == '1': 92 # No need to recurse. 93 return test_env.run_executable(cmd, env) 94 95 pid = None 96 xvfb = 'Xvfb' 97 try: 98 if sys.platform == 'linux2': 99 # Defaults to X display 9. 100 display = ':9' 101 pid = start_xvfb(xvfb, display) 102 if not pid: 103 return 1 104 env['DISPLAY'] = display 105 if not wait_for_xvfb(os.path.join(build_dir, 'xdisplaycheck'), env): 106 return 3 107 # Inhibit recursion. 108 env['_CHROMIUM_INSIDE_XVFB'] = '1' 109 # Some ChromeOS tests need a window manager. Technically, it could be 110 # another script but that would be overkill. 111 try: 112 wm_cmd = ['openbox'] 113 subprocess.Popen( 114 wm_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) 115 except OSError: 116 print >> sys.stderr, 'Failed to run %s' % ' '.join(wm_cmd) 117 return 1 118 return test_env.run_executable(cmd, env) 119 finally: 120 if pid: 121 kill(pid) 122 123 124 def main(): 125 if len(sys.argv) < 3: 126 print >> sys.stderr, ( 127 'Usage: xvfb.py [path to build_dir] [command args...]') 128 return 2 129 return run_executable(sys.argv[2:], sys.argv[1], os.environ.copy()) 130 131 132 if __name__ == "__main__": 133 sys.exit(main()) 134