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."""
18 def _kill(proc
, send_signal
):
19 """Kills |proc| and ignores exceptions thrown for non-existent processes."""
21 os
.kill(proc
.pid
, send_signal
)
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
:
31 _kill(proc
, signal
.SIGTERM
)
32 thread
= threading
.Thread(target
=proc
.wait
)
35 thread
.join(timeout_in_seconds
)
37 print >> sys
.stderr
, 'Xvfb running after SIGTERM, trying SIGKILL.'
38 _kill(proc
, signal
.SIGKILL
)
40 thread
.join(timeout_in_seconds
)
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."""
48 subprocess
.check_output([xdisplaycheck
], stderr
=subprocess
.STDOUT
, env
=env
)
50 print >> sys
.stderr
, 'Failed to load %s with cwd=%s' % (
51 xdisplaycheck
, os
.getcwd())
53 except subprocess
.CalledProcessError
as e
:
54 print >> sys
.stderr
, ('Xvfb failed to load (code %d) according to %s' %
55 (e
.returncode
, xdisplaycheck
))
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.
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.
78 assert should_start_xvfb(env
)
79 assert env
.get('_CHROMIUM_INSIDE_XVFB') != '1'
80 env
['_CHROMIUM_INSIDE_XVFB'] = '1'
81 env
['DISPLAY'] = display
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
):
94 print 'Xvfb still running after xdisplaycheck failure, stopping.'
97 print 'Xvfb exited (code %d) after xdisplaycheck failure.' % rc
99 for l
in xvfb_proc
.communicate()[0].splitlines():
103 # Some ChromeOS tests need a window manager.
104 openbox_proc
= subprocess
.Popen('openbox', stdout
=subprocess
.PIPE
,
105 stderr
=subprocess
.STDOUT
, env
=env
)
107 print >> sys
.stderr
, 'Failed to start Xvfb or Openbox: %s' % str(e
)
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.
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
:
127 return test_env
.run_executable(cmd
, env
)
134 if len(sys
.argv
) < 3:
135 print >> sys
.stderr
, (
136 'Usage: xvfb.py [path to build_dir] [command args...]')
138 return run_executable(sys
.argv
[2:], sys
.argv
[1], os
.environ
.copy())
141 if __name__
== "__main__":