Credit Nir Aides for r77288
[python.git] / Lib / bsddb / test / test_basics.py
blob0be76dbb5fd68063336542234e2cb009ba87fc7c
1 """
2 Basic TestCases for BTree and hash DBs, with and without a DBEnv, with
3 various DB flags, etc.
4 """
6 import os
7 import errno
8 import string
9 from pprint import pprint
10 import unittest
11 import time
13 from test_all import db, test_support, verbose, get_new_environment_path, \
14 get_new_database_path
16 DASH = '-'
19 #----------------------------------------------------------------------
21 class VersionTestCase(unittest.TestCase):
22 def test00_version(self):
23 info = db.version()
24 if verbose:
25 print '\n', '-=' * 20
26 print 'bsddb.db.version(): %s' % (info, )
27 print db.DB_VERSION_STRING
28 print '-=' * 20
29 self.assertEqual(info, (db.DB_VERSION_MAJOR, db.DB_VERSION_MINOR,
30 db.DB_VERSION_PATCH))
32 #----------------------------------------------------------------------
34 class BasicTestCase(unittest.TestCase):
35 dbtype = db.DB_UNKNOWN # must be set in derived class
36 dbopenflags = 0
37 dbsetflags = 0
38 dbmode = 0660
39 dbname = None
40 useEnv = 0
41 envflags = 0
42 envsetflags = 0
44 _numKeys = 1002 # PRIVATE. NOTE: must be an even value
46 def setUp(self):
47 if self.useEnv:
48 self.homeDir=get_new_environment_path()
49 try:
50 self.env = db.DBEnv()
51 self.env.set_lg_max(1024*1024)
52 self.env.set_tx_max(30)
53 self.env.set_tx_timestamp(int(time.time()))
54 self.env.set_flags(self.envsetflags, 1)
55 self.env.open(self.homeDir, self.envflags | db.DB_CREATE)
56 self.filename = "test"
57 # Yes, a bare except is intended, since we're re-raising the exc.
58 except:
59 test_support.rmtree(self.homeDir)
60 raise
61 else:
62 self.env = None
63 self.filename = get_new_database_path()
65 # create and open the DB
66 self.d = db.DB(self.env)
67 self.d.set_flags(self.dbsetflags)
68 if self.dbname:
69 self.d.open(self.filename, self.dbname, self.dbtype,
70 self.dbopenflags|db.DB_CREATE, self.dbmode)
71 else:
72 self.d.open(self.filename, # try out keyword args
73 mode = self.dbmode,
74 dbtype = self.dbtype,
75 flags = self.dbopenflags|db.DB_CREATE)
77 self.populateDB()
80 def tearDown(self):
81 self.d.close()
82 if self.env is not None:
83 self.env.close()
84 test_support.rmtree(self.homeDir)
85 else:
86 os.remove(self.filename)
90 def populateDB(self, _txn=None):
91 d = self.d
93 for x in range(self._numKeys//2):
94 key = '%04d' % (self._numKeys - x) # insert keys in reverse order
95 data = self.makeData(key)
96 d.put(key, data, _txn)
98 d.put('empty value', '', _txn)
100 for x in range(self._numKeys//2-1):
101 key = '%04d' % x # and now some in forward order
102 data = self.makeData(key)
103 d.put(key, data, _txn)
105 if _txn:
106 _txn.commit()
108 num = len(d)
109 if verbose:
110 print "created %d records" % num
113 def makeData(self, key):
114 return DASH.join([key] * 5)
118 #----------------------------------------
120 def test01_GetsAndPuts(self):
121 d = self.d
123 if verbose:
124 print '\n', '-=' * 30
125 print "Running %s.test01_GetsAndPuts..." % self.__class__.__name__
127 for key in ['0001', '0100', '0400', '0700', '0999']:
128 data = d.get(key)
129 if verbose:
130 print data
132 self.assertEqual(d.get('0321'), '0321-0321-0321-0321-0321')
134 # By default non-existent keys return None...
135 self.assertEqual(d.get('abcd'), None)
137 # ...but they raise exceptions in other situations. Call
138 # set_get_returns_none() to change it.
139 try:
140 d.delete('abcd')
141 except db.DBNotFoundError, val:
142 import sys
143 if sys.version_info[0] < 3 :
144 self.assertEqual(val[0], db.DB_NOTFOUND)
145 else :
146 self.assertEqual(val.args[0], db.DB_NOTFOUND)
147 if verbose: print val
148 else:
149 self.fail("expected exception")
152 d.put('abcd', 'a new record')
153 self.assertEqual(d.get('abcd'), 'a new record')
155 d.put('abcd', 'same key')
156 if self.dbsetflags & db.DB_DUP:
157 self.assertEqual(d.get('abcd'), 'a new record')
158 else:
159 self.assertEqual(d.get('abcd'), 'same key')
162 try:
163 d.put('abcd', 'this should fail', flags=db.DB_NOOVERWRITE)
164 except db.DBKeyExistError, val:
165 import sys
166 if sys.version_info[0] < 3 :
167 self.assertEqual(val[0], db.DB_KEYEXIST)
168 else :
169 self.assertEqual(val.args[0], db.DB_KEYEXIST)
170 if verbose: print val
171 else:
172 self.fail("expected exception")
174 if self.dbsetflags & db.DB_DUP:
175 self.assertEqual(d.get('abcd'), 'a new record')
176 else:
177 self.assertEqual(d.get('abcd'), 'same key')
180 d.sync()
181 d.close()
182 del d
184 self.d = db.DB(self.env)
185 if self.dbname:
186 self.d.open(self.filename, self.dbname)
187 else:
188 self.d.open(self.filename)
189 d = self.d
191 self.assertEqual(d.get('0321'), '0321-0321-0321-0321-0321')
192 if self.dbsetflags & db.DB_DUP:
193 self.assertEqual(d.get('abcd'), 'a new record')
194 else:
195 self.assertEqual(d.get('abcd'), 'same key')
197 rec = d.get_both('0555', '0555-0555-0555-0555-0555')
198 if verbose:
199 print rec
201 self.assertEqual(d.get_both('0555', 'bad data'), None)
203 # test default value
204 data = d.get('bad key', 'bad data')
205 self.assertEqual(data, 'bad data')
207 # any object can pass through
208 data = d.get('bad key', self)
209 self.assertEqual(data, self)
211 s = d.stat()
212 self.assertEqual(type(s), type({}))
213 if verbose:
214 print 'd.stat() returned this dictionary:'
215 pprint(s)
218 #----------------------------------------
220 def test02_DictionaryMethods(self):
221 d = self.d
223 if verbose:
224 print '\n', '-=' * 30
225 print "Running %s.test02_DictionaryMethods..." % \
226 self.__class__.__name__
228 for key in ['0002', '0101', '0401', '0701', '0998']:
229 data = d[key]
230 self.assertEqual(data, self.makeData(key))
231 if verbose:
232 print data
234 self.assertEqual(len(d), self._numKeys)
235 keys = d.keys()
236 self.assertEqual(len(keys), self._numKeys)
237 self.assertEqual(type(keys), type([]))
239 d['new record'] = 'a new record'
240 self.assertEqual(len(d), self._numKeys+1)
241 keys = d.keys()
242 self.assertEqual(len(keys), self._numKeys+1)
244 d['new record'] = 'a replacement record'
245 self.assertEqual(len(d), self._numKeys+1)
246 keys = d.keys()
247 self.assertEqual(len(keys), self._numKeys+1)
249 if verbose:
250 print "the first 10 keys are:"
251 pprint(keys[:10])
253 self.assertEqual(d['new record'], 'a replacement record')
255 # We check also the positional parameter
256 self.assertEqual(d.has_key('0001', None), 1)
257 # We check also the keyword parameter
258 self.assertEqual(d.has_key('spam', txn=None), 0)
260 items = d.items()
261 self.assertEqual(len(items), self._numKeys+1)
262 self.assertEqual(type(items), type([]))
263 self.assertEqual(type(items[0]), type(()))
264 self.assertEqual(len(items[0]), 2)
266 if verbose:
267 print "the first 10 items are:"
268 pprint(items[:10])
270 values = d.values()
271 self.assertEqual(len(values), self._numKeys+1)
272 self.assertEqual(type(values), type([]))
274 if verbose:
275 print "the first 10 values are:"
276 pprint(values[:10])
280 #----------------------------------------
282 def test03_SimpleCursorStuff(self, get_raises_error=0, set_raises_error=0):
283 if verbose:
284 print '\n', '-=' * 30
285 print "Running %s.test03_SimpleCursorStuff (get_error %s, set_error %s)..." % \
286 (self.__class__.__name__, get_raises_error, set_raises_error)
288 if self.env and self.dbopenflags & db.DB_AUTO_COMMIT:
289 txn = self.env.txn_begin()
290 else:
291 txn = None
292 c = self.d.cursor(txn=txn)
294 rec = c.first()
295 count = 0
296 while rec is not None:
297 count = count + 1
298 if verbose and count % 100 == 0:
299 print rec
300 try:
301 rec = c.next()
302 except db.DBNotFoundError, val:
303 if get_raises_error:
304 import sys
305 if sys.version_info[0] < 3 :
306 self.assertEqual(val[0], db.DB_NOTFOUND)
307 else :
308 self.assertEqual(val.args[0], db.DB_NOTFOUND)
309 if verbose: print val
310 rec = None
311 else:
312 self.fail("unexpected DBNotFoundError")
313 self.assertEqual(c.get_current_size(), len(c.current()[1]),
314 "%s != len(%r)" % (c.get_current_size(), c.current()[1]))
316 self.assertEqual(count, self._numKeys)
319 rec = c.last()
320 count = 0
321 while rec is not None:
322 count = count + 1
323 if verbose and count % 100 == 0:
324 print rec
325 try:
326 rec = c.prev()
327 except db.DBNotFoundError, val:
328 if get_raises_error:
329 import sys
330 if sys.version_info[0] < 3 :
331 self.assertEqual(val[0], db.DB_NOTFOUND)
332 else :
333 self.assertEqual(val.args[0], db.DB_NOTFOUND)
334 if verbose: print val
335 rec = None
336 else:
337 self.fail("unexpected DBNotFoundError")
339 self.assertEqual(count, self._numKeys)
341 rec = c.set('0505')
342 rec2 = c.current()
343 self.assertEqual(rec, rec2)
344 self.assertEqual(rec[0], '0505')
345 self.assertEqual(rec[1], self.makeData('0505'))
346 self.assertEqual(c.get_current_size(), len(rec[1]))
348 # make sure we get empty values properly
349 rec = c.set('empty value')
350 self.assertEqual(rec[1], '')
351 self.assertEqual(c.get_current_size(), 0)
353 try:
354 n = c.set('bad key')
355 except db.DBNotFoundError, val:
356 import sys
357 if sys.version_info[0] < 3 :
358 self.assertEqual(val[0], db.DB_NOTFOUND)
359 else :
360 self.assertEqual(val.args[0], db.DB_NOTFOUND)
361 if verbose: print val
362 else:
363 if set_raises_error:
364 self.fail("expected exception")
365 if n != None:
366 self.fail("expected None: %r" % (n,))
368 rec = c.get_both('0404', self.makeData('0404'))
369 self.assertEqual(rec, ('0404', self.makeData('0404')))
371 try:
372 n = c.get_both('0404', 'bad data')
373 except db.DBNotFoundError, val:
374 import sys
375 if sys.version_info[0] < 3 :
376 self.assertEqual(val[0], db.DB_NOTFOUND)
377 else :
378 self.assertEqual(val.args[0], db.DB_NOTFOUND)
379 if verbose: print val
380 else:
381 if get_raises_error:
382 self.fail("expected exception")
383 if n != None:
384 self.fail("expected None: %r" % (n,))
386 if self.d.get_type() == db.DB_BTREE:
387 rec = c.set_range('011')
388 if verbose:
389 print "searched for '011', found: ", rec
391 rec = c.set_range('011',dlen=0,doff=0)
392 if verbose:
393 print "searched (partial) for '011', found: ", rec
394 if rec[1] != '': self.fail('expected empty data portion')
396 ev = c.set_range('empty value')
397 if verbose:
398 print "search for 'empty value' returned", ev
399 if ev[1] != '': self.fail('empty value lookup failed')
401 c.set('0499')
402 c.delete()
403 try:
404 rec = c.current()
405 except db.DBKeyEmptyError, val:
406 if get_raises_error:
407 import sys
408 if sys.version_info[0] < 3 :
409 self.assertEqual(val[0], db.DB_KEYEMPTY)
410 else :
411 self.assertEqual(val.args[0], db.DB_KEYEMPTY)
412 if verbose: print val
413 else:
414 self.fail("unexpected DBKeyEmptyError")
415 else:
416 if get_raises_error:
417 self.fail('DBKeyEmptyError exception expected')
419 c.next()
420 c2 = c.dup(db.DB_POSITION)
421 self.assertEqual(c.current(), c2.current())
423 c2.put('', 'a new value', db.DB_CURRENT)
424 self.assertEqual(c.current(), c2.current())
425 self.assertEqual(c.current()[1], 'a new value')
427 c2.put('', 'er', db.DB_CURRENT, dlen=0, doff=5)
428 self.assertEqual(c2.current()[1], 'a newer value')
430 c.close()
431 c2.close()
432 if txn:
433 txn.commit()
435 # time to abuse the closed cursors and hope we don't crash
436 methods_to_test = {
437 'current': (),
438 'delete': (),
439 'dup': (db.DB_POSITION,),
440 'first': (),
441 'get': (0,),
442 'next': (),
443 'prev': (),
444 'last': (),
445 'put':('', 'spam', db.DB_CURRENT),
446 'set': ("0505",),
448 for method, args in methods_to_test.items():
449 try:
450 if verbose:
451 print "attempting to use a closed cursor's %s method" % \
452 method
453 # a bug may cause a NULL pointer dereference...
454 apply(getattr(c, method), args)
455 except db.DBError, val:
456 import sys
457 if sys.version_info[0] < 3 :
458 self.assertEqual(val[0], 0)
459 else :
460 self.assertEqual(val.args[0], 0)
461 if verbose: print val
462 else:
463 self.fail("no exception raised when using a buggy cursor's"
464 "%s method" % method)
467 # free cursor referencing a closed database, it should not barf:
469 oldcursor = self.d.cursor(txn=txn)
470 self.d.close()
472 # this would originally cause a segfault when the cursor for a
473 # closed database was cleaned up. it should not anymore.
474 # SF pybsddb bug id 667343
475 del oldcursor
477 def test03b_SimpleCursorWithoutGetReturnsNone0(self):
478 # same test but raise exceptions instead of returning None
479 if verbose:
480 print '\n', '-=' * 30
481 print "Running %s.test03b_SimpleCursorStuffWithoutGetReturnsNone..." % \
482 self.__class__.__name__
484 old = self.d.set_get_returns_none(0)
485 self.assertEqual(old, 2)
486 self.test03_SimpleCursorStuff(get_raises_error=1, set_raises_error=1)
488 def test03b_SimpleCursorWithGetReturnsNone1(self):
489 # same test but raise exceptions instead of returning None
490 if verbose:
491 print '\n', '-=' * 30
492 print "Running %s.test03b_SimpleCursorStuffWithoutGetReturnsNone..." % \
493 self.__class__.__name__
495 old = self.d.set_get_returns_none(1)
496 self.test03_SimpleCursorStuff(get_raises_error=0, set_raises_error=1)
499 def test03c_SimpleCursorGetReturnsNone2(self):
500 # same test but raise exceptions instead of returning None
501 if verbose:
502 print '\n', '-=' * 30
503 print "Running %s.test03c_SimpleCursorStuffWithoutSetReturnsNone..." % \
504 self.__class__.__name__
506 old = self.d.set_get_returns_none(1)
507 self.assertEqual(old, 2)
508 old = self.d.set_get_returns_none(2)
509 self.assertEqual(old, 1)
510 self.test03_SimpleCursorStuff(get_raises_error=0, set_raises_error=0)
512 #----------------------------------------
514 def test04_PartialGetAndPut(self):
515 d = self.d
516 if verbose:
517 print '\n', '-=' * 30
518 print "Running %s.test04_PartialGetAndPut..." % \
519 self.__class__.__name__
521 key = "partialTest"
522 data = "1" * 1000 + "2" * 1000
523 d.put(key, data)
524 self.assertEqual(d.get(key), data)
525 self.assertEqual(d.get(key, dlen=20, doff=990),
526 ("1" * 10) + ("2" * 10))
528 d.put("partialtest2", ("1" * 30000) + "robin" )
529 self.assertEqual(d.get("partialtest2", dlen=5, doff=30000), "robin")
531 # There seems to be a bug in DB here... Commented out the test for
532 # now.
533 ##self.assertEqual(d.get("partialtest2", dlen=5, doff=30010), "")
535 if self.dbsetflags != db.DB_DUP:
536 # Partial put with duplicate records requires a cursor
537 d.put(key, "0000", dlen=2000, doff=0)
538 self.assertEqual(d.get(key), "0000")
540 d.put(key, "1111", dlen=1, doff=2)
541 self.assertEqual(d.get(key), "0011110")
543 #----------------------------------------
545 def test05_GetSize(self):
546 d = self.d
547 if verbose:
548 print '\n', '-=' * 30
549 print "Running %s.test05_GetSize..." % self.__class__.__name__
551 for i in range(1, 50000, 500):
552 key = "size%s" % i
553 #print "before ", i,
554 d.put(key, "1" * i)
555 #print "after",
556 self.assertEqual(d.get_size(key), i)
557 #print "done"
559 #----------------------------------------
561 def test06_Truncate(self):
562 d = self.d
563 if verbose:
564 print '\n', '-=' * 30
565 print "Running %s.test99_Truncate..." % self.__class__.__name__
567 d.put("abcde", "ABCDE");
568 num = d.truncate()
569 self.assert_(num >= 1, "truncate returned <= 0 on non-empty database")
570 num = d.truncate()
571 self.assertEqual(num, 0,
572 "truncate on empty DB returned nonzero (%r)" % (num,))
574 #----------------------------------------
576 def test07_verify(self):
577 # Verify bug solved in 4.7.3pre8
578 self.d.close()
579 d = db.DB(self.env)
580 d.verify(self.filename)
583 #----------------------------------------
586 #----------------------------------------------------------------------
589 class BasicBTreeTestCase(BasicTestCase):
590 dbtype = db.DB_BTREE
593 class BasicHashTestCase(BasicTestCase):
594 dbtype = db.DB_HASH
597 class BasicBTreeWithThreadFlagTestCase(BasicTestCase):
598 dbtype = db.DB_BTREE
599 dbopenflags = db.DB_THREAD
602 class BasicHashWithThreadFlagTestCase(BasicTestCase):
603 dbtype = db.DB_HASH
604 dbopenflags = db.DB_THREAD
607 class BasicWithEnvTestCase(BasicTestCase):
608 dbopenflags = db.DB_THREAD
609 useEnv = 1
610 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
612 #----------------------------------------
614 def test08_EnvRemoveAndRename(self):
615 if not self.env:
616 return
618 if verbose:
619 print '\n', '-=' * 30
620 print "Running %s.test08_EnvRemoveAndRename..." % self.__class__.__name__
622 # can't rename or remove an open DB
623 self.d.close()
625 newname = self.filename + '.renamed'
626 self.env.dbrename(self.filename, None, newname)
627 self.env.dbremove(newname)
629 # dbremove and dbrename are in 4.1 and later
630 if db.version() < (4,1):
631 del test08_EnvRemoveAndRename
633 #----------------------------------------
635 class BasicBTreeWithEnvTestCase(BasicWithEnvTestCase):
636 dbtype = db.DB_BTREE
639 class BasicHashWithEnvTestCase(BasicWithEnvTestCase):
640 dbtype = db.DB_HASH
643 #----------------------------------------------------------------------
645 class BasicTransactionTestCase(BasicTestCase):
646 import sys
647 if sys.version_info[:3] < (2, 4, 0):
648 def assertTrue(self, expr, msg=None):
649 self.failUnless(expr,msg=msg)
651 dbopenflags = db.DB_THREAD | db.DB_AUTO_COMMIT
652 useEnv = 1
653 envflags = (db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK |
654 db.DB_INIT_TXN)
655 envsetflags = db.DB_AUTO_COMMIT
658 def tearDown(self):
659 self.txn.commit()
660 BasicTestCase.tearDown(self)
663 def populateDB(self):
664 txn = self.env.txn_begin()
665 BasicTestCase.populateDB(self, _txn=txn)
667 self.txn = self.env.txn_begin()
670 def test06_Transactions(self):
671 d = self.d
672 if verbose:
673 print '\n', '-=' * 30
674 print "Running %s.test06_Transactions..." % self.__class__.__name__
676 self.assertEqual(d.get('new rec', txn=self.txn), None)
677 d.put('new rec', 'this is a new record', self.txn)
678 self.assertEqual(d.get('new rec', txn=self.txn),
679 'this is a new record')
680 self.txn.abort()
681 self.assertEqual(d.get('new rec'), None)
683 self.txn = self.env.txn_begin()
685 self.assertEqual(d.get('new rec', txn=self.txn), None)
686 d.put('new rec', 'this is a new record', self.txn)
687 self.assertEqual(d.get('new rec', txn=self.txn),
688 'this is a new record')
689 self.txn.commit()
690 self.assertEqual(d.get('new rec'), 'this is a new record')
692 self.txn = self.env.txn_begin()
693 c = d.cursor(self.txn)
694 rec = c.first()
695 count = 0
696 while rec is not None:
697 count = count + 1
698 if verbose and count % 100 == 0:
699 print rec
700 rec = c.next()
701 self.assertEqual(count, self._numKeys+1)
703 c.close() # Cursors *MUST* be closed before commit!
704 self.txn.commit()
706 # flush pending updates
707 try:
708 self.env.txn_checkpoint (0, 0, 0)
709 except db.DBIncompleteError:
710 pass
712 statDict = self.env.log_stat(0);
713 self.assert_(statDict.has_key('magic'))
714 self.assert_(statDict.has_key('version'))
715 self.assert_(statDict.has_key('cur_file'))
716 self.assert_(statDict.has_key('region_nowait'))
718 # must have at least one log file present:
719 logs = self.env.log_archive(db.DB_ARCH_ABS | db.DB_ARCH_LOG)
720 self.assertNotEqual(logs, None)
721 for log in logs:
722 if verbose:
723 print 'log file: ' + log
724 if db.version() >= (4,2):
725 logs = self.env.log_archive(db.DB_ARCH_REMOVE)
726 self.assertTrue(not logs)
728 self.txn = self.env.txn_begin()
730 #----------------------------------------
732 def test08_TxnTruncate(self):
733 d = self.d
734 if verbose:
735 print '\n', '-=' * 30
736 print "Running %s.test08_TxnTruncate..." % self.__class__.__name__
738 d.put("abcde", "ABCDE");
739 txn = self.env.txn_begin()
740 num = d.truncate(txn)
741 self.assert_(num >= 1, "truncate returned <= 0 on non-empty database")
742 num = d.truncate(txn)
743 self.assertEqual(num, 0,
744 "truncate on empty DB returned nonzero (%r)" % (num,))
745 txn.commit()
747 #----------------------------------------
749 def test09_TxnLateUse(self):
750 txn = self.env.txn_begin()
751 txn.abort()
752 try:
753 txn.abort()
754 except db.DBError, e:
755 pass
756 else:
757 raise RuntimeError, "DBTxn.abort() called after DB_TXN no longer valid w/o an exception"
759 txn = self.env.txn_begin()
760 txn.commit()
761 try:
762 txn.commit()
763 except db.DBError, e:
764 pass
765 else:
766 raise RuntimeError, "DBTxn.commit() called after DB_TXN no longer valid w/o an exception"
769 class BTreeTransactionTestCase(BasicTransactionTestCase):
770 dbtype = db.DB_BTREE
772 class HashTransactionTestCase(BasicTransactionTestCase):
773 dbtype = db.DB_HASH
777 #----------------------------------------------------------------------
779 class BTreeRecnoTestCase(BasicTestCase):
780 dbtype = db.DB_BTREE
781 dbsetflags = db.DB_RECNUM
783 def test08_RecnoInBTree(self):
784 d = self.d
785 if verbose:
786 print '\n', '-=' * 30
787 print "Running %s.test08_RecnoInBTree..." % self.__class__.__name__
789 rec = d.get(200)
790 self.assertEqual(type(rec), type(()))
791 self.assertEqual(len(rec), 2)
792 if verbose:
793 print "Record #200 is ", rec
795 c = d.cursor()
796 c.set('0200')
797 num = c.get_recno()
798 self.assertEqual(type(num), type(1))
799 if verbose:
800 print "recno of d['0200'] is ", num
802 rec = c.current()
803 self.assertEqual(c.set_recno(num), rec)
805 c.close()
809 class BTreeRecnoWithThreadFlagTestCase(BTreeRecnoTestCase):
810 dbopenflags = db.DB_THREAD
812 #----------------------------------------------------------------------
814 class BasicDUPTestCase(BasicTestCase):
815 dbsetflags = db.DB_DUP
817 def test09_DuplicateKeys(self):
818 d = self.d
819 if verbose:
820 print '\n', '-=' * 30
821 print "Running %s.test09_DuplicateKeys..." % \
822 self.__class__.__name__
824 d.put("dup0", "before")
825 for x in "The quick brown fox jumped over the lazy dog.".split():
826 d.put("dup1", x)
827 d.put("dup2", "after")
829 data = d.get("dup1")
830 self.assertEqual(data, "The")
831 if verbose:
832 print data
834 c = d.cursor()
835 rec = c.set("dup1")
836 self.assertEqual(rec, ('dup1', 'The'))
838 next_reg = c.next()
839 self.assertEqual(next_reg, ('dup1', 'quick'))
841 rec = c.set("dup1")
842 count = c.count()
843 self.assertEqual(count, 9)
845 next_dup = c.next_dup()
846 self.assertEqual(next_dup, ('dup1', 'quick'))
848 rec = c.set('dup1')
849 while rec is not None:
850 if verbose:
851 print rec
852 rec = c.next_dup()
854 c.set('dup1')
855 rec = c.next_nodup()
856 self.assertNotEqual(rec[0], 'dup1')
857 if verbose:
858 print rec
860 c.close()
864 class BTreeDUPTestCase(BasicDUPTestCase):
865 dbtype = db.DB_BTREE
867 class HashDUPTestCase(BasicDUPTestCase):
868 dbtype = db.DB_HASH
870 class BTreeDUPWithThreadTestCase(BasicDUPTestCase):
871 dbtype = db.DB_BTREE
872 dbopenflags = db.DB_THREAD
874 class HashDUPWithThreadTestCase(BasicDUPTestCase):
875 dbtype = db.DB_HASH
876 dbopenflags = db.DB_THREAD
879 #----------------------------------------------------------------------
881 class BasicMultiDBTestCase(BasicTestCase):
882 dbname = 'first'
884 def otherType(self):
885 if self.dbtype == db.DB_BTREE:
886 return db.DB_HASH
887 else:
888 return db.DB_BTREE
890 def test10_MultiDB(self):
891 d1 = self.d
892 if verbose:
893 print '\n', '-=' * 30
894 print "Running %s.test10_MultiDB..." % self.__class__.__name__
896 d2 = db.DB(self.env)
897 d2.open(self.filename, "second", self.dbtype,
898 self.dbopenflags|db.DB_CREATE)
899 d3 = db.DB(self.env)
900 d3.open(self.filename, "third", self.otherType(),
901 self.dbopenflags|db.DB_CREATE)
903 for x in "The quick brown fox jumped over the lazy dog".split():
904 d2.put(x, self.makeData(x))
906 for x in string.letters:
907 d3.put(x, x*70)
909 d1.sync()
910 d2.sync()
911 d3.sync()
912 d1.close()
913 d2.close()
914 d3.close()
916 self.d = d1 = d2 = d3 = None
918 self.d = d1 = db.DB(self.env)
919 d1.open(self.filename, self.dbname, flags = self.dbopenflags)
920 d2 = db.DB(self.env)
921 d2.open(self.filename, "second", flags = self.dbopenflags)
922 d3 = db.DB(self.env)
923 d3.open(self.filename, "third", flags = self.dbopenflags)
925 c1 = d1.cursor()
926 c2 = d2.cursor()
927 c3 = d3.cursor()
929 count = 0
930 rec = c1.first()
931 while rec is not None:
932 count = count + 1
933 if verbose and (count % 50) == 0:
934 print rec
935 rec = c1.next()
936 self.assertEqual(count, self._numKeys)
938 count = 0
939 rec = c2.first()
940 while rec is not None:
941 count = count + 1
942 if verbose:
943 print rec
944 rec = c2.next()
945 self.assertEqual(count, 9)
947 count = 0
948 rec = c3.first()
949 while rec is not None:
950 count = count + 1
951 if verbose:
952 print rec
953 rec = c3.next()
954 self.assertEqual(count, len(string.letters))
957 c1.close()
958 c2.close()
959 c3.close()
961 d2.close()
962 d3.close()
966 # Strange things happen if you try to use Multiple DBs per file without a
967 # DBEnv with MPOOL and LOCKing...
969 class BTreeMultiDBTestCase(BasicMultiDBTestCase):
970 dbtype = db.DB_BTREE
971 dbopenflags = db.DB_THREAD
972 useEnv = 1
973 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
975 class HashMultiDBTestCase(BasicMultiDBTestCase):
976 dbtype = db.DB_HASH
977 dbopenflags = db.DB_THREAD
978 useEnv = 1
979 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
982 class PrivateObject(unittest.TestCase) :
983 import sys
984 if sys.version_info[:3] < (2, 4, 0):
985 def assertTrue(self, expr, msg=None):
986 self.failUnless(expr,msg=msg)
988 def tearDown(self) :
989 del self.obj
991 def test01_DefaultIsNone(self) :
992 self.assertEqual(self.obj.get_private(), None)
994 def test02_assignment(self) :
995 a = "example of private object"
996 self.obj.set_private(a)
997 b = self.obj.get_private()
998 self.assertTrue(a is b) # Object identity
1000 def test03_leak_assignment(self) :
1001 import sys
1002 a = "example of private object"
1003 refcount = sys.getrefcount(a)
1004 self.obj.set_private(a)
1005 self.assertEqual(refcount+1, sys.getrefcount(a))
1006 self.obj.set_private(None)
1007 self.assertEqual(refcount, sys.getrefcount(a))
1009 def test04_leak_GC(self) :
1010 import sys
1011 a = "example of private object"
1012 refcount = sys.getrefcount(a)
1013 self.obj.set_private(a)
1014 self.obj = None
1015 self.assertEqual(refcount, sys.getrefcount(a))
1017 class DBEnvPrivateObject(PrivateObject) :
1018 def setUp(self) :
1019 self.obj = db.DBEnv()
1021 class DBPrivateObject(PrivateObject) :
1022 def setUp(self) :
1023 self.obj = db.DB()
1025 class CrashAndBurn(unittest.TestCase) :
1026 import sys
1027 if sys.version_info[:3] < (2, 4, 0):
1028 def assertTrue(self, expr, msg=None):
1029 self.failUnless(expr,msg=msg)
1031 #def test01_OpenCrash(self) :
1032 # # See http://bugs.python.org/issue3307
1033 # self.assertRaises(db.DBInvalidArgError, db.DB, None, 65535)
1035 def test02_DBEnv_dealloc(self):
1036 # http://bugs.python.org/issue3885
1037 import gc
1038 self.assertRaises(db.DBInvalidArgError, db.DBEnv, ~db.DB_RPCCLIENT)
1039 gc.collect()
1042 #----------------------------------------------------------------------
1043 #----------------------------------------------------------------------
1045 def test_suite():
1046 suite = unittest.TestSuite()
1048 suite.addTest(unittest.makeSuite(VersionTestCase))
1049 suite.addTest(unittest.makeSuite(BasicBTreeTestCase))
1050 suite.addTest(unittest.makeSuite(BasicHashTestCase))
1051 suite.addTest(unittest.makeSuite(BasicBTreeWithThreadFlagTestCase))
1052 suite.addTest(unittest.makeSuite(BasicHashWithThreadFlagTestCase))
1053 suite.addTest(unittest.makeSuite(BasicBTreeWithEnvTestCase))
1054 suite.addTest(unittest.makeSuite(BasicHashWithEnvTestCase))
1055 suite.addTest(unittest.makeSuite(BTreeTransactionTestCase))
1056 suite.addTest(unittest.makeSuite(HashTransactionTestCase))
1057 suite.addTest(unittest.makeSuite(BTreeRecnoTestCase))
1058 suite.addTest(unittest.makeSuite(BTreeRecnoWithThreadFlagTestCase))
1059 suite.addTest(unittest.makeSuite(BTreeDUPTestCase))
1060 suite.addTest(unittest.makeSuite(HashDUPTestCase))
1061 suite.addTest(unittest.makeSuite(BTreeDUPWithThreadTestCase))
1062 suite.addTest(unittest.makeSuite(HashDUPWithThreadTestCase))
1063 suite.addTest(unittest.makeSuite(BTreeMultiDBTestCase))
1064 suite.addTest(unittest.makeSuite(HashMultiDBTestCase))
1065 suite.addTest(unittest.makeSuite(DBEnvPrivateObject))
1066 suite.addTest(unittest.makeSuite(DBPrivateObject))
1067 suite.addTest(unittest.makeSuite(CrashAndBurn))
1069 return suite
1072 if __name__ == '__main__':
1073 unittest.main(defaultTest='test_suite')