Update activity log owners
[chromium-blink-merge.git] / testing / xvfb.py
blob62815b2e789181448afbb03929a53991c7562455
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.
6 """Runs tests with Xvfb and Openbox on Linux and normally on other platforms."""
8 import os
9 import platform
10 import signal
11 import subprocess
12 import sys
13 import threading
15 import test_env
18 def _kill(proc, send_signal):
19 """Kills |proc| and ignores exceptions thrown for non-existent processes."""
20 try:
21 os.kill(proc.pid, send_signal)
22 except OSError:
23 pass
26 def kill(proc, timeout_in_seconds=10):
27 """Tries to kill |proc| gracefully with a timeout for each signal."""
28 if not proc or not proc.pid:
29 return
31 _kill(proc, signal.SIGTERM)
32 thread = threading.Thread(target=proc.wait)
33 thread.start()
35 thread.join(timeout_in_seconds)
36 if thread.is_alive():
37 print >> sys.stderr, 'Xvfb running after SIGTERM, trying SIGKILL.'
38 _kill(proc, signal.SIGKILL)
40 thread.join(timeout_in_seconds)
41 if thread.is_alive():
42 print >> sys.stderr, 'Xvfb running after SIGTERM and SIGKILL; good luck!'
45 def wait_for_xvfb(xdisplaycheck, env):
46 """Waits for xvfb to be fully initialized by using xdisplaycheck."""
47 try:
48 subprocess.check_output([xdisplaycheck], stderr=subprocess.STDOUT, env=env)
49 except OSError:
50 print >> sys.stderr, 'Failed to load %s with cwd=%s' % (
51 xdisplaycheck, os.getcwd())
52 return False
53 except subprocess.CalledProcessError as e:
54 print >> sys.stderr, ('Xvfb failed to load (code %d) according to %s' %
55 (e.returncode, xdisplaycheck))
56 return False
58 return True
61 def should_start_xvfb(env):
62 """Xvfb is only used on Linux and shouldn't be invoked recursively."""
63 return sys.platform == 'linux2' and env.get('_CHROMIUM_INSIDE_XVFB') != '1'
66 def start_xvfb(env, build_dir, xvfb_path='Xvfb', display=':9'):
67 """Start a virtual X server that can run tests without an existing X session.
69 Returns the Xvfb and Openbox process Popen objects, or None on failure.
70 The |env| dictionary is modified to set the DISPLAY and prevent re-entry.
72 Args:
73 env: The os.environ dictionary [copy] to check for re-entry.
74 build_dir: The path of the build directory, used for xdisplaycheck.
75 xvfb_path: The path to Xvfb.
76 display: The X display number to use.
77 """
78 assert should_start_xvfb(env)
79 assert env.get('_CHROMIUM_INSIDE_XVFB') != '1'
80 env['_CHROMIUM_INSIDE_XVFB'] = '1'
81 env['DISPLAY'] = display
82 xvfb_proc = None
83 openbox_proc = None
85 try:
86 xvfb_cmd = [xvfb_path, display, '-screen', '0', '1024x768x24', '-ac',
87 '-nolisten', 'tcp', '-dpi', '96']
88 xvfb_proc = subprocess.Popen(xvfb_cmd, stdout=subprocess.PIPE,
89 stderr=subprocess.STDOUT)
91 if not wait_for_xvfb(os.path.join(build_dir, 'xdisplaycheck'), env):
92 rc = xvfb_proc.poll()
93 if rc is None:
94 print 'Xvfb still running after xdisplaycheck failure, stopping.'
95 kill(xvfb_proc)
96 else:
97 print 'Xvfb exited (code %d) after xdisplaycheck failure.' % rc
98 print 'Xvfb output:'
99 for l in xvfb_proc.communicate()[0].splitlines():
100 print '> %s' % l
101 return (None, None)
103 # Some ChromeOS tests need a window manager.
104 openbox_proc = subprocess.Popen('openbox', stdout=subprocess.PIPE,
105 stderr=subprocess.STDOUT, env=env)
106 except OSError as e:
107 print >> sys.stderr, 'Failed to start Xvfb or Openbox: %s' % str(e)
108 kill(xvfb_proc)
109 kill(openbox_proc)
110 return (None, None)
112 return (xvfb_proc, openbox_proc)
115 def run_executable(cmd, build_dir, env):
116 """Runs an executable within Xvfb on Linux or normally on other platforms.
118 Returns the exit code of the specified commandline, or 1 on failure.
120 xvfb = None
121 openbox = None
122 if should_start_xvfb(env):
123 (xvfb, openbox) = start_xvfb(env, build_dir)
124 if not xvfb or not xvfb.pid or not openbox or not openbox.pid:
125 return 1
126 try:
127 return test_env.run_executable(cmd, env)
128 finally:
129 kill(xvfb)
130 kill(openbox)
133 def main():
134 if len(sys.argv) < 3:
135 print >> sys.stderr, (
136 'Usage: xvfb.py [path to build_dir] [command args...]')
137 return 2
138 return run_executable(sys.argv[2:], sys.argv[1], os.environ.copy())
141 if __name__ == "__main__":
142 sys.exit(main())