From b02b36705b6aa3397eded86c399c814b1f325096 Mon Sep 17 00:00:00 2001 From: Guido van Rossum <guido@python.org> Date: Tue, 27 Aug 2002 18:19:37 +0000 Subject: [PATCH] The beginnings of a test suite for ClientCache.py. This will cause three failures with the current version of ClientCache.py, because some of the tests were specifically written to verify certain bugs. I will check in fixes for thse bugs shortly. --- src/ZEO/tests/testClientCache.py | 241 +++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 src/ZEO/tests/testClientCache.py diff --git a/src/ZEO/tests/testClientCache.py b/src/ZEO/tests/testClientCache.py new file mode 100644 index 00000000..89579a50 --- /dev/null +++ b/src/ZEO/tests/testClientCache.py @@ -0,0 +1,241 @@ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE +# +############################################################################## +"""Test suite for the ZEO.ClientCache module. + +At times, we do 'white box' testing, i.e. we know about the internals +of the ClientCache object.""" + +import os +import time +import tempfile +import unittest + +from ZEO.ClientCache import ClientCache + +class ClientCacheTests(unittest.TestCase): + + def setUp(self): + unittest.TestCase.setUp(self) + self.cache = ClientCache() + self.cache.open() + + def tearDown(self): + self.cache.close() + unittest.TestCase.tearDown(self) + + def testOpenClose(self): + pass # All the work is done by setUp() / tearDown() + + def testStoreLoad(self): + cache = self.cache + oid = 'abcdefgh' + data = '1234'*100 + serial = 'ABCDEFGH' + cache.store(oid, data, serial, '', '', '') + loaded = cache.load(oid, '') + self.assertEqual(loaded, (data, serial)) + + def testMissingLoad(self): + cache = self.cache + oid = 'abcdefgh' + data = '1234'*100 + serial = 'ABCDEFGH' + cache.store(oid, data, serial, '', '', '') + loaded = cache.load('garbage1', '') + self.assertEqual(loaded, None) + + def testInvalidate(self): + cache = self.cache + oid = 'abcdefgh' + data = '1234'*100 + serial = 'ABCDEFGH' + cache.store(oid, data, serial, '', '', '') + loaded = cache.load(oid, '') + self.assertEqual(loaded, (data, serial)) + cache.invalidate(oid, '') + loaded = cache.load(oid, '') + self.assertEqual(loaded, None) + + def testVersion(self): + cache = self.cache + oid = 'abcdefgh' + data = '1234'*100 + serial = 'ABCDEFGH' + vname = 'myversion' + vdata = '5678'*200 + vserial = 'IJKLMNOP' + cache.store(oid, data, serial, vname, vdata, vserial) + loaded = cache.load(oid, '') + self.assertEqual(loaded, (data, serial)) + vloaded = cache.load(oid, vname) + self.assertEqual(vloaded, (vdata, vserial)) + + def testVersionOnly(self): + cache = self.cache + oid = 'abcdefgh' + data = '' + serial = '' + vname = 'myversion' + vdata = '5678'*200 + vserial = 'IJKLMNOP' + cache.store(oid, data, serial, vname, vdata, vserial) + loaded = cache.load(oid, '') + self.assertEqual(loaded, None) + vloaded = cache.load(oid, vname) + self.assertEqual(vloaded, (vdata, vserial)) + + def testInvalidateNonVersion(self): + cache = self.cache + oid = 'abcdefgh' + data = '1234'*100 + serial = 'ABCDEFGH' + vname = 'myversion' + vdata = '5678'*200 + vserial = 'IJKLMNOP' + cache.store(oid, data, serial, vname, vdata, vserial) + loaded = cache.load(oid, '') + self.assertEqual(loaded, (data, serial)) + vloaded = cache.load(oid, vname) + self.assertEqual(vloaded, (vdata, vserial)) + cache.invalidate(oid, '') + loaded = cache.load(oid, '') + self.assertEqual(loaded, None) + # The version data is also invalidated at this point + vloaded = cache.load(oid, vname) + self.assertEqual(vloaded, None) + + def testInvalidateVersion(self): + # Invalidating a version should not invalidate the non-version data. + # (This tests for the same bug as testInvalidatePersists below.) + cache = self.cache + oid = 'abcdefgh' + data = '1234'*100 + serial = 'ABCDEFGH' + cache.store(oid, data, serial, '', '', '') + loaded = cache.load(oid, '') + self.assertEqual(loaded, (data, serial)) + cache.invalidate(oid, 'bogus') + loaded = cache.load(oid, '') + self.assertEqual(loaded, (data, serial)) + + def testVerify(self): + cache = self.cache + def verifier(oid, serial, vserial): + results.append((oid, serial, vserial)) + results = [] + cache.verify(verifier) + self.assertEqual(results, []) + oid = 'abcdefgh' + data = '1234'*100 + serial = 'ABCDEFGH' + cache.store(oid, data, serial, '', '', '') + results = [] + cache.verify(verifier) + self.assertEqual(results, [(oid, serial, None)]) + +class PersistentClientCacheTests(unittest.TestCase): + + def setUp(self): + unittest.TestCase.setUp(self) + self.vardir = os.getcwd() # Don't use /tmp, it's a security risk + self.cachesize = 10*1000*1000 + self.storagename = 'foo' + self.clientname = 'test' + # Predict file names + fn0 = 'c%s-%s-0.zec' % (self.storagename, self.clientname) + fn1 = 'c%s-%s-1.zec' % (self.storagename, self.clientname) + for fn in fn0, fn1: + fn = os.path.join(self.vardir, fn) + try: + os.unlink(fn) + except os.error: + pass + self.openCache() + + def openCache(self): + self.cache = ClientCache(storage=self.storagename, + size=self.cachesize, + client=self.clientname, + var=self.vardir) + self.cache.open() + + def reopenCache(self): + self.cache.close() + self.openCache() + return self.cache + + def tearDown(self): + self.cache.close() + for filename in self.cache._p: + if filename is not None: + try: + os.unlink(filename) + except os.error: + pass + unittest.TestCase.tearDown(self) + + def testCacheFileSelection(self): + # A bug in __init__ read the wrong slice of the file to determine + # the serial number of the first record, reading the + # last byte of the data size plus the first seven bytes of the + # serial number. This caused random selection of the proper + # 'current' file when a persistent cache was opened. + cache = self.cache + self.assertEqual(cache._current, 0) # Check that file 0 is current + oid = 'abcdefgh' + data = '1234' + serial = 'ABCDEFGH' + cache.store(oid, data, serial, '', '', '') + cache.checkSize(10*self.cachesize) # Force a file flip + self.assertEqual(cache._current, 1) # Check that the flip worked + oid = 'abcdefgh' + data = '123' + serial = 'ABCDEFGZ' + cache.store(oid, data, serial, '', '', '') + cache = self.reopenCache() + loaded = cache.load(oid, '') + # Check that we got the most recent data: + self.assertEqual(loaded, (data, serial)) + self.assertEqual(cache._current, 1) # Double check that 1 is current + + def testInvalidationPersists(self): + # A bug in invalidate() caused invalidation to overwrite the + # 2nd byte of the data size on disk, rather rather than + # overwriting the status byte. For certain data sizes this + # can be observed by reopening a persistent cache: the + # invalidated data will appear valid (but with altered size). + cache = self.cache + magicsize = (ord('i') + 1) << 16 + cache = self.cache + oid = 'abcdefgh' + data = '!'*magicsize + serial = 'ABCDEFGH' + cache.store(oid, data, serial, '', '', '') + loaded = cache.load(oid, '') + self.assertEqual(loaded, (data, serial)) + cache.invalidate(oid, '') + cache = self.reopenCache() + loaded = cache.load(oid, '') + if loaded != None: + self.fail("invalidated data resurrected, size %d, was %d" % + (len(loaded[0]), len(data))) + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(ClientCacheTests)) + suite.addTest(unittest.makeSuite(PersistentClientCacheTests)) + return suite + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') -- 2.30.9