summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/test/functional/autotour.py212
-rw-r--r--chrome/test/functional/exploratory.py66
-rw-r--r--[-rwxr-xr-x]chrome/test/functional/infobars.py0
-rw-r--r--chrome/test/functional/test_basic.py2
-rw-r--r--chrome/test/pyautolib/pyauto.py17
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__':