diff options
author | nirnimesh@chromium.org <nirnimesh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-17 02:24:53 +0000 |
---|---|---|
committer | nirnimesh@chromium.org <nirnimesh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-17 02:24:53 +0000 |
commit | 1f73dcad1fe1d80cd9d5a1afb60ad5d56dc52619 (patch) | |
tree | 1818d0460aff534430970df7445c5c4fde42be51 | |
parent | bf712f8ee12c3045ed390005887acb28e2bc7d49 (diff) | |
download | chromium_src-1f73dcad1fe1d80cd9d5a1afb60ad5d56dc52619.zip chromium_src-1f73dcad1fe1d80cd9d5a1afb60ad5d56dc52619.tar.gz chromium_src-1f73dcad1fe1d80cd9d5a1afb60ad5d56dc52619.tar.bz2 |
Cleanup and improve failure messages
- Cleanup some stuff. Remove unused files.
- Provide links to docs in some failure conditions and add make some error
messages better.
R=dtu@chromium.org
BUG=
TEST=
Review URL: http://codereview.chromium.org/7172032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@89440 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/test/functional/autotour.py | 212 | ||||
-rw-r--r-- | chrome/test/functional/exploratory.py | 66 | ||||
-rw-r--r--[-rwxr-xr-x] | chrome/test/functional/infobars.py | 0 | ||||
-rw-r--r-- | chrome/test/functional/test_basic.py | 2 | ||||
-rw-r--r-- | chrome/test/pyautolib/pyauto.py | 17 |
5 files changed, 14 insertions, 283 deletions
diff --git a/chrome/test/functional/autotour.py b/chrome/test/functional/autotour.py deleted file mode 100644 index 7947550..0000000 --- a/chrome/test/functional/autotour.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2010 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import logging -import random -import time - - -"""Autotour is a semi automatic exploratory framework for exploring actions -defined on an object. It uses decorators to mark methods as actions and an -explorer object to explore. -""" - -def GodelAction(weight=1, requires=''): - """Action Decorator - - This function is the key to exploration. In effect, it annotates the wrapping - function with attributes such as is_action = True and sets some weights and - the requires condition. The explorer can invoke functions based on these - attributes. - - Args: - weight: Weight for the action, default is set to 1. Can be any number >= 0 - requires: Precondition for an action to be executed. This usually points - to a function which returns a boolean result. - """ - def custom(target): - """This is the decorator which sets the attributes for - is_action, weight and requires. - - Args: - target: Function to be decorated. - - Returns: - The wrapped function with correct attributes set. - """ - def wrapper(self, *args, **kwargs): - target(self, *args, **kwargs) - wrapper.is_action = True - wrapper.weight = weight - wrapper.requires = requires - return wrapper - return custom - - -class Godel(object): - """Base class for all exploratory objects. - - All objects that wish to be explored must inherit this class. - It provides an important method GetActions, which looks at all the functions - and returns only those that have the is_action attribute set. - """ - - def Initialize(self, uniqueid): - self._uniqueid = uniqueid - - def GetName(self): - return type(self).__name__ + str(self._uniqueid) - - def GetActions(self): - """Gets all the actions for this class.""" - return [method for method in dir(self) - if hasattr(getattr(self, method), 'is_action')] - - def GetWeight(self, method): - """Returns the weight of a given method. - - Args: - method: Name of the Method whose Weight is queried - """ - method_obj = getattr(self, method) - return getattr(method_obj, 'weight', 1) - - def SetWeight(self, method, weight): - """Sets the weight for a given method.""" - method_obj = getattr(self, method) - method_obj.im_func.weight = weight - - -class Explorer(object): - """Explorer class that controls the exploration of the object. - - This class has methods to add the exploration object and - initiate exploration on them. - """ - - def __init__(self): - self._seed = time.time() - logging.info('#Seeded with %s' % self._seed) - random.seed(self._seed) - self._actionlimit = -1 - self._godels = [] - self._fh = logging.FileHandler(str(self._seed)) - self._log = logging.getLogger() - self._log.addHandler(self._fh) - self._log.setLevel(logging.DEBUG) - self._uniqueid = 0 - - def NextId(self): - """Gets the NextId by incrementing a counter.""" - self._uniqueid = self._uniqueid + 1 - return self._uniqueid - - def Add(self, obj): - """Adds an object which inherits from Godel to be explored. - - Args: - obj: Object to be explored which usually inherits from the Godel class. - """ - uniqueid = self.NextId() - obj.Initialize(uniqueid) - name = type(obj).__name__ - self._log.info('%s = %s()' % (name + str(uniqueid), name)) - self._godels.append(obj) - - def MeetsRequirement(self, godel, methodname): - """Method that returns true if the method's precondition is satisfied. - It does so by using the attribute "Requires" which is set by the decorator - and invokes it which must return a boolean value - Args: - godel: Godel object on which the requirement needs to be tested. - methodname: Method name which needs to be called to test. - Returns: - True if the methodname invoked returned True or methodname was empty, - False otherwise - """ - method = getattr(godel, methodname) - requires = method.im_func.requires - if callable(requires): - return requires(godel) - else: - if len(requires) > 0: - precondition = getattr(godel, requires) - return precondition() - else: - return True - - def GetAvailableActions(self): - """Returns a list of only those actions that satisfy their preconditions""" - action_list = [] - for godel in self._godels: - for action in godel.GetActions(): - if self.MeetsRequirement(godel, action): - action_list.append([godel, action, godel.GetWeight(action)]) - - return action_list - - def Choose(self, action_list): - """Choosing function which allows to choose a method based on random - but weighted scale. So if one method has twice the weight, it is twice as - likely to be choosen than the other. - - Args: - action_list: A list of Actions from which to choose. - - Returns: - Chosen Action or None. - """ - total = sum([action_info[2] for action_info in action_list]) - # Find a pivot value randomly from he total weight. - index = random.randint(0, total) - for action_info in action_list: - # Decrease the total weight by the current action weight. - total = total - action_info[2] - # If total has fallen below the pivot, then we select the current action - if total <= index: - return action_info; - return None - - def Execute(self, action_info): - """Executes the action and logs to console the action taken. - - Args: - action_info: Action Info for the action to execute. - action_info[0] is the object on which the action is to be invoked. - action_info[1] is the name of the method which is to be invoked. - action_info[2] is the weight of the method. - - """ - action = getattr(action_info[0], action_info[1]) - self._log.info('%s.%s()' % (action_info[0].GetName(), action_info[1])) - action() - - def Explore(self, function=None): - """Sets the exploration in progress by repeatedly seeing if - any actions are available and if so continues to call them. It times out - after specified action limit. - - Args: - function: A function which can be called to determine if the execution - should continue. This function is invoked after each step and - if it returns True, execution stops. This is useful in writing - tests which explore until a particular condition is met. - - Returns: - True, if given |function| returns True, OR if no more action could be - chosen. False, otherwise. - """ - count = 0 - while(True): - if self._actionlimit > 0 and count > self._actionlimit: - return False - action_list = self.GetAvailableActions() - action_info = self.Choose(action_list) - if action_info is None: - return function is None - self.Execute(action_info) - count = count + 1 - if function is not None and function(): - return True
\ No newline at end of file diff --git a/chrome/test/functional/exploratory.py b/chrome/test/functional/exploratory.py deleted file mode 100644 index 2228166..0000000 --- a/chrome/test/functional/exploratory.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2010 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import logging - -import pyauto_functional -from pyauto import PyUITest -from pyauto import GURL - -import autotour - - -class ChromeTest(autotour.Godel, PyUITest): - """Test Example class which explores OpenTab, CloseTab and Navigate - actions and calls them randomly using the Exploratory framework. - Each method defines a weight and a precondition to test - using the GodelAction decorator before it can be called. The exploratory - framework uses these annotation and automatically calls different actions - and drives browser testing. - """ - def __init__(self, methodName='runTest', **kwargs): - PyUITest.__init__(self, methodName=methodName, **kwargs) - self._tab_count = 0 - - def CanOpenTab(self): - """Pre condition for opening a tab.""" - return self._tab_count < 5 - - def CanCloseTab(self): - """Pre condition for closing a tab.""" - return self._tab_count > 1 - - @autotour.GodelAction(10, CanOpenTab) - def OpenTab(self): - """Opens a new tab and goes to Google.com in the first window.""" - logging.info('In Open Tab') - self._tab_count = self._tab_count + 1 - self.AppendTab(GURL('http://www.google.com')) - - @autotour.GodelAction(10, CanCloseTab) - def CloseTab(self): - """Closes the first tab in the first window.""" - logging.info('In Close Tab') - self._tab_count = self._tab_count - 1 - self.GetBrowserWindow(0).GetTab(0).Close(True) - - @autotour.GodelAction(10, CanCloseTab) - def Navigate(self): - """Navigates to yahoo.com in the current window.""" - logging.info("In Navigate") - self.NavigateToURL('http://www.yahoo.com') - - def testExplore(self): - e = autotour.Explorer() - logging.info('Explorer created') - e.Add(self) - logging.info('Object added') - e.Explore() - logging.info('Done') - - -if __name__ == '__main__': - pyauto_functional.Main() - diff --git a/chrome/test/functional/infobars.py b/chrome/test/functional/infobars.py index 5019e75..5019e75 100755..100644 --- a/chrome/test/functional/infobars.py +++ b/chrome/test/functional/infobars.py diff --git a/chrome/test/functional/test_basic.py b/chrome/test/functional/test_basic.py index 1470dd2..789001d 100644 --- a/chrome/test/functional/test_basic.py +++ b/chrome/test/functional/test_basic.py @@ -13,7 +13,7 @@ class SimpleTest(pyauto.PyUITest): def testCanOpenGoogle(self): """Navigate to Google.""" - self.NavigateToURL("http://www.google.com") + self.NavigateToURL('http://www.google.com') def testHTTP(self): """Basic test over local http server.""" diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py index d975258..9b47ff0 100644 --- a/chrome/test/pyautolib/pyauto.py +++ b/chrome/test/pyautolib/pyauto.py @@ -72,16 +72,19 @@ def _LocateBinDirs(): _LocateBinDirs() +_PYAUTO_DOC_URL = 'http://dev.chromium.org/developers/testing/pyauto' + try: import pyautolib # Needed so that all additional classes (like: FilePath, GURL) exposed by # swig interface get available in this module. from pyautolib import * except ImportError: - print >>sys.stderr, "Could not locate built libraries. Did you build?" + print >>sys.stderr, 'Could not locate pyautolib shared libraries. ' \ + 'Did you build?\n Documentation: %s' % _PYAUTO_DOC_URL # Mac requires python2.5 even when not the default 'python' (e.g. 10.6) if 'darwin' == sys.platform and sys.version_info[:2] != (2,5): - print >>sys.stderr, "*\n* Perhaps use 'python2.5', not 'python' ?\n*" + print >>sys.stderr, '*\n* Perhaps use "python2.5", not "python" ?\n*' raise # Should go after sys.path is set appropriately @@ -603,7 +606,8 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase): timeout = self.action_max_timeout_ms() result = self._SendJSONRequest(windex, json.dumps(cmd_dict), timeout) if len(result) == 0: - raise JSONInterfaceError('Automation call received no response.') + raise JSONInterfaceError('Automation call %s received empty response. ' + 'Perhaps the browser crashed.' % cmd_dict) ret_dict = json.loads(result) if ret_dict.has_key('error'): raise JSONInterfaceError(ret_dict['error']) @@ -3725,7 +3729,12 @@ class Main(object): result = PyAutoTextTestRuner(verbosity=verbosity).run(pyauto_suite) del loaded_tests # Need to destroy test cases before the suite del pyauto_suite - sys.exit(not result.wasSuccessful()) + successful = result.wasSuccessful() + if not successful: + pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename) + print >>sys.stderr, 'Tests can be disabled by editing %s. ' \ + 'Ref: %s' % (pyauto_tests_file, _PYAUTO_DOC_URL) + sys.exit(not successful) if __name__ == '__main__': |