blob: 25cc77cafc7ac2838373d1d6ade8e902edc2d08e [file] [log] [blame]
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +00001"""
2Basic TestCases for BTree and hash DBs, with and without a DBEnv, with
3various DB flags, etc.
4"""
5
Barry Warsaw9a0d7792002-12-30 20:53:52 +00006import os
7import sys
8import errno
9import shutil
10import string
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +000011import tempfile
12from pprint import pprint
13import unittest
14
15from bsddb import db
16
Barry Warsaw9a0d7792002-12-30 20:53:52 +000017from test_all import verbose
18
19DASH = '-'
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +000020
21
22#----------------------------------------------------------------------
23
24class VersionTestCase(unittest.TestCase):
25 def test00_version(self):
26 info = db.version()
27 if verbose:
28 print '\n', '-=' * 20
29 print 'bsddb.db.version(): %s' % (info, )
30 print db.DB_VERSION_STRING
31 print '-=' * 20
Barry Warsaw9a0d7792002-12-30 20:53:52 +000032 assert info == (db.DB_VERSION_MAJOR, db.DB_VERSION_MINOR,
33 db.DB_VERSION_PATCH)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +000034
35#----------------------------------------------------------------------
36
37class BasicTestCase(unittest.TestCase):
38 dbtype = db.DB_UNKNOWN # must be set in derived class
39 dbopenflags = 0
40 dbsetflags = 0
41 dbmode = 0660
42 dbname = None
43 useEnv = 0
44 envflags = 0
Barry Warsaw9a0d7792002-12-30 20:53:52 +000045 envsetflags = 0
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +000046
47 def setUp(self):
48 if self.useEnv:
49 homeDir = os.path.join(os.path.dirname(sys.argv[0]), 'db_home')
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +000050 self.homeDir = homeDir
Barry Warsaw9a0d7792002-12-30 20:53:52 +000051 try:
52 shutil.rmtree(homeDir)
53 except OSError, e:
54 # unix returns ENOENT, windows returns ESRCH
55 if e.errno not in (errno.ENOENT, errno.ESRCH): raise
56 os.mkdir(homeDir)
57 try:
58 self.env = db.DBEnv()
59 self.env.set_lg_max(1024*1024)
60 self.env.set_flags(self.envsetflags, 1)
61 self.env.open(homeDir, self.envflags | db.DB_CREATE)
62 tempfile.tempdir = homeDir
63 self.filename = os.path.split(tempfile.mktemp())[1]
64 tempfile.tempdir = None
65 # Yes, a bare except is intended, since we're re-raising the exc.
66 except:
67 shutil.rmtree(homeDir)
68 raise
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +000069 else:
70 self.env = None
71 self.filename = tempfile.mktemp()
72
73 # create and open the DB
74 self.d = db.DB(self.env)
75 self.d.set_flags(self.dbsetflags)
76 if self.dbname:
77 self.d.open(self.filename, self.dbname, self.dbtype,
78 self.dbopenflags|db.DB_CREATE, self.dbmode)
79 else:
80 self.d.open(self.filename, # try out keyword args
81 mode = self.dbmode,
Barry Warsaw9a0d7792002-12-30 20:53:52 +000082 dbtype = self.dbtype,
83 flags = self.dbopenflags|db.DB_CREATE)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +000084
85 self.populateDB()
86
87
88 def tearDown(self):
89 self.d.close()
90 if self.env is not None:
91 self.env.close()
Barry Warsaw9a0d7792002-12-30 20:53:52 +000092 shutil.rmtree(self.homeDir)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +000093 ## Make a new DBEnv to remove the env files from the home dir.
94 ## (It can't be done while the env is open, nor after it has been
95 ## closed, so we make a new one to do it.)
96 #e = db.DBEnv()
97 #e.remove(self.homeDir)
98 #os.remove(os.path.join(self.homeDir, self.filename))
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +000099 else:
100 os.remove(self.filename)
101
102
103
104 def populateDB(self):
105 d = self.d
106 for x in range(500):
107 key = '%04d' % (1000 - x) # insert keys in reverse order
108 data = self.makeData(key)
109 d.put(key, data)
110
111 for x in range(500):
112 key = '%04d' % x # and now some in forward order
113 data = self.makeData(key)
114 d.put(key, data)
115
116 num = len(d)
117 if verbose:
118 print "created %d records" % num
119
120
121 def makeData(self, key):
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000122 return DASH.join([key] * 5)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000123
124
125
126 #----------------------------------------
127
128 def test01_GetsAndPuts(self):
129 d = self.d
130
131 if verbose:
132 print '\n', '-=' * 30
133 print "Running %s.test01_GetsAndPuts..." % self.__class__.__name__
134
135 for key in ['0001', '0100', '0400', '0700', '0999']:
136 data = d.get(key)
137 if verbose:
138 print data
139
140 assert d.get('0321') == '0321-0321-0321-0321-0321'
141
142 # By default non-existant keys return None...
143 assert d.get('abcd') == None
144
145 # ...but they raise exceptions in other situations. Call
146 # set_get_returns_none() to change it.
147 try:
148 d.delete('abcd')
149 except db.DBNotFoundError, val:
150 assert val[0] == db.DB_NOTFOUND
151 if verbose: print val
152 else:
153 self.fail("expected exception")
154
155
156 d.put('abcd', 'a new record')
157 assert d.get('abcd') == 'a new record'
158
159 d.put('abcd', 'same key')
160 if self.dbsetflags & db.DB_DUP:
161 assert d.get('abcd') == 'a new record'
162 else:
163 assert d.get('abcd') == 'same key'
164
165
166 try:
167 d.put('abcd', 'this should fail', flags=db.DB_NOOVERWRITE)
168 except db.DBKeyExistError, val:
169 assert val[0] == db.DB_KEYEXIST
170 if verbose: print val
171 else:
172 self.fail("expected exception")
173
174 if self.dbsetflags & db.DB_DUP:
175 assert d.get('abcd') == 'a new record'
176 else:
177 assert d.get('abcd') == 'same key'
178
179
180 d.sync()
181 d.close()
182 del d
183
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
190
191 assert d.get('0321') == '0321-0321-0321-0321-0321'
192 if self.dbsetflags & db.DB_DUP:
193 assert d.get('abcd') == 'a new record'
194 else:
195 assert d.get('abcd') == 'same key'
196
197 rec = d.get_both('0555', '0555-0555-0555-0555-0555')
198 if verbose:
199 print rec
200
201 assert d.get_both('0555', 'bad data') == None
202
203 # test default value
204 data = d.get('bad key', 'bad data')
205 assert data == 'bad data'
206
207 # any object can pass through
208 data = d.get('bad key', self)
209 assert data == self
210
211 s = d.stat()
212 assert type(s) == type({})
213 if verbose:
214 print 'd.stat() returned this dictionary:'
215 pprint(s)
216
217
218 #----------------------------------------
219
220 def test02_DictionaryMethods(self):
221 d = self.d
222
223 if verbose:
224 print '\n', '-=' * 30
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000225 print "Running %s.test02_DictionaryMethods..." % \
226 self.__class__.__name__
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000227
228 for key in ['0002', '0101', '0401', '0701', '0998']:
229 data = d[key]
230 assert data == self.makeData(key)
231 if verbose:
232 print data
233
234 assert len(d) == 1000
235 keys = d.keys()
236 assert len(keys) == 1000
237 assert type(keys) == type([])
238
239 d['new record'] = 'a new record'
240 assert len(d) == 1001
241 keys = d.keys()
242 assert len(keys) == 1001
243
244 d['new record'] = 'a replacement record'
245 assert len(d) == 1001
246 keys = d.keys()
247 assert len(keys) == 1001
248
249 if verbose:
250 print "the first 10 keys are:"
251 pprint(keys[:10])
252
253 assert d['new record'] == 'a replacement record'
254
255 assert d.has_key('0001') == 1
256 assert d.has_key('spam') == 0
257
258 items = d.items()
259 assert len(items) == 1001
260 assert type(items) == type([])
261 assert type(items[0]) == type(())
262 assert len(items[0]) == 2
263
264 if verbose:
265 print "the first 10 items are:"
266 pprint(items[:10])
267
268 values = d.values()
269 assert len(values) == 1001
270 assert type(values) == type([])
271
272 if verbose:
273 print "the first 10 values are:"
274 pprint(values[:10])
275
276
277
278 #----------------------------------------
279
280 def test03_SimpleCursorStuff(self):
281 if verbose:
282 print '\n', '-=' * 30
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000283 print "Running %s.test03_SimpleCursorStuff..." % \
284 self.__class__.__name__
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000285
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000286 if self.env and self.dbopenflags & db.DB_AUTO_COMMIT:
287 txn = self.env.txn_begin()
288 else:
289 txn = None
290 c = self.d.cursor(txn=txn)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000291
292 rec = c.first()
293 count = 0
294 while rec is not None:
295 count = count + 1
296 if verbose and count % 100 == 0:
297 print rec
298 rec = c.next()
299
300 assert count == 1000
301
302
303 rec = c.last()
304 count = 0
305 while rec is not None:
306 count = count + 1
307 if verbose and count % 100 == 0:
308 print rec
309 rec = c.prev()
310
311 assert count == 1000
312
313 rec = c.set('0505')
314 rec2 = c.current()
315 assert rec == rec2
316 assert rec[0] == '0505'
317 assert rec[1] == self.makeData('0505')
318
319 try:
320 c.set('bad key')
321 except db.DBNotFoundError, val:
322 assert val[0] == db.DB_NOTFOUND
323 if verbose: print val
324 else:
325 self.fail("expected exception")
326
327 rec = c.get_both('0404', self.makeData('0404'))
328 assert rec == ('0404', self.makeData('0404'))
329
330 try:
331 c.get_both('0404', 'bad data')
332 except db.DBNotFoundError, val:
333 assert val[0] == db.DB_NOTFOUND
334 if verbose: print val
335 else:
336 self.fail("expected exception")
337
338 if self.d.get_type() == db.DB_BTREE:
339 rec = c.set_range('011')
340 if verbose:
341 print "searched for '011', found: ", rec
342
343 rec = c.set_range('011',dlen=0,doff=0)
344 if verbose:
345 print "searched (partial) for '011', found: ", rec
346 if rec[1] != '': set.fail('expected empty data portion')
347
348 c.set('0499')
349 c.delete()
350 try:
351 rec = c.current()
352 except db.DBKeyEmptyError, val:
353 assert val[0] == db.DB_KEYEMPTY
354 if verbose: print val
355 else:
356 self.fail('exception expected')
357
358 c.next()
359 c2 = c.dup(db.DB_POSITION)
360 assert c.current() == c2.current()
361
362 c2.put('', 'a new value', db.DB_CURRENT)
363 assert c.current() == c2.current()
364 assert c.current()[1] == 'a new value'
365
366 c2.put('', 'er', db.DB_CURRENT, dlen=0, doff=5)
367 assert c2.current()[1] == 'a newer value'
368
369 c.close()
370 c2.close()
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000371 if txn:
372 txn.commit()
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000373
374 # time to abuse the closed cursors and hope we don't crash
375 methods_to_test = {
376 'current': (),
377 'delete': (),
378 'dup': (db.DB_POSITION,),
379 'first': (),
380 'get': (0,),
381 'next': (),
382 'prev': (),
383 'last': (),
384 'put':('', 'spam', db.DB_CURRENT),
385 'set': ("0505",),
386 }
387 for method, args in methods_to_test.items():
388 try:
389 if verbose:
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000390 print "attempting to use a closed cursor's %s method" % \
391 method
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000392 # a bug may cause a NULL pointer dereference...
393 apply(getattr(c, method), args)
394 except db.DBError, val:
395 assert val[0] == 0
396 if verbose: print val
397 else:
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000398 self.fail("no exception raised when using a buggy cursor's"
399 "%s method" % method)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000400
Gregory P. Smithb6c9f782003-01-17 08:42:50 +0000401 #
402 # free cursor referencing a closed database, it should not barf:
403 #
404 oldcursor = self.d.cursor(txn=txn)
405 self.d.close()
406
407 # this would originally cause a segfault when the cursor for a
408 # closed database was cleaned up. it should not anymore.
409 # SF pybsddb bug id 667343
410 del oldcursor
411
412
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000413 #----------------------------------------
414
415 def test04_PartialGetAndPut(self):
416 d = self.d
417 if verbose:
418 print '\n', '-=' * 30
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000419 print "Running %s.test04_PartialGetAndPut..." % \
420 self.__class__.__name__
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000421
422 key = "partialTest"
423 data = "1" * 1000 + "2" * 1000
424 d.put(key, data)
425 assert d.get(key) == data
426 assert d.get(key, dlen=20, doff=990) == ("1" * 10) + ("2" * 10)
427
428 d.put("partialtest2", ("1" * 30000) + "robin" )
429 assert d.get("partialtest2", dlen=5, doff=30000) == "robin"
430
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000431 # There seems to be a bug in DB here... Commented out the test for
432 # now.
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000433 ##assert d.get("partialtest2", dlen=5, doff=30010) == ""
434
435 if self.dbsetflags != db.DB_DUP:
436 # Partial put with duplicate records requires a cursor
437 d.put(key, "0000", dlen=2000, doff=0)
438 assert d.get(key) == "0000"
439
440 d.put(key, "1111", dlen=1, doff=2)
441 assert d.get(key) == "0011110"
442
443 #----------------------------------------
444
445 def test05_GetSize(self):
446 d = self.d
447 if verbose:
448 print '\n', '-=' * 30
449 print "Running %s.test05_GetSize..." % self.__class__.__name__
450
451 for i in range(1, 50000, 500):
452 key = "size%s" % i
453 #print "before ", i,
454 d.put(key, "1" * i)
455 #print "after",
456 assert d.get_size(key) == i
457 #print "done"
458
459 #----------------------------------------
460
461 def test06_Truncate(self):
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000462 if db.version() < (3,3):
463 # truncate is a feature of BerkeleyDB 3.3 and above
464 return
465
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000466 d = self.d
467 if verbose:
468 print '\n', '-=' * 30
469 print "Running %s.test99_Truncate..." % self.__class__.__name__
470
471 d.put("abcde", "ABCDE");
472 num = d.truncate()
473 assert num >= 1, "truncate returned <= 0 on non-empty database"
474 num = d.truncate()
475 assert num == 0, "truncate on empty DB returned nonzero (%s)" % `num`
476
477#----------------------------------------------------------------------
478
479
480class BasicBTreeTestCase(BasicTestCase):
481 dbtype = db.DB_BTREE
482
483
484class BasicHashTestCase(BasicTestCase):
485 dbtype = db.DB_HASH
486
487
488class BasicBTreeWithThreadFlagTestCase(BasicTestCase):
489 dbtype = db.DB_BTREE
490 dbopenflags = db.DB_THREAD
491
492
493class BasicHashWithThreadFlagTestCase(BasicTestCase):
494 dbtype = db.DB_HASH
495 dbopenflags = db.DB_THREAD
496
497
498class BasicBTreeWithEnvTestCase(BasicTestCase):
499 dbtype = db.DB_BTREE
500 dbopenflags = db.DB_THREAD
501 useEnv = 1
502 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
503
504
505class BasicHashWithEnvTestCase(BasicTestCase):
506 dbtype = db.DB_HASH
507 dbopenflags = db.DB_THREAD
508 useEnv = 1
509 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
510
511
512#----------------------------------------------------------------------
513
514class BasicTransactionTestCase(BasicTestCase):
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000515 dbopenflags = db.DB_THREAD | db.DB_AUTO_COMMIT
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000516 useEnv = 1
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000517 envflags = (db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK |
518 db.DB_INIT_TXN)
519 envsetflags = db.DB_AUTO_COMMIT
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000520
521
522 def tearDown(self):
523 self.txn.commit()
524 BasicTestCase.tearDown(self)
525
526
527 def populateDB(self):
528 d = self.d
529 txn = self.env.txn_begin()
530 for x in range(500):
531 key = '%04d' % (1000 - x) # insert keys in reverse order
532 data = self.makeData(key)
533 d.put(key, data, txn)
534
535 for x in range(500):
536 key = '%04d' % x # and now some in forward order
537 data = self.makeData(key)
538 d.put(key, data, txn)
539
540 txn.commit()
541
542 num = len(d)
543 if verbose:
544 print "created %d records" % num
545
546 self.txn = self.env.txn_begin()
547
548
549
550 def test06_Transactions(self):
551 d = self.d
552 if verbose:
553 print '\n', '-=' * 30
554 print "Running %s.test06_Transactions..." % self.__class__.__name__
555
556 assert d.get('new rec', txn=self.txn) == None
557 d.put('new rec', 'this is a new record', self.txn)
558 assert d.get('new rec', txn=self.txn) == 'this is a new record'
559 self.txn.abort()
560 assert d.get('new rec') == None
561
562 self.txn = self.env.txn_begin()
563
564 assert d.get('new rec', txn=self.txn) == None
565 d.put('new rec', 'this is a new record', self.txn)
566 assert d.get('new rec', txn=self.txn) == 'this is a new record'
567 self.txn.commit()
568 assert d.get('new rec') == 'this is a new record'
569
570 self.txn = self.env.txn_begin()
571 c = d.cursor(self.txn)
572 rec = c.first()
573 count = 0
574 while rec is not None:
575 count = count + 1
576 if verbose and count % 100 == 0:
577 print rec
578 rec = c.next()
579 assert count == 1001
580
581 c.close() # Cursors *MUST* be closed before commit!
582 self.txn.commit()
583
584 # flush pending updates
585 try:
586 self.env.txn_checkpoint (0, 0, 0)
587 except db.DBIncompleteError:
588 pass
589
590 # must have at least one log file present:
591 logs = self.env.log_archive(db.DB_ARCH_ABS | db.DB_ARCH_LOG)
592 assert logs != None
593 for log in logs:
594 if verbose:
595 print 'log file: ' + log
596
597 self.txn = self.env.txn_begin()
598
599 #----------------------------------------
600
601 def test07_TxnTruncate(self):
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000602 if db.version() < (3,3):
603 # truncate is a feature of BerkeleyDB 3.3 and above
604 return
605
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000606 d = self.d
607 if verbose:
608 print '\n', '-=' * 30
609 print "Running %s.test07_TxnTruncate..." % self.__class__.__name__
610
611 d.put("abcde", "ABCDE");
612 txn = self.env.txn_begin()
613 num = d.truncate(txn)
614 assert num >= 1, "truncate returned <= 0 on non-empty database"
615 num = d.truncate(txn)
616 assert num == 0, "truncate on empty DB returned nonzero (%s)" % `num`
617 txn.commit()
618
Gregory P. Smithc25fd3f2003-01-17 07:52:59 +0000619 #----------------------------------------
620
621 def test08_TxnLateUse(self):
622 txn = self.env.txn_begin()
623 txn.abort()
624 try:
625 txn.abort()
626 except db.DBError, e:
627 pass
628 else:
629 raise RuntimeError, "DBTxn.abort() called after DB_TXN no longer valid w/o an exception"
630
631 txn = self.env.txn_begin()
632 txn.commit()
633 try:
634 txn.commit()
635 except db.DBError, e:
636 pass
637 else:
638 raise RuntimeError, "DBTxn.commit() called after DB_TXN no longer valid w/o an exception"
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000639
640
641class BTreeTransactionTestCase(BasicTransactionTestCase):
642 dbtype = db.DB_BTREE
643
644class HashTransactionTestCase(BasicTransactionTestCase):
645 dbtype = db.DB_HASH
646
647
648
649#----------------------------------------------------------------------
650
651class BTreeRecnoTestCase(BasicTestCase):
652 dbtype = db.DB_BTREE
653 dbsetflags = db.DB_RECNUM
654
655 def test07_RecnoInBTree(self):
656 d = self.d
657 if verbose:
658 print '\n', '-=' * 30
659 print "Running %s.test07_RecnoInBTree..." % self.__class__.__name__
660
661 rec = d.get(200)
662 assert type(rec) == type(())
663 assert len(rec) == 2
664 if verbose:
665 print "Record #200 is ", rec
666
667 c = d.cursor()
668 c.set('0200')
669 num = c.get_recno()
670 assert type(num) == type(1)
671 if verbose:
672 print "recno of d['0200'] is ", num
673
674 rec = c.current()
675 assert c.set_recno(num) == rec
676
677 c.close()
678
679
680
681class BTreeRecnoWithThreadFlagTestCase(BTreeRecnoTestCase):
682 dbopenflags = db.DB_THREAD
683
684#----------------------------------------------------------------------
685
686class BasicDUPTestCase(BasicTestCase):
687 dbsetflags = db.DB_DUP
688
689 def test08_DuplicateKeys(self):
690 d = self.d
691 if verbose:
692 print '\n', '-=' * 30
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000693 print "Running %s.test08_DuplicateKeys..." % \
694 self.__class__.__name__
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000695
696 d.put("dup0", "before")
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000697 for x in "The quick brown fox jumped over the lazy dog.".split():
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000698 d.put("dup1", x)
699 d.put("dup2", "after")
700
701 data = d.get("dup1")
702 assert data == "The"
703 if verbose:
704 print data
705
706 c = d.cursor()
707 rec = c.set("dup1")
708 assert rec == ('dup1', 'The')
709
710 next = c.next()
711 assert next == ('dup1', 'quick')
712
713 rec = c.set("dup1")
714 count = c.count()
715 assert count == 9
716
717 next_dup = c.next_dup()
718 assert next_dup == ('dup1', 'quick')
719
720 rec = c.set('dup1')
721 while rec is not None:
722 if verbose:
723 print rec
724 rec = c.next_dup()
725
726 c.set('dup1')
727 rec = c.next_nodup()
728 assert rec[0] != 'dup1'
729 if verbose:
730 print rec
731
732 c.close()
733
734
735
736class BTreeDUPTestCase(BasicDUPTestCase):
737 dbtype = db.DB_BTREE
738
739class HashDUPTestCase(BasicDUPTestCase):
740 dbtype = db.DB_HASH
741
742class BTreeDUPWithThreadTestCase(BasicDUPTestCase):
743 dbtype = db.DB_BTREE
744 dbopenflags = db.DB_THREAD
745
746class HashDUPWithThreadTestCase(BasicDUPTestCase):
747 dbtype = db.DB_HASH
748 dbopenflags = db.DB_THREAD
749
750
751#----------------------------------------------------------------------
752
753class BasicMultiDBTestCase(BasicTestCase):
754 dbname = 'first'
755
756 def otherType(self):
757 if self.dbtype == db.DB_BTREE:
758 return db.DB_HASH
759 else:
760 return db.DB_BTREE
761
762 def test09_MultiDB(self):
763 d1 = self.d
764 if verbose:
765 print '\n', '-=' * 30
766 print "Running %s.test09_MultiDB..." % self.__class__.__name__
767
768 d2 = db.DB(self.env)
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000769 d2.open(self.filename, "second", self.dbtype,
770 self.dbopenflags|db.DB_CREATE)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000771 d3 = db.DB(self.env)
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000772 d3.open(self.filename, "third", self.otherType(),
773 self.dbopenflags|db.DB_CREATE)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000774
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000775 for x in "The quick brown fox jumped over the lazy dog".split():
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000776 d2.put(x, self.makeData(x))
777
778 for x in string.letters:
779 d3.put(x, x*70)
780
781 d1.sync()
782 d2.sync()
783 d3.sync()
784 d1.close()
785 d2.close()
786 d3.close()
787
788 self.d = d1 = d2 = d3 = None
789
790 self.d = d1 = db.DB(self.env)
791 d1.open(self.filename, self.dbname, flags = self.dbopenflags)
792 d2 = db.DB(self.env)
793 d2.open(self.filename, "second", flags = self.dbopenflags)
794 d3 = db.DB(self.env)
795 d3.open(self.filename, "third", flags = self.dbopenflags)
796
797 c1 = d1.cursor()
798 c2 = d2.cursor()
799 c3 = d3.cursor()
800
801 count = 0
802 rec = c1.first()
803 while rec is not None:
804 count = count + 1
805 if verbose and (count % 50) == 0:
806 print rec
807 rec = c1.next()
808 assert count == 1000
809
810 count = 0
811 rec = c2.first()
812 while rec is not None:
813 count = count + 1
814 if verbose:
815 print rec
816 rec = c2.next()
817 assert count == 9
818
819 count = 0
820 rec = c3.first()
821 while rec is not None:
822 count = count + 1
823 if verbose:
824 print rec
825 rec = c3.next()
826 assert count == 52
827
828
829 c1.close()
830 c2.close()
831 c3.close()
832
833 d2.close()
834 d3.close()
835
836
837
838# Strange things happen if you try to use Multiple DBs per file without a
839# DBEnv with MPOOL and LOCKing...
840
841class BTreeMultiDBTestCase(BasicMultiDBTestCase):
842 dbtype = db.DB_BTREE
843 dbopenflags = db.DB_THREAD
844 useEnv = 1
845 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
846
847class HashMultiDBTestCase(BasicMultiDBTestCase):
848 dbtype = db.DB_HASH
849 dbopenflags = db.DB_THREAD
850 useEnv = 1
851 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
852
853
854#----------------------------------------------------------------------
855#----------------------------------------------------------------------
856
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000857def test_suite():
858 suite = unittest.TestSuite()
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000859
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000860 suite.addTest(unittest.makeSuite(VersionTestCase))
861 suite.addTest(unittest.makeSuite(BasicBTreeTestCase))
862 suite.addTest(unittest.makeSuite(BasicHashTestCase))
863 suite.addTest(unittest.makeSuite(BasicBTreeWithThreadFlagTestCase))
864 suite.addTest(unittest.makeSuite(BasicHashWithThreadFlagTestCase))
865 suite.addTest(unittest.makeSuite(BasicBTreeWithEnvTestCase))
866 suite.addTest(unittest.makeSuite(BasicHashWithEnvTestCase))
867 suite.addTest(unittest.makeSuite(BTreeTransactionTestCase))
868 suite.addTest(unittest.makeSuite(HashTransactionTestCase))
869 suite.addTest(unittest.makeSuite(BTreeRecnoTestCase))
870 suite.addTest(unittest.makeSuite(BTreeRecnoWithThreadFlagTestCase))
871 suite.addTest(unittest.makeSuite(BTreeDUPTestCase))
872 suite.addTest(unittest.makeSuite(HashDUPTestCase))
873 suite.addTest(unittest.makeSuite(BTreeDUPWithThreadTestCase))
874 suite.addTest(unittest.makeSuite(HashDUPWithThreadTestCase))
875 suite.addTest(unittest.makeSuite(BTreeMultiDBTestCase))
876 suite.addTest(unittest.makeSuite(HashMultiDBTestCase))
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000877
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000878 return suite
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000879
880
881if __name__ == '__main__':
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000882 unittest.main(defaultTest='test_suite')