forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
xvfb.py
153 lines (130 loc) · 5.62 KB
/
xvfb.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# 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.
"""Functions to setup xvfb, which is used by the linux machines.
"""
import os
import signal
import subprocess
import tempfile
import time
def xvfb_display_index(_child_build_name):
return '9'
def xvfb_pid_filename(child_build_name):
"""Returns the filename to the Xvfb pid file. This name is unique for each
builder. This is used by the linux builders."""
return os.path.join(
tempfile.gettempdir(),
'xvfb-' + xvfb_display_index(child_build_name) + '.pid'
)
def start_virtual_x(child_build_name, build_dir):
"""Start a virtual X server and set the DISPLAY environment variable so sub
processes will use the virtual X server. Also start openbox. This only works
on Linux and assumes that xvfb and openbox are installed.
Args:
child_build_name: The name of the build that we use for the pid file.
E.g., webkit-rel-linux.
build_dir: The directory where binaries are produced. If this is non-empty,
we try running xdisplaycheck from |build_dir| to verify our X
connection.
"""
# We use a pid file to make sure we don't have any xvfb processes running
# from a previous test run.
stop_virtual_x(child_build_name)
xdisplaycheck_path = None
if build_dir:
xdisplaycheck_path = os.path.join(build_dir, 'xdisplaycheck')
display = ':%s' % xvfb_display_index(child_build_name)
# Note we don't add the optional screen here (+ '.0')
os.environ['DISPLAY'] = display
# Parts of Xvfb use a hard-coded "/tmp" for its temporary directory.
# This can cause a failure when those parts expect to hardlink against
# files that were created in "TEMPDIR" / "TMPDIR".
#
# See: https://crbug.com/715848
env = os.environ.copy()
if env.get('TMPDIR') and env['TMPDIR'] != '/tmp':
print('Overriding TMPDIR to "/tmp" for Xvfb, was: %s' % (env['TMPDIR'],))
env['TMPDIR'] = '/tmp'
if xdisplaycheck_path and os.path.exists(xdisplaycheck_path):
print('Verifying Xvfb is not running ...')
checkstarttime = time.time()
xdisplayproc = subprocess.Popen([xdisplaycheck_path, '--noserver'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
env=env)
# Wait for xdisplaycheck to exit.
logs = xdisplayproc.communicate()[0]
if xdisplayproc.returncode == 0:
print('xdisplaycheck says there is a display still running, exiting...')
raise Exception('Display already present.')
xvfb_lock_filename = '/tmp/.X%s-lock' % xvfb_display_index(child_build_name)
if os.path.exists(xvfb_lock_filename):
print('Removing stale xvfb lock file %r' % xvfb_lock_filename)
try:
os.unlink(xvfb_lock_filename)
except OSError as err:
print('Removing xvfb lock file failed: %s' % err)
# Figure out which X server to try.
cmd = 'Xvfb'
# Start 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.
proc = subprocess.Popen([
cmd, display, '-screen', '0', '1280x800x24', '-ac', '-dpi', '96',
'-maxclients', '512', '-extension', 'MIT-SHM'
],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
env=env)
pid_filename = xvfb_pid_filename(child_build_name)
open(pid_filename, 'w').write(str(proc.pid))
# Wait for Xvfb to start up.
time.sleep(10)
# Verify that Xvfb has started by using xdisplaycheck.
if xdisplaycheck_path and os.path.exists(xdisplaycheck_path):
print('Verifying Xvfb has started...')
checkstarttime = time.time()
xdisplayproc = subprocess.Popen([xdisplaycheck_path],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
# Wait for xdisplaycheck to exit.
logs = xdisplayproc.communicate()[0]
checktime = time.time() - checkstarttime
if xdisplayproc.returncode != 0:
print('xdisplaycheck failed after %d seconds.' % checktime)
print('xdisplaycheck output:')
for line in logs.splitlines():
print('> %s' % line)
return_code = proc.poll()
if return_code is None:
print('Xvfb still running, stopping.')
proc.terminate()
else:
print('Xvfb exited, code %d' % return_code)
print('Xvfb output:')
for line in proc.communicate()[0].splitlines():
print('> %s' % line)
raise Exception(logs)
print('xdisplaycheck succeeded after %d seconds.' % checktime)
print('xdisplaycheck output:')
for line in logs.splitlines():
print('> %s' % line)
print('...OK')
# Some ChromeOS tests need a window manager.
subprocess.Popen('openbox', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
print('Window manager (openbox) started.')
def stop_virtual_x(child_build_name):
"""Try and stop the virtual X server if one was started with StartVirtualX.
When the X server dies, it takes down the window manager with it.
If a virtual x server is not running, this method does nothing."""
pid_filename = xvfb_pid_filename(child_build_name)
if os.path.exists(pid_filename):
xvfb_pid = int(open(pid_filename).read())
print('Stopping Xvfb with pid %d ...' % xvfb_pid)
# If the process doesn't exist, we raise an exception that we can ignore.
try:
os.kill(xvfb_pid, signal.SIGKILL)
except OSError:
print('... killing failed, presuming unnecessary.')
os.remove(pid_filename)
print('Xvfb pid file removed')