diff --git a/mozilla/testing/performance/talos/bcontroller.py b/mozilla/testing/performance/talos/bcontroller.py index 6f107f27433..8f79b61d12d 100644 --- a/mozilla/testing/performance/talos/bcontroller.py +++ b/mozilla/testing/performance/talos/bcontroller.py @@ -43,7 +43,9 @@ import time import subprocess import threading import platform -import ffprocess +from ffprocess_linux import LinuxProcess +from ffprocess_mac import MacProcess +from ffprocess_win32 import Win32Process from utils import talosError import sys import getopt @@ -52,15 +54,17 @@ import stat if platform.system() == "Linux": platform_type = 'unix_' + ffprocess = LinuxProcess() elif platform.system() in ("Windows", "Microsoft"): import win32pdh import win32api import win32event import win32con platform_type = 'win_' + ffprocess = Win32Process() elif platform.system() == "Darwin": platform_type = 'unix_' - + ffprocess = MacProcess() class BrowserWaiter(threading.Thread): diff --git a/mozilla/testing/performance/talos/ffprocess.py b/mozilla/testing/performance/talos/ffprocess.py index 7fb6956b024..240e0c3df68 100755 --- a/mozilla/testing/performance/talos/ffprocess.py +++ b/mozilla/testing/performance/talos/ffprocess.py @@ -48,82 +48,85 @@ import time import subprocess from utils import talosError -if platform.system() == "Linux": - from ffprocess_linux import * -elif platform.system() in ("Windows", "Microsoft"): - from ffprocess_win32 import * -elif platform.system() == "Darwin": - from ffprocess_mac import * - -def RunProcessAndWaitForOutput(command, process_name, browser_wait, output_regex, timeout): - """Runs the given process and waits for the output that matches the given - regular expression. Stops if the process exits early or times out. - - Args: - command: String containing command to run - process_name: Name of the process to run, in case it has to be killed - browser_wait: Amount of time allowed for the browser to cleanly close - output_regex: Regular expression to check against each output line. - If the output matches, the process is terminated and - the function returns. - timeout: Time to wait before terminating the process and returning - - Returns: - A tuple (match, timedout) where match is the match of the regular - expression, and timed out is true if the process timed out and - false otherwise. - """ - - # Start the process - process = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True, shell=True, env=os.environ) - handle = process.stdout - - # Wait for it to print output, terminate, or time out. - time_elapsed = 0 - output = '' - interval = 2 # Wait 2 seconds in between checks - - while time_elapsed < timeout: - time.sleep(interval) - time_elapsed += interval - - (bytes, current_output) = NonBlockingReadProcessOutput(handle) - output += current_output +class FFProcess(object): - result = output_regex.search(output) - if result: - try: - return_val = result.group(1) - timer=0 - while ((process.poll() is None) and timer < browser_wait): - time.sleep(1) - timer+=1 - TerminateAllProcesses(browser_wait, process_name) - return (return_val, False) - except IndexError: - # Didn't really match + def __init__(self): pass - # Timed out. - TerminateAllProcesses(browser_wait, process_name) - return (None, True) + def RunProcessAndWaitForOutput(self, command, process_name, browser_wait, output_regex, timeout): + """Runs the given process and waits for the output that matches the given + regular expression. Stops if the process exits early or times out. -def checkBrowserAlive(process_name): - #is the browser actually up? - return (ProcessesWithNameExist(process_name) and not ProcessesWithNameExist("crashreporter", "talkback", "dwwin")) + Args: + command: String containing command to run + process_name: Name of the process to run, in case it has to be killed + browser_wait: Amount of time allowed for the browser to cleanly close + output_regex: Regular expression to check against each output line. + If the output matches, the process is terminated and + the function returns. + timeout: Time to wait before terminating the process and returning -def checkAllProcesses(process_name): - #is anything browser related active? - return ProcessesWithNameExist(process_name, "crashreporter", "talkback", "dwwin") + Returns: + A tuple (match, timedout) where match is the match of the regular + expression, and timed out is true if the process timed out and + false otherwise. + """ -def cleanupProcesses(process_name, browser_wait): - #kill any remaining browser processes - TerminateAllProcesses(browser_wait, process_name, "crashreporter", "dwwin", "talkback") - #check if anything is left behind - if checkAllProcesses(process_name): - #this is for windows machines. when attempting to send kill messages to win processes the OS - # always gives the process a chance to close cleanly before terminating it, this takes longer - # and we need to give it a little extra time to complete - time.sleep(browser_wait) - if checkAllProcesses(process_name): - raise talosError("failed to cleanup") + # Start the process + process = subprocess.Popen(command, + stdout=subprocess.PIPE, + universal_newlines=True, + shell=True, + env=os.environ) + handle = process.stdout + + # Wait for it to print output, terminate, or time out. + time_elapsed = 0 + output = '' + interval = 2 # Wait 2 seconds in between checks + + while time_elapsed < timeout: + time.sleep(interval) + time_elapsed += interval + + (bytes, current_output) = self.NonBlockingReadProcessOutput(handle) + output += current_output + + result = output_regex.search(output) + if result: + try: + return_val = result.group(1) + timer=0 + while ((process.poll() is None) and timer < browser_wait): + time.sleep(1) + timer+=1 + self.TerminateAllProcesses(browser_wait, process_name) + return (return_val, False) + except IndexError: + # Didn't really match + pass + + # Timed out. + self.TerminateAllProcesses(browser_wait, process_name) + return (None, True) + + def checkBrowserAlive(self, process_name): + #is the browser actually up? + return (self.ProcessesWithNameExist(process_name) and + not self.ProcessesWithNameExist("crashreporter", "talkback", "dwwin")) + + def checkAllProcesses(self, process_name): + #is anything browser related active? + return self.ProcessesWithNameExist(process_name, "crashreporter", "talkback", "dwwin") + + def cleanupProcesses(self, process_name, browser_wait): + #kill any remaining browser processes + self.TerminateAllProcesses(browser_wait, process_name, "crashreporter", "dwwin", "talkback") + #check if anything is left behind + if self.checkAllProcesses(process_name): + #this is for windows machines. when attempting to send kill messages to win processes the OS + # always gives the process a chance to close cleanly before terminating it, this takes longer + # and we need to give it a little extra time to complete + time.sleep(browser_wait) + if self.checkAllProcesses(process_name): + raise talosError("failed to cleanup") diff --git a/mozilla/testing/performance/talos/ffprocess_linux.py b/mozilla/testing/performance/talos/ffprocess_linux.py index 5c1d67d7824..cf62cf52342 100644 --- a/mozilla/testing/performance/talos/ffprocess_linux.py +++ b/mozilla/testing/performance/talos/ffprocess_linux.py @@ -40,140 +40,163 @@ import signal import os from select import select import time +from ffprocess import FFProcess +class LinuxProcess(FFProcess): -def GenerateBrowserCommandLine(browser_path, extra_args, profile_dir, url): - """Generates the command line for a process to run Browser + def __init__(self): + pass - Args: - browser_path: String containing the path to the browser to use - profile_dir: String containing the directory of the profile to run Browser in - url: String containing url to start with. - """ + def GenerateBrowserCommandLine(self, browser_path, extra_args, profile_dir, url): + """Generates the command line for a process to run Browser - profile_arg = '' - if profile_dir: - profile_arg = '-profile %s' % profile_dir + Args: + browser_path: String containing the path to the browser to use + profile_dir: String containing the directory of the profile to run Browser in + url: String containing url to start with. + """ - cmd = '%s %s %s %s' % (browser_path, - extra_args, - profile_arg, - url) - return cmd + profile_arg = '' + if profile_dir: + profile_arg = '-profile %s' % profile_dir + + cmd = '%s %s %s %s' % (browser_path, + extra_args, + profile_arg, + url) + return cmd -def GetPidsByName(process_name): - """Searches for processes containing a given string. - This function is UNIX specific. + def GetPidsByName(self, process_name): + """Searches for processes containing a given string. + This function is UNIX specific. - Args: - process_name: The string to be searched for + Args: + process_name: The string to be searched for - Returns: - A list of PIDs containing the string. An empty list is returned if none are - found. - """ + Returns: + A list of PIDs containing the string. An empty list is returned if none are + found. + """ - matchingPids = [] + matchingPids = [] - command = ['ps', 'ax'] - handle = subprocess.Popen(command, stdout=subprocess.PIPE) + command = ['ps', 'ax'] + handle = subprocess.Popen(command, stdout=subprocess.PIPE) - # wait for the process to terminate - handle.wait() - data = handle.stdout.read() + # wait for the process to terminate + handle.wait() + data = handle.stdout.read() - # find all matching processes and add them to the list - for line in data.splitlines(): - if line.find('defunct') != -1: - continue - if line.find(process_name) >= 0: - # splits by whitespace, the first one should be the pid - pid = int(line.split()[0]) - matchingPids.append(pid) + # find all matching processes and add them to the list + for line in data.splitlines(): + if line.find('defunct') != -1: + continue + if line.find(process_name) >= 0: + # splits by whitespace, the first one should be the pid + pid = int(line.split()[0]) + matchingPids.append(pid) - return matchingPids + return matchingPids -def ProcessesWithNameExist(*process_names): - """Returns true if there are any processes running with the - given name. Useful to check whether a Browser process is still running + def ProcessesWithNameExist(self, *process_names): + """Returns true if there are any processes running with the + given name. Useful to check whether a Browser process is still running - Args: - process_names: String or strings containing the process name, i.e. "firefox" + Args: + process_names: String or strings containing the process name, i.e. "firefox" - Returns: - True if any processes with that name are running, False otherwise. - """ + Returns: + True if any processes with that name are running, False otherwise. + """ - for process_name in process_names: - pids = GetPidsByName(process_name) - if len(pids) > 0: - return True - return False + for process_name in process_names: + pids = self.GetPidsByName(process_name) + if len(pids) > 0: + return True + return False -def TerminateProcess(pid, timeout): - """Helper function to terminate a process, given the pid + def TerminateProcess(self, pid, timeout): + """Helper function to terminate a process, given the pid - Args: - pid: integer process id of the process to terminate. - """ - try: - if ProcessesWithNameExist(str(pid)): - os.kill(pid, signal.SIGSEGV) - time.sleep(timeout) - if ProcessesWithNameExist(str(pid)): - os.kill(pid, signal.SIGTERM) - time.sleep(timeout) - if ProcessesWithNameExist(str(pid)): - os.kill(pid, signal.SIGKILL) - except OSError, (errno, strerror): - print 'WARNING: failed os.kill: %s : %s' % (errno, strerror) + Args: + pid: integer process id of the process to terminate. + """ + try: + if self.ProcessesWithNameExist(str(pid)): + os.kill(pid, signal.SIGSEGV) + time.sleep(timeout) + if self.ProcessesWithNameExist(str(pid)): + os.kill(pid, signal.SIGTERM) + time.sleep(timeout) + if self.ProcessesWithNameExist(str(pid)): + os.kill(pid, signal.SIGKILL) + except OSError, (errno, strerror): + print 'WARNING: failed os.kill: %s : %s' % (errno, strerror) -def TerminateAllProcesses(timeout, *process_names): - """Helper function to terminate all processes with the given process name + def TerminateAllProcesses(self, timeout, *process_names): + """Helper function to terminate all processes with the given process name - Args: - process_names: String or strings containing the process name, i.e. "firefox" - """ + Args: + process_names: String or strings containing the process name, i.e. "firefox" + """ - # Get all the process ids of running instances of this process, - # and terminate them - for process_name in process_names: - pids = GetPidsByName(process_name) - for pid in pids: - TerminateProcess(pid, timeout) + # Get all the process ids of running instances of this process, + # and terminate them + for process_name in process_names: + pids = self.GetPidsByName(process_name) + for pid in pids: + self.TerminateProcess(pid, timeout) -def NonBlockingReadProcessOutput(handle): - """Does a non-blocking read from the output of the process - with the given handle. + def NonBlockingReadProcessOutput(self, handle): + """Does a non-blocking read from the output of the process + with the given handle. - Args: - handle: The process handle returned from os.popen() + Args: + handle: The process handle returned from os.popen() + + Returns: + A tuple (bytes, output) containing the number of output + bytes read, and the actual output. + """ - Returns: - A tuple (bytes, output) containing the number of output - bytes read, and the actual output. - """ + output = "" + num_avail = 0 - output = "" - num_avail = 0 + # check for data + # select() does not seem to work well with pipes. + # after data is available once it *always* thinks there is data available + # readline() will continue to return an empty string however + # so we can use this behavior to work around the problem + while select([handle], [], [], 0)[0]: + line = handle.readline() + if line: + output += line + else: + break + # this statement is true for encodings that have 1byte/char + num_avail = len(output) + + return (num_avail, output) - # check for data - # select() does not seem to work well with pipes. - # after data is available once it *always* thinks there is data available - # readline() will continue to return an empty string however - # so we can use this behavior to work around the problem - while select([handle], [], [], 0)[0]: - line = handle.readline() - if line: - output += line - else: - break - # this statement is true for encodings that have 1byte/char - num_avail = len(output) + def MakeDirectoryContentsWritable(self, dirname): + """Recursively makes all the contents of a directory writable. + Uses os.chmod(filename, 0755). - return (num_avail, output) + Args: + dirname: Name of the directory to make contents writable. + """ + try: + for (root, dirs, files) in os.walk(dirname): + os.chmod(root, 0755) + for filename in files: + try: + os.chmod(os.path.join(root, filename), 0755) + except OSError, (errno, strerror): + print 'WARNING: failed to os.chmod(%s): %s : %s' % (os.path.join(root, filename), errno, strerror) + except OSError, (errno, strerror): + print 'WARNING: failed to MakeDirectoryContentsWritable: %s : %s' % (errno, strerror) diff --git a/mozilla/testing/performance/talos/ffprocess_mac.py b/mozilla/testing/performance/talos/ffprocess_mac.py index 54e03aa7b39..eeb82d79fce 100644 --- a/mozilla/testing/performance/talos/ffprocess_mac.py +++ b/mozilla/testing/performance/talos/ffprocess_mac.py @@ -45,136 +45,160 @@ import signal import os import time from select import select +from ffprocess import FFProcess + +class MacProcess(FFProcess): + + def __init__(self): + pass + + def GenerateBrowserCommandLine(self, browser_path, extra_args, profile_dir, url): + """Generates the command line for a process to run Browser + + Args: + browser_path: String containing the path to the browser binary to use + profile_dir: String containing the directory of the profile to run Browser in + url: String containing url to start with. + """ + + profile_arg = '' + if profile_dir: + profile_arg = '-profile %s' % profile_dir + + cmd = '%s -foreground %s %s %s' % (browser_path, + extra_args, + profile_arg, + url) + return cmd -def GenerateBrowserCommandLine(browser_path, extra_args, profile_dir, url): - """Generates the command line for a process to run Browser + def GetPidsByName(self, process_name): + """Searches for processes containing a given string. - Args: - browser_path: String containing the path to the browser binary to use - profile_dir: String containing the directory of the profile to run Browser in - url: String containing url to start with. - """ + Args: + process_name: The string to be searched for - profile_arg = '' - if profile_dir: - profile_arg = '-profile %s' % profile_dir + Returns: + A list of PIDs containing the string. An empty list is returned if none are + found. + """ - cmd = '%s -foreground %s %s %s' % (browser_path, - extra_args, - profile_arg, - url) - return cmd - - -def GetPidsByName(process_name): - """Searches for processes containing a given string. - - Args: - process_name: The string to be searched for - - Returns: - A list of PIDs containing the string. An empty list is returned if none are - found. - """ - - matchingPids = [] + matchingPids = [] - command = ['ps -Acj'] - handle = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True, shell=True) + command = ['ps -Acj'] + handle = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True, shell=True) - # wait for the process to terminate - handle.wait() - data = handle.stdout.readlines() + # wait for the process to terminate + handle.wait() + data = handle.stdout.readlines() - # find all matching processes and add them to the list - for line in data: - #overlook the mac crashreporter daemon - if line.find("crashreporterd") >= 0: - continue - if line.find('defunct') != -1: - continue - #overlook zombie processes - if line.find("Z+") >= 0: - continue - if line.find(process_name) >= 0: - # splits by whitespace, the first one should be the pid - pid = int(line.split()[1]) - matchingPids.append(pid) + # find all matching processes and add them to the list + for line in data: + #overlook the mac crashreporter daemon + if line.find("crashreporterd") >= 0: + continue + if line.find('defunct') != -1: + continue + #overlook zombie processes + if line.find("Z+") >= 0: + continue + if line.find(process_name) >= 0: + # splits by whitespace, the first one should be the pid + pid = int(line.split()[1]) + matchingPids.append(pid) - return matchingPids + return matchingPids -def ProcessesWithNameExist(*process_names): - """Returns true if there are any processes running with the - given name. Useful to check whether a Browser process is still running + def ProcessesWithNameExist(self, *process_names): + """Returns true if there are any processes running with the + given name. Useful to check whether a Browser process is still running - Args: - process_names: String or strings containing the process name, i.e. "firefox" + Args: + process_names: String or strings containing the process name, i.e. "firefox" - Returns: - True if any processes with that name are running, False otherwise. - """ - for process_name in process_names: - pids = GetPidsByName(process_name) - if len(pids) > 0: - return True - return False + Returns: + True if any processes with that name are running, False otherwise. + """ + for process_name in process_names: + pids = self.GetPidsByName(process_name) + if len(pids) > 0: + return True + return False -def TerminateProcess(pid, timeout): - """Helper function to terminate a process, given the pid + def TerminateProcess(self, pid, timeout): + """Helper function to terminate a process, given the pid - Args: - pid: integer process id of the process to terminate. - """ - try: - if ProcessesWithNameExist(str(pid)): - os.kill(pid, signal.SIGTERM) - time.sleep(timeout) - if ProcessesWithNameExist(str(pid)): - os.kill(pid, signal.SIGKILL) - except OSError, (errno, strerror): - print 'WARNING: failed os.kill: %s : %s' % (errno, strerror) + Args: + pid: integer process id of the process to terminate. + """ + try: + if self.ProcessesWithNameExist(str(pid)): + os.kill(pid, signal.SIGTERM) + time.sleep(timeout) + if self.ProcessesWithNameExist(str(pid)): + os.kill(pid, signal.SIGKILL) + except OSError, (errno, strerror): + print 'WARNING: failed os.kill: %s : %s' % (errno, strerror) -def TerminateAllProcesses(timeout, *process_names): - """Helper function to terminate all processes with the given process name + def TerminateAllProcesses(self, timeout, *process_names): + """Helper function to terminate all processes with the given process name - Args: - process_names: String or strings containing the process name, i.e. "firefox" - """ - for process_name in process_names: - pids = GetPidsByName(process_name) - for pid in pids: - TerminateProcess(pid, timeout) + Args: + process_names: String or strings containing the process name, i.e. "firefox" + """ + for process_name in process_names: + pids = self.GetPidsByName(process_name) + for pid in pids: + self.TerminateProcess(pid, timeout) -def NonBlockingReadProcessOutput(handle): - """Does a non-blocking read from the output of the process - with the given handle. + def NonBlockingReadProcessOutput(self, handle): + """Does a non-blocking read from the output of the process + with the given handle. - Args: - handle: The process handle returned from os.popen() + Args: + handle: The process handle returned from os.popen() - Returns: - A tuple (bytes, output) containing the number of output - bytes read, and the actual output. - """ + Returns: + A tuple (bytes, output) containing the number of output + bytes read, and the actual output. + """ - output = "" - num_avail = 0 + output = "" + num_avail = 0 - # check for data - # select() does not seem to work well with pipes. - # after data is available once it *always* thinks there is data available - # readline() will continue to return an empty string however - # so we can use this behavior to work around the problem - while select([handle], [], [], 0)[0]: - line = handle.readline() - if line: - output += line - else: - break - # this statement is true for encodings that have 1byte/char - num_avail = len(output) + # check for data + # select() does not seem to work well with pipes. + # after data is available once it *always* thinks there is data available + # readline() will continue to return an empty string however + # so we can use this behavior to work around the problem + while select([handle], [], [], 0)[0]: + line = handle.readline() + if line: + output += line + else: + break + # this statement is true for encodings that have 1byte/char + num_avail = len(output) + + return (num_avail, output) + + def MakeDirectoryContentsWritable(self, dirname): + """Recursively makes all the contents of a directory writable. + Uses os.chmod(filename, 0755). + + Args: + dirname: Name of the directory to make contents writable. + """ + try: + for (root, dirs, files) in os.walk(dirname): + os.chmod(root, 0755) + for filename in files: + try: + os.chmod(os.path.join(root, filename), 0755) + except OSError, (errno, strerror): + print 'WARNING: failed to os.chmod(%s): %s : %s' % (os.path.join(root, filename), errno, strerror) + except OSError, (errno, strerror): + print 'WARNING: failed to MakeDirectoryContentsWritable: %s : %s' % (errno, strerror) - return (num_avail, output) diff --git a/mozilla/testing/performance/talos/ffprocess_win32.py b/mozilla/testing/performance/talos/ffprocess_win32.py index d2ffb1f93d9..c8fe25ffb93 100644 --- a/mozilla/testing/performance/talos/ffprocess_win32.py +++ b/mozilla/testing/performance/talos/ffprocess_win32.py @@ -35,111 +35,139 @@ # # ***** END LICENSE BLOCK ***** -import win32api -import win32file -import win32pdhutil -import win32pdh -import win32pipe -import msvcrt +from ffprocess import FFProcess +import os + +try: + import win32api + import win32file + import win32pdhutil + import win32pdh + import win32pipe + import msvcrt +except: + pass + +class Win32Process(FFProcess): + def __init__(self): + pass + + def GenerateBrowserCommandLine(self, browser_path, extra_args, profile_dir, url): + """Generates the command line for a process to run Browser + + Args: + browser_path: String containing the path to the browser exe to use + profile_dir: String containing the directory of the profile to run Browser in + url: String containing url to start with. + """ + + profile_arg = '' + if profile_dir: + profile_dir = profile_dir.replace('\\', '\\\\\\') + profile_arg = '-profile %s' % profile_dir + + cmd = '%s %s %s %s' % (browser_path, + extra_args, + profile_arg, + url) + return cmd -def GenerateBrowserCommandLine(browser_path, extra_args, profile_dir, url): - """Generates the command line for a process to run Browser + def TerminateProcess(self, pid): + """Helper function to terminate a process, given the pid - Args: - browser_path: String containing the path to the browser exe to use - profile_dir: String containing the directory of the profile to run Browser in - url: String containing url to start with. - """ + Args: + pid: integer process id of the process to terminate. + """ - profile_arg = '' - if profile_dir: - profile_dir = profile_dir.replace('\\', '\\\\\\') - profile_arg = '-profile %s' % profile_dir - - cmd = '%s %s %s %s' % (browser_path, - extra_args, - profile_arg, - url) - return cmd + PROCESS_TERMINATE = 1 + handle = win32api.OpenProcess(PROCESS_TERMINATE, False, pid) + win32api.TerminateProcess(handle, -1) + win32api.CloseHandle(handle) -def TerminateProcess(pid): - """Helper function to terminate a process, given the pid + def ProcessesWithNameExist(self, *process_names): + """Returns true if there are any processes running with the + given name. Useful to check whether a Browser process is still running - Args: - pid: integer process id of the process to terminate. - """ + Args: + process_name: String or strings containing the process name, i.e. "firefox" - PROCESS_TERMINATE = 1 - handle = win32api.OpenProcess(PROCESS_TERMINATE, False, pid) - win32api.TerminateProcess(handle, -1) - win32api.CloseHandle(handle) + Returns: + True if any processes with that name are running, False otherwise. + """ + + for process_name in process_names: + try: + # refresh list of processes + win32pdh.EnumObjects(None, None, 0, 1) + pids = win32pdhutil.FindPerformanceAttributesByName(process_name, counter="ID Process") + if len(pids) > 0: + return True + except: + # Might get an exception if there are no instances of the process running. + continue + return False -def ProcessesWithNameExist(*process_names): - """Returns true if there are any processes running with the - given name. Useful to check whether a Browser process is still running + def TerminateAllProcesses(self, *process_names): + """Helper function to terminate all processes with the given process name - Args: - process_name: String or strings containing the process name, i.e. "firefox" - - Returns: - True if any processes with that name are running, False otherwise. - """ - - for process_name in process_names: - try: - # refresh list of processes - win32pdh.EnumObjects(None, None, 0, 1) - pids = win32pdhutil.FindPerformanceAttributesByName(process_name, counter="ID Process") - if len(pids) > 0: - return True - except: - # Might get an exception if there are no instances of the process running. - continue - return False + Args: + process_name: String or strings containing the process name, i.e. "firefox" + """ + for process_name in process_names: + # Get all the process ids of running instances of this process, and terminate them. + try: + # refresh list of processes + win32pdh.EnumObjects(None, None, 0, 1) + pids = win32pdhutil.FindPerformanceAttributesByName(process_name, counter="ID Process") + for pid in pids: + self.TerminateProcess(pid) + except: + # Might get an exception if there are no instances of the process running. + continue -def TerminateAllProcesses(*process_names): - """Helper function to terminate all processes with the given process name + def NonBlockingReadProcessOutput(self, handle): + """Does a non-blocking read from the output of the process + with the given handle. - Args: - process_name: String or strings containing the process name, i.e. "firefox" - """ - for process_name in process_names: - # Get all the process ids of running instances of this process, and terminate them. - try: - # refresh list of processes - win32pdh.EnumObjects(None, None, 0, 1) - pids = win32pdhutil.FindPerformanceAttributesByName(process_name, counter="ID Process") - for pid in pids: - TerminateProcess(pid) - except: - # Might get an exception if there are no instances of the process running. - continue + Args: + handle: The process handle returned from os.popen() + Returns: + A tuple (bytes, output) containing the number of output + bytes read, and the actual output. + """ -def NonBlockingReadProcessOutput(handle): - """Does a non-blocking read from the output of the process - with the given handle. + output = "" - Args: - handle: The process handle returned from os.popen() + try: + osfhandle = msvcrt.get_osfhandle(handle.fileno()) + (read, num_avail, num_message) = win32pipe.PeekNamedPipe(osfhandle, 0) + if num_avail > 0: + (error_code, output) = win32file.ReadFile(osfhandle, num_avail, None) - Returns: - A tuple (bytes, output) containing the number of output - bytes read, and the actual output. - """ + return (num_avail, output) + except: + return (0, output) + + def MakeDirectoryContentsWritable(self, dirname): + """Recursively makes all the contents of a directory writable. + Uses os.chmod(filename, 0777), which works on Windows. - output = "" + Args: + dirname: Name of the directory to make contents writable. + """ - try: - osfhandle = msvcrt.get_osfhandle(handle.fileno()) - (read, num_avail, num_message) = win32pipe.PeekNamedPipe(osfhandle, 0) - if num_avail > 0: - (error_code, output) = win32file.ReadFile(osfhandle, num_avail, None) - - return (num_avail, output) - except: - return (0, output) + try: + for (root, dirs, files) in os.walk(dirname): + os.chmod(root, 0777) + for filename in files: + try: + os.chmod(os.path.join(root, filename), 0777) + except OSError, (errno, strerror): + print 'WARNING: failed to os.chmod(%s): %s : %s' % (os.path.join(root, filename), errno, strerror) + except OSError, (errno, strerror): + print 'WARNING: failed to MakeDirectoryContentsWritable: %s : %s' % (errno, strerror) diff --git a/mozilla/testing/performance/talos/ffsetup.py b/mozilla/testing/performance/talos/ffsetup.py index 92ae77ad86e..bfbb09d0d68 100644 --- a/mozilla/testing/performance/talos/ffsetup.py +++ b/mozilla/testing/performance/talos/ffsetup.py @@ -55,122 +55,122 @@ import glob import utils from utils import talosError import subprocess -import ffprocess -if platform.system() == "Linux": - from ffprofile_unix import * -elif platform.system() in ("Windows", "Microsoft"): - from ffprofile_win32 import * -elif platform.system() == "Darwin": - from ffprofile_unix import * +class FFSetup(object): -def PrefString(name, value, newline): - """Helper function to create a pref string for profile prefs.js - in the form 'user_pref("name", value);' + ffprocess = None - Args: - name: String containing name of pref - value: String containing value of pref - newline: Line ending to use, i.e. '\n' or '\r\n' + def __init__(self, procmgr): + self.ffprocess = procmgr - Returns: - String containing 'user_pref("name", value);' - """ + def PrefString(self, name, value, newline): + """Helper function to create a pref string for profile prefs.js + in the form 'user_pref("name", value);' - out_value = str(value) - if type(value) == bool: - # Write bools as "true"/"false", not "True"/"False". - out_value = out_value.lower() - if type(value) == str: - # Write strings with quotes around them. - out_value = '"%s"' % value - return 'user_pref("%s", %s);%s' % (name, out_value, newline) + Args: + name: String containing name of pref + value: String containing value of pref + newline: Line ending to use, i.e. '\n' or '\r\n' + + Returns: + String containing 'user_pref("name", value);' + """ + + out_value = str(value) + if type(value) == bool: + # Write bools as "true"/"false", not "True"/"False". + out_value = out_value.lower() + if type(value) == str: + # Write strings with quotes around them. + out_value = '"%s"' % value + return 'user_pref("%s", %s);%s' % (name, out_value, newline) -def CreateTempProfileDir(source_profile, prefs, extensions): - """Creates a temporary profile directory from the source profile directory - and adds the given prefs and links to extensions. + def CreateTempProfileDir(self, source_profile, prefs, extensions): + """Creates a temporary profile directory from the source profile directory + and adds the given prefs and links to extensions. - Args: - source_profile: String containing the absolute path of the source profile - directory to copy from. - prefs: Preferences to set in the prefs.js file of the new profile. Format: - {"PrefName1" : "PrefValue1", "PrefName2" : "PrefValue2"} - extensions: Guids and paths of extensions to link to. Format: - {"{GUID1}" : "c:\\Path\\to\\ext1", "{GUID2}", "c:\\Path\\to\\ext2"} + Args: + source_profile: String containing the absolute path of the source profile + directory to copy from. + prefs: Preferences to set in the prefs.js file of the new profile. Format: + {"PrefName1" : "PrefValue1", "PrefName2" : "PrefValue2"} + extensions: Guids and paths of extensions to link to. Format: + {"{GUID1}" : "c:\\Path\\to\\ext1", "{GUID2}", "c:\\Path\\to\\ext2"} - Returns: - String containing the absolute path of the profile directory. - """ + Returns: + String containing the absolute path of the profile directory. + """ - # Create a temporary directory for the profile, and copy the - # source profile to it. - temp_dir = tempfile.mkdtemp() - profile_dir = os.path.join(temp_dir, 'profile') - shutil.copytree(source_profile, profile_dir) - MakeDirectoryContentsWritable(profile_dir) + # Create a temporary directory for the profile, and copy the + # source profile to it. + temp_dir = tempfile.mkdtemp() + profile_dir = os.path.join(temp_dir, 'profile') + shutil.copytree(source_profile, profile_dir) + self.ffprocess.MakeDirectoryContentsWritable(profile_dir) - # Copy the user-set prefs to user.js - user_js_filename = os.path.join(profile_dir, 'user.js') - user_js_file = open(user_js_filename, 'w') - for pref in prefs: - user_js_file.write(PrefString(pref, prefs[pref], '\n')) - user_js_file.close() + # Copy the user-set prefs to user.js + user_js_filename = os.path.join(profile_dir, 'user.js') + user_js_file = open(user_js_filename, 'w') + for pref in prefs: + user_js_file.write(self.PrefString(pref, prefs[pref], '\n')) + user_js_file.close() - # Add links to all the extensions. - extension_dir = os.path.join(profile_dir, "extensions") - if not os.path.exists(extension_dir): - os.makedirs(extension_dir) - for extension in extensions: - link_file = open(os.path.join(extension_dir, extension), 'w') - link_file.write(extensions[extension]) - link_file.close() + # Add links to all the extensions. + extension_dir = os.path.join(profile_dir, "extensions") + if not os.path.exists(extension_dir): + os.makedirs(extension_dir) + for extension in extensions: + link_file = open(os.path.join(extension_dir, extension), 'w') + link_file.write(extensions[extension]) + link_file.close() - return temp_dir, profile_dir + return temp_dir, profile_dir -def InstallInBrowser(browser_path, dir_path): - """ - Take the given directory and copies it to appropriate location in the given - browser install - """ - # add the provided directory to the given browser install - fromfiles = glob.glob(os.path.join(dir_path, '*')) - todir = os.path.join(os.path.dirname(browser_path), os.path.basename(os.path.normpath(dir_path))) - for fromfile in fromfiles: - if not os.path.isfile(os.path.join(todir, os.path.basename(fromfile))): - shutil.copy(fromfile, todir) - utils.debug("installed " + fromfile) - else: - utils.debug("WARNING: file already installed (" + fromfile + ")") + def InstallInBrowser(self, browser_path, dir_path): + """ + Take the given directory and copies it to appropriate location in the given + browser install + """ + # add the provided directory to the given browser install + fromfiles = glob.glob(os.path.join(dir_path, '*')) + todir = os.path.join(os.path.dirname(browser_path), os.path.basename(os.path.normpath(dir_path))) + for fromfile in fromfiles: + if not os.path.isfile(os.path.join(todir, os.path.basename(fromfile))): + shutil.copy(fromfile, todir) + utils.debug("installed " + fromfile) + else: + utils.debug("WARNING: file already installed (" + fromfile + ")") -def InitializeNewProfile(browser_path, process, browser_wait, extra_args, profile_dir, init_url, log): - """Runs browser with the new profile directory, to negate any performance - hit that could occur as a result of starting up with a new profile. - Also kills the "extra" browser that gets spawned the first time browser - is run with a new profile. + def InitializeNewProfile(self, browser_path, process, browser_wait, extra_args, profile_dir, init_url, log): + """Runs browser with the new profile directory, to negate any performance + hit that could occur as a result of starting up with a new profile. + Also kills the "extra" browser that gets spawned the first time browser + is run with a new profile. - Args: - browser_path: String containing the path to the browser exe - profile_dir: The full path to the profile directory to load - """ - PROFILE_REGEX = re.compile('__metrics(.*)__metrics', re.DOTALL|re.MULTILINE) - command_line = ffprocess.GenerateBrowserCommandLine(browser_path, extra_args, profile_dir, init_url) - process = subprocess.Popen('python bcontroller.py --command "%s" --name %s --timeout %d --log %s' % (command_line, process, browser_wait, log), universal_newlines=True, shell=True, bufsize=0, env=os.environ) - res = 0 - total_time = 0 - while total_time < 600: #10 minutes - time.sleep(1) - if process.poll() != None: #browser_controller completed, file now full - if not os.path.isfile(log): - raise talosError("no output from browser") - results_file = open(log, "r") - results_raw = results_file.read() - results_file.close() - match = PROFILE_REGEX.search(results_raw) - if match: - res = 1 - print match.group(1) - break - total_time += 1 + Args: + browser_path: String containing the path to the browser exe + profile_dir: The full path to the profile directory to load + """ + PROFILE_REGEX = re.compile('__metrics(.*)__metrics', re.DOTALL|re.MULTILINE) + command_line = self.ffprocess.GenerateBrowserCommandLine(browser_path, extra_args, profile_dir, init_url) + process = subprocess.Popen('python bcontroller.py --command "%s" --name %s --timeout %d --log %s' % (command_line, process, browser_wait, log), universal_newlines=True, shell=True, bufsize=0, env=os.environ) + res = 0 + total_time = 0 + while total_time < 600: #10 minutes + time.sleep(1) + if process.poll() != None: #browser_controller completed, file now full + if not os.path.isfile(log): + raise talosError("no output from browser") + results_file = open(log, "r") + results_raw = results_file.read() + results_file.close() + match = PROFILE_REGEX.search(results_raw) + if match: + res = 1 + print match.group(1) + break + import ffprocess + total_time += 1 - return res + return res diff --git a/mozilla/testing/performance/talos/run_tests.py b/mozilla/testing/performance/talos/run_tests.py index 92fc3cae201..7ad59ef0b89 100755 --- a/mozilla/testing/performance/talos/run_tests.py +++ b/mozilla/testing/performance/talos/run_tests.py @@ -52,7 +52,7 @@ import re import utils from utils import talosError import post_file -import ttest +from ttest import TTest def shortName(name): if name == "Working Set": @@ -380,7 +380,7 @@ def test_file(filename): testname = test['name'] utils.stamped_msg("Running test " + testname, "Started") try: - browser_dump, counter_dump, print_format = ttest.runTest(browser_config, test) + browser_dump, counter_dump, print_format = TTest().runTest(browser_config, test) utils.debug("Received test results: " + " ".join(browser_dump)) results[testname] = [browser_dump, counter_dump, print_format] # If we're doing CSV, write this test immediately (bug 419367) diff --git a/mozilla/testing/performance/talos/ttest.py b/mozilla/testing/performance/talos/ttest.py index d6f0138a6c1..6dc77466ff3 100644 --- a/mozilla/testing/performance/talos/ttest.py +++ b/mozilla/testing/performance/talos/ttest.py @@ -61,278 +61,306 @@ import utils import glob from utils import talosError -import ffprocess -import ffsetup +from ffprocess_linux import LinuxProcess +from ffprocess_win32 import Win32Process +from ffprocess_mac import MacProcess +from ffsetup import FFSetup +class TTest(object): -if platform.system() == "Linux": - from cmanager_linux import * - platform_type = 'linux_' -elif platform.system() in ("Windows", "Microsoft"): - from cmanager_win32 import * - platform_type = 'win_' -elif platform.system() == "Darwin": - from cmanager_mac import * - platform_type = 'mac_' + _ffsetup = None + _ffprocess = None + platform_type = '' - -# Regular expression for getting results from most tests -RESULTS_REGEX = re.compile('__start_report(.*?)__end_report.*?__startTimestamp(.*?)__endTimestamp.*?__startSecondTimestamp(.*?)__endSecondTimestamp', + # Regular expression for getting results from most tests + RESULTS_REGEX = re.compile('__start_report(.*?)__end_report.*?__startTimestamp(.*?)__endTimestamp.*?__startSecondTimestamp(.*?)__endSecondTimestamp', re.DOTALL | re.MULTILINE) -# Regular expression to get stats for page load test (Tp) - should go away once data passing is standardized -RESULTS_TP_REGEX = re.compile('__start_tp_report(.*?)__end_tp_report.*?__startTimestamp(.*?)__endTimestamp.*?__startSecondTimestamp(.*?)__endSecondTimestamp', + # Regular expression to get stats for page load test (Tp) - + #should go away once data passing is standardized + RESULTS_TP_REGEX = re.compile('__start_tp_report(.*?)__end_tp_report.*?__startTimestamp(.*?)__endTimestamp.*?__startSecondTimestamp(.*?)__endSecondTimestamp', re.DOTALL | re.MULTILINE) -RESULTS_REGEX_FAIL = re.compile('__FAIL(.*?)__FAIL', re.DOTALL|re.MULTILINE) + RESULTS_REGEX_FAIL = re.compile('__FAIL(.*?)__FAIL', re.DOTALL|re.MULTILINE) -def createProfile(profile_path, browser_config): - # Create the new profile - temp_dir, profile_dir = ffsetup.CreateTempProfileDir(profile_path, - browser_config['preferences'], - browser_config['extensions']) - utils.debug("created profile") - return profile_dir, temp_dir + def __init__(self): + cmanager = None + if platform.system() == "Linux": + cmanager = __import__('cmanager_linux') + self.platform_type = 'linux_' + self._ffprocess = LinuxProcess() + elif platform.system() in ("Windows", "Microsoft"): + cmanager = __import__('cmanager_win32') + self.platform_type = 'win_' + self._ffprocess = Win32Process() + elif platform.system() == "Darwin": + cmanager = __import__('cmanager_mac') + self.platform_type = 'mac_' + self._ffprocess = MacProcess() -def initializeProfile(profile_dir, browser_config): - if not (ffsetup.InitializeNewProfile(browser_config['browser_path'], browser_config['process'], browser_config['browser_wait'], browser_config['extra_args'], profile_dir, browser_config['init_url'], browser_config['browser_log'])): - raise talosError("failed to initialize browser") - time.sleep(browser_config['browser_wait']) - if ffprocess.checkAllProcesses(browser_config['process']): - raise talosError("browser failed to close after being initialized") + self._ffsetup = FFSetup(self._ffprocess) -def cleanupProfile(dir): - # Delete the temp profile directory Make it writeable first, - # because every once in a while browser seems to drop a read-only - # file into it. - ffsetup.MakeDirectoryContentsWritable(dir) - shutil.rmtree(dir) + def createProfile(self, profile_path, browser_config): + # Create the new profile + temp_dir, profile_dir = self._ffsetup.CreateTempProfileDir(profile_path, + browser_config['preferences'], + browser_config['extensions']) + utils.debug("created profile") + return profile_dir, temp_dir -def checkForCrashes(browser_config, profile_dir): - if platform.system() in ('Windows', 'Microsoft'): - stackwalkpaths = ['win32', 'minidump_stackwalk.exe'] - elif platform.system() == 'Linux': - if platform.machine() == 'armv6l': - stackwalkpaths = ['maemo', 'minidump_stackwalk'] + def initializeProfile(self, profile_dir, browser_config): + if not (self._ffsetup.InitializeNewProfile(browser_config['browser_path'], + browser_config['process'], + browser_config['browser_wait'], + browser_config['extra_args'], + profile_dir, + browser_config['init_url'], + browser_config['browser_log'])): + raise talosError("failed to initialize browser") + time.sleep(browser_config['browser_wait']) + if self._ffprocess.checkAllProcesses(browser_config['process']): + raise talosError("browser failed to close after being initialized") + + def cleanupProfile(self, dir): + # Delete the temp profile directory Make it writeable first, + # because every once in a while browser seems to drop a read-only + # file into it. + self._ffprocess.MakeDirectoryContentsWritable(dir) + shutil.rmtree(dir) + + def checkForCrashes(self, browser_config, profile_dir): + if platform.system() in ('Windows', 'Microsoft'): + stackwalkpaths = ['win32', 'minidump_stackwalk.exe'] + elif platform.system() == 'Linux': + if platform.machine() == 'armv6l': + stackwalkpaths = ['maemo', 'minidump_stackwalk'] + else: + stackwalkpaths = ['linux', 'minidump_stackwalk'] + elif platform.system() == 'Darwin': + stackwalkpaths = ['osx', 'minidump_stackwalk'] else: - stackwalkpaths = ['linux', 'minidump_stackwalk'] - elif platform.system() == 'Darwin': - stackwalkpaths = ['osx', 'minidump_stackwalk'] - else: - return - stackwalkbin = os.path.join(os.path.dirname(__file__), 'breakpad', *stackwalkpaths) + return + stackwalkbin = os.path.join(os.path.dirname(__file__), 'breakpad', *stackwalkpaths) + + found = False + for dump in glob.glob(os.path.join(profile_dir, 'minidumps', '*.dmp')): + utils.noisy("Found crashdump: " + dump) + if browser_config['symbols_path']: + nullfd = open(os.devnull, 'w') + subprocess.call([stackwalkbin, dump, browser_config['symbols_path']], stderr=nullfd) + nullfd.close() + os.remove(dump) + found = True + + if found: + raise talosError("crash during run (stack found)") + + def runTest(self, browser_config, test_config): + """ + Runs an url based test on the browser as specified in the browser_config dictionary + + Args: + browser_config: Dictionary of configuration options for the browser (paths, prefs, etc) + test_config : Dictionary of configuration for the given test (url, cycles, counters, etc) + + """ + + utils.debug("operating with platform_type : " + self.platform_type) + counters = test_config[self.platform_type + 'counters'] + resolution = test_config['resolution'] + all_browser_results = [] + all_counter_results = [] + format = "" + utils.setEnvironmentVars(browser_config['env']) + utils.setEnvironmentVars({'MOZ_CRASHREPORTER_NO_REPORT': '1'}) - found = False - for dump in glob.glob(os.path.join(profile_dir, 'minidumps', '*.dmp')): - utils.noisy("Found crashdump: " + dump) if browser_config['symbols_path']: - nullfd = open(os.devnull, 'w') - subprocess.call([stackwalkbin, dump, browser_config['symbols_path']], stderr=nullfd) - nullfd.close() - os.remove(dump) - found = True + utils.setEnvironmentVars({'MOZ_CRASHREPORTER': '1'}) + else: + utils.setEnvironmentVars({'MOZ_CRASHREPORTER_DISABLE': '1'}) - if found: - raise talosError("crash during run (stack found)") + utils.setEnvironmentVars({"LD_LIBRARY_PATH" : os.path.dirname(browser_config['browser_path'])}) -def runTest(browser_config, test_config): - """ - Runs an url based test on the browser as specified in the browser_config dictionary + profile_dir = None + + try: + if self._ffprocess.checkAllProcesses(browser_config['process']): + msg = " already running before testing started (unclean system)" + utils.debug(browser_config['process'] + msg) + raise talosError("system not clean") - Args: - browser_config: Dictionary of configuration options for the browser (paths, prefs, etc) - test_config : Dictionary of configuration for the given test (url, cycles, counters, etc) + # add any provided directories to the installed browser + for dir in browser_config['dirs']: + self._ffsetup.InstallInBrowser(browser_config['browser_path'], + browser_config['dirs'][dir]) - """ - - utils.debug("operating with platform_type : " + platform_type) - counters = test_config[platform_type + 'counters'] - resolution = test_config['resolution'] - all_browser_results = [] - all_counter_results = [] - format = "" - utils.setEnvironmentVars(browser_config['env']) - utils.setEnvironmentVars({'MOZ_CRASHREPORTER_NO_REPORT': '1'}) - - if browser_config['symbols_path']: - utils.setEnvironmentVars({'MOZ_CRASHREPORTER': '1'}) - else: - utils.setEnvironmentVars({'MOZ_CRASHREPORTER_DISABLE': '1'}) - - utils.setEnvironmentVars({"LD_LIBRARY_PATH" : os.path.dirname(browser_config['browser_path'])}) - - profile_dir = None - - try: - if ffprocess.checkAllProcesses(browser_config['process']): - utils.debug(browser_config['process'] + " already running before testing started (unclean system)") - raise talosError("system not clean") - - # add any provided directories to the installed browser - for dir in browser_config['dirs']: - ffsetup.InstallInBrowser(browser_config['browser_path'], browser_config['dirs'][dir]) - - # make profile path work cross-platform - test_config['profile_path'] = os.path.normpath(test_config['profile_path']) - profile_dir, temp_dir = createProfile(test_config['profile_path'], browser_config) - if os.path.isfile(browser_config['browser_log']): - os.chmod(browser_config['browser_log'], 0777) - os.remove(browser_config['browser_log']) - initializeProfile(profile_dir, browser_config) + # make profile path work cross-platform + test_config['profile_path'] = os.path.normpath(test_config['profile_path']) + profile_dir, temp_dir = self.createProfile(test_config['profile_path'], browser_config) + if os.path.isfile(browser_config['browser_log']): + os.chmod(browser_config['browser_log'], 0777) + os.remove(browser_config['browser_log']) + self.initializeProfile(profile_dir, browser_config) - utils.debug("initialized " + browser_config['process']) - if test_config['shutdown']: - shutdown = [] + utils.debug("initialized " + browser_config['process']) + if test_config['shutdown']: + shutdown = [] - for i in range(test_config['cycles']): - if os.path.isfile(browser_config['browser_log']): - os.chmod(browser_config['browser_log'], 0777) - os.remove(browser_config['browser_log']) - time.sleep(browser_config['browser_wait']) #wait out the browser closing - # check to see if the previous cycle is still hanging around - if (i > 0) and ffprocess.checkAllProcesses(browser_config['process']): - raise talosError("previous cycle still running") + for i in range(test_config['cycles']): + if os.path.isfile(browser_config['browser_log']): + os.chmod(browser_config['browser_log'], 0777) + os.remove(browser_config['browser_log']) + time.sleep(browser_config['browser_wait']) #wait out the browser closing + # check to see if the previous cycle is still hanging around + if (i > 0) and self._ffprocess.checkAllProcesses(browser_config['process']): + raise talosError("previous cycle still running") - # Execute the test's head script if there is one - if 'head' in test_config: - try: - subprocess.call(['python', test_config['head']]) - except: - raise talosError("error executing head script: %s" % sys.exc_info()[0]) + # Execute the test's head script if there is one + if 'head' in test_config: + try: + subprocess.call(['python', test_config['head']]) + except: + raise talosError("error executing head script: %s" % sys.exc_info()[0]) - # Run the test - browser_results = "" - if 'timeout' in test_config: - timeout = test_config['timeout'] - else: - timeout = 7200 # 2 hours - total_time = 0 - output = '' - url = test_config['url'] - command_line = ffprocess.GenerateBrowserCommandLine(browser_config['browser_path'], browser_config['extra_args'], profile_dir, url) + # Run the test + browser_results = "" + if 'timeout' in test_config: + timeout = test_config['timeout'] + else: + timeout = 7200 # 2 hours + total_time = 0 + output = '' + url = test_config['url'] + command_line = self._ffprocess.GenerateBrowserCommandLine(browser_config['browser_path'], + browser_config['extra_args'], + profile_dir, + url) - utils.debug("command line: " + command_line) + utils.debug("command line: " + command_line) - if 'url_mod' in test_config: - process = subprocess.Popen('python bcontroller.py --command "%s" --mod "%s" --name %s --timeout %d --log %s' % (command_line, test_config['url_mod'], browser_config['process'], browser_config['browser_wait'], browser_config['browser_log']), universal_newlines=True, shell=True, bufsize=0, env=os.environ) - else: - process = subprocess.Popen('python bcontroller.py --command "%s" --name %s --timeout %d --log %s' % (command_line, browser_config['process'], browser_config['browser_wait'], browser_config['browser_log']), universal_newlines=True, shell=True, bufsize=0, env=os.environ) + if 'url_mod' in test_config: + process = subprocess.Popen('python bcontroller.py --command "%s" --mod "%s" --name %s --timeout %d --log %s' % (command_line, test_config['url_mod'], browser_config['process'], browser_config['browser_wait'], browser_config['browser_log']), universal_newlines=True, shell=True, bufsize=0, env=os.environ) + else: + process = subprocess.Popen('python bcontroller.py --command "%s" --name %s --timeout %d --log %s' % (command_line, browser_config['process'], browser_config['browser_wait'], browser_config['browser_log']), universal_newlines=True, shell=True, bufsize=0, env=os.environ) - #give browser a chance to open - # this could mean that we are losing the first couple of data points as the tests starts, but if we don't provide - # some time for the browser to start we have trouble connecting the CounterManager to it - time.sleep(browser_config['browser_wait']) - #set up the counters for this test - if counters: - cm = CounterManager(browser_config['process'], counters) - cm.startMonitor() - counter_results = {} - for counter in counters: - counter_results[counter] = [] + #give browser a chance to open + # this could mean that we are losing the first couple of data points + # as the tests starts, but if we don't provide + # some time for the browser to start we have trouble connecting the CounterManager to it + time.sleep(browser_config['browser_wait']) + #set up the counters for this test + if counters: + cm = cmanager.CounterManager(browser_config['process'], counters) + cm.startMonitor() + counter_results = {} + for counter in counters: + counter_results[counter] = [] - startTime = -1 - dumpResult = "" - while total_time < timeout: #the main test loop, monitors counters and checks for browser ouptut - # Sleep for [resolution] seconds - time.sleep(resolution) - total_time += resolution - if os.path.isfile(browser_config['browser_log']): - results_file = open(browser_config['browser_log'], "r") - fileData = results_file.read() - results_file.close() - utils.noisy(fileData.replace(dumpResult, '')) - dumpResult = fileData + startTime = -1 + dumpResult = "" + #the main test loop, monitors counters and checks for browser ouptut + while total_time < timeout: + # Sleep for [resolution] seconds + time.sleep(resolution) + total_time += resolution + if os.path.isfile(browser_config['browser_log']): + results_file = open(browser_config['browser_log'], "r") + fileData = results_file.read() + results_file.close() + utils.noisy(fileData.replace(dumpResult, '')) + dumpResult = fileData - # Get the output from all the possible counters - for count_type in counters: - val = cm.getCounterValue(count_type) - if (val): - counter_results[count_type].append(val) - if process.poll() != None: #browser_controller completed, file now full - #stop the counter manager since this test is complete - if counters: - cm.stopMonitor() - if not os.path.isfile(browser_config['browser_log']): - raise talosError("no output from browser") - results_file = open(browser_config['browser_log'], "r") - results_raw = results_file.read() - results_file.close() + # Get the output from all the possible counters + for count_type in counters: + val = cm.getCounterValue(count_type) + if (val): + counter_results[count_type].append(val) + if process.poll() != None: #browser_controller completed, file now full + #stop the counter manager since this test is complete + if counters: + cm.stopMonitor() + if not os.path.isfile(browser_config['browser_log']): + raise talosError("no output from browser") + results_file = open(browser_config['browser_log'], "r") + results_raw = results_file.read() + results_file.close() - match = RESULTS_REGEX.search(results_raw) - if match: - browser_results += match.group(1) - startTime = int(match.group(2)) - endTime = int(match.group(3)) - format = "tsformat" - break - #TODO: this a stop gap until all of the tests start outputting the same format - match = RESULTS_TP_REGEX.search(results_raw) - if match: - browser_results += match.group(1) - startTime = int(match.group(2)) - endTime = int(match.group(3)) - format = "tpformat" - break - match = RESULTS_REGEX_FAIL.search(results_raw) - if match: - browser_results += match.group(1) - raise talosError(match.group(1)) - raise talosError("unrecognized output format") + match = self.RESULTS_REGEX.search(results_raw) + if match: + browser_results += match.group(1) + startTime = int(match.group(2)) + endTime = int(match.group(3)) + format = "tsformat" + break + #TODO: this a stop gap until all of the tests start outputting the same format + match = self.RESULTS_TP_REGEX.search(results_raw) + if match: + browser_results += match.group(1) + startTime = int(match.group(2)) + endTime = int(match.group(3)) + format = "tpformat" + break + match = self.RESULTS_REGEX_FAIL.search(results_raw) + if match: + browser_results += match.group(1) + raise talosError(match.group(1)) + raise talosError("unrecognized output format") - if total_time >= timeout: - raise talosError("timeout exceeded") + if total_time >= timeout: + raise talosError("timeout exceeded") - time.sleep(browser_config['browser_wait']) - #clean up the process - timer = 0 - while ((process.poll() is None) and timer < browser_config['browser_wait']): - time.sleep(1) - timer+=1 + time.sleep(browser_config['browser_wait']) + #clean up the process + timer = 0 + while ((process.poll() is None) and timer < browser_config['browser_wait']): + time.sleep(1) + timer+=1 - if test_config['shutdown']: - shutdown.append(endTime - startTime) + if test_config['shutdown']: + shutdown.append(endTime - startTime) - checkForCrashes(browser_config, profile_dir) + self.checkForCrashes(browser_config, profile_dir) - all_browser_results.append(browser_results) - all_counter_results.append(counter_results) + all_browser_results.append(browser_results) + all_counter_results.append(counter_results) - # Execute the test's tail script if there is one - if 'tail' in test_config: - try: - subprocess.call(['python', test_config['tail']]) - except: - raise talosError("error executing tail script: %s" % sys.exc_info()[0]) + # Execute the test's tail script if there is one + if 'tail' in test_config: + try: + subprocess.call(['python', test_config['tail']]) + except: + raise talosError("error executing tail script: %s" % sys.exc_info()[0]) - ffprocess.cleanupProcesses(browser_config['process'], browser_config['browser_wait']) - cleanupProfile(temp_dir) + self._ffprocess.cleanupProcesses(browser_config['process'], browser_config['browser_wait']) + self.cleanupProfile(temp_dir) - utils.restoreEnvironmentVars() - if test_config['shutdown']: - all_counter_results.append({'shutdown' : shutdown}) - return (all_browser_results, all_counter_results, format) - except: - try: - if 'cm' in vars(): - cm.stopMonitor() + utils.restoreEnvironmentVars() + if test_config['shutdown']: + all_counter_results.append({'shutdown' : shutdown}) + return (all_browser_results, all_counter_results, format) + except: + try: + if 'cm' in vars(): + cm.stopMonitor() - if os.path.isfile(browser_config['browser_log']): - results_file = open(browser_config['browser_log'], "r") - results_raw = results_file.read() - results_file.close() - utils.noisy(results_raw) + if os.path.isfile(browser_config['browser_log']): + results_file = open(browser_config['browser_log'], "r") + results_raw = results_file.read() + results_file.close() + utils.noisy(results_raw) - ffprocess.cleanupProcesses(browser_config['process'], browser_config['browser_wait']) + self._ffprocess.cleanupProcesses(browser_config['process'], + browser_config['browser_wait']) - if profile_dir: - try: - checkForCrashes(browser_config, profile_dir) - except talosError: - pass + if profile_dir: + try: + self.checkForCrashes(browser_config, profile_dir) + except talosError: + pass - if vars().has_key('temp_dir'): - cleanupProfile(temp_dir) - except talosError, te: - utils.debug("cleanup error: " + te.msg) - except: - utils.debug("unknown error during cleanup") - raise + if vars().has_key('temp_dir'): + self.cleanupProfile(temp_dir) + except talosError, te: + utils.debug("cleanup error: " + te.msg) + except: + utils.debug("unknown error during cleanup") + raise