# Copyright (C) 2016 Igalia S.L. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import os import sys import tempfile import logging import subprocess try: import psutil except ImportError: pass from webkitpy.benchmark_runner.utils import force_remove from browser_driver import BrowserDriver _log = logging.getLogger(__name__) class LinuxBrowserDriver(BrowserDriver): browser_name = None process_search_list = [] platform = 'linux' def __init__(self): self.process_name = self._get_first_executable_path_from_list(self.process_search_list) if self.process_name is None: raise ValueError('Cant find executable for browser {browser_name}. Searched list: {browser_process_list}'.format( browser_name=self.browser_name, browser_process_list=self.process_search_list)) def prepare_env(self, device_id): self._browser_process = None self._browser_arguments = None self._temp_profiledir = tempfile.mkdtemp() self._test_environ = dict(os.environ) self._test_environ['HOME'] = self._temp_profiledir def restore_env(self): force_remove(self._temp_profiledir) def close_browsers(self): if self._browser_process: if self._browser_process.poll() is None: # still running if 'psutil' in sys.modules: main_browser_process = psutil.Process(self._browser_process.pid) browser_children = main_browser_process.children(recursive=True) _log.info('Killing browser {browser_name} with pid {browser_pid} and cmd: {browser_cmd}'.format( browser_name=self.browser_name, browser_pid=self._browser_process.pid, browser_cmd=' '.join(main_browser_process.cmdline()).strip() or main_browser_process.name())) main_browser_process.kill() for browser_child in browser_children: if browser_child.is_running(): _log.info('Killing still alive {browser_name} child with pid {browser_pid} and cmd: {browser_cmd}'.format( browser_name=self.browser_name, browser_pid=browser_child.pid, browser_cmd=' '.join(browser_child.cmdline()).strip() or browser_child.name())) browser_child.kill() else: _log.info('Killing browser {browser_name} with pid {browser_pid}'.format( browser_name=self.browser_name, browser_pid=self._browser_process.pid)) self._browser_process.kill() _log.warning('python psutil not found, cant check for ' 'still-alive browser childs to kill.') else: _log.error('Browser {browser_name} with pid {browser_pid} ended prematurely with return code {browser_retcode}.'.format( browser_name=self.browser_name, browser_pid=self._browser_process.pid, browser_retcode=self._browser_process.returncode)) def launch_url(self, url, options, browser_build_path): if not self._browser_arguments: self._browser_arguments = [url] exec_args = [self.process_name] + self._browser_arguments _log.info('Executing: {browser_cmdline}'.format(browser_cmdline=' '.join(exec_args))) self._browser_process = subprocess.Popen(exec_args, env=self._test_environ, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) def _get_first_executable_path_from_list(self, searchlist): searchpath = [os.path.curdir] + os.environ['PATH'].split(os.pathsep) for program in searchlist: for path in searchpath: fullpath = os.path.abspath(os.path.join(path, program)) if os.path.isfile(fullpath) and os.access(fullpath, os.X_OK): return fullpath return None def _screen_size(self): # load_subclasses() from __init__.py will load this file to # check the platform defined. Do here a lazy import instead of # trying to import the Gtk module on the global scope of this # file to avoid ImportError errors on other platforms. # Python imports are cached and only run once, so this should be ok. import gi gi.require_version('Gtk', '3.0') gi.require_version('Gdk', '3.0') from gi.repository import Gtk, Gdk if Gtk.get_major_version() == 3 and Gtk.get_minor_version() < 22: screen = Gtk.Window().get_screen() return screen.get_monitor_geometry(screen.get_primary_monitor()) else: display = Gdk.Display.get_default() monitor = display.get_primary_monitor() return monitor.get_geometry()