[KSS-checkins] r53362 - in kukit/kss.demo/branch/1.4-kss-test/kss/demo: . browser selenium_utils tests
reebalazs at codespeak.net
reebalazs at codespeak.net
Fri Apr 4 22:43:39 CEST 2008
Author: reebalazs
Date: Fri Apr 4 22:43:37 2008
New Revision: 53362
Added:
kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_layer.py (contents, props changed)
kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_layers.txt (contents, props changed)
kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_suite.py (contents, props changed)
kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/base.py (contents, props changed)
kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/test_doc.py (contents, props changed)
Modified:
kukit/kss.demo/branch/1.4-kss-test/kss/demo/__init__.py
kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/registry.py
kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/setDevMode.html
kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/setProdMode.html
kukit/kss.demo/branch/1.4-kss-test/kss/demo/registry.py
kukit/kss.demo/branch/1.4-kss-test/kss/demo/resource.py
kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_utils/builder.py
kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/test_demoview.py
Log:
Implement selenium layers properly.
Modified: kukit/kss.demo/branch/1.4-kss-test/kss/demo/__init__.py
==============================================================================
--- kukit/kss.demo/branch/1.4-kss-test/kss/demo/__init__.py (original)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/__init__.py Fri Apr 4 22:43:37 2008
@@ -1,4 +1,15 @@
+from resource import (
+ KSSSeleniumTestCase,
+ KSSSeleniumTestDirectory,
+ KSSSeleniumTestCaseList,
+ KSSSeleniumEmptyTestCase,
+ KSSSeleniumSandboxCreationTestCase,
+ KSSDemo,
+ )
+from selenium_layer import KSSSeleniumTestLayerBase
+from selenium_suite import KSSSeleniumTestSuite
+
try:
import Products.Five
except ImportError:
Modified: kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/registry.py
==============================================================================
--- kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/registry.py (original)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/registry.py Fri Apr 4 22:43:37 2008
@@ -5,6 +5,7 @@
from zope.component import getUtility
from zope.interface import implements
from kss.demo.selenium_utils.builder import cookSeleniumTests
+from kss.demo.selenium_layer import LayerTree
import os.path
import re
import urllib
@@ -71,16 +72,15 @@
"""Get selenium tests annotated with title and href."""
registry = getUtility(IKSSDemoRegistry)
results = []
- for suite in registry.test_suites:
- if not suite.application.lower() == application.strip().lower():
- continue
- relative_urls = suite.get_relative_urls(self)
- for relative_url in relative_urls:
- results.append(dict(
- href = relative_url,
- title = self._url_to_title(relative_url),
- ))
- return results
+ # Filter suites that we need.
+ suites = [suite for suite in registry.test_suites
+ if suite.application.lower() == application.strip().lower()]
+ # Build a tree with the suite, to find the optimal setup / teardown sequence.
+ tree = LayerTree(suites)
+ return [dict(
+ href = relative_url,
+ title = self._url_to_title(relative_url),
+ ) for relative_url in tree.get_relative_urls(self)]
@staticmethod
def _url_to_title(url):
Modified: kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/setDevMode.html
==============================================================================
--- kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/setDevMode.html (original)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/setDevMode.html Fri Apr 4 22:43:37 2008
@@ -1,7 +1,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-<title>basic_commands</title>
+<title>Set development mode</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
Modified: kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/setProdMode.html
==============================================================================
--- kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/setProdMode.html (original)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/browser/setProdMode.html Fri Apr 4 22:43:37 2008
@@ -1,7 +1,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-<title>basic_commands</title>
+<title>Set production mode</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
Modified: kukit/kss.demo/branch/1.4-kss-test/kss/demo/registry.py
==============================================================================
--- kukit/kss.demo/branch/1.4-kss-test/kss/demo/registry.py (original)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/registry.py Fri Apr 4 22:43:37 2008
@@ -12,7 +12,7 @@
IKSSDemoRegistryEvent,
IKSSSeleniumTestSuite
)
-from resource import KSSSeleniumTestSuite
+from selenium_suite import KSSSeleniumTestSuite
from zope.component.interfaces import (
IUtilityRegistration,
IRegistered,
Modified: kukit/kss.demo/branch/1.4-kss-test/kss/demo/resource.py
==============================================================================
--- kukit/kss.demo/branch/1.4-kss-test/kss/demo/resource.py (original)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/resource.py Fri Apr 4 22:43:37 2008
@@ -2,7 +2,6 @@
from interfaces import (
IKSSDemo,
IKSSSeleniumTestCaseCollection,
- IKSSSeleniumTestSuite,
)
import itertools
import sys, os.path
@@ -36,18 +35,15 @@
"Abstract base class to help collection implementation"
def find_test_root_dir(self):
- # XXX This must be called directly from the __init__ of the class
- # and it is able to find out the directory where the class
- # was defined from.
#
# Zope CA magic used to find where the class is defined from
frame = sys._getframe(2)
- locals = frame.f_locals
+ f_locals = frame.f_locals
# Try to make sure we were called from a class def
- if (locals is frame.f_globals) or ('__module__' not in locals):
- raise TypeError("classProvides can be used only from a class definition.")
+ if (f_locals is frame.f_globals) or ('__module__' not in f_locals):
+ raise TypeError("The %r suite class can be used only from inside a class definition." % (self.__class__, ))
# store it
- self.test_root_dir = getRootDirOfModule(locals['__module__'])
+ self.test_root_dir = getRootDirOfModule(f_locals['__module__'])
def find_absolute_path(self, filename):
"Returns the absolute path of the filename based on the test root directory."
@@ -70,7 +66,7 @@
test_filename = self.find_absolute_path(self.test_filename)
return [test_filename]
- def get_relative_urls(self, view):
+ def get_relative_urls(self, view, tree=None):
return self.make_relative_urls_from_paths(self.get_testcase_paths())
class KSSSeleniumTestDirectory(KSSSeleniumTestCaseCollectionBase):
@@ -96,7 +92,7 @@
test_filenames = (filename[1] for filename in test_filenames)
return test_filenames
- def get_relative_urls(self, view):
+ def get_relative_urls(self, view, tree=None):
return self.make_relative_urls_from_paths(self.get_testcase_paths())
class KSSSeleniumTestCaseList(KSSSeleniumTestCaseCollectionBase):
@@ -111,8 +107,8 @@
def get_testcase_paths(self):
return itertools.chain(*[case.get_testcase_paths() for case in self.cases])
- def get_relative_urls(self, view):
- return itertools.chain(*[case.get_relative_urls(view) for case in self.cases])
+ def get_relative_urls(self, view, tree=None):
+ return itertools.chain(*(case.get_relative_urls(view, tree) for case in self.cases))
class KSSSeleniumEmptyTestCase(KSSSeleniumTestCaseCollectionBase):
"""An empty test case."""
@@ -121,11 +117,11 @@
def get_testcase_paths(self):
return ()
- def get_relative_urls(self, view):
+ def get_relative_urls(self, view, tree=None):
return ()
-class KSSSandboxCreationTestCase(KSSSeleniumTestCaseCollectionBase):
+class KSSSeleniumSandboxCreationTestCase(KSSSeleniumTestCaseCollectionBase):
"""A method that can be used for sandbox creation.
It is a factory-generated test. It visits a page with a button
@@ -148,93 +144,10 @@
def get_testcase_paths(self):
return ()
- def get_relative_urls(self, view):
+ def get_relative_urls(self, view, tree=None):
relative_url = "@@kss-selenium-create-sandbox-test.html?method_name=%s&admin_username=%s&admin_password=%s" % (
self.method_name,
view.request.get('admin_username', ''),
view.request.get('admin_password', ''))
return (relative_url, )
-# --
-# The Suite itself is a collection, but provides a way to use layers with setup and
-# tesrdown from the registry.
-# --
-
-class KSSSeleniumTestLayerBase(object):
- setup = KSSSeleniumEmptyTestCase()
- teardown = KSSSeleniumEmptyTestCase()
-
-
-# XXX TODO Currently the tuest suite handles the setup and teardown
-# of the layer. The suites with the same layer should have a common
-# setup. Very easy to implement.
-class KSSSeleniumTestSuite(KSSSeleniumTestCaseCollectionBase):
- """Represents a selenium suite,
- that makes part of an applicaion and a component,
- as well as an optional (test) layer.
- """
- implements(IKSSSeleniumTestSuite)
-
- # convenience access for page templates
- __allow_access_to_unprotected_subobjects__ = 1
-
- tests = KSSSeleniumEmptyTestCase()
- component = u''
- application = u''
- # default is an empty layer.
- layer = KSSSeleniumTestLayerBase
- dual_mode = True
-
- # resources we use for dual mode
- set_devel_mode = KSSSeleniumTestCase('browser/setDevMode.html')
- set_prod_mode = KSSSeleniumTestCase('browser/setProdMode.html')
-
- def __init__(self, tests=None, component=u'', application=u'', layer=None, dual_mode=None):
- if tests is not None:
- self.tests = tests
- self.test_root_dir = self.tests.test_root_dir
- if component:
- self.component = component
- if application:
- self.application = application
- if layer is not None:
- self.layer = layer
- if dual_mode is not None:
- self.dual_mode = dual_mode
-
- def get_testcase_paths(self):
- return itertools.chain(
- * (case.get_testcase_paths() for case in self.iterables)
- )
-
- def get_relative_urls(self, view):
- return itertools.chain(
- * (case.get_relative_urls(view) for case in self.iterables)
- )
-
- @property
- def iterables(self):
- # Check if we have tests at all. If no, we don't need the
- # setup/teardown.
- #
- # The next expression decided if the iterator yields any resuls
- # TODO make an empty() on the interface ?
- if tuple(itertools.islice(self.tests.get_relative_urls(self), 0, 1)):
- if self.dual_mode:
- return (
- self.layer.setup,
- self.set_devel_mode,
- self.tests,
- self.set_prod_mode,
- self.tests,
- self.layer.teardown,
- )
- else:
- return (
- self.layer.setup,
- self.tests,
- self.layer.teardown,
- )
- else:
- # No tests, nothing to do.
- return ()
Added: kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_layer.py
==============================================================================
--- (empty file)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_layer.py Fri Apr 4 22:43:37 2008
@@ -0,0 +1,202 @@
+"""\
+Layers for Selenium tests
+
+The goal of this structures to allow to generate the setup / teardown
+sequence in an optimal way. Since we have to group tests to be
+executed in the same layer, and trim away layers with no tests,
+this must be done for each list of selected testcases.
+"""
+
+import itertools
+from resource import KSSSeleniumEmptyTestCase, KSSSeleniumTestCase
+
+class metalayer(type):
+ def __init__(cls, name, bases, attrs):
+ # If setup or teardown are not declared, we consider
+ # them as empty.
+ if 'setup' not in attrs:
+ attrs['setup'] = KSSSeleniumEmptyTestCase()
+ if 'teardown' not in attrs:
+ attrs['teardown'] = KSSSeleniumEmptyTestCase()
+ # Set up the class
+ super(metalayer, cls).__init__(name, bases, attrs)
+
+class KSSSeleniumTestLayerBase(object):
+ __metaclass__ = metalayer
+ setup = KSSSeleniumEmptyTestCase()
+ teardown = KSSSeleniumEmptyTestCase()
+
+class LayerTreeNode(object):
+ """An active tree node
+
+ It participates in a Tree, it contains a list of suites.
+ If the list of suites is empty, that means this layer
+ is "inactive" in the tree: it is needed for the setup / teardown
+ sequence, but contains no tests itself.
+ """
+
+ # resources we use for dual mode
+ set_devel_mode = KSSSeleniumTestCase('browser/setDevMode.html')
+ set_prod_mode = KSSSeleniumTestCase('browser/setProdMode.html')
+
+ def __init__(self, tree, layer):
+ self.tree = tree
+ self.suites = []
+ self.layer = layer
+ self.base_layer = None
+ self.child_nodes = []
+
+ def add_suite(self, suite):
+ assert suite.layer == self.layer, "Suite must have the same layer."
+ self.suites.append(suite)
+
+ def add_parents(self):
+ layer = self.layer
+ # A layer must be a subclass of the base class.
+ assert issubclass(layer, KSSSeleniumTestLayerBase), \
+ "Layers must be classes inheriting from KSSSeleniumTestLayerBase."
+ # Find out the bases. We only consider bases
+ # that inherit from the base class.
+ try:
+ bases = layer.__bases__
+ except AttributeError:
+ raise Exception, "Layers must be classes."
+ bases = (base for base in bases if issubclass(base, KSSSeleniumTestLayerBase))
+ # We are only interested in the first base.
+ # (In case of multi inheritence we could have more bases,
+ # and although this is hardly imaginable as use case, it is supported anyway.)
+ bases = tuple(itertools.islice(bases, 0, 1))
+ # There must be one base,
+ # unless we are at the root node.
+ if not bases:
+ # We found the root.
+ assert layer == KSSSeleniumTestLayerBase, "This should not happen."
+ self.tree.root = self
+ else:
+ if len(bases) > 1:
+ raise Exception, "Double inheritence of layers is not supported."
+ base_layer = bases[0]
+ # Add this layer to the tree as well, and remember it.
+ base_node = self.tree.add_layer(base_layer)
+ # Mark ourselves as a child node.
+ self.base_node = base_node
+ base_node.child_nodes.append(self)
+
+ def get_testcase_paths_for_layer(self):
+ """Give the absolute paths "owned" for the layer itself."""
+ # order does not matter here.
+ # Just needed to enable these resources.
+ # Also: enable the set devel / prod resources always.
+ if self.base_layer is not None:
+ base_layer_tests = self.tree.lookup_layer(self.base_layer).get_testcase_paths_for_layer(),
+ else:
+ # We are at the root.
+ base_layer_tests = ()
+ # Compose all paths
+ return itertools.chain(
+ base_layer_tests,
+ self.layer.setup.get_testcase_paths(),
+ self.layer.teardown.get_testcase_paths(),
+ self.set_devel_mode.get_testcase_paths(),
+ self.set_prod_mode.get_testcase_paths(),
+ )
+
+ def get_relative_urls_for_own_tests(self, view):
+ """Generate the tests in all suites in this layer subtree. No setup or teardown.
+
+ This is needed to decide if we can prune a part of the tree (if there are no tests,
+ setup and teardown are not needed either.)
+ """
+ return itertools.chain(
+ # Our own tests
+ itertools.chain(*(suite.tests.get_relative_urls(view, self.tree) for suite in self.suites)),
+ # Tests from the child layers
+ itertools.chain(*(node.get_relative_urls_for_own_tests(view) for node in self.child_nodes)),
+ )
+
+ def get_relative_urls(self, view):
+ """Generate the walking order for the node and its subtree."""
+ # Look ahead check if we have any tests at all.
+ suite_tests_lookahead = self.get_relative_urls_for_own_tests(view)
+ # Do we have tests at all?
+ # If not, we just don't want to emit setup and teardown at all.
+ if tuple(itertools.islice(suite_tests_lookahead, 0, 1)):
+ # Does any of our suites have dual mode?
+ suites_by_duality = {True: [], False: []}
+ for suite in self.suites:
+ suites_by_duality[suite.dual_mode].append(suite)
+ # Create the tests for suites.
+ # Look ahead check if we have any dual tests at all.
+ dual_tests_lookahead = itertools.chain(*(suite.tests.get_relative_urls(view, self.tree) for suite in suites_by_duality[True]))
+ if tuple(itertools.islice(dual_tests_lookahead, 0, 1)):
+ # We do have some dual tests. So we need to run them twice and set
+ # development and production modes for this.
+ dual_tests = itertools.chain(
+ # Dual mode tests from the suites in this layer, in Development mode
+ self.set_devel_mode.get_relative_urls(view, self.tree),
+ itertools.chain(*(suite.tests.get_relative_urls(view, self.tree) for suite in suites_by_duality[True])),
+ # Dual mode tests from the suites in this layer, in Production mode
+ self.set_prod_mode.get_relative_urls(view, self.tree),
+ itertools.chain(*(suite.tests.get_relative_urls(view, self.tree) for suite in suites_by_duality[True])),
+ )
+ else:
+ # No dual mode tests
+ dual_tests = ()
+ # Now put them together with setup and teardown
+ return itertools.chain(
+ # Setup from parent layer
+ self.layer.setup.get_relative_urls(view, self.tree),
+ # Dual mode tests from the suites in this layer
+ dual_tests,
+ # Single mode tests from the suites in this layer
+ itertools.chain(*(suite.tests.get_relative_urls(view, self.tree) for suite in suites_by_duality[False])),
+ # Add tests recursively from contained layers
+ itertools.chain(*(node.get_relative_urls(view) for node in self.child_nodes)),
+ # Teardown to parent layer
+ self.layer.teardown.get_relative_urls(view, self.tree),
+ )
+ else:
+ # No tests at all.
+ return ()
+
+class LayerTree(object):
+ """Builds an inheritence tree from the suites passed in.
+ """
+ def __init__(self, suites=()):
+ self.suites = []
+ self.nodes = {}
+ self.root = None
+ self.add_suites(suites)
+
+ def add_suites(self, suites):
+ for suite in suites:
+ self.add_suite(suite)
+
+ def add_suite(self, suite):
+ # make sure we have the layer
+ node = self.add_layer(suite.layer)
+ # Add the suite to the node.
+ node.add_suite(suite)
+
+ def add_layer(self, layer):
+ # We must fetch the layer node from the tree,
+ # or create it and its inheritence path to the root layer.
+ try:
+ node = self.nodes[layer]
+ except KeyError:
+ # create and remember the tree node
+ node = self.nodes[layer] = LayerTreeNode(self, layer)
+ # Recursively process parents of the node
+ node.add_parents()
+ # caller may access the node
+ return node
+
+ def lookup_layer(self, layer):
+ return self.nodes[layer]
+
+ def get_relative_urls(self, view):
+ """Generate all tests in the tree."""
+ if not self.root:
+ # no root, no tests.
+ return ()
+ return self.root.get_relative_urls(view)
Added: kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_layers.txt
==============================================================================
--- (empty file)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_layers.txt Fri Apr 4 22:43:37 2008
@@ -0,0 +1,282 @@
+====================
+Selenium test layers
+====================
+
+We can make our own layer by inheritance from the base class.
+
+ >>> from kss.demo import KSSSeleniumTestLayerBase
+
+Create the class:
+
+ >>> class aLayer(KSSSeleniumTestLayerBase):
+ ... pass
+
+Since we did not overwrite setup and teardown, they must be emtpy.
+
+ >>> aLayer.setup
+ <kss.demo.resource.KSSSeleniumEmptyTestCase object at ...>
+ >>> aLayer.teardown
+ <kss.demo.resource.KSSSeleniumEmptyTestCase object at ...>
+
+
+Specifying setup and teardown for a layer
+-----------------------------------------
+
+A more sensible use case is to create some setup and teardown for
+ourselves. We will create test cases that refer to non-existent
+files, now.
+
+ >>> from kss.demo import KSSSeleniumTestCase
+
+ >>> class aLayer(KSSSeleniumTestLayerBase):
+ ... setup = KSSSeleniumTestCase('1')
+ ... teardown = KSSSeleniumTestCase('2')
+
+ >>> aLayer.setup
+ <kss.demo.resource.KSSSeleniumTestCase object at ...>
+ >>> aLayer.teardown
+ <kss.demo.resource.KSSSeleniumTestCase object at ...>
+
+We also check the actual urls that will result the testing
+sequence. Note that get_relative_urls would take the view
+in normal use, but it is not important for this test.
+
+ >>> tuple(aLayer.setup.get_relative_urls(None))
+ ('@@resource?path=1',)
+ >>> tuple(aLayer.teardown.get_relative_urls(None))
+ ('@@resource?path=2',)
+
+If I inherit from this layer, and I do not overwrite setup
+or teardown, it still gets an empty value.
+
+ >>> class zLayer(KSSSeleniumTestLayerBase):
+ ... setup = KSSSeleniumTestCase('3')
+
+ >>> zLayer.setup
+ <kss.demo.resource.KSSSeleniumTestCase object at ...>
+ >>> tuple(zLayer.setup.get_relative_urls(None))
+ ('@@resource?path=3',)
+
+ >>> zLayer.teardown
+ <kss.demo.resource.KSSSeleniumEmptyTestCase object at ...>
+
+
+Inheriting layers
+-----------------
+
+Now, let us inherit a layer from another layer.
+
+ >>> class bLayer(aLayer):
+ ... setup = KSSSeleniumTestCase('5')
+ ... teardown = KSSSeleniumTestCase('6')
+
+And another one.
+
+ >>> class cLayer(aLayer):
+ ... setup = KSSSeleniumTestCase('7')
+ ... teardown = KSSSeleniumTestCase('8')
+
+Even we inherit more.
+
+ >>> class dLayer(cLayer):
+ ... setup = KSSSeleniumTestCase('9')
+ ... teardown = KSSSeleniumTestCase('10')
+
+ >>> class eLayer(cLayer):
+ ... setup = KSSSeleniumTestCase('11')
+ ... teardown = KSSSeleniumTestCase('12')
+
+
+This results in the following inheritence structure::
+
+ a
+ |
+ ------
+ | |
+ b c
+ |
+ ------
+ | |
+ d e
+
+
+Using layers from suites
+========================
+
+We define suites that use the above layers.
+
+ >>> from kss.demo import KSSSeleniumTestSuite
+
+The following definition to define a suite would fail:
+
+ >>> aSuite = KSSSeleniumTestSuite(
+ ... tests = KSSSeleniumTestCase('ta'),
+ ... layer = aLayer,
+ ... )
+ Traceback (most recent call last):
+ ...
+ TypeError: The <class 'kss.demo.resource.KSSSeleniumTestCase'> suite class can be used only from inside a class definition.
+
+As the error message says, we must define the class from inside another
+class. This is used to locate files relatively from the module where the
+definition is. So we have to define them from a dummy plugin (however the plugin
+itself play no role in testing).
+
+ >>> class DummyPlugin(object):
+ ...
+ ... aSuite = KSSSeleniumTestSuite(
+ ... tests = KSSSeleniumTestCase('ta'),
+ ... layer = aLayer,
+ ... )
+ >>> aSuite = DummyPlugin.aSuite
+
+The layers whose tests are active, will build a tree to compute the
+optimal setup-teardown order.
+
+ >>> from kss.demo.selenium_layer import LayerTree
+
+ >>> tree = LayerTree((aSuite, ))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=...setDevMode.html', '@@resource?path=ta', '@@resource?path=...setProdMode.html', '@@resource?path=ta', '@@resource?path=2')
+
+As we can see in the above results, the tests are generated properly with setup and teardown.
+
+If more cases use the same layer, they are grouped. They also just need to change
+the production mode twice:
+
+ >>> class DummyPlugin2(object):
+ ...
+ ... a2Suite = KSSSeleniumTestSuite(
+ ... tests = KSSSeleniumTestCase('ta2'),
+ ... layer = aLayer,
+ ... )
+ >>> a2Suite = DummyPlugin2.a2Suite
+
+ >>> tree = LayerTree((aSuite, a2Suite))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=...setDevMode.html', '@@resource?path=ta', '@@resource?path=ta2', '@@resource?path=...setProdMode.html', '@@resource?path=ta', '@@resource?path=ta2', '@@resource?path=2')
+
+Now, let's see the tests for the other suites:
+
+ >>> class DummyPlugin3(object):
+ ...
+ ... bSuite = KSSSeleniumTestSuite(
+ ... tests = KSSSeleniumTestCase('tb'),
+ ... layer = bLayer,
+ ... )
+ ...
+ ... cSuite = KSSSeleniumTestSuite(
+ ... tests = KSSSeleniumTestCase('tc'),
+ ... layer = cLayer,
+ ... )
+ ...
+ ... dSuite = KSSSeleniumTestSuite(
+ ... tests = KSSSeleniumTestCase('td'),
+ ... layer = dLayer,
+ ... )
+ ...
+ ... d2Suite = KSSSeleniumTestSuite(
+ ... tests = KSSSeleniumTestCase('td2'),
+ ... layer = dLayer,
+ ... )
+ ... eSuite = KSSSeleniumTestSuite(
+ ... tests = KSSSeleniumTestCase('te'),
+ ... layer = eLayer,
+ ... )
+ ...
+ >>> bSuite = DummyPlugin3.bSuite
+ >>> cSuite = DummyPlugin3.cSuite
+ >>> dSuite = DummyPlugin3.dSuite
+ >>> d2Suite = DummyPlugin3.d2Suite
+ >>> eSuite = DummyPlugin3.eSuite
+
+And see what happens if only suite "d" is selected. We can see that the setup and teardown sequence is correct.
+
+ >>> tree = LayerTree((dSuite, ))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=7', '@@resource?path=9', '@@resource?path=...setDevMode.html', '@@resource?path=td', '@@resource?path=...setProdMode.html', '@@resource?path=td', '@@resource?path=10', '@@resource?path=8', '@@resource?path=2')
+
+
+Replay this with a bunch of other tests added. Setup and teardown is executed ideally.
+In this case we have more dev / prod mode changes, since these are the fastest
+they are wrapped inside the layer.
+
+ >>> tree = LayerTree((cSuite, dSuite, d2Suite))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=7', '@@resource?path=...setDevMode.html', '@@resource?path=tc', '@@resource?path=...setProdMode.html', '@@resource?path=tc', '@@resource?path=9', '@@resource?path=...setDevMode.html', '@@resource?path=td', '@@resource?path=td2', '@@resource?path=...setProdMode.html', '@@resource?path=td', '@@resource?path=td2', '@@resource?path=10', '@@resource?path=8', '@@resource?path=2')
+
+So far we have only tried single path setups. Let's now try a split route.
+The setup and teardown work correctly in one level.
+
+ >>> tree = LayerTree((aSuite, bSuite, cSuite))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=...setDevMode.html', '@@resource?path=ta', '@@resource?path=...setProdMode.html', '@@resource?path=ta', '@@resource?path=5', '@@resource?path=...setDevMode.html', '@@resource?path=tb', '@@resource?path=...setProdMode.html', '@@resource?path=tb', '@@resource?path=6', '@@resource?path=7', '@@resource?path=...setDevMode.html', '@@resource?path=tc', '@@resource?path=...setProdMode.html', '@@resource?path=tc', '@@resource?path=8', '@@resource?path=2')
+
+
+Another functionality is that certain tests may mark that they don't want
+to be in dual mode:
+
+ >>> class DummyPlugin4(object):
+ ...
+ ... b2Suite = KSSSeleniumTestSuite(
+ ... tests = KSSSeleniumTestCase('tb2'),
+ ... layer = bLayer,
+ ... dual_mode = False,
+ ... )
+ >>> b2Suite = DummyPlugin4.b2Suite
+
+ >>> tree = LayerTree((b2Suite, ))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=5', '@@resource?path=tb2', '@@resource?path=6', '@@resource?path=2')
+
+This is also true if both dual and single mode tests are in the same layer. In this case
+the tests will wun in the end, which in practice means Production mode.
+
+ >>> tree = LayerTree((bSuite, b2Suite))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=5', '@@resource?path=...setDevMode.html', '@@resource?path=tb', '@@resource?path=...setProdMode.html', '@@resource?path=tb', '@@resource?path=tb2', '@@resource?path=6', '@@resource?path=2')
+
+Now let's add a bunch of suites:
+
+ >>> tree = LayerTree((aSuite, a2Suite, bSuite, b2Suite, cSuite, dSuite, d2Suite, eSuite))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=...setDevMode.html', '@@resource?path=ta', '@@resource?path=ta2', '@@resource?path=...setProdMode.html', '@@resource?path=ta', '@@resource?path=ta2', '@@resource?path=5', '@@resource?path=...setDevMode.html', '@@resource?path=tb', '@@resource?path=...setProdMode.html', '@@resource?path=tb', '@@resource?path=tb2', '@@resource?path=6', '@@resource?path=7', '@@resource?path=...setDevMode.html', '@@resource?path=tc', '@@resource?path=...setProdMode.html', '@@resource?path=tc', '@@resource?path=9', '@@resource?path=...setDevMode.html', '@@resource?path=td', '@@resource?path=td2', '@@resource?path=...setProdMode.html', '@@resource?path=td', '@@resource?path=td2', '@@resource?path=10', '@@resource?path=11', '@@resource?path=...setDevMode.html', '@@resource?path=te', '@@resource?path=...setProdMode.html', '@@resource?path=te', '@@resource?path=12', '@@resource?path=8', '@@resource?path=2')
+
+
+Finally, we still need to check the following:
+Suites that are empty are skipped, and no setup teardown or devel / prod mode is generated for them.
+
+ >>> class DummyPlugin5(object):
+ ...
+ ... a3Suite = KSSSeleniumTestSuite(
+ ...
+ ... )
+ ...
+ ... b3Suite = KSSSeleniumTestSuite(
+ ... )
+ >>> a3Suite = DummyPlugin5.a3Suite
+ >>> b3Suite = DummyPlugin5.b3Suite
+
+ >>> tree = LayerTree((a3Suite, ))
+ >>> tuple(tree.get_relative_urls(None))
+ ()
+
+ >>> tree = LayerTree((a3Suite, aSuite))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=...setDevMode.html', '@@resource?path=ta', '@@resource?path=...setProdMode.html', '@@resource?path=ta', '@@resource?path=2')
+
+ >>> tree = LayerTree((a3Suite, b3Suite))
+ >>> tuple(tree.get_relative_urls(None))
+ ()
+
+ >>> tree = LayerTree((a3Suite, b3Suite, bSuite))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=5', '@@resource?path=...setDevMode.html', '@@resource?path=tb', '@@resource?path=...setProdMode.html', '@@resource?path=tb', '@@resource?path=6', '@@resource?path=2')
+
+ >>> tree = LayerTree((aSuite, a3Suite, b3Suite, bSuite))
+ >>> tuple(tree.get_relative_urls(None))
+ ('@@resource?path=1', '@@resource?path=...setDevMode.html', '@@resource?path=ta', '@@resource?path=...setProdMode.html', '@@resource?path=ta', '@@resource?path=5', '@@resource?path=...setDevMode.html', '@@resource?path=tb', '@@resource?path=...setProdMode.html', '@@resource?path=tb', '@@resource?path=6', '@@resource?path=2')
+
+
+And this concludes the layer tests.
+
Added: kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_suite.py
==============================================================================
--- (empty file)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_suite.py Fri Apr 4 22:43:37 2008
@@ -0,0 +1,65 @@
+
+import itertools
+from resource import (
+ KSSSeleniumTestCaseCollectionBase,
+ KSSSeleniumEmptyTestCase,
+ )
+from interfaces import IKSSSeleniumTestSuite
+from selenium_layer import LayerTree, KSSSeleniumTestLayerBase
+from zope.interface import implements
+
+# --
+# The Suite itself is a collection, but provides a way to use layers with setup and
+# tesrdown from the registry.
+# --
+
+class KSSSeleniumTestSuite(KSSSeleniumTestCaseCollectionBase):
+ """Represents a selenium suite,
+ that makes part of an applicaion and a component,
+ as well as an optional (test) layer.
+ """
+ implements(IKSSSeleniumTestSuite)
+
+ # convenience access for page templates
+ __allow_access_to_unprotected_subobjects__ = 1
+
+ tests = KSSSeleniumEmptyTestCase()
+ component = u''
+ application = u''
+ # default is an empty layer.
+ layer = KSSSeleniumTestLayerBase
+ dual_mode = True
+
+ def __init__(self, tests=None, component=u'', application=u'', layer=None, dual_mode=None):
+ if tests is not None:
+ self.tests = tests
+ if component:
+ self.component = component
+ if application:
+ self.application = application
+ if layer is not None:
+ self.layer = layer
+ if dual_mode is not None:
+ self.dual_mode = dual_mode
+
+ def get_testcase_paths(self, tree=None):
+ # No need to care for order. We only need to give
+ # access to resources that we "own":
+ # from our setup, own tests, and
+ # teardown.
+ #
+ if not tree:
+ # Just handle this suite individually.
+ tree = LayerTree()
+ tree.add_suites((self, ))
+ return itertools.chain(
+ self.tests.get_testcase_paths(),
+ tree.lookup_layer(self.layer).get_testcase_paths_for_layer()
+ )
+
+ def get_relative_urls(self, view, tree=None):
+ # Just handle this suite individually,
+ # even if we had a tree passed in.
+ tree = LayerTree()
+ tree.add_suites((self, ))
+ return tree.get_relative_urls(view)
Modified: kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_utils/builder.py
==============================================================================
--- kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_utils/builder.py (original)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/selenium_utils/builder.py Fri Apr 4 22:43:37 2008
@@ -8,7 +8,12 @@
# root directory finding code
def getRootDirOfModule(module_name):
- return os.path.dirname(sys.modules[module_name].__file__)
+ if module_name == '__builtin__':
+ # This may happen in tests and interactively,
+ # and it's sensible to use an absolute path in this case.
+ return ''
+ else:
+ return os.path.dirname(sys.modules[module_name].__file__)
def getRootDirOfClass(cls):
return getRootDirOfModule(cls.__module__)
Added: kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/base.py
==============================================================================
--- (empty file)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/base.py Fri Apr 4 22:43:37 2008
@@ -0,0 +1,13 @@
+
+from Products.Five.zcml import load_config
+from kss.core.tests.base import KSSViewTestCase
+import kss.demo
+
+class KSSDemoTestLayer(KSSViewTestCase.layer):
+ @classmethod
+ def setUp(cls):
+ load_config('meta.zcml', package=kss.demo)
+ load_config('configure.zcml', package=kss.demo)
+
+class KSSDemoTestCaseBase(KSSViewTestCase):
+ layer = KSSDemoTestLayer
Modified: kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/test_demoview.py
==============================================================================
--- kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/test_demoview.py (original)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/test_demoview.py Fri Apr 4 22:43:37 2008
@@ -17,30 +17,22 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
#
-import unittest, os
-from zope.testing import doctest
-from Testing.ZopeTestCase import ZopeTestCase
-from kss.core.tests.base import KSSViewTestCase
-from Products.Five.zcml import load_string, load_config
-import kss.demo
+import unittest
+from base import KSSDemoTestCaseBase
try:
import Products.Five
+ Products = Products # to satisfy pyflakes
except AttributeError:
from kss.demo.simplecontent_z3 import SimpleContent
+ SimpleContent = SimpleContent # to satisfy pyflakes
else:
from kss.demo.simplecontent import SimpleContent
-class KSSDemoTestCase(KSSViewTestCase):
-
- class layer(KSSViewTestCase.layer):
- @classmethod
- def setUp(cls):
- load_config('meta.zcml', package=kss.demo)
- load_config('configure.zcml', package=kss.demo)
+class KSSDemoTestCase(KSSDemoTestCaseBase):
def afterSetUp(self):
- KSSViewTestCase.afterSetUp(self)
+ KSSDemoTestCaseBase.afterSetUp(self)
self.setDebugRequest()
self.folder._setObject('demo', SimpleContent('Demo', 'Demo'))
self.view = self.folder.demo.restrictedTraverse('getDivContent')
Added: kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/test_doc.py
==============================================================================
--- (empty file)
+++ kukit/kss.demo/branch/1.4-kss-test/kss/demo/tests/test_doc.py Fri Apr 4 22:43:37 2008
@@ -0,0 +1,28 @@
+# Copyright (c) 2008
+# Authors:
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+import unittest
+import doctest
+from zope.testing.doctestunit import DocFileSuite
+
+def test_suite():
+ return unittest.TestSuite((
+ DocFileSuite('selenium_layers.txt',
+ package = 'kss.demo',
+ optionflags = doctest.ELLIPSIS,
+ ),
+ ))
More information about the Kukit-checkins
mailing list