0001 """ 0002 Basic TestCases for BTree and hash DBs, with and without a DBEnv, with 0003 various DB flags, etc. 0004 """ 0005 0006 import os 0007 import sys 0008 import errno 0009 import shutil 0010 import string 0011 import tempfile 0012 from pprint import pprint 0013 import unittest 0014 0015 try: 0016 # For Pythons w/distutils pybsddb 0017 from bsddb3 import db 0018 except ImportError: 0019 # For Python 2.3 0020 from bsddb import db 0021 0022 from test_all import verbose 0023 0024 DASH = '-' 0025 0026 0027 #---------------------------------------------------------------------- 0028 0029 class VersionTestCase(unittest.TestCase): 0030 def test00_version(self): 0031 info = db.version() 0032 if verbose: 0033 print '\n', '-=' * 20 0034 print 'bsddb.db.version(): %s' % (info, ) 0035 print db.DB_VERSION_STRING 0036 print '-=' * 20 0037 assert info == (db.DB_VERSION_MAJOR, db.DB_VERSION_MINOR, 0038 db.DB_VERSION_PATCH) 0039 0040 #---------------------------------------------------------------------- 0041 0042 class BasicTestCase(unittest.TestCase): 0043 dbtype = db.DB_UNKNOWN # must be set in derived class 0044 dbopenflags = 0 0045 dbsetflags = 0 0046 dbmode = 0660 0047 dbname = None 0048 useEnv = 0 0049 envflags = 0 0050 envsetflags = 0 0051 0052 _numKeys = 1002 # PRIVATE. NOTE: must be an even value 0053 0054 def setUp(self): 0055 if self.useEnv: 0056 homeDir = os.path.join(os.path.dirname(sys.argv[0]), 'db_home') 0057 self.homeDir = homeDir 0058 try: 0059 shutil.rmtree(homeDir) 0060 except OSError, e: 0061 # unix returns ENOENT, windows returns ESRCH 0062 if e.errno not in (errno.ENOENT, errno.ESRCH): raise 0063 os.mkdir(homeDir) 0064 try: 0065 self.env = db.DBEnv() 0066 self.env.set_lg_max(1024*1024) 0067 self.env.set_flags(self.envsetflags, 1) 0068 self.env.open(homeDir, self.envflags | db.DB_CREATE) 0069 tempfile.tempdir = homeDir 0070 self.filename = os.path.split(tempfile.mktemp())[1] 0071 tempfile.tempdir = None 0072 # Yes, a bare except is intended, since we're re-raising the exc. 0073 except: 0074 shutil.rmtree(homeDir) 0075 raise 0076 else: 0077 self.env = None 0078 self.filename = tempfile.mktemp() 0079 0080 # create and open the DB 0081 self.d = db.DB(self.env) 0082 self.d.set_flags(self.dbsetflags) 0083 if self.dbname: 0084 self.d.open(self.filename, self.dbname, self.dbtype, 0085 self.dbopenflags|db.DB_CREATE, self.dbmode) 0086 else: 0087 self.d.open(self.filename, # try out keyword args 0088 mode = self.dbmode, 0089 dbtype = self.dbtype, 0090 flags = self.dbopenflags|db.DB_CREATE) 0091 0092 self.populateDB() 0093 0094 0095 def tearDown(self): 0096 self.d.close() 0097 if self.env is not None: 0098 self.env.close() 0099 shutil.rmtree(self.homeDir) 0100 ## Make a new DBEnv to remove the env files from the home dir. 0101 ## (It can't be done while the env is open, nor after it has been 0102 ## closed, so we make a new one to do it.) 0103 #e = db.DBEnv() 0104 #e.remove(self.homeDir) 0105 #os.remove(os.path.join(self.homeDir, self.filename)) 0106 else: 0107 os.remove(self.filename) 0108 0109 0110 0111 def populateDB(self, _txn=None): 0112 d = self.d 0113 0114 for x in range(self._numKeys/2): 0115 key = '%04d' % (self._numKeys - x) # insert keys in reverse order 0116 data = self.makeData(key) 0117 d.put(key, data, _txn) 0118 0119 d.put('empty value', '', _txn) 0120 0121 for x in range(self._numKeys/2-1): 0122 key = '%04d' % x # and now some in forward order 0123 data = self.makeData(key) 0124 d.put(key, data, _txn) 0125 0126 if _txn: 0127 _txn.commit() 0128 0129 num = len(d) 0130 if verbose: 0131 print "created %d records" % num 0132 0133 0134 def makeData(self, key): 0135 return DASH.join([key] * 5) 0136 0137 0138 0139 #---------------------------------------- 0140 0141 def test01_GetsAndPuts(self): 0142 d = self.d 0143 0144 if verbose: 0145 print '\n', '-=' * 30 0146 print "Running %s.test01_GetsAndPuts..." % self.__class__.__name__ 0147 0148 for key in ['0001', '0100', '0400', '0700', '0999']: 0149 data = d.get(key) 0150 if verbose: 0151 print data 0152 0153 assert d.get('0321') == '0321-0321-0321-0321-0321' 0154 0155 # By default non-existant keys return None... 0156 assert d.get('abcd') == None 0157 0158 # ...but they raise exceptions in other situations. Call 0159 # set_get_returns_none() to change it. 0160 try: 0161 d.delete('abcd') 0162 except db.DBNotFoundError, val: 0163 assert val[0] == db.DB_NOTFOUND 0164 if verbose: print val 0165 else: 0166 self.fail("expected exception") 0167 0168 0169 d.put('abcd', 'a new record') 0170 assert d.get('abcd') == 'a new record' 0171 0172 d.put('abcd', 'same key') 0173 if self.dbsetflags & db.DB_DUP: 0174 assert d.get('abcd') == 'a new record' 0175 else: 0176 assert d.get('abcd') == 'same key' 0177 0178 0179 try: 0180 d.put('abcd', 'this should fail', flags=db.DB_NOOVERWRITE) 0181 except db.DBKeyExistError, val: 0182 assert val[0] == db.DB_KEYEXIST 0183 if verbose: print val 0184 else: 0185 self.fail("expected exception") 0186 0187 if self.dbsetflags & db.DB_DUP: 0188 assert d.get('abcd') == 'a new record' 0189 else: 0190 assert d.get('abcd') == 'same key' 0191 0192 0193 d.sync() 0194 d.close() 0195 del d 0196 0197 self.d = db.DB(self.env) 0198 if self.dbname: 0199 self.d.open(self.filename, self.dbname) 0200 else: 0201 self.d.open(self.filename) 0202 d = self.d 0203 0204 assert d.get('0321') == '0321-0321-0321-0321-0321' 0205 if self.dbsetflags & db.DB_DUP: 0206 assert d.get('abcd') == 'a new record' 0207 else: 0208 assert d.get('abcd') == 'same key' 0209 0210 rec = d.get_both('0555', '0555-0555-0555-0555-0555') 0211 if verbose: 0212 print rec 0213 0214 assert d.get_both('0555', 'bad data') == None 0215 0216 # test default value 0217 data = d.get('bad key', 'bad data') 0218 assert data == 'bad data' 0219 0220 # any object can pass through 0221 data = d.get('bad key', self) 0222 assert data == self 0223 0224 s = d.stat() 0225 assert type(s) == type({}) 0226 if verbose: 0227 print 'd.stat() returned this dictionary:' 0228 pprint(s) 0229 0230 0231 #---------------------------------------- 0232 0233 def test02_DictionaryMethods(self): 0234 d = self.d 0235 0236 if verbose: 0237 print '\n', '-=' * 30 0238 print "Running %s.test02_DictionaryMethods..." % \ 0239 self.__class__.__name__ 0240 0241 for key in ['0002', '0101', '0401', '0701', '0998']: 0242 data = d[key] 0243 assert data == self.makeData(key) 0244 if verbose: 0245 print data 0246 0247 assert len(d) == self._numKeys 0248 keys = d.keys() 0249 assert len(keys) == self._numKeys 0250 assert type(keys) == type([]) 0251 0252 d['new record'] = 'a new record' 0253 assert len(d) == self._numKeys+1 0254 keys = d.keys() 0255 assert len(keys) == self._numKeys+1 0256 0257 d['new record'] = 'a replacement record' 0258 assert len(d) == self._numKeys+1 0259 keys = d.keys() 0260 assert len(keys) == self._numKeys+1 0261 0262 if verbose: 0263 print "the first 10 keys are:" 0264 pprint(keys[:10]) 0265 0266 assert d['new record'] == 'a replacement record' 0267 0268 assert d.has_key('0001') == 1 0269 assert d.has_key('spam') == 0 0270 0271 items = d.items() 0272 assert len(items) == self._numKeys+1 0273 assert type(items) == type([]) 0274 assert type(items[0]) == type(()) 0275 assert len(items[0]) == 2 0276 0277 if verbose: 0278 print "the first 10 items are:" 0279 pprint(items[:10]) 0280 0281 values = d.values() 0282 assert len(values) == self._numKeys+1 0283 assert type(values) == type([]) 0284 0285 if verbose: 0286 print "the first 10 values are:" 0287 pprint(values[:10]) 0288 0289 0290 0291 #---------------------------------------- 0292 0293 def test03_SimpleCursorStuff(self, get_raises_error=0, set_raises_error=0): 0294 if verbose: 0295 print '\n', '-=' * 30 0296 print "Running %s.test03_SimpleCursorStuff (get_error %s, set_error %s)..." % \ 0297 (self.__class__.__name__, get_raises_error, set_raises_error) 0298 0299 if self.env and self.dbopenflags & db.DB_AUTO_COMMIT: 0300 txn = self.env.txn_begin() 0301 else: 0302 txn = None 0303 c = self.d.cursor(txn=txn) 0304 0305 rec = c.first() 0306 count = 0 0307 while rec is not None: 0308 count = count + 1 0309 if verbose and count % 100 == 0: 0310 print rec 0311 try: 0312 rec = c.next() 0313 except db.DBNotFoundError, val: 0314 if get_raises_error: 0315 assert val[0] == db.DB_NOTFOUND 0316 if verbose: print val 0317 rec = None 0318 else: 0319 self.fail("unexpected DBNotFoundError") 0320 assert c.get_current_size() == len(c.current()[1]), "%s != len(%r)" % (c.get_current_size(), c.current()[1]) 0321 0322 assert count == self._numKeys 0323 0324 0325 rec = c.last() 0326 count = 0 0327 while rec is not None: 0328 count = count + 1 0329 if verbose and count % 100 == 0: 0330 print rec 0331 try: 0332 rec = c.prev() 0333 except db.DBNotFoundError, val: 0334 if get_raises_error: 0335 assert val[0] == db.DB_NOTFOUND 0336 if verbose: print val 0337 rec = None 0338 else: 0339 self.fail("unexpected DBNotFoundError") 0340 0341 assert count == self._numKeys 0342 0343 rec = c.set('0505') 0344 rec2 = c.current() 0345 assert rec == rec2 0346 assert rec[0] == '0505' 0347 assert rec[1] == self.makeData('0505') 0348 assert c.get_current_size() == len(rec[1]) 0349 0350 # make sure we get empty values properly 0351 rec = c.set('empty value') 0352 assert rec[1] == '' 0353 assert c.get_current_size() == 0 0354 0355 try: 0356 n = c.set('bad key') 0357 except db.DBNotFoundError, val: 0358 assert val[0] == db.DB_NOTFOUND 0359 if verbose: print val 0360 else: 0361 if set_raises_error: 0362 self.fail("expected exception") 0363 if n != None: 0364 self.fail("expected None: %r" % (n,)) 0365 0366 rec = c.get_both('0404', self.makeData('0404')) 0367 assert rec == ('0404', self.makeData('0404')) 0368 0369 try: 0370 n = c.get_both('0404', 'bad data') 0371 except db.DBNotFoundError, val: 0372 assert val[0] == db.DB_NOTFOUND 0373 if verbose: print val 0374 else: 0375 if get_raises_error: 0376 self.fail("expected exception") 0377 if n != None: 0378 self.fail("expected None: %r" % (n,)) 0379 0380 if self.d.get_type() == db.DB_BTREE: 0381 rec = c.set_range('011') 0382 if verbose: 0383 print "searched for '011', found: ", rec 0384 0385 rec = c.set_range('011',dlen=0,doff=0) 0386 if verbose: 0387 print "searched (partial) for '011', found: ", rec 0388 if rec[1] != '': self.fail('expected empty data portion') 0389 0390 ev = c.set_range('empty value') 0391 if verbose: 0392 print "search for 'empty value' returned", ev 0393 if ev[1] != '': self.fail('empty value lookup failed') 0394 0395 c.set('0499') 0396 c.delete() 0397 try: 0398 rec = c.current() 0399 except db.DBKeyEmptyError, val: 0400 assert val[0] == db.DB_KEYEMPTY 0401 if verbose: print val 0402 else: 0403 self.fail('exception expected') 0404 0405 c.next() 0406 c2 = c.dup(db.DB_POSITION) 0407 assert c.current() == c2.current() 0408 0409 c2.put('', 'a new value', db.DB_CURRENT) 0410 assert c.current() == c2.current() 0411 assert c.current()[1] == 'a new value' 0412 0413 c2.put('', 'er', db.DB_CURRENT, dlen=0, doff=5) 0414 assert c2.current()[1] == 'a newer value' 0415 0416 c.close() 0417 c2.close() 0418 if txn: 0419 txn.commit() 0420 0421 # time to abuse the closed cursors and hope we don't crash 0422 methods_to_test = { 0423 'current': (), 0424 'delete': (), 0425 'dup': (db.DB_POSITION,), 0426 'first': (), 0427 'get': (0,), 0428 'next': (), 0429 'prev': (), 0430 'last': (), 0431 'put':('', 'spam', db.DB_CURRENT), 0432 'set': ("0505",), 0433 } 0434 for method, args in methods_to_test.items(): 0435 try: 0436 if verbose: 0437 print "attempting to use a closed cursor's %s method" % \ 0438 method 0439 # a bug may cause a NULL pointer dereference... 0440 apply(getattr(c, method), args) 0441 except db.DBError, val: 0442 assert val[0] == 0 0443 if verbose: print val 0444 else: 0445 self.fail("no exception raised when using a buggy cursor's" 0446 "%s method" % method) 0447 0448 # 0449 # free cursor referencing a closed database, it should not barf: 0450 # 0451 oldcursor = self.d.cursor(txn=txn) 0452 self.d.close() 0453 0454 # this would originally cause a segfault when the cursor for a 0455 # closed database was cleaned up. it should not anymore. 0456 # SF pybsddb bug id 667343 0457 del oldcursor 0458 0459 def test03b_SimpleCursorWithoutGetReturnsNone0(self): 0460 # same test but raise exceptions instead of returning None 0461 if verbose: 0462 print '\n', '-=' * 30 0463 print "Running %s.test03b_SimpleCursorStuffWithoutGetReturnsNone..." % \ 0464 self.__class__.__name__ 0465 0466 old = self.d.set_get_returns_none(0) 0467 assert old == 2 0468 self.test03_SimpleCursorStuff(get_raises_error=1, set_raises_error=1) 0469 0470 def test03b_SimpleCursorWithGetReturnsNone1(self): 0471 # same test but raise exceptions instead of returning None 0472 if verbose: 0473 print '\n', '-=' * 30 0474 print "Running %s.test03b_SimpleCursorStuffWithoutGetReturnsNone..." % \ 0475 self.__class__.__name__ 0476 0477 old = self.d.set_get_returns_none(1) 0478 self.test03_SimpleCursorStuff(get_raises_error=0, set_raises_error=1) 0479 0480 0481 def test03c_SimpleCursorGetReturnsNone2(self): 0482 # same test but raise exceptions instead of returning None 0483 if verbose: 0484 print '\n', '-=' * 30 0485 print "Running %s.test03c_SimpleCursorStuffWithoutSetReturnsNone..." % \ 0486 self.__class__.__name__ 0487 0488 old = self.d.set_get_returns_none(1) 0489 assert old == 2 0490 old = self.d.set_get_returns_none(2) 0491 assert old == 1 0492 self.test03_SimpleCursorStuff(get_raises_error=0, set_raises_error=0) 0493 0494 #---------------------------------------- 0495 0496 def test04_PartialGetAndPut(self): 0497 d = self.d 0498 if verbose: 0499 print '\n', '-=' * 30 0500 print "Running %s.test04_PartialGetAndPut..." % \ 0501 self.__class__.__name__ 0502 0503 key = "partialTest" 0504 data = "1" * 1000 + "2" * 1000 0505 d.put(key, data) 0506 assert d.get(key) == data 0507 assert d.get(key, dlen=20, doff=990) == ("1" * 10) + ("2" * 10) 0508 0509 d.put("partialtest2", ("1" * 30000) + "robin" ) 0510 assert d.get("partialtest2", dlen=5, doff=30000) == "robin" 0511 0512 # There seems to be a bug in DB here... Commented out the test for 0513 # now. 0514 ##assert d.get("partialtest2", dlen=5, doff=30010) == "" 0515 0516 if self.dbsetflags != db.DB_DUP: 0517 # Partial put with duplicate records requires a cursor 0518 d.put(key, "0000", dlen=2000, doff=0) 0519 assert d.get(key) == "0000" 0520 0521 d.put(key, "1111", dlen=1, doff=2) 0522 assert d.get(key) == "0011110" 0523 0524 #---------------------------------------- 0525 0526 def test05_GetSize(self): 0527 d = self.d 0528 if verbose: 0529 print '\n', '-=' * 30 0530 print "Running %s.test05_GetSize..." % self.__class__.__name__ 0531 0532 for i in range(1, 50000, 500): 0533 key = "size%s" % i 0534 #print "before ", i, 0535 d.put(key, "1" * i) 0536 #print "after", 0537 assert d.get_size(key) == i 0538 #print "done" 0539 0540 #---------------------------------------- 0541 0542 def test06_Truncate(self): 0543 if db.version() < (3,3): 0544 # truncate is a feature of BerkeleyDB 3.3 and above 0545 return 0546 0547 d = self.d 0548 if verbose: 0549 print '\n', '-=' * 30 0550 print "Running %s.test99_Truncate..." % self.__class__.__name__ 0551 0552 d.put("abcde", "ABCDE"); 0553 num = d.truncate() 0554 assert num >= 1, "truncate returned <= 0 on non-empty database" 0555 num = d.truncate() 0556 assert num == 0, "truncate on empty DB returned nonzero (%r)" % (num,) 0557 0558 #---------------------------------------------------------------------- 0559 0560 0561 class BasicBTreeTestCase(BasicTestCase): 0562 dbtype = db.DB_BTREE 0563 0564 0565 class BasicHashTestCase(BasicTestCase): 0566 dbtype = db.DB_HASH 0567 0568 0569 class BasicBTreeWithThreadFlagTestCase(BasicTestCase): 0570 dbtype = db.DB_BTREE 0571 dbopenflags = db.DB_THREAD 0572 0573 0574 class BasicHashWithThreadFlagTestCase(BasicTestCase): 0575 dbtype = db.DB_HASH 0576 dbopenflags = db.DB_THREAD 0577 0578 0579 class BasicBTreeWithEnvTestCase(BasicTestCase): 0580 dbtype = db.DB_BTREE 0581 dbopenflags = db.DB_THREAD 0582 useEnv = 1 0583 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK 0584 0585 0586 class BasicHashWithEnvTestCase(BasicTestCase): 0587 dbtype = db.DB_HASH 0588 dbopenflags = db.DB_THREAD 0589 useEnv = 1 0590 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK 0591 0592 0593 #---------------------------------------------------------------------- 0594 0595 class BasicTransactionTestCase(BasicTestCase): 0596 dbopenflags = db.DB_THREAD | db.DB_AUTO_COMMIT 0597 useEnv = 1 0598 envflags = (db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK | 0599 db.DB_INIT_TXN) 0600 envsetflags = db.DB_AUTO_COMMIT 0601 0602 0603 def tearDown(self): 0604 self.txn.commit() 0605 BasicTestCase.tearDown(self) 0606 0607 0608 def populateDB(self): 0609 txn = self.env.txn_begin() 0610 BasicTestCase.populateDB(self, _txn=txn) 0611 0612 self.txn = self.env.txn_begin() 0613 0614 0615 0616 def test06_Transactions(self): 0617 d = self.d 0618 if verbose: 0619 print '\n', '-=' * 30 0620 print "Running %s.test06_Transactions..." % self.__class__.__name__ 0621 0622 assert d.get('new rec', txn=self.txn) == None 0623 d.put('new rec', 'this is a new record', self.txn) 0624 assert d.get('new rec', txn=self.txn) == 'this is a new record' 0625 self.txn.abort() 0626 assert d.get('new rec') == None 0627 0628 self.txn = self.env.txn_begin() 0629 0630 assert d.get('new rec', txn=self.txn) == None 0631 d.put('new rec', 'this is a new record', self.txn) 0632 assert d.get('new rec', txn=self.txn) == 'this is a new record' 0633 self.txn.commit() 0634 assert d.get('new rec') == 'this is a new record' 0635 0636 self.txn = self.env.txn_begin() 0637 c = d.cursor(self.txn) 0638 rec = c.first() 0639 count = 0 0640 while rec is not None: 0641 count = count + 1 0642 if verbose and count % 100 == 0: 0643 print rec 0644 rec = c.next() 0645 assert count == self._numKeys+1 0646 0647 c.close() # Cursors *MUST* be closed before commit! 0648 self.txn.commit() 0649 0650 # flush pending updates 0651 try: 0652 self.env.txn_checkpoint (0, 0, 0) 0653 except db.DBIncompleteError: 0654 pass 0655 0656 # must have at least one log file present: 0657 logs = self.env.log_archive(db.DB_ARCH_ABS | db.DB_ARCH_LOG) 0658 assert logs != None 0659 for log in logs: 0660 if verbose: 0661 print 'log file: ' + log 0662 0663 self.txn = self.env.txn_begin() 0664 0665 #---------------------------------------- 0666 0667 def test07_TxnTruncate(self): 0668 if db.version() < (3,3): 0669 # truncate is a feature of BerkeleyDB 3.3 and above 0670 return 0671 0672 d = self.d 0673 if verbose: 0674 print '\n', '-=' * 30 0675 print "Running %s.test07_TxnTruncate..." % self.__class__.__name__ 0676 0677 d.put("abcde", "ABCDE"); 0678 txn = self.env.txn_begin() 0679 num = d.truncate(txn) 0680 assert num >= 1, "truncate returned <= 0 on non-empty database" 0681 num = d.truncate(txn) 0682 assert num == 0, "truncate on empty DB returned nonzero (%r)" % (num,) 0683 txn.commit() 0684 0685 #---------------------------------------- 0686 0687 def test08_TxnLateUse(self): 0688 txn = self.env.txn_begin() 0689 txn.abort() 0690 try: 0691 txn.abort() 0692 except db.DBError, e: 0693 pass 0694 else: 0695 raise RuntimeError, "DBTxn.abort() called after DB_TXN no longer valid w/o an exception" 0696 0697 txn = self.env.txn_begin() 0698 txn.commit() 0699 try: 0700 txn.commit() 0701 except db.DBError, e: 0702 pass 0703 else: 0704 raise RuntimeError, "DBTxn.commit() called after DB_TXN no longer valid w/o an exception" 0705 0706 0707 class BTreeTransactionTestCase(BasicTransactionTestCase): 0708 dbtype = db.DB_BTREE 0709 0710 class HashTransactionTestCase(BasicTransactionTestCase): 0711 dbtype = db.DB_HASH 0712 0713 0714 0715 #---------------------------------------------------------------------- 0716 0717 class BTreeRecnoTestCase(BasicTestCase): 0718 dbtype = db.DB_BTREE 0719 dbsetflags = db.DB_RECNUM 0720 0721 def test07_RecnoInBTree(self): 0722 d = self.d 0723 if verbose: 0724 print '\n', '-=' * 30 0725 print "Running %s.test07_RecnoInBTree..." % self.__class__.__name__ 0726 0727 rec = d.get(200) 0728 assert type(rec) == type(()) 0729 assert len(rec) == 2 0730 if verbose: 0731 print "Record #200 is ", rec 0732 0733 c = d.cursor() 0734 c.set('0200') 0735 num = c.get_recno() 0736 assert type(num) == type(1) 0737 if verbose: 0738 print "recno of d['0200'] is ", num 0739 0740 rec = c.current() 0741 assert c.set_recno(num) == rec 0742 0743 c.close() 0744 0745 0746 0747 class BTreeRecnoWithThreadFlagTestCase(BTreeRecnoTestCase): 0748 dbopenflags = db.DB_THREAD 0749 0750 #---------------------------------------------------------------------- 0751 0752 class BasicDUPTestCase(BasicTestCase): 0753 dbsetflags = db.DB_DUP 0754 0755 def test08_DuplicateKeys(self): 0756 d = self.d 0757 if verbose: 0758 print '\n', '-=' * 30 0759 print "Running %s.test08_DuplicateKeys..." % \ 0760 self.__class__.__name__ 0761 0762 d.put("dup0", "before") 0763 for x in "The quick brown fox jumped over the lazy dog.".split(): 0764 d.put("dup1", x) 0765 d.put("dup2", "after") 0766 0767 data = d.get("dup1") 0768 assert data == "The" 0769 if verbose: 0770 print data 0771 0772 c = d.cursor() 0773 rec = c.set("dup1") 0774 assert rec == ('dup1', 'The') 0775 0776 next = c.next() 0777 assert next == ('dup1', 'quick') 0778 0779 rec = c.set("dup1") 0780 count = c.count() 0781 assert count == 9 0782 0783 next_dup = c.next_dup() 0784 assert next_dup == ('dup1', 'quick') 0785 0786 rec = c.set('dup1') 0787 while rec is not None: 0788 if verbose: 0789 print rec 0790 rec = c.next_dup() 0791 0792 c.set('dup1') 0793 rec = c.next_nodup() 0794 assert rec[0] != 'dup1' 0795 if verbose: 0796 print rec 0797 0798 c.close() 0799 0800 0801 0802 class BTreeDUPTestCase(BasicDUPTestCase): 0803 dbtype = db.DB_BTREE 0804 0805 class HashDUPTestCase(BasicDUPTestCase): 0806 dbtype = db.DB_HASH 0807 0808 class BTreeDUPWithThreadTestCase(BasicDUPTestCase): 0809 dbtype = db.DB_BTREE 0810 dbopenflags = db.DB_THREAD 0811 0812 class HashDUPWithThreadTestCase(BasicDUPTestCase): 0813 dbtype = db.DB_HASH 0814 dbopenflags = db.DB_THREAD 0815 0816 0817 #---------------------------------------------------------------------- 0818 0819 class BasicMultiDBTestCase(BasicTestCase): 0820 dbname = 'first' 0821 0822 def otherType(self): 0823 if self.dbtype == db.DB_BTREE: 0824 return db.DB_HASH 0825 else: 0826 return db.DB_BTREE 0827 0828 def test09_MultiDB(self): 0829 d1 = self.d 0830 if verbose: 0831 print '\n', '-=' * 30 0832 print "Running %s.test09_MultiDB..." % self.__class__.__name__ 0833 0834 d2 = db.DB(self.env) 0835 d2.open(self.filename, "second", self.dbtype, 0836 self.dbopenflags|db.DB_CREATE) 0837 d3 = db.DB(self.env) 0838 d3.open(self.filename, "third", self.otherType(), 0839 self.dbopenflags|db.DB_CREATE) 0840 0841 for x in "The quick brown fox jumped over the lazy dog".split(): 0842 d2.put(x, self.makeData(x)) 0843 0844 for x in string.letters: 0845 d3.put(x, x*70) 0846 0847 d1.sync() 0848 d2.sync() 0849 d3.sync() 0850 d1.close() 0851 d2.close() 0852 d3.close() 0853 0854 self.d = d1 = d2 = d3 = None 0855 0856 self.d = d1 = db.DB(self.env) 0857 d1.open(self.filename, self.dbname, flags = self.dbopenflags) 0858 d2 = db.DB(self.env) 0859 d2.open(self.filename, "second", flags = self.dbopenflags) 0860 d3 = db.DB(self.env) 0861 d3.open(self.filename, "third", flags = self.dbopenflags) 0862 0863 c1 = d1.cursor() 0864 c2 = d2.cursor() 0865 c3 = d3.cursor() 0866 0867 count = 0 0868 rec = c1.first() 0869 while rec is not None: 0870 count = count + 1 0871 if verbose and (count % 50) == 0: 0872 print rec 0873 rec = c1.next() 0874 assert count == self._numKeys 0875 0876 count = 0 0877 rec = c2.first() 0878 while rec is not None: 0879 count = count + 1 0880 if verbose: 0881 print rec 0882 rec = c2.next() 0883 assert count == 9 0884 0885 count = 0 0886 rec = c3.first() 0887 while rec is not None: 0888 count = count + 1 0889 if verbose: 0890 print rec 0891 rec = c3.next() 0892 assert count == 52 0893 0894 0895 c1.close() 0896 c2.close() 0897 c3.close() 0898 0899 d2.close() 0900 d3.close() 0901 0902 0903 0904 # Strange things happen if you try to use Multiple DBs per file without a 0905 # DBEnv with MPOOL and LOCKing... 0906 0907 class BTreeMultiDBTestCase(BasicMultiDBTestCase): 0908 dbtype = db.DB_BTREE 0909 dbopenflags = db.DB_THREAD 0910 useEnv = 1 0911 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK 0912 0913 class HashMultiDBTestCase(BasicMultiDBTestCase): 0914 dbtype = db.DB_HASH 0915 dbopenflags = db.DB_THREAD 0916 useEnv = 1 0917 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK 0918 0919 0920 #---------------------------------------------------------------------- 0921 #---------------------------------------------------------------------- 0922 0923 def test_suite(): 0924 suite = unittest.TestSuite() 0925 0926 suite.addTest(unittest.makeSuite(VersionTestCase)) 0927 suite.addTest(unittest.makeSuite(BasicBTreeTestCase)) 0928 suite.addTest(unittest.makeSuite(BasicHashTestCase)) 0929 suite.addTest(unittest.makeSuite(BasicBTreeWithThreadFlagTestCase)) 0930 suite.addTest(unittest.makeSuite(BasicHashWithThreadFlagTestCase)) 0931 suite.addTest(unittest.makeSuite(BasicBTreeWithEnvTestCase)) 0932 suite.addTest(unittest.makeSuite(BasicHashWithEnvTestCase)) 0933 suite.addTest(unittest.makeSuite(BTreeTransactionTestCase)) 0934 suite.addTest(unittest.makeSuite(HashTransactionTestCase)) 0935 suite.addTest(unittest.makeSuite(BTreeRecnoTestCase)) 0936 suite.addTest(unittest.makeSuite(BTreeRecnoWithThreadFlagTestCase)) 0937 suite.addTest(unittest.makeSuite(BTreeDUPTestCase)) 0938 suite.addTest(unittest.makeSuite(HashDUPTestCase)) 0939 suite.addTest(unittest.makeSuite(BTreeDUPWithThreadTestCase)) 0940 suite.addTest(unittest.makeSuite(HashDUPWithThreadTestCase)) 0941 suite.addTest(unittest.makeSuite(BTreeMultiDBTestCase)) 0942 suite.addTest(unittest.makeSuite(HashMultiDBTestCase)) 0943 0944 return suite 0945 0946 0947 if __name__ == '__main__': 0948 unittest.main(defaultTest='test_suite') 0949
Generated by PyXR 0.9.4