Commit 3cee19a4 authored by Hanno Schlichting's avatar Hanno Schlichting

Removed more HelpSys references.

parent 13f7f34f
......@@ -11,6 +11,8 @@ https://zope.readthedocs.io/en/2.13/CHANGES.html
Bugs Fixed
++++++++++
- Remove more HelpSys references.
Features Added
++++++++++++++
......
......@@ -315,7 +315,7 @@ class ZopeIterator(Iterator):
return super(ZopeIterator, self).item()
# 'first' and 'last' are Zope 2 enhancements to the TALES iterator
# spec. See help/tal-repeat.stx for more info
# spec.
def first(self, name=None):
if self.start:
return True
......
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Session Data Manager',
help_product='Sessions',
help_topic='session-add.stx'
form_title='Add Session Data Manager'
)">
<FORM ACTION="constructSessionDataManager" METHOD="POST">
......
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Browser Id Manager',
help_product='Sessions',
help_topic='browser-add.stx'
form_title='Add Browser Id Manager'
)">
<FORM ACTION="constructBrowserIdManager" METHOD="POST">
......
<dtml-var manage_page_header>
<dtml-var "manage_tabs(this(), _,
form_title='Manage Session Data Manager',
help_product='Sessions',
help_topic='session-change.stx'
form_title='Manage Session Data Manager'
)">
......
<dtml-var manage_page_header>
<dtml-var "manage_tabs(this(), _,
form_title='Manage Browser Id Manager',
help_product='Sessions',
help_topic='browser-change.stx'
form_title='Manage Browser Id Manager'
)">
<FORM ACTION="manage_changeBrowserIdManager" METHOD="POST">
......
......@@ -14,7 +14,7 @@
o See Also
- "Transient Object API":../../Transience/Help/TransienceInterfaces.py
- "Transient Object API":../../Transience/TransienceInterfaces.py
"""
from zope.interface import Interface
......
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Temporary Folder',
help_product='TemporaryFolder',
help_topic='TemporaryFolder.stx'
form_title='Add Temporary Folder'
)">
<form action="constructTemporaryFolder" method="POST">
......
How Transience Works
The object responsible for managing the expiration of "transient"
objects is the TransientObjectContainer, the class definition for
which is located in
Products.Transience.Transience.TransientObjectContainer. An
instance of this class is found in the default Zope installation at
/temp_folder/session_data.
The TransientObjectContainer (TOC) holds Transient Objects (TOs).
A TO is obtained via its container via a call to
TOC.new_or_existing(key), where "key" is usually the "browser id"
associated with a visitor (See Products.Session.BrowserIdManager).
If the TOC has a "current" TO corresponding to "key", it is
returned.
If the TOC does not have a "current" TO corresponding to "key", (due
to the expiration of the TO or because it never existed in the first
place) a "new" TO is manufactured and returned.
Timeslices
Transience defines the notion of a "timeslice". A "timeslice" is an
integer that represents some "slice" of time, defined by a "period".
For example, if a period is 20 seconds long, three ordered time
slices might be expressed as 0, 20, and 40. The next timeslice
would be 60, and so on. For an absolute time to "belong" to a
timeslice, it would need to be equal to or greater than one
timeslice integer, but less than the subsequent timeslice integer.
Data Structures Maintained by a Transient Object Container
The TOC maintains three important kinds of data structures:
- a "_data" structure, which is an IOBTree mapping a "timeslice"
integer to a "bucket" (see next bullet for definition of bucket).
- One or more "buckets", which are OOBTree objects which map a "key"
(usually browser id) to a TransientObject. Buckets are stored
inside of the "_data" structure. There is a concept of a
"current" bucket, which is the bucket that is contained within the
_data structured with a key equal to the "current" timeslice.
A current bucket must always exist (this is an invariant).
- A "max_timeslice" integer, which is equal to the "largest"
timeslice for which there exists a bucket in the _data structure.
This is an optimization given that key operations against BTrees
can be slow and could cause conflicts (the same could be achieved
via _data.maxKey() otherwise).
When a Transient Object is created via new_or_existing, it is added
to the "current" bucket. As time goes by, the bucket to which the
TO was added ceases to be the "current" bucket. If the transient
object is "accessed" (it is called up out of the TOC via the TOC's
'get' method), it is again moved to the "current" bucket defined by
the current time's timeslice.
During the course of normal operations, a TransientObject will move
from an "old" bucket to the "current" bucket many times, as long as
it continues to be accessed. It is possible for a TransientObject
to never expire, as long as it is called up out of its TOC often
enough.
If a TransientObject is not accessed in the period of time defined by
the TOC's "timeout", it is eventually garbage collected.
How the TransientObjectContainer Determines if a TransientObject is "Current"
All "current" timeslice buckets (as specified by the timeout) are
searched for the transient object, most recent bucket first.
Housekeeping: Finalization, Garbage Collection, and Bucket
Replentishing
The TOC performs "finalization", "garbage collection", and "bucket
replentishing". It typically performs these tasks "in-band"
(although it is possible to do the housekeeping tasks "out of band"
as well: see the methods of the Transient Object Container with
"housekeep" in their names). "In band" housekeeping implies that
the TOC does not maintain a separate thread or process that wakes up
every so often to clean up. Instead, during the course of normal
operations, the TOC opportunistically performs housekeeping functions.
Finalization is defined as optionally calling a function at bucket
expiration time against all transient objects contained within that
bucket. The optional function call is user-defined, but it is
managed by the "notifyDel" method of the TOC.
Garbage collection is defined as deleting "expired" buckets in the
_data structure (the _data structure maps a timeslice to a bucket).
Typically this is done by throwing away one or more buckets in the
_data structure after they expire.
Bucket replentishing is defined as the action of (opportunistically)
creating more buckets to insert into the the _data structure,
replacing ones that are deleted during garbage collection. The act
of deleting a bucket does not necessarily imply that a new bucket
will be immediately created thereafter. We create new buckets in
batches to reduce the possibility of conflicts.
Finalization is attempted on every call to the transience machinery
to make TOs appear to expire "on time". Garbage collection and
replentishment is performed on a somewhat random basis to avoid
unnecessary conflicts.
Goals
- A low number of ZODB conflict errors (which reduce performance).
- Stability.
To Do
- Testing under ZEO.
......@@ -104,15 +104,10 @@ class TransientObjectContainer(SimpleItem):
implements(ItemWithId,
StringKeyedHomogeneousItemContainer,
TransientItemContainer,
)
)
manage_options = (
{ 'label': 'Manage',
'action': 'manage_container',
'help': ('Transience', 'Transience.stx')
},
{ 'label': 'Security',
'action': 'manage_access'
},
{'label': 'Manage', 'action': 'manage_container'},
{'label': 'Security', 'action': 'manage_access'},
)
security = ClassSecurityInfo()
......
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Transient Object Container',
help_product='Transience',
help_topic='Transience-add.stx'
form_title='Add Transient Object Container'
)">
<FORM ACTION="constructTransientObjectContainer" METHOD="POST">
......
<dtml-var manage_page_header>
<dtml-var "manage_tabs(this(), _,
form_title='Change Transient Object Container',
help_product='Transience',
help_topic='Transience-change.stx'
form_title='Change Transient Object Container'
)">
<form action="manage_changeTransientObjectContainer" method="post">
......
<style type="text/css"> <!-- li { margin: 1em } --> </style>
ZopeTestCase API Reference
A nicely rendered version of this document can be found at
http://zope.org/Members/shh/ZopeTestCaseWiki/ApiReference
Module Testing.ZopeTestCase
Top-level package exposing names from contained modules
Constants
folder_name
user_name
user_password
user_role
standard_permissions
portal_name
Functions
hasProduct(name)
installProduct(name, quiet=0)
app()
close(app)
main()
_print(msg)
ZopeDocTestSuite(module=None, **kw)
ZopeDocFileSuite(*paths, **kw)
FunctionalDocTestSuite(module=None, **kw)
FunctionalDocFileSuite(*paths, **kw)
Classes
TestCase
ZopeTestCase
FunctionalTestCase
PortalTestCase
Sandboxed
Functional
WarningsHook
Modules
ZopeLite as Zope
utils
doctest
transaction
Module ZopeLite
Lightweight replacement for the Zope module
Constants
DB
Functions
hasProduct(name)
installProduct(name, quiet=0)
app(connection=None)
sandbox(base=None)
startup()
_print(msg)
Module base
Basic infrastructure for Zope testing
Functions
app()
close(app)
Classes
TestCase
Class TestCase
Base test case for Zope testing
(derived from unittest.TestCase)
Interfaces
implements(IZopeTestCase)
Methods
afterSetUp()
beforeTearDown()
afterClear()
beforeSetUp()
beforeClose()
Module ZopeTestCase
Test case and fixture for Zope testing
Constants
folder_name
user_name
user_password
user_role
standard_permissions
Classes
ZopeTestCase
FunctionalTestCase
Class ZopeTestCase
Base test case for Zope testing
(derived from base.TestCase)
Interfaces
implements(IZopeSecurity)
Methods
setRoles(roles, name=user_name)
setPermissions(permissions, role=user_role)
login(name=user_name)
logout()
Class FunctionalTestCase
Convenience class for functional unit testing
(derived from Functional and ZopeTestCase)
Interfaces
*See base classes*
Methods
*See base classes*
Module PortalTestCase
Test case and fixture for testing CMF-based applications
Constants
portal_name
user_name
user_password
Classes
PortalTestCase
Class PortalTestCase
Base test case for CMF testing
(derived from base.TestCase)
Interfaces
implements(IPortalTestCase, IPortalSecurity)
Methods
getPortal()
createMemberarea(name)
setRoles(roles, name=user_name)
setPermissions(permissions, role='Member')
login(name=user_name)
logout()
Module sandbox
ZODB sandbox support
Classes
Sandboxed
Class Sandboxed
Sandbox support mix-in for xTestCases
Interfaces
*No interfaces*
Methods
*No public methods*
Module functional
Functional testing support
Classes
Functional
Class Functional
Functional testing mix-in for xTestCases
Interfaces
implements(IFunctional)
Methods
publish(path, basic=None, env=None, extra=None, request_method='GET', stdin=None)
Module utils
Utility functions to extend the test environment
Functions
setupCoreSessions(app=None)
setupSiteErrorLog(app=None)
startZServer(number_of_threads=1, log=None)
importObjectFromFile(container, filename, quiet=0)
appcall(func, *args, **kw)
<style type="text/css"> <!-- li { margin: 1em } --> </style>
Functional Testing Readme
The functional testing support of ZopeTestCase was inspired by
Marius Gedminas' work for Zope 3.
Deriving from the 'Functional' mix-in (and an xTestCase) adds a
'publish' method to your test case class. Tests can call
'self.publish(path, basic=None, env=None, extra=None, request_method='GET', stdin=None)',
passing a path and, optionally, basic-auth info and form data.
The path may contain a query string.
'publish' returns an enhanced Response object, that can be queried
for status, response body, headers, etc.
'publish' invokes the ZPublisher machinery just as if the request
had come in through ZServer. This allows for high-level testing
of things like argument marshalling, form validation, and traversal.
Note that the tests have *full access to the ZODB*. This means you
can easily prepare a fixture for 'publish' and/or check the impact
of a publication on the database. This represents a major advantage
over purely URL-based test environments!
Please see the 'testFunctional.py' example test for more.
While the modules are called 'functional.py' in both Zope 3 and
ZopeTestCase, it is current wisdom that such tests are not truly
"functional tests", but rather "integration tests".
True functional tests, in their most-helpful guise as "acceptance
tests", must be able to test the end-user experience. For web
applications this means: browser simulation.
Plone 2 comes with an 'ftests' package combining the functional
testing support of ZopeTestCase with the "mechanize" browser
simulator library: http://wwwsearch.sourceforge.net/mechanize/
(For some version of 2, currently only available from the Plone
CVS HEAD.)
Read the Source
Amen. Read 'functional.py' and 'sandbox.py' if you want to know
what's going on behind the scenes.
This diff is collapsed.
<style type="text/css"> <!-- li { margin: 1em } --> </style>
PortalTestCase Readme
The PortalTestCase class is a close relative of the ZopeTestCase
class. It was devised at the Plone Castle Sprint to form the base of an
integration testing framework for Plone 2.0. Thanks to Gidon Friedman
and Godefroid Chapelle for their collaboration.
Much of what is true for ZopeTestCase is true for PortalTestCase as well:
* PortalTestCase handles the ZODB connection, transaction, and
application object; and it provides a REQUEST.
* PortalTestCase sets up a user folder and a user.
* PortalTestCase provides the same hooks as ZopeTestCase.
* PortalTestCase implements the same security interfaces as
ZopeTestCase.
What's different?
* PortalTestCase is designed for testing CMF-based applications.
* The fixture is slightly more complex, consisting of a portal object,
a userfolder + user, and the user's memberarea.
* For flexibility, the portal is *not* created by the base class but
must be provided by the user (typically a derived xTestCase) of the
PortalTestCase base class.
* Subclasses will have to override 'getPortal' to return the object
serving as the portal.
* The portal will however be configured by the machinery which means
creating a user and a fresh memberarea for every test.
* Subclasses may override 'createMemberarea' to provide customized
and/or more lightweight memberareas to the tests. This can improve
performance quite significantly.
Feature Comparison:
ZopeTestCase
* 1 user + 1 role
* Folder contains user folder and role definition
* Folder also serves as workarea
* User is logged in
* Provides attributes::
self.app
self.app.REQUEST
self.folder
self.folder.acl_users
PortalTestCase
* 1 user + 'Member' role
* Portal contains user folder and role definition
* User's home folder serves as workarea
* User is logged in
* Provides attributes::
self.app
self.app.REQUEST
self.portal
self.portal.acl_users
self.folder
Read the Source
As always, I recommend to look at the source code of both
'ZopeTestCase.py' and 'PortalTestCase.py' for all the details you may need.
Interface documentation can be found in 'interfaces.py'.
The test framework shipping with Plone 2.0 is a good example of how the
PortalTestCase class can be put to use.
<style type="text/css"> <!-- li { margin: 1em } --> </style>
ZopeTestCase Readme
The ZopeTestCase package has been developed in the hope that it will make
testing Zope packages more convenient. It has features to support various
scenarios from unit-testing individual components inside a "toy" environment
to running regression tests against live ZEO servers.
To add a test suite to a Zope package:
1. Make a 'tests' subdirectory.
2. Create an (empty) '__init__.py' in 'tests' to make it a package.
Once a test suite has been set up, you can add test modules:
1. Create a file with a name matching 'test*.py'.
2. Import the 'ZopeTestCase' package as in 'from Testing import ZopeTestCase'
and define one or more subclasses of 'ZopeTestCase.ZopeTestCase'.
3. Define methods for the test classes. Each method's name must start
with 'test'. It should test one small case, preferably using a PyUnit
assertion method. Here's a minimal example::
class ExampleTest(ZopeTestCase.ZopeTestCase):
def testAddition(self):
self.assertEqual(1+1, 2)
4. You can add 'afterSetUp' and 'beforeTearDown' methods that are automatically
called after the fixture has been set up and before the fixture is destroyed
respectively.
Note that there is a skeleton test suite named 'testSkeleton.py' that you
may copy into your 'tests' directory and take it from there.
See the sample tests in the 'ZopeTestCase' directory for details on writing
your own tests.
<style type="text/css"> <!-- li { margin: 1em } --> </style>
Default Fixture
- **'self.app'** is the root application object of the test ZODB (contains Control_Panel, ...)
Note that a ZODB connections has already been opened and a transaction begun at this point.
- **'self.app.REQUEST'** is the request object. Note that the REQUEST is rather minimal because
ZPublisher is not involved when running tests, and as such many REQUEST variables are never
set. Feel free to add to the REQUEST whatever your tests require.
- **'self.folder'** is the work area. This folder will be created anew for each test and thrown
away once the test has finished. The name of the folder is 'test_folder_1_'. You should
use the 'ZopeTestCase.folder_name' constant when you need the folder's name. 'self.folder' is a
reference to the object at 'self.app[folder_name]'.
A default role definition ('ZopeTestCase.user_role') is added to the folder, and a list of
permissions ('ZopeTestCase.standard_permissions') is assigned to the role.
- **'self.folder.acl_users'** is the user folder providing a security context to the work area.
A default user account is added to the user folder with name 'test_user_1_' and password 'secret'.
You should use the 'ZopeTestCase.user_name' constant when you need the user's name, the
'ZopeTestCase.user_password' constant when you need the user's password.
The default user has a single role, 'ZopeTestCase.user_role'.
At the end of the setup process the default user is logged in, and the 'afterSetUp' hook is called.
Security API
- **'self.setRoles(roles, name=user_name)'** allows to change the roles assigned to a user.
If the 'name' argument is omitted, changes the roles of the default user.
- **'self.setPermissions(permissions, role=user_role)'** allows to change the permissions
assigned to a role. If the 'role' argument is omitted, changes the permissions of the
default role.
- **'self.login(name=user_name)'** allows to log in as a specified user.
If the 'name' argument is omitted, logs in as the default user.
- **'self.logout()'** allows to log out and become 'Anonymous User'.
Testing Security
- **'ob.restrictedTraverse("attr")'** is a simple way to check whether the currently logged in user is
allowed to access attribute 'attr' of object 'ob'.
- **'getSecurityManager().validate(None, ob, "attr", ob.attr)'** uses the security manager to do the same.
The convenience method 'getSecurityManager().validateValue(ob.attr)' will no longer work
in Zope 2.8.
Also see the 'testPythonScript.py' example test.
Note that you have the entire Zope security API at your disposal to further refine your fixture.
E.g. to add another user call 'self.folder.acl_users.userFolderAddUser("user2", "secret", ["role2"], [])'.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment