source: python/trunk/Lib/bsddb/test/test_basics.py

Last change on this file was 391, checked in by dmik, 11 years ago

python: Merge vendor 2.7.6 to trunk.

  • Property svn:eol-style set to native
File size: 35.4 KB
Line 
1"""
2Basic TestCases for BTree and hash DBs, with and without a DBEnv, with
3various DB flags, etc.
4"""
5
6import os
7import errno
8import string
9from pprint import pprint
10import unittest
11import time
12import sys
13
14from test_all import db, test_support, verbose, get_new_environment_path, \
15 get_new_database_path
16
17DASH = '-'
18
19
20#----------------------------------------------------------------------
21
22class VersionTestCase(unittest.TestCase):
23 def test00_version(self):
24 info = db.version()
25 if verbose:
26 print '\n', '-=' * 20
27 print 'bsddb.db.version(): %s' % (info, )
28 print db.DB_VERSION_STRING
29 print '-=' * 20
30 self.assertEqual(info, (db.DB_VERSION_MAJOR, db.DB_VERSION_MINOR,
31 db.DB_VERSION_PATCH))
32
33#----------------------------------------------------------------------
34
35class BasicTestCase(unittest.TestCase):
36 dbtype = db.DB_UNKNOWN # must be set in derived class
37 cachesize = (0, 1024*1024, 1)
38 dbopenflags = 0
39 dbsetflags = 0
40 dbmode = 0660
41 dbname = None
42 useEnv = 0
43 envflags = 0
44 envsetflags = 0
45
46 _numKeys = 1002 # PRIVATE. NOTE: must be an even value
47
48 def setUp(self):
49 if self.useEnv:
50 self.homeDir=get_new_environment_path()
51 try:
52 self.env = db.DBEnv()
53 self.env.set_lg_max(1024*1024)
54 self.env.set_tx_max(30)
55 self._t = int(time.time())
56 self.env.set_tx_timestamp(self._t)
57 self.env.set_flags(self.envsetflags, 1)
58 self.env.open(self.homeDir, self.envflags | db.DB_CREATE)
59 self.filename = "test"
60 # Yes, a bare except is intended, since we're re-raising the exc.
61 except:
62 test_support.rmtree(self.homeDir)
63 raise
64 else:
65 self.env = None
66 self.filename = get_new_database_path()
67
68 # create and open the DB
69 self.d = db.DB(self.env)
70 if not self.useEnv :
71 self.d.set_cachesize(*self.cachesize)
72 cachesize = self.d.get_cachesize()
73 self.assertEqual(cachesize[0], self.cachesize[0])
74 self.assertEqual(cachesize[2], self.cachesize[2])
75 # Berkeley DB expands the cache 25% accounting overhead,
76 # if the cache is small.
77 self.assertEqual(125, int(100.0*cachesize[1]/self.cachesize[1]))
78 self.d.set_flags(self.dbsetflags)
79 if self.dbname:
80 self.d.open(self.filename, self.dbname, self.dbtype,
81 self.dbopenflags|db.DB_CREATE, self.dbmode)
82 else:
83 self.d.open(self.filename, # try out keyword args
84 mode = self.dbmode,
85 dbtype = self.dbtype,
86 flags = self.dbopenflags|db.DB_CREATE)
87
88 if not self.useEnv:
89 self.assertRaises(db.DBInvalidArgError,
90 self.d.set_cachesize, *self.cachesize)
91
92 self.populateDB()
93
94
95 def tearDown(self):
96 self.d.close()
97 if self.env is not None:
98 self.env.close()
99 test_support.rmtree(self.homeDir)
100 else:
101 os.remove(self.filename)
102
103
104
105 def populateDB(self, _txn=None):
106 d = self.d
107
108 for x in range(self._numKeys//2):
109 key = '%04d' % (self._numKeys - x) # insert keys in reverse order
110 data = self.makeData(key)
111 d.put(key, data, _txn)
112
113 d.put('empty value', '', _txn)
114
115 for x in range(self._numKeys//2-1):
116 key = '%04d' % x # and now some in forward order
117 data = self.makeData(key)
118 d.put(key, data, _txn)
119
120 if _txn:
121 _txn.commit()
122
123 num = len(d)
124 if verbose:
125 print "created %d records" % num
126
127
128 def makeData(self, key):
129 return DASH.join([key] * 5)
130
131
132
133 #----------------------------------------
134
135 def test01_GetsAndPuts(self):
136 d = self.d
137
138 if verbose:
139 print '\n', '-=' * 30
140 print "Running %s.test01_GetsAndPuts..." % self.__class__.__name__
141
142 for key in ['0001', '0100', '0400', '0700', '0999']:
143 data = d.get(key)
144 if verbose:
145 print data
146
147 self.assertEqual(d.get('0321'), '0321-0321-0321-0321-0321')
148
149 # By default non-existent keys return None...
150 self.assertEqual(d.get('abcd'), None)
151
152 # ...but they raise exceptions in other situations. Call
153 # set_get_returns_none() to change it.
154 try:
155 d.delete('abcd')
156 except db.DBNotFoundError, val:
157 if sys.version_info < (2, 6) :
158 self.assertEqual(val[0], db.DB_NOTFOUND)
159 else :
160 self.assertEqual(val.args[0], db.DB_NOTFOUND)
161 if verbose: print val
162 else:
163 self.fail("expected exception")
164
165
166 d.put('abcd', 'a new record')
167 self.assertEqual(d.get('abcd'), 'a new record')
168
169 d.put('abcd', 'same key')
170 if self.dbsetflags & db.DB_DUP:
171 self.assertEqual(d.get('abcd'), 'a new record')
172 else:
173 self.assertEqual(d.get('abcd'), 'same key')
174
175
176 try:
177 d.put('abcd', 'this should fail', flags=db.DB_NOOVERWRITE)
178 except db.DBKeyExistError, val:
179 if sys.version_info < (2, 6) :
180 self.assertEqual(val[0], db.DB_KEYEXIST)
181 else :
182 self.assertEqual(val.args[0], db.DB_KEYEXIST)
183 if verbose: print val
184 else:
185 self.fail("expected exception")
186
187 if self.dbsetflags & db.DB_DUP:
188 self.assertEqual(d.get('abcd'), 'a new record')
189 else:
190 self.assertEqual(d.get('abcd'), 'same key')
191
192
193 d.sync()
194 d.close()
195 del d
196
197 self.d = db.DB(self.env)
198 if self.dbname:
199 self.d.open(self.filename, self.dbname)
200 else:
201 self.d.open(self.filename)
202 d = self.d
203
204 self.assertEqual(d.get('0321'), '0321-0321-0321-0321-0321')
205 if self.dbsetflags & db.DB_DUP:
206 self.assertEqual(d.get('abcd'), 'a new record')
207 else:
208 self.assertEqual(d.get('abcd'), 'same key')
209
210 rec = d.get_both('0555', '0555-0555-0555-0555-0555')
211 if verbose:
212 print rec
213
214 self.assertEqual(d.get_both('0555', 'bad data'), None)
215
216 # test default value
217 data = d.get('bad key', 'bad data')
218 self.assertEqual(data, 'bad data')
219
220 # any object can pass through
221 data = d.get('bad key', self)
222 self.assertEqual(data, self)
223
224 s = d.stat()
225 self.assertEqual(type(s), type({}))
226 if verbose:
227 print 'd.stat() returned this dictionary:'
228 pprint(s)
229
230
231 #----------------------------------------
232
233 def test02_DictionaryMethods(self):
234 d = self.d
235
236 if verbose:
237 print '\n', '-=' * 30
238 print "Running %s.test02_DictionaryMethods..." % \
239 self.__class__.__name__
240
241 for key in ['0002', '0101', '0401', '0701', '0998']:
242 data = d[key]
243 self.assertEqual(data, self.makeData(key))
244 if verbose:
245 print data
246
247 self.assertEqual(len(d), self._numKeys)
248 keys = d.keys()
249 self.assertEqual(len(keys), self._numKeys)
250 self.assertEqual(type(keys), type([]))
251
252 d['new record'] = 'a new record'
253 self.assertEqual(len(d), self._numKeys+1)
254 keys = d.keys()
255 self.assertEqual(len(keys), self._numKeys+1)
256
257 d['new record'] = 'a replacement record'
258 self.assertEqual(len(d), self._numKeys+1)
259 keys = d.keys()
260 self.assertEqual(len(keys), self._numKeys+1)
261
262 if verbose:
263 print "the first 10 keys are:"
264 pprint(keys[:10])
265
266 self.assertEqual(d['new record'], 'a replacement record')
267
268# We check also the positional parameter
269 self.assertEqual(d.has_key('0001', None), 1)
270# We check also the keyword parameter
271 self.assertEqual(d.has_key('spam', txn=None), 0)
272
273 items = d.items()
274 self.assertEqual(len(items), self._numKeys+1)
275 self.assertEqual(type(items), type([]))
276 self.assertEqual(type(items[0]), type(()))
277 self.assertEqual(len(items[0]), 2)
278
279 if verbose:
280 print "the first 10 items are:"
281 pprint(items[:10])
282
283 values = d.values()
284 self.assertEqual(len(values), self._numKeys+1)
285 self.assertEqual(type(values), type([]))
286
287 if verbose:
288 print "the first 10 values are:"
289 pprint(values[:10])
290
291
292 #----------------------------------------
293
294 def test02b_SequenceMethods(self):
295 d = self.d
296
297 for key in ['0002', '0101', '0401', '0701', '0998']:
298 data = d[key]
299 self.assertEqual(data, self.makeData(key))
300 if verbose:
301 print data
302
303 self.assertTrue(hasattr(d, "__contains__"))
304 self.assertTrue("0401" in d)
305 self.assertFalse("1234" in d)
306
307
308 #----------------------------------------
309
310 def test03_SimpleCursorStuff(self, get_raises_error=0, set_raises_error=0):
311 if verbose:
312 print '\n', '-=' * 30
313 print "Running %s.test03_SimpleCursorStuff (get_error %s, set_error %s)..." % \
314 (self.__class__.__name__, get_raises_error, set_raises_error)
315
316 if self.env and self.dbopenflags & db.DB_AUTO_COMMIT:
317 txn = self.env.txn_begin()
318 else:
319 txn = None
320 c = self.d.cursor(txn=txn)
321
322 rec = c.first()
323 count = 0
324 while rec is not None:
325 count = count + 1
326 if verbose and count % 100 == 0:
327 print rec
328 try:
329 rec = c.next()
330 except db.DBNotFoundError, val:
331 if get_raises_error:
332 if sys.version_info < (2, 6) :
333 self.assertEqual(val[0], db.DB_NOTFOUND)
334 else :
335 self.assertEqual(val.args[0], db.DB_NOTFOUND)
336 if verbose: print val
337 rec = None
338 else:
339 self.fail("unexpected DBNotFoundError")
340 self.assertEqual(c.get_current_size(), len(c.current()[1]),
341 "%s != len(%r)" % (c.get_current_size(), c.current()[1]))
342
343 self.assertEqual(count, self._numKeys)
344
345
346 rec = c.last()
347 count = 0
348 while rec is not None:
349 count = count + 1
350 if verbose and count % 100 == 0:
351 print rec
352 try:
353 rec = c.prev()
354 except db.DBNotFoundError, val:
355 if get_raises_error:
356 if sys.version_info < (2, 6) :
357 self.assertEqual(val[0], db.DB_NOTFOUND)
358 else :
359 self.assertEqual(val.args[0], db.DB_NOTFOUND)
360 if verbose: print val
361 rec = None
362 else:
363 self.fail("unexpected DBNotFoundError")
364
365 self.assertEqual(count, self._numKeys)
366
367 rec = c.set('0505')
368 rec2 = c.current()
369 self.assertEqual(rec, rec2)
370 self.assertEqual(rec[0], '0505')
371 self.assertEqual(rec[1], self.makeData('0505'))
372 self.assertEqual(c.get_current_size(), len(rec[1]))
373
374 # make sure we get empty values properly
375 rec = c.set('empty value')
376 self.assertEqual(rec[1], '')
377 self.assertEqual(c.get_current_size(), 0)
378
379 try:
380 n = c.set('bad key')
381 except db.DBNotFoundError, val:
382 if sys.version_info < (2, 6) :
383 self.assertEqual(val[0], db.DB_NOTFOUND)
384 else :
385 self.assertEqual(val.args[0], db.DB_NOTFOUND)
386 if verbose: print val
387 else:
388 if set_raises_error:
389 self.fail("expected exception")
390 if n is not None:
391 self.fail("expected None: %r" % (n,))
392
393 rec = c.get_both('0404', self.makeData('0404'))
394 self.assertEqual(rec, ('0404', self.makeData('0404')))
395
396 try:
397 n = c.get_both('0404', 'bad data')
398 except db.DBNotFoundError, val:
399 if sys.version_info < (2, 6) :
400 self.assertEqual(val[0], db.DB_NOTFOUND)
401 else :
402 self.assertEqual(val.args[0], db.DB_NOTFOUND)
403 if verbose: print val
404 else:
405 if get_raises_error:
406 self.fail("expected exception")
407 if n is not None:
408 self.fail("expected None: %r" % (n,))
409
410 if self.d.get_type() == db.DB_BTREE:
411 rec = c.set_range('011')
412 if verbose:
413 print "searched for '011', found: ", rec
414
415 rec = c.set_range('011',dlen=0,doff=0)
416 if verbose:
417 print "searched (partial) for '011', found: ", rec
418 if rec[1] != '': self.fail('expected empty data portion')
419
420 ev = c.set_range('empty value')
421 if verbose:
422 print "search for 'empty value' returned", ev
423 if ev[1] != '': self.fail('empty value lookup failed')
424
425 c.set('0499')
426 c.delete()
427 try:
428 rec = c.current()
429 except db.DBKeyEmptyError, val:
430 if get_raises_error:
431 if sys.version_info < (2, 6) :
432 self.assertEqual(val[0], db.DB_KEYEMPTY)
433 else :
434 self.assertEqual(val.args[0], db.DB_KEYEMPTY)
435 if verbose: print val
436 else:
437 self.fail("unexpected DBKeyEmptyError")
438 else:
439 if get_raises_error:
440 self.fail('DBKeyEmptyError exception expected')
441
442 c.next()
443 c2 = c.dup(db.DB_POSITION)
444 self.assertEqual(c.current(), c2.current())
445
446 c2.put('', 'a new value', db.DB_CURRENT)
447 self.assertEqual(c.current(), c2.current())
448 self.assertEqual(c.current()[1], 'a new value')
449
450 c2.put('', 'er', db.DB_CURRENT, dlen=0, doff=5)
451 self.assertEqual(c2.current()[1], 'a newer value')
452
453 c.close()
454 c2.close()
455 if txn:
456 txn.commit()
457
458 # time to abuse the closed cursors and hope we don't crash
459 methods_to_test = {
460 'current': (),
461 'delete': (),
462 'dup': (db.DB_POSITION,),
463 'first': (),
464 'get': (0,),
465 'next': (),
466 'prev': (),
467 'last': (),
468 'put':('', 'spam', db.DB_CURRENT),
469 'set': ("0505",),
470 }
471 for method, args in methods_to_test.items():
472 try:
473 if verbose:
474 print "attempting to use a closed cursor's %s method" % \
475 method
476 # a bug may cause a NULL pointer dereference...
477 getattr(c, method)(*args)
478 except db.DBError, val:
479 if sys.version_info < (2, 6) :
480 self.assertEqual(val[0], 0)
481 else :
482 self.assertEqual(val.args[0], 0)
483 if verbose: print val
484 else:
485 self.fail("no exception raised when using a buggy cursor's"
486 "%s method" % method)
487
488 #
489 # free cursor referencing a closed database, it should not barf:
490 #
491 oldcursor = self.d.cursor(txn=txn)
492 self.d.close()
493
494 # this would originally cause a segfault when the cursor for a
495 # closed database was cleaned up. it should not anymore.
496 # SF pybsddb bug id 667343
497 del oldcursor
498
499 def test03b_SimpleCursorWithoutGetReturnsNone0(self):
500 # same test but raise exceptions instead of returning None
501 if verbose:
502 print '\n', '-=' * 30
503 print "Running %s.test03b_SimpleCursorStuffWithoutGetReturnsNone..." % \
504 self.__class__.__name__
505
506 old = self.d.set_get_returns_none(0)
507 self.assertEqual(old, 2)
508 self.test03_SimpleCursorStuff(get_raises_error=1, set_raises_error=1)
509
510 def test03b_SimpleCursorWithGetReturnsNone1(self):
511 # same test but raise exceptions instead of returning None
512 if verbose:
513 print '\n', '-=' * 30
514 print "Running %s.test03b_SimpleCursorStuffWithoutGetReturnsNone..." % \
515 self.__class__.__name__
516
517 old = self.d.set_get_returns_none(1)
518 self.test03_SimpleCursorStuff(get_raises_error=0, set_raises_error=1)
519
520
521 def test03c_SimpleCursorGetReturnsNone2(self):
522 # same test but raise exceptions instead of returning None
523 if verbose:
524 print '\n', '-=' * 30
525 print "Running %s.test03c_SimpleCursorStuffWithoutSetReturnsNone..." % \
526 self.__class__.__name__
527
528 old = self.d.set_get_returns_none(1)
529 self.assertEqual(old, 2)
530 old = self.d.set_get_returns_none(2)
531 self.assertEqual(old, 1)
532 self.test03_SimpleCursorStuff(get_raises_error=0, set_raises_error=0)
533
534 if db.version() >= (4, 6):
535 def test03d_SimpleCursorPriority(self) :
536 c = self.d.cursor()
537 c.set_priority(db.DB_PRIORITY_VERY_LOW) # Positional
538 self.assertEqual(db.DB_PRIORITY_VERY_LOW, c.get_priority())
539 c.set_priority(priority=db.DB_PRIORITY_HIGH) # Keyword
540 self.assertEqual(db.DB_PRIORITY_HIGH, c.get_priority())
541 c.close()
542
543 #----------------------------------------
544
545 def test04_PartialGetAndPut(self):
546 d = self.d
547 if verbose:
548 print '\n', '-=' * 30
549 print "Running %s.test04_PartialGetAndPut..." % \
550 self.__class__.__name__
551
552 key = "partialTest"
553 data = "1" * 1000 + "2" * 1000
554 d.put(key, data)
555 self.assertEqual(d.get(key), data)
556 self.assertEqual(d.get(key, dlen=20, doff=990),
557 ("1" * 10) + ("2" * 10))
558
559 d.put("partialtest2", ("1" * 30000) + "robin" )
560 self.assertEqual(d.get("partialtest2", dlen=5, doff=30000), "robin")
561
562 # There seems to be a bug in DB here... Commented out the test for
563 # now.
564 ##self.assertEqual(d.get("partialtest2", dlen=5, doff=30010), "")
565
566 if self.dbsetflags != db.DB_DUP:
567 # Partial put with duplicate records requires a cursor
568 d.put(key, "0000", dlen=2000, doff=0)
569 self.assertEqual(d.get(key), "0000")
570
571 d.put(key, "1111", dlen=1, doff=2)
572 self.assertEqual(d.get(key), "0011110")
573
574 #----------------------------------------
575
576 def test05_GetSize(self):
577 d = self.d
578 if verbose:
579 print '\n', '-=' * 30
580 print "Running %s.test05_GetSize..." % self.__class__.__name__
581
582 for i in range(1, 50000, 500):
583 key = "size%s" % i
584 #print "before ", i,
585 d.put(key, "1" * i)
586 #print "after",
587 self.assertEqual(d.get_size(key), i)
588 #print "done"
589
590 #----------------------------------------
591
592 def test06_Truncate(self):
593 d = self.d
594 if verbose:
595 print '\n', '-=' * 30
596 print "Running %s.test06_Truncate..." % self.__class__.__name__
597
598 d.put("abcde", "ABCDE");
599 num = d.truncate()
600 self.assertTrue(num >= 1, "truncate returned <= 0 on non-empty database")
601 num = d.truncate()
602 self.assertEqual(num, 0,
603 "truncate on empty DB returned nonzero (%r)" % (num,))
604
605 #----------------------------------------
606
607 def test07_verify(self):
608 # Verify bug solved in 4.7.3pre8
609 self.d.close()
610 d = db.DB(self.env)
611 d.verify(self.filename)
612
613
614 #----------------------------------------
615
616 if db.version() >= (4, 6):
617 def test08_exists(self) :
618 self.d.put("abcde", "ABCDE")
619 self.assertTrue(self.d.exists("abcde") == True,
620 "DB->exists() returns wrong value")
621 self.assertTrue(self.d.exists("x") == False,
622 "DB->exists() returns wrong value")
623
624 #----------------------------------------
625
626 if db.version() >= (4, 7):
627 def test_compact(self) :
628 d = self.d
629 self.assertEqual(0, d.compact(flags=db.DB_FREELIST_ONLY))
630 self.assertEqual(0, d.compact(flags=db.DB_FREELIST_ONLY))
631 d.put("abcde", "ABCDE");
632 d.put("bcde", "BCDE");
633 d.put("abc", "ABC");
634 d.put("monty", "python");
635 d.delete("abc")
636 d.delete("bcde")
637 d.compact(start='abcde', stop='monty', txn=None,
638 compact_fillpercent=42, compact_pages=1,
639 compact_timeout=50000000,
640 flags=db.DB_FREELIST_ONLY|db.DB_FREE_SPACE)
641
642 #----------------------------------------
643
644#----------------------------------------------------------------------
645
646
647class BasicBTreeTestCase(BasicTestCase):
648 dbtype = db.DB_BTREE
649
650
651class BasicHashTestCase(BasicTestCase):
652 dbtype = db.DB_HASH
653
654
655class BasicBTreeWithThreadFlagTestCase(BasicTestCase):
656 dbtype = db.DB_BTREE
657 dbopenflags = db.DB_THREAD
658
659
660class BasicHashWithThreadFlagTestCase(BasicTestCase):
661 dbtype = db.DB_HASH
662 dbopenflags = db.DB_THREAD
663
664
665class BasicWithEnvTestCase(BasicTestCase):
666 dbopenflags = db.DB_THREAD
667 useEnv = 1
668 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
669
670 #----------------------------------------
671
672 def test09_EnvRemoveAndRename(self):
673 if not self.env:
674 return
675
676 if verbose:
677 print '\n', '-=' * 30
678 print "Running %s.test09_EnvRemoveAndRename..." % self.__class__.__name__
679
680 # can't rename or remove an open DB
681 self.d.close()
682
683 newname = self.filename + '.renamed'
684 self.env.dbrename(self.filename, None, newname)
685 self.env.dbremove(newname)
686
687 #----------------------------------------
688
689class BasicBTreeWithEnvTestCase(BasicWithEnvTestCase):
690 dbtype = db.DB_BTREE
691
692
693class BasicHashWithEnvTestCase(BasicWithEnvTestCase):
694 dbtype = db.DB_HASH
695
696
697#----------------------------------------------------------------------
698
699class BasicTransactionTestCase(BasicTestCase):
700 if (sys.version_info < (2, 7)) or ((sys.version_info >= (3, 0)) and
701 (sys.version_info < (3, 2))) :
702 def assertIn(self, a, b, msg=None) :
703 return self.assertTrue(a in b, msg=msg)
704
705 dbopenflags = db.DB_THREAD | db.DB_AUTO_COMMIT
706 useEnv = 1
707 envflags = (db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK |
708 db.DB_INIT_TXN)
709 envsetflags = db.DB_AUTO_COMMIT
710
711
712 def tearDown(self):
713 self.txn.commit()
714 BasicTestCase.tearDown(self)
715
716
717 def populateDB(self):
718 txn = self.env.txn_begin()
719 BasicTestCase.populateDB(self, _txn=txn)
720
721 self.txn = self.env.txn_begin()
722
723
724 def test06_Transactions(self):
725 d = self.d
726 if verbose:
727 print '\n', '-=' * 30
728 print "Running %s.test06_Transactions..." % self.__class__.__name__
729
730 self.assertEqual(d.get('new rec', txn=self.txn), None)
731 d.put('new rec', 'this is a new record', self.txn)
732 self.assertEqual(d.get('new rec', txn=self.txn),
733 'this is a new record')
734 self.txn.abort()
735 self.assertEqual(d.get('new rec'), None)
736
737 self.txn = self.env.txn_begin()
738
739 self.assertEqual(d.get('new rec', txn=self.txn), None)
740 d.put('new rec', 'this is a new record', self.txn)
741 self.assertEqual(d.get('new rec', txn=self.txn),
742 'this is a new record')
743 self.txn.commit()
744 self.assertEqual(d.get('new rec'), 'this is a new record')
745
746 self.txn = self.env.txn_begin()
747 c = d.cursor(self.txn)
748 rec = c.first()
749 count = 0
750 while rec is not None:
751 count = count + 1
752 if verbose and count % 100 == 0:
753 print rec
754 rec = c.next()
755 self.assertEqual(count, self._numKeys+1)
756
757 c.close() # Cursors *MUST* be closed before commit!
758 self.txn.commit()
759
760 # flush pending updates
761 self.env.txn_checkpoint (0, 0, 0)
762
763 statDict = self.env.log_stat(0);
764 self.assertIn('magic', statDict)
765 self.assertIn('version', statDict)
766 self.assertIn('cur_file', statDict)
767 self.assertIn('region_nowait', statDict)
768
769 # must have at least one log file present:
770 logs = self.env.log_archive(db.DB_ARCH_ABS | db.DB_ARCH_LOG)
771 self.assertNotEqual(logs, None)
772 for log in logs:
773 if verbose:
774 print 'log file: ' + log
775 logs = self.env.log_archive(db.DB_ARCH_REMOVE)
776 self.assertTrue(not logs)
777
778 self.txn = self.env.txn_begin()
779
780 #----------------------------------------
781
782 if db.version() >= (4, 6):
783 def test08_exists(self) :
784 txn = self.env.txn_begin()
785 self.d.put("abcde", "ABCDE", txn=txn)
786 txn.commit()
787 txn = self.env.txn_begin()
788 self.assertTrue(self.d.exists("abcde", txn=txn) == True,
789 "DB->exists() returns wrong value")
790 self.assertTrue(self.d.exists("x", txn=txn) == False,
791 "DB->exists() returns wrong value")
792 txn.abort()
793
794 #----------------------------------------
795
796 def test09_TxnTruncate(self):
797 d = self.d
798 if verbose:
799 print '\n', '-=' * 30
800 print "Running %s.test09_TxnTruncate..." % self.__class__.__name__
801
802 d.put("abcde", "ABCDE");
803 txn = self.env.txn_begin()
804 num = d.truncate(txn)
805 self.assertTrue(num >= 1, "truncate returned <= 0 on non-empty database")
806 num = d.truncate(txn)
807 self.assertEqual(num, 0,
808 "truncate on empty DB returned nonzero (%r)" % (num,))
809 txn.commit()
810
811 #----------------------------------------
812
813 def test10_TxnLateUse(self):
814 txn = self.env.txn_begin()
815 txn.abort()
816 try:
817 txn.abort()
818 except db.DBError, e:
819 pass
820 else:
821 raise RuntimeError, "DBTxn.abort() called after DB_TXN no longer valid w/o an exception"
822
823 txn = self.env.txn_begin()
824 txn.commit()
825 try:
826 txn.commit()
827 except db.DBError, e:
828 pass
829 else:
830 raise RuntimeError, "DBTxn.commit() called after DB_TXN no longer valid w/o an exception"
831
832
833 #----------------------------------------
834
835
836 if db.version() >= (4, 4):
837 def test_txn_name(self) :
838 txn=self.env.txn_begin()
839 self.assertEqual(txn.get_name(), "")
840 txn.set_name("XXYY")
841 self.assertEqual(txn.get_name(), "XXYY")
842 txn.set_name("")
843 self.assertEqual(txn.get_name(), "")
844 txn.abort()
845
846 #----------------------------------------
847
848
849 def test_txn_set_timeout(self) :
850 txn=self.env.txn_begin()
851 txn.set_timeout(1234567, db.DB_SET_LOCK_TIMEOUT)
852 txn.set_timeout(2345678, flags=db.DB_SET_TXN_TIMEOUT)
853 txn.abort()
854
855 #----------------------------------------
856
857 def test_get_tx_max(self) :
858 self.assertEqual(self.env.get_tx_max(), 30)
859
860 def test_get_tx_timestamp(self) :
861 self.assertEqual(self.env.get_tx_timestamp(), self._t)
862
863
864
865class BTreeTransactionTestCase(BasicTransactionTestCase):
866 dbtype = db.DB_BTREE
867
868class HashTransactionTestCase(BasicTransactionTestCase):
869 dbtype = db.DB_HASH
870
871
872
873#----------------------------------------------------------------------
874
875class BTreeRecnoTestCase(BasicTestCase):
876 dbtype = db.DB_BTREE
877 dbsetflags = db.DB_RECNUM
878
879 def test09_RecnoInBTree(self):
880 d = self.d
881 if verbose:
882 print '\n', '-=' * 30
883 print "Running %s.test09_RecnoInBTree..." % self.__class__.__name__
884
885 rec = d.get(200)
886 self.assertEqual(type(rec), type(()))
887 self.assertEqual(len(rec), 2)
888 if verbose:
889 print "Record #200 is ", rec
890
891 c = d.cursor()
892 c.set('0200')
893 num = c.get_recno()
894 self.assertEqual(type(num), type(1))
895 if verbose:
896 print "recno of d['0200'] is ", num
897
898 rec = c.current()
899 self.assertEqual(c.set_recno(num), rec)
900
901 c.close()
902
903
904
905class BTreeRecnoWithThreadFlagTestCase(BTreeRecnoTestCase):
906 dbopenflags = db.DB_THREAD
907
908#----------------------------------------------------------------------
909
910class BasicDUPTestCase(BasicTestCase):
911 dbsetflags = db.DB_DUP
912
913 def test10_DuplicateKeys(self):
914 d = self.d
915 if verbose:
916 print '\n', '-=' * 30
917 print "Running %s.test10_DuplicateKeys..." % \
918 self.__class__.__name__
919
920 d.put("dup0", "before")
921 for x in "The quick brown fox jumped over the lazy dog.".split():
922 d.put("dup1", x)
923 d.put("dup2", "after")
924
925 data = d.get("dup1")
926 self.assertEqual(data, "The")
927 if verbose:
928 print data
929
930 c = d.cursor()
931 rec = c.set("dup1")
932 self.assertEqual(rec, ('dup1', 'The'))
933
934 next_reg = c.next()
935 self.assertEqual(next_reg, ('dup1', 'quick'))
936
937 rec = c.set("dup1")
938 count = c.count()
939 self.assertEqual(count, 9)
940
941 next_dup = c.next_dup()
942 self.assertEqual(next_dup, ('dup1', 'quick'))
943
944 rec = c.set('dup1')
945 while rec is not None:
946 if verbose:
947 print rec
948 rec = c.next_dup()
949
950 c.set('dup1')
951 rec = c.next_nodup()
952 self.assertNotEqual(rec[0], 'dup1')
953 if verbose:
954 print rec
955
956 c.close()
957
958
959
960class BTreeDUPTestCase(BasicDUPTestCase):
961 dbtype = db.DB_BTREE
962
963class HashDUPTestCase(BasicDUPTestCase):
964 dbtype = db.DB_HASH
965
966class BTreeDUPWithThreadTestCase(BasicDUPTestCase):
967 dbtype = db.DB_BTREE
968 dbopenflags = db.DB_THREAD
969
970class HashDUPWithThreadTestCase(BasicDUPTestCase):
971 dbtype = db.DB_HASH
972 dbopenflags = db.DB_THREAD
973
974
975#----------------------------------------------------------------------
976
977class BasicMultiDBTestCase(BasicTestCase):
978 dbname = 'first'
979
980 def otherType(self):
981 if self.dbtype == db.DB_BTREE:
982 return db.DB_HASH
983 else:
984 return db.DB_BTREE
985
986 def test11_MultiDB(self):
987 d1 = self.d
988 if verbose:
989 print '\n', '-=' * 30
990 print "Running %s.test11_MultiDB..." % self.__class__.__name__
991
992 d2 = db.DB(self.env)
993 d2.open(self.filename, "second", self.dbtype,
994 self.dbopenflags|db.DB_CREATE)
995 d3 = db.DB(self.env)
996 d3.open(self.filename, "third", self.otherType(),
997 self.dbopenflags|db.DB_CREATE)
998
999 for x in "The quick brown fox jumped over the lazy dog".split():
1000 d2.put(x, self.makeData(x))
1001
1002 for x in string.letters:
1003 d3.put(x, x*70)
1004
1005 d1.sync()
1006 d2.sync()
1007 d3.sync()
1008 d1.close()
1009 d2.close()
1010 d3.close()
1011
1012 self.d = d1 = d2 = d3 = None
1013
1014 self.d = d1 = db.DB(self.env)
1015 d1.open(self.filename, self.dbname, flags = self.dbopenflags)
1016 d2 = db.DB(self.env)
1017 d2.open(self.filename, "second", flags = self.dbopenflags)
1018 d3 = db.DB(self.env)
1019 d3.open(self.filename, "third", flags = self.dbopenflags)
1020
1021 c1 = d1.cursor()
1022 c2 = d2.cursor()
1023 c3 = d3.cursor()
1024
1025 count = 0
1026 rec = c1.first()
1027 while rec is not None:
1028 count = count + 1
1029 if verbose and (count % 50) == 0:
1030 print rec
1031 rec = c1.next()
1032 self.assertEqual(count, self._numKeys)
1033
1034 count = 0
1035 rec = c2.first()
1036 while rec is not None:
1037 count = count + 1
1038 if verbose:
1039 print rec
1040 rec = c2.next()
1041 self.assertEqual(count, 9)
1042
1043 count = 0
1044 rec = c3.first()
1045 while rec is not None:
1046 count = count + 1
1047 if verbose:
1048 print rec
1049 rec = c3.next()
1050 self.assertEqual(count, len(string.letters))
1051
1052
1053 c1.close()
1054 c2.close()
1055 c3.close()
1056
1057 d2.close()
1058 d3.close()
1059
1060
1061
1062# Strange things happen if you try to use Multiple DBs per file without a
1063# DBEnv with MPOOL and LOCKing...
1064
1065class BTreeMultiDBTestCase(BasicMultiDBTestCase):
1066 dbtype = db.DB_BTREE
1067 dbopenflags = db.DB_THREAD
1068 useEnv = 1
1069 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
1070
1071class HashMultiDBTestCase(BasicMultiDBTestCase):
1072 dbtype = db.DB_HASH
1073 dbopenflags = db.DB_THREAD
1074 useEnv = 1
1075 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
1076
1077
1078class PrivateObject(unittest.TestCase) :
1079 def tearDown(self) :
1080 del self.obj
1081
1082 def test01_DefaultIsNone(self) :
1083 self.assertEqual(self.obj.get_private(), None)
1084
1085 def test02_assignment(self) :
1086 a = "example of private object"
1087 self.obj.set_private(a)
1088 b = self.obj.get_private()
1089 self.assertTrue(a is b) # Object identity
1090
1091 def test03_leak_assignment(self) :
1092 a = "example of private object"
1093 refcount = sys.getrefcount(a)
1094 self.obj.set_private(a)
1095 self.assertEqual(refcount+1, sys.getrefcount(a))
1096 self.obj.set_private(None)
1097 self.assertEqual(refcount, sys.getrefcount(a))
1098
1099 def test04_leak_GC(self) :
1100 a = "example of private object"
1101 refcount = sys.getrefcount(a)
1102 self.obj.set_private(a)
1103 self.obj = None
1104 self.assertEqual(refcount, sys.getrefcount(a))
1105
1106class DBEnvPrivateObject(PrivateObject) :
1107 def setUp(self) :
1108 self.obj = db.DBEnv()
1109
1110class DBPrivateObject(PrivateObject) :
1111 def setUp(self) :
1112 self.obj = db.DB()
1113
1114class CrashAndBurn(unittest.TestCase) :
1115 #def test01_OpenCrash(self) :
1116 # # See http://bugs.python.org/issue3307
1117 # self.assertRaises(db.DBInvalidArgError, db.DB, None, 65535)
1118
1119 if db.version() < (4, 8) :
1120 def test02_DBEnv_dealloc(self):
1121 # http://bugs.python.org/issue3885
1122 import gc
1123 self.assertRaises(db.DBInvalidArgError, db.DBEnv, ~db.DB_RPCCLIENT)
1124 gc.collect()
1125
1126
1127#----------------------------------------------------------------------
1128#----------------------------------------------------------------------
1129
1130def test_suite():
1131 suite = unittest.TestSuite()
1132
1133 suite.addTest(unittest.makeSuite(VersionTestCase))
1134 suite.addTest(unittest.makeSuite(BasicBTreeTestCase))
1135 suite.addTest(unittest.makeSuite(BasicHashTestCase))
1136 suite.addTest(unittest.makeSuite(BasicBTreeWithThreadFlagTestCase))
1137 suite.addTest(unittest.makeSuite(BasicHashWithThreadFlagTestCase))
1138 suite.addTest(unittest.makeSuite(BasicBTreeWithEnvTestCase))
1139 suite.addTest(unittest.makeSuite(BasicHashWithEnvTestCase))
1140 suite.addTest(unittest.makeSuite(BTreeTransactionTestCase))
1141 suite.addTest(unittest.makeSuite(HashTransactionTestCase))
1142 suite.addTest(unittest.makeSuite(BTreeRecnoTestCase))
1143 suite.addTest(unittest.makeSuite(BTreeRecnoWithThreadFlagTestCase))
1144 suite.addTest(unittest.makeSuite(BTreeDUPTestCase))
1145 suite.addTest(unittest.makeSuite(HashDUPTestCase))
1146 suite.addTest(unittest.makeSuite(BTreeDUPWithThreadTestCase))
1147 suite.addTest(unittest.makeSuite(HashDUPWithThreadTestCase))
1148 suite.addTest(unittest.makeSuite(BTreeMultiDBTestCase))
1149 suite.addTest(unittest.makeSuite(HashMultiDBTestCase))
1150 suite.addTest(unittest.makeSuite(DBEnvPrivateObject))
1151 suite.addTest(unittest.makeSuite(DBPrivateObject))
1152 suite.addTest(unittest.makeSuite(CrashAndBurn))
1153
1154 return suite
1155
1156
1157if __name__ == '__main__':
1158 unittest.main(defaultTest='test_suite')
Note: See TracBrowser for help on using the repository browser.