Commit dcfb60ab authored by Jim Fulton's avatar Jim Fulton

Reimplemented DemoStorage to be just a wrapper around a base storage

and a changes storage.
parent 13c9c035
This diff is collapsed.
DemoStorage demo (doctest)
--------------------------
Note that most people will configure the storage through ZConfig. If
you are one of those people, you may want to stop here. :) The
examples below show you how to use the storage from Python, but they
also exercise lots of details you might not be interested in.
To see how this works, we'll start by creating a base storage and
puting an object (in addition to the root object) in it:
>>> from ZODB.FileStorage import FileStorage
>>> base = FileStorage('base.fs')
>>> from ZODB.DB import DB
>>> db = DB(base)
>>> from persistent.mapping import PersistentMapping
>>> conn = db.open()
>>> conn.root()['1'] = PersistentMapping({'a': 1, 'b':2})
>>> import transaction
>>> transaction.commit()
>>> db.close()
>>> import os
>>> original_size = os.path.getsize('base.fs')
Now, lets reopen the base storage in read-only mode:
>>> base = FileStorage('base.fs', read_only=True)
And open a new storage to store changes:
>>> changes = FileStorage('changes.fs')
and combine the 2 in a demofilestorage:
>>> from ZODB.DemoStorage import DemoStorage
>>> storage = DemoStorage(base=base, changes=changes)
If there are no transactions, the storage reports the lastTransaction
of the base database:
>>> storage.lastTransaction() == base.lastTransaction()
True
Let's add some data:
>>> db = DB(storage)
>>> conn = db.open()
>>> items = conn.root()['1'].items()
>>> items.sort()
>>> items
[('a', 1), ('b', 2)]
>>> conn.root()['2'] = PersistentMapping({'a': 3, 'b':4})
>>> transaction.commit()
>>> conn.root()['2']['c'] = 5
>>> transaction.commit()
Here we can see that we haven't modified the base storage:
>>> original_size == os.path.getsize('base.fs')
True
But we have modified the changes database:
>>> len(changes)
2
Our lastTransaction reflects the lastTransaction of the changes:
>>> storage.lastTransaction() > base.lastTransaction()
True
>>> storage.lastTransaction() == changes.lastTransaction()
True
Let's walk over some of the methods so ewe can see how we delegate to
the new underlying storages:
>>> from ZODB.utils import p64, u64
>>> storage.load(p64(0), '') == changes.load(p64(0), '')
True
>>> storage.load(p64(0), '') == base.load(p64(0), '')
False
>>> storage.load(p64(1), '') == base.load(p64(1), '')
True
>>> serial = base.getTid(p64(0))
>>> storage.loadSerial(p64(0), serial) == base.loadSerial(p64(0), serial)
True
>>> serial = changes.getTid(p64(0))
>>> storage.loadSerial(p64(0), serial) == changes.loadSerial(p64(0),
... serial)
True
The object id of the new object is quite random, and typically large:
>>> print u64(conn.root()['2']._p_oid)
7106521602475165646
Let's look at some other methods:
>>> storage.getName()
"DemoStorage('base.fs', 'changes.fs')"
>>> storage.sortKey() == changes.sortKey()
True
>>> storage.getSize() == changes.getSize()
True
>>> len(storage) == len(changes)
True
Undo methods are simply copied from the changes storage:
>>> [getattr(storage, name) == getattr(changes, name)
... for name in ('supportsUndo', 'undo', 'undoLog', 'undoInfo')
... ]
[True, True, True, True]
......@@ -174,9 +174,9 @@
<sectiontype name="demostorage" datatype=".DemoStorage"
implements="ZODB.storage">
<key name="name" default="Demo Storage"/>
<section type="ZODB.storage" name="*" attribute="base"/>
<key name="quota" datatype="integer"/>
<key name="name" />
<section type="ZODB.storage" name="*" attribute="base" />
<section type="ZODB.storage" name="changes" attribute="changes" />
</sectiontype>
......
......@@ -125,9 +125,11 @@ class DemoStorage(BaseConfig):
base = self.config.base.open()
else:
base = None
return DemoStorage(self.config.name,
base=base,
quota=self.config.quota)
if self.config.changes:
changes = self.config.changes.open()
else:
changes = None
return DemoStorage(self.config.name, base=base, changes=changes)
class FileStorage(BaseConfig):
......
......@@ -12,18 +12,36 @@
#
##############################################################################
import unittest
import random
import transaction
from ZODB.DB import DB
from zope.testing import doctest
import zope.testing.setupstack
import ZODB.utils
import ZODB.DemoStorage
from ZODB.tests import StorageTestBase, BasicStorage
from ZODB.tests import Synchronization
class DemoStorageTests(StorageTestBase.StorageTestBase,
BasicStorage.BasicStorage,
Synchronization.SynchronizedStorage,
):
from ZODB.tests import (
BasicStorage,
HistoryStorage,
IteratorStorage,
MTStorage,
PackableStorage,
RevisionStorage,
StorageTestBase,
Synchronization,
)
class DemoStorageTests(
StorageTestBase.StorageTestBase,
BasicStorage.BasicStorage,
HistoryStorage.HistoryStorage,
IteratorStorage.ExtendedIteratorStorage,
IteratorStorage.IteratorStorage,
MTStorage.MTStorage,
PackableStorage.PackableStorage,
RevisionStorage.RevisionStorage,
Synchronization.SynchronizedStorage,
):
def setUp(self):
self._storage = ZODB.DemoStorage.DemoStorage()
......@@ -44,7 +62,26 @@ class DemoStorageTests(StorageTestBase.StorageTestBase,
self.assertEqual(s2.load(ZODB.utils.z64, ''),
self._storage.load(ZODB.utils.z64, ''))
def checkLengthAndBool(self):
self.assertEqual(len(self._storage), 0)
self.assert_(not self._storage)
db = DB(self._storage) # creates object 0. :)
self.assertEqual(len(self._storage), 1)
self.assert_(self._storage)
conn = db.open()
for i in range(10):
conn.root()[i] = conn.root().__class__()
transaction.commit()
self.assertEqual(len(self._storage), 11)
self.assert_(self._storage)
def checkLoadBeforeUndo(self):
pass # we don't support undo yet
checkUndoZombie = checkLoadBeforeUndo
def checkPackWithMultiDatabaseReferences(self):
pass # we never do gc
class DemoStorageWrappedBase(DemoStorageTests):
def setUp(self):
......@@ -59,29 +96,92 @@ class DemoStorageWrappedBase(DemoStorageTests):
def _makeBaseStorage(self):
raise NotImplementedError
class DemoStorageWrappedAroundFileStorage(DemoStorageWrappedBase):
class DemoStorageWrappedAroundMappingStorage(DemoStorageWrappedBase):
def _makeBaseStorage(self):
from ZODB.MappingStorage import MappingStorage
return MappingStorage()
class DemoStorageWrappedAroundMappingStorage(DemoStorageWrappedBase):
class DemoStorageWrappedAroundFileStorage(DemoStorageWrappedBase):
def _makeBaseStorage(self):
from ZODB.FileStorage import FileStorage
return FileStorage('FileStorageTests.fs')
def setUp(test):
random.seed(0)
zope.testing.setupstack.setUpDirectory(test)
zope.testing.setupstack.register(test, transaction.abort)
def testSomeDelegation():
r"""
>>> class S:
... def __init__(self, name):
... self.name = name
... def registerDB(self, db):
... print self.name, db
... def close(self):
... print self.name, 'closed'
... sortKey = getSize = __len__ = history = getTid = None
... tpc_finish = tpc_vote = tpc_transaction = None
... _lock_acquire = _lock_release = lambda: None
... getName = lambda self: 'S'
... isReadOnly = tpc_transaction = None
... supportsUndo = undo = undoLog = undoInfo = None
... supportsTransactionalUndo = None
... def new_oid(self):
... return '\0' * 8
... def tpc_begin(self, t, tid, status):
... print 'begin', tid, status
... def tpc_abort(self, t):
... pass
>>> from ZODB.DemoStorage import DemoStorage
>>> storage = DemoStorage(base=S(1), changes=S(2))
>>> storage.registerDB(1)
2 1
>>> storage.close()
1 closed
2 closed
>>> storage.tpc_begin(1, 2, 3)
begin 2 3
>>> storage.tpc_abort(1)
"""
def test_suite():
return unittest.TestSuite((
doctest.DocFileSuite('synchronized.txt'),
doctest.DocTestSuite(
setUp=setUp, tearDown=zope.testing.setupstack.tearDown,
),
doctest.DocFileSuite(
'README.txt',
setUp=setUp, tearDown=zope.testing.setupstack.tearDown,
),
))
def test_suite():
suite = unittest.TestSuite()
suite = unittest.TestSuite((
doctest.DocTestSuite(
setUp=setUp, tearDown=zope.testing.setupstack.tearDown,
),
doctest.DocFileSuite(
'../DemoStorage.test',
setUp=setUp, tearDown=zope.testing.setupstack.tearDown,
),
))
suite.addTest(unittest.makeSuite(DemoStorageTests, 'check'))
suite.addTest(unittest.makeSuite(DemoStorageWrappedAroundFileStorage,
'check'))
suite.addTest(unittest.makeSuite(DemoStorageWrappedAroundMappingStorage,
'check'))
return suite
if __name__ == "__main__":
loader = unittest.TestLoader()
loader.testMethodPrefix = "check"
unittest.main(testLoader=loader)
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