• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
8For simplicity in gyp targets, this script just runs the test normal on
9non-linux platforms.
10"""
11
12import os
13import platform
14import signal
15import subprocess
16import sys
17
18import test_env
19
20
21def 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
31def 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
43def 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
62def 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
81def 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
124def 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
132if __name__ == "__main__":
133  sys.exit(main())
134