summaryrefslogtreecommitdiffstats
path: root/infra/scripts/legacy/scripts/slave/xvfb.py
blob: f5f357764358527eb361fc23bf2d2f1b026f9a29 (plain)
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
# 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 platform
import signal
import subprocess
import tempfile
import time

def _XvfbDisplayIndex(slave_build_name):
  return '9'

def _XvfbPidFilename(slave_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-' + _XvfbDisplayIndex(slave_build_name)  + '.pid')


def StartVirtualX(slave_build_name, build_dir, with_wm=True, server_dir=None):
  """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:
    slave_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.
    with_wm: Whether we add a window manager to the display too.
    server_dir: Directory to search for the server executable.
  """
  # We use a pid file to make sure we don't have any xvfb processes running
  # from a previous test run.
  StopVirtualX(slave_build_name)

  xdisplaycheck_path = None
  if build_dir:
    xdisplaycheck_path = os.path.join(build_dir, 'xdisplaycheck')

  display = ':%s' % _XvfbDisplayIndex(slave_build_name)
  # Note we don't add the optional screen here (+ '.0')
  os.environ['DISPLAY'] = display

  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)
    # 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.')

  # Figure out which X server to try.
  cmd = 'Xvfb'
  if server_dir and os.path.exists(server_dir):
    cmd = os.path.join(server_dir, 'Xvfb.' + platform.architecture()[0])
    if not os.path.exists(cmd):
      cmd = os.path.join(server_dir, 'Xvfb')
    if not os.path.exists(cmd):
      print 'No Xvfb found in designated server path:', server_dir
      raise Exception('No virtual server')

  # 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', '1024x768x24', '-ac',
                           '-dpi', '96'],
                          stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  xvfb_pid_filename = _XvfbPidFilename(slave_build_name)
  open(xvfb_pid_filename, 'w').write(str(proc.pid))

  # 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 l in logs.splitlines():
        print '> %s' % l
      rc = proc.poll()
      if rc is None:
        print 'Xvfb still running, stopping.'
        proc.terminate()
      else:
        print 'Xvfb exited, code %d' % rc

      print 'Xvfb output:'
      for l in proc.communicate()[0].splitlines():
        print '> %s' % l
      raise Exception(logs)
    else:
      print 'xdisplaycheck succeeded after %d seconds.' % checktime
      print 'xdisplaycheck output:'
      for l in logs.splitlines():
        print '> %s' % l
    print '...OK'

  if with_wm:
    # Some ChromeOS tests need a window manager.
    subprocess.Popen('openbox', stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT)
    print 'Window manager (openbox) started.'
  else:
    print 'No window manager required.'



def StopVirtualX(slave_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."""
  xvfb_pid_filename = _XvfbPidFilename(slave_build_name)
  if os.path.exists(xvfb_pid_filename):
    xvfb_pid = int(open(xvfb_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(xvfb_pid_filename)
    print 'Xvfb pid file removed'