def run_executable(cmd, build_dir, env): """Runs an executable within a xvfb buffer on linux or normally on other platforms. Requires that both xvfb and icewm are installed on linux. Detects recursion with an environment variable and do not create a recursive X buffer if present. """ # First look if we are inside a display. if env.get('_CHROMIUM_INSIDE_XVFB') == '1': # No need to recurse. return test_env.run_executable(cmd, env) pid = None xvfb = 'Xvfb' try: if sys.platform == 'linux2': # Defaults to X display 9. display = ':9' pid = start_xvfb(xvfb, display) env['DISPLAY'] = display if not wait_for_xvfb(os.path.join(build_dir, 'xdisplaycheck'), env): return 3 # Inhibit recursion. env['_CHROMIUM_INSIDE_XVFB'] = '1' # Some ChromeOS tests need a window manager. Technically, it could be # another script but that would be overkill. subprocess.Popen( 'icewm', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) return test_env.run_executable(cmd, env) finally: if pid: kill(pid)
def run_executable(cmd, env): """Runs an executable within Xvfb on Linux or normally on other platforms. Returns the exit code of the specified commandline, or 1 on failure. """ if sys.platform == 'linux2': if env.get('_CHROMIUM_INSIDE_XVFB') == '1': openbox_proc = None xcompmgr_proc = None try: # Some ChromeOS tests need a window manager. openbox_proc = subprocess.Popen('openbox', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) # Some tests need a compositing wm to make use of transparent visuals. xcompmgr_proc = subprocess.Popen('xcompmgr', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) return test_env.run_executable(cmd, env) except OSError as e: print >> sys.stderr, 'Failed to start Xvfb or Openbox: %s' % str(e) return 1 finally: kill(openbox_proc) kill(xcompmgr_proc) else: env['_CHROMIUM_INSIDE_XVFB'] = '1' return subprocess.call(['xvfb-run', '-a', "--server-args=-screen 0 " "1280x800x24 -ac -nolisten tcp -dpi 96", __file__] + cmd, env=env) else: return test_env.run_executable(cmd, env)
def run_executable(cmd, build_dir, env): """Runs an executable within a xvfb buffer on linux or normally on other platforms. Requires that both xvfb and openbox are installed on linux. Detects recursion with an environment variable and do not create a recursive X buffer if present. """ # First look if we are inside a display. if env.get('_CHROMIUM_INSIDE_XVFB') == '1': # No need to recurse. return test_env.run_executable(cmd, env) xvfb_proc = None xvfb = 'Xvfb' try: if sys.platform == 'linux2': # Defaults to X display 9. display = ':9' xvfb_proc = start_xvfb(xvfb, display) if not xvfb_proc or not xvfb_proc.pid: return 1 env['DISPLAY'] = display if not wait_for_xvfb(os.path.join(build_dir, 'xdisplaycheck'), env): rc = xvfb_proc.poll() if rc is None: print 'Xvfb still running, stopping.' xvfb_proc.terminate() else: print 'Xvfb exited, code %d' % rc print 'Xvfb output:' for l in xvfb_proc.communicate()[0].splitlines(): print '> %s' % l return 3 # Inhibit recursion. env['_CHROMIUM_INSIDE_XVFB'] = '1' # Some ChromeOS tests need a window manager. Technically, it could be # another script but that would be overkill. try: wm_cmd = ['openbox'] subprocess.Popen( wm_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) except OSError: print >> sys.stderr, 'Failed to run %s' % ' '.join(wm_cmd) return 1 return test_env.run_executable(cmd, env) finally: # When the X server dies, it takes down the window manager with it. if xvfb_proc and xvfb_proc.pid: kill(xvfb_proc.pid)
def run_executable(cmd, env): """Runs an executable within Xvfb on Linux or normally on other platforms. Returns the exit code of the specified commandline, or 1 on failure. """ # It might seem counterintuitive to support a --no-xvfb flag in a script # whose only job is to start xvfb, but doing so allows us to consolidate # the logic in the layers of buildbot scripts so that we *always* use # xvfb by default and don't have to worry about the distinction, it # can remain solely under the control of the test invocation itself. use_xvfb = True if '--no-xvfb' in cmd: use_xvfb = False cmd.remove('--no-xvfb') if sys.platform == 'linux2' and use_xvfb: if env.get('_CHROMIUM_INSIDE_XVFB') == '1': openbox_proc = None xcompmgr_proc = None try: # Some ChromeOS tests need a window manager. openbox_proc = subprocess.Popen('openbox', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) # Some tests need a compositing wm to make use of transparent visuals. xcompmgr_proc = subprocess.Popen('xcompmgr', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) return test_env.run_executable(cmd, env) except OSError as e: print >> sys.stderr, 'Failed to start Xvfb or Openbox: %s' % str(e) return 1 finally: kill(openbox_proc) kill(xcompmgr_proc) else: env['_CHROMIUM_INSIDE_XVFB'] = '1' xvfb_script = __file__ if xvfb_script.endswith('.pyc'): xvfb_script = xvfb_script[:-1] return subprocess.call(['xvfb-run', '-a', "--server-args=-screen 0 " "1280x800x24 -ac -nolisten tcp -dpi 96", xvfb_script] + cmd, env=env) else: return test_env.run_executable(cmd, env)
def run_executable(cmd, build_dir, env): """Runs an executable within Xvfb on Linux or normally on other platforms. Returns the exit code of the specified commandline, or 1 on failure. """ xvfb = None openbox = None if should_start_xvfb(env): (xvfb, openbox) = start_xvfb(env, build_dir) if not xvfb or not xvfb.pid or not openbox or not openbox.pid: return 1 try: return test_env.run_executable(cmd, env) finally: kill(xvfb) kill(openbox)
def run_executable(cmd, build_dir, env): """Runs an executable within a xvfb buffer on linux or normally on other platforms. Requires that both xvfb and icewm are installed on linux. """ pid = None xvfb = 'Xvfb' try: if sys.platform == 'linux2': # Defaults to X display 9. display = ':9' pid = start_xvfb(xvfb, display) env['DISPLAY'] = display if not wait_for_xvfb(os.path.join(build_dir, 'xdisplaycheck'), env): return 3 # Some ChromeOS tests need a window manager. Technically, it could be # another script but that would be overkill. subprocess.Popen( 'icewm', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) return test_env.run_executable(cmd, env) finally: if pid: kill(pid)
def _run_with_weston(cmd, env, stdoutfile): weston_proc = None try: signal.signal(signal.SIGTERM, raise_weston_error) signal.signal(signal.SIGINT, raise_weston_error) dbus_pid = launch_dbus(env) # The bundled weston (//third_party/weston) is used by Linux Ozone Wayland # CI and CQ testers and compiled by //ui/ozone/platform/wayland whenever # there is a dependency on the Ozone/Wayland and use_bundled_weston is set # in gn args. However, some tests do not require Wayland or do not use # //ui/ozone at all, but still have --use-weston flag set by the # OZONE_WAYLAND variant (see //testing/buildbot/variants.pyl). This results # in failures and those tests cannot be run because of the exception that # informs about missing weston binary. Thus, to overcome the issue before # a better solution is found, add a check for the "weston" binary here and # run tests without Wayland compositor if the weston binary is not found. # TODO(https://1178788): find a better solution. if not os.path.isfile("./weston"): print('Weston is not available. Starting without Wayland compositor') return test_env.run_executable(cmd, env, stdoutfile) # Set $XDG_RUNTIME_DIR if it is not set. _set_xdg_runtime_dir(env) # Weston is compiled along with the Ozone/Wayland platform, and is # fetched as data deps. Thus, run it from the current directory. # # Weston is used with the following flags: # 1) --backend=headless-backend.so - runs Weston in a headless mode # that does not require a real GPU card. # 2) --idle-time=0 - disables idle timeout, which prevents Weston # to enter idle state. Otherwise, Weston stops to send frame callbacks, # and tests start to time out (this typically happens after 300 seconds - # the default time after which Weston enters the idle state). # 3) --width && --height set size of a virtual display: we need to set # an adequate size so that tests can have more room for managing size # of windows. # 4) --use-gl - Runs Weston using hardware acceleration instead of # SwiftShader. weston_cmd = ['./weston', '--backend=headless-backend.so', '--idle-time=0', '--width=1024', '--height=768', '--modules=test-plugin.so'] if '--weston-use-gl' in cmd: weston_cmd.append('--use-gl') cmd.remove('--weston-use-gl') if '--weston-debug-logging' in cmd: cmd.remove('--weston-debug-logging') env = copy.deepcopy(env) env['WAYLAND_DEBUG'] = '1' weston_proc_display = None for _ in range(10): weston_proc = subprocess.Popen( weston_cmd, stderr=subprocess.STDOUT, env=env) # Get the $WAYLAND_DISPLAY set by Weston and pass it to the test launcher. # Please note that this env variable is local for the process. That's the # reason we have to read it from Weston separately. weston_proc_display = _get_display_from_weston(weston_proc.pid) if weston_proc_display is not None: break # Weston could launch and we found the display. # If we couldn't find the display after 10 tries, raise an exception. if weston_proc_display is None: raise _WestonProcessError('Failed to start Weston.') env['WAYLAND_DISPLAY'] = weston_proc_display return test_env.run_executable(cmd, env, stdoutfile) except OSError as e: print('Failed to start Weston: %s\n' % str(e), file=sys.stderr) return 1 except _WestonProcessError as e: print('Weston fail: %s\n' % str(e), file=sys.stderr) return 1 finally: kill(weston_proc, 'weston') # dbus-daemon is not a subprocess, so we can't SIGTERM+waitpid() on it. # To ensure it exits, use SIGKILL which should be safe since all other # processes that it would have been servicing have exited. if dbus_pid: os.kill(dbus_pid, signal.SIGKILL)
def _run_with_xvfb(cmd, env, stdoutfile, use_openbox, use_xcompmgr): openbox_proc = None xcompmgr_proc = None xvfb_proc = None xwmstartupcheck_proc = None xvfb_ready = MutableBoolean() def set_xvfb_ready(*_): xvfb_ready.setvalue(True) dbus_pid = None try: signal.signal(signal.SIGTERM, raise_xvfb_error) signal.signal(signal.SIGINT, raise_xvfb_error) # Before [1], the maximum number of X11 clients was 256. After, the default # limit is 256 with a configurable maximum of 512. On systems with a large # number of CPUs, the old limit of 256 may be hit for certain test suites # [2] [3], so we set the limit to 512 when possible. This flag is not # available on Ubuntu 16.04 or 18.04, so a feature check is required. Xvfb # does not have a '-version' option, so checking the '-help' output is # required. # # [1] d206c240c0b85c4da44f073d6e9a692afb6b96d2 # [2] https://crbug.com/1187948 # [3] https://crbug.com/1120107 xvfb_help = subprocess.check_output( ['Xvfb', '-help'], stderr=subprocess.STDOUT).decode('utf8') # Due to race condition for display number, Xvfb might fail to run. # If it does fail, try again up to 10 times, similarly to xvfb-run. for _ in range(10): xvfb_ready.setvalue(False) display = find_display() xvfb_cmd = ['Xvfb', display, '-screen', '0', '1280x800x24', '-ac', '-nolisten', 'tcp', '-dpi', '96', '+extension', 'RANDR'] if '-maxclients' in xvfb_help: xvfb_cmd += ['-maxclients', '512'] # Sets SIGUSR1 to ignore for Xvfb to signal current process # when it is ready. Due to race condition, USR1 signal could be sent # before the process resets the signal handler, we cannot rely on # signal handler to change on time. signal.signal(signal.SIGUSR1, signal.SIG_IGN) xvfb_proc = subprocess.Popen(xvfb_cmd, stderr=subprocess.STDOUT, env=env) signal.signal(signal.SIGUSR1, set_xvfb_ready) for _ in range(10): time.sleep(.1) # gives Xvfb time to start or fail. if xvfb_ready.getvalue() or xvfb_proc.poll() is not None: break # xvfb sent ready signal, or already failed and stopped. if xvfb_proc.poll() is None: break # xvfb is running, can proceed. if xvfb_proc.poll() is not None: raise _XvfbProcessError('Failed to start after 10 tries') env['DISPLAY'] = display # Set dummy variable for scripts. env['XVFB_DISPLAY'] = display dbus_pid = launch_dbus(env) if use_openbox: # This is not ideal, but x11_unittests require that (other X11 tests have # a race with the openbox as well, but they take more time to initialize. # And thus, they do no time out compate to the x11_unittests that are # quick enough to start up before openbox is ready. # TODO(dpranke): remove this nasty hack once the test() template is # reworked. wait_for_openbox = False wait_openbox_program = './xwmstartupcheck' if not os.path.isfile(wait_openbox_program): wait_for_openbox = False # Creates a dummy window that waits for a ReparentNotify event that is # sent whenever Openbox WM starts. Must be started before the OpenBox WM # so that it does not miss the event. This helper program is located in # the current build directory. The program terminates automatically after # 30 seconds of waiting for the event. if wait_for_openbox: xwmstartupcheck_proc = subprocess.Popen( wait_openbox_program, stderr=subprocess.STDOUT, env=env) openbox_proc = subprocess.Popen( ['openbox', '--sm-disable'], stderr=subprocess.STDOUT, env=env) # Wait until execution is done. Does not block if the process has already # been terminated. In that case, it's safe to read the return value. if wait_for_openbox: xwmstartupcheck_proc.wait() if xwmstartupcheck_proc.returncode != 0: raise _XvfbProcessError('Failed to get OpenBox up.') if use_xcompmgr: xcompmgr_proc = subprocess.Popen( 'xcompmgr', stderr=subprocess.STDOUT, env=env) return test_env.run_executable(cmd, env, stdoutfile) except OSError as e: print('Failed to start Xvfb or Openbox: %s\n' % str(e), file=sys.stderr) return 1 except _XvfbProcessError as e: print('Xvfb fail: %s\n' % str(e), file=sys.stderr) return 1 finally: kill(openbox_proc, 'openbox') kill(xcompmgr_proc, 'xcompmgr') kill(xvfb_proc, 'Xvfb') # dbus-daemon is not a subprocess, so we can't SIGTERM+waitpid() on it. # To ensure it exits, use SIGKILL which should be safe since all other # processes that it would have been servicing have exited. if dbus_pid: os.kill(dbus_pid, signal.SIGKILL)
def _run_with_xvfb(cmd, env, stdoutfile, use_openbox, use_xcompmgr): env['_CHROMIUM_INSIDE_XVFB'] = '1' openbox_proc = None xcompmgr_proc = None xvfb_proc = None xvfb_ready = MutableBoolean() def set_xvfb_ready(*_): xvfb_ready.setvalue(True) try: signal.signal(signal.SIGTERM, raise_xvfb_error) signal.signal(signal.SIGINT, raise_xvfb_error) # Due to race condition for display number, Xvfb might fail to run. # If it does fail, try again up to 10 times, similarly to xvfb-run. for _ in range(10): xvfb_ready.setvalue(False) display = find_display() # Sets SIGUSR1 to ignore for Xvfb to signal current process # when it is ready. Due to race condition, USR1 signal could be sent # before the process resets the signal handler, we cannot rely on # signal handler to change on time. signal.signal(signal.SIGUSR1, signal.SIG_IGN) xvfb_proc = subprocess.Popen( ['Xvfb', display, '-screen', '0', '1280x800x24', '-ac', '-nolisten', 'tcp', '-dpi', '96', '+extension', 'RANDR'], stderr=subprocess.STDOUT, env=env) signal.signal(signal.SIGUSR1, set_xvfb_ready) for _ in range(10): time.sleep(.1) # gives Xvfb time to start or fail. if xvfb_ready.getvalue() or xvfb_proc.poll() is not None: break # xvfb sent ready signal, or already failed and stopped. if xvfb_proc.poll() is None: break # xvfb is running, can proceed. if xvfb_proc.poll() is not None: raise _XvfbProcessError('Failed to start after 10 tries') env['DISPLAY'] = display dbus_pid = launch_dbus(env) if use_openbox: openbox_proc = subprocess.Popen( 'openbox', stderr=subprocess.STDOUT, env=env) if use_xcompmgr: xcompmgr_proc = subprocess.Popen( 'xcompmgr', stderr=subprocess.STDOUT, env=env) return test_env.run_executable(cmd, env, stdoutfile) except OSError as e: print >> sys.stderr, 'Failed to start Xvfb or Openbox: %s' % str(e) return 1 except _XvfbProcessError as e: print >> sys.stderr, 'Xvfb fail: %s' % str(e) return 1 finally: kill(openbox_proc, 'openbox') kill(xcompmgr_proc, 'xcompmgr') kill(xvfb_proc, 'Xvfb') # dbus-daemon is not a subprocess, so we can't SIGTERM+waitpid() on it. # To ensure it exits, use SIGKILL which should be safe since all other # processes that it would have been servicing have exited. if dbus_pid: os.kill(dbus_pid, signal.SIGKILL)
def _run_with_xvfb(cmd, env, stdoutfile, use_openbox, use_xcompmgr): env['_CHROMIUM_INSIDE_XVFB'] = '1' openbox_proc = None xcompmgr_proc = None xvfb_proc = None xwmstartupcheck_proc = None xvfb_ready = MutableBoolean() def set_xvfb_ready(*_): xvfb_ready.setvalue(True) try: signal.signal(signal.SIGTERM, raise_xvfb_error) signal.signal(signal.SIGINT, raise_xvfb_error) # Due to race condition for display number, Xvfb might fail to run. # If it does fail, try again up to 10 times, similarly to xvfb-run. for _ in range(10): xvfb_ready.setvalue(False) display = find_display() # Sets SIGUSR1 to ignore for Xvfb to signal current process # when it is ready. Due to race condition, USR1 signal could be sent # before the process resets the signal handler, we cannot rely on # signal handler to change on time. signal.signal(signal.SIGUSR1, signal.SIG_IGN) xvfb_proc = subprocess.Popen([ 'Xvfb', display, '-screen', '0', '1280x800x24', '-ac', '-nolisten', 'tcp', '-dpi', '96', '+extension', 'RANDR' ], stderr=subprocess.STDOUT, env=env) signal.signal(signal.SIGUSR1, set_xvfb_ready) for _ in range(10): time.sleep(.1) # gives Xvfb time to start or fail. if xvfb_ready.getvalue() or xvfb_proc.poll() is not None: break # xvfb sent ready signal, or already failed and stopped. if xvfb_proc.poll() is None: break # xvfb is running, can proceed. if xvfb_proc.poll() is not None: raise _XvfbProcessError('Failed to start after 10 tries') env['DISPLAY'] = display dbus_pid = launch_dbus(env) if use_openbox: # This is not ideal, but x11_unittests require that (other X11 tests have # a race with the openbox as well, but they take more time to initialize. # And thus, they do no time out compate to the x11_unittests that are # quick enough to start up before openbox is ready. # TODO(dpranke): remove this nasty hack once the test() template is # reworked. wait_for_openbox = False wait_openbox_program = './xwmstartupcheck' if not os.path.isfile(wait_openbox_program): wait_for_openbox = False # Creates a dummy window that waits for a ReparentNotify event that is # sent whenever Openbox WM starts. Must be started before the OpenBox WM # so that it does not miss the event. This helper program is located in # the current build directory. The program terminates automatically after # 30 seconds of waiting for the event. if wait_for_openbox: xwmstartupcheck_proc = subprocess.Popen( wait_openbox_program, stderr=subprocess.STDOUT, env=env) openbox_proc = subprocess.Popen(['openbox', '--sm-disable'], stderr=subprocess.STDOUT, env=env) # Wait until execution is done. Does not block if the process has already # been terminated. In that case, it's safe to read the return value. if wait_for_openbox: xwmstartupcheck_proc.wait() if xwmstartupcheck_proc.returncode is not 0: raise _XvfbProcessError('Failed to get OpenBox up.') if use_xcompmgr: xcompmgr_proc = subprocess.Popen('xcompmgr', stderr=subprocess.STDOUT, env=env) return test_env.run_executable(cmd, env, stdoutfile) except OSError as e: print('Failed to start Xvfb or Openbox: %s\n' % str(e), file=sys.stderr) return 1 except _XvfbProcessError as e: print('Xvfb fail: %s\n' % str(e), file=sys.stderr) return 1 finally: kill(openbox_proc, 'openbox') kill(xcompmgr_proc, 'xcompmgr') kill(xvfb_proc, 'Xvfb') # dbus-daemon is not a subprocess, so we can't SIGTERM+waitpid() on it. # To ensure it exits, use SIGKILL which should be safe since all other # processes that it would have been servicing have exited. if dbus_pid: os.kill(dbus_pid, signal.SIGKILL)
def run_executable(cmd, env, stdoutfile=None, use_openbox=True, use_xcompmgr=True): """Runs an executable within Xvfb on Linux or normally on other platforms. The method sets SIGUSR1 handler for Xvfb to return SIGUSR1 when it is ready for connections. https://www.x.org/archive/X11R7.5/doc/man/man1/Xserver.1.html under Signals. Args: cmd: Command to be executed. env: A copy of environment variables, "DISPLAY" and "_CHROMIUM_INSIDE_XVFB" will be set if Xvfb is used. stdoutfile: If provided, symbolization via script is disabled and stdout is written to this file as well as to stdout. use_openbox: A flag to use openbox process. Some ChromeOS tests need a window manager. use_xcompmgr: A flag to use xcompmgr process. Some tests need a compositing wm to make use of transparent visuals. Returns: the exit code of the specified commandline, or 1 on failure. """ # It might seem counterintuitive to support a --no-xvfb flag in a script # whose only job is to start xvfb, but doing so allows us to consolidate # the logic in the layers of buildbot scripts so that we *always* use # xvfb by default and don't have to worry about the distinction, it # can remain solely under the control of the test invocation itself. use_xvfb = True if '--no-xvfb' in cmd: use_xvfb = False cmd.remove('--no-xvfb') if sys.platform == 'linux2' and use_xvfb: env['_CHROMIUM_INSIDE_XVFB'] = '1' openbox_proc = None xcompmgr_proc = None xvfb_proc = None xvfb_ready = MutableBoolean() def set_xvfb_ready(*_): xvfb_ready.setvalue(True) try: signal.signal(signal.SIGTERM, raise_xvfb_error) signal.signal(signal.SIGINT, raise_xvfb_error) # Due to race condition for display number, Xvfb might fail to run. # If it does fail, try again up to 10 times, similarly to xvfb-run. for _ in range(10): xvfb_ready.setvalue(False) display = find_display() # Sets SIGUSR1 to ignore for Xvfb to signal current process # when it is ready. Due to race condition, USR1 signal could be sent # before the process resets the signal handler, we cannot rely on # signal handler to change on time. signal.signal(signal.SIGUSR1, signal.SIG_IGN) xvfb_proc = subprocess.Popen([ 'Xvfb', display, '-screen', '0', '1280x800x24', '-ac', '-nolisten', 'tcp', '-dpi', '96', '+extension', 'RANDR' ], stderr=subprocess.STDOUT, env=env) signal.signal(signal.SIGUSR1, set_xvfb_ready) for _ in range(10): time.sleep(.1) # gives Xvfb time to start or fail. if xvfb_ready.getvalue() or xvfb_proc.poll() is not None: break # xvfb sent ready signal, or already failed and stopped. if xvfb_proc.poll() is None: break # xvfb is running, can proceed. if xvfb_proc.poll() is not None: raise _XvfbProcessError('Failed to start after 10 tries') env['DISPLAY'] = display if use_openbox: openbox_proc = subprocess.Popen('openbox', stderr=subprocess.STDOUT, env=env) if use_xcompmgr: xcompmgr_proc = subprocess.Popen('xcompmgr', stderr=subprocess.STDOUT, env=env) return test_env.run_executable(cmd, env, stdoutfile) except OSError as e: print >> sys.stderr, 'Failed to start Xvfb or Openbox: %s' % str(e) return 1 except _XvfbProcessError as e: print >> sys.stderr, 'Xvfb fail: %s' % str(e) return 1 finally: kill(openbox_proc) kill(xcompmgr_proc) kill(xvfb_proc) else: return test_env.run_executable(cmd, env, stdoutfile)