blob: 7524b35eaf6a1ad34b78de98a528707cd199f1b5 [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
401 #----------------------------------------
402
403 def test04_PartialGetAndPut(self):
404 d = self.d
405 if verbose:
406 print '\n', '-=' * 30
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000407 print "Running %s.test04_PartialGetAndPut..." % \
408 self.__class__.__name__
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000409
410 key = "partialTest"
411 data = "1" * 1000 + "2" * 1000
412 d.put(key, data)
413 assert d.get(key) == data
414 assert d.get(key, dlen=20, doff=990) == ("1" * 10) + ("2" * 10)
415
416 d.put("partialtest2", ("1" * 30000) + "robin" )
417 assert d.get("partialtest2", dlen=5, doff=30000) == "robin"
418
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000419 # There seems to be a bug in DB here... Commented out the test for
420 # now.
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000421 ##assert d.get("partialtest2", dlen=5, doff=30010) == ""
422
423 if self.dbsetflags != db.DB_DUP:
424 # Partial put with duplicate records requires a cursor
425 d.put(key, "0000", dlen=2000, doff=0)
426 assert d.get(key) == "0000"
427
428 d.put(key, "1111", dlen=1, doff=2)
429 assert d.get(key) == "0011110"
430
431 #----------------------------------------
432
433 def test05_GetSize(self):
434 d = self.d
435 if verbose:
436 print '\n', '-=' * 30
437 print "Running %s.test05_GetSize..." % self.__class__.__name__
438
439 for i in range(1, 50000, 500):
440 key = "size%s" % i
441 #print "before ", i,
442 d.put(key, "1" * i)
443 #print "after",
444 assert d.get_size(key) == i
445 #print "done"
446
447 #----------------------------------------
448
449 def test06_Truncate(self):
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000450 if db.version() < (3,3):
451 # truncate is a feature of BerkeleyDB 3.3 and above
452 return
453
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000454 d = self.d
455 if verbose:
456 print '\n', '-=' * 30
457 print "Running %s.test99_Truncate..." % self.__class__.__name__
458
459 d.put("abcde", "ABCDE");
460 num = d.truncate()
461 assert num >= 1, "truncate returned <= 0 on non-empty database"
462 num = d.truncate()
463 assert num == 0, "truncate on empty DB returned nonzero (%s)" % `num`
464
465#----------------------------------------------------------------------
466
467
468class BasicBTreeTestCase(BasicTestCase):
469 dbtype = db.DB_BTREE
470
471
472class BasicHashTestCase(BasicTestCase):
473 dbtype = db.DB_HASH
474
475
476class BasicBTreeWithThreadFlagTestCase(BasicTestCase):
477 dbtype = db.DB_BTREE
478 dbopenflags = db.DB_THREAD
479
480
481class BasicHashWithThreadFlagTestCase(BasicTestCase):
482 dbtype = db.DB_HASH
483 dbopenflags = db.DB_THREAD
484
485
486class BasicBTreeWithEnvTestCase(BasicTestCase):
487 dbtype = db.DB_BTREE
488 dbopenflags = db.DB_THREAD
489 useEnv = 1
490 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
491
492
493class BasicHashWithEnvTestCase(BasicTestCase):
494 dbtype = db.DB_HASH
495 dbopenflags = db.DB_THREAD
496 useEnv = 1
497 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
498
499
500#----------------------------------------------------------------------
501
502class BasicTransactionTestCase(BasicTestCase):
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000503 dbopenflags = db.DB_THREAD | db.DB_AUTO_COMMIT
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000504 useEnv = 1
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000505 envflags = (db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK |
506 db.DB_INIT_TXN)
507 envsetflags = db.DB_AUTO_COMMIT
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000508
509
510 def tearDown(self):
511 self.txn.commit()
512 BasicTestCase.tearDown(self)
513
514
515 def populateDB(self):
516 d = self.d
517 txn = self.env.txn_begin()
518 for x in range(500):
519 key = '%04d' % (1000 - x) # insert keys in reverse order
520 data = self.makeData(key)
521 d.put(key, data, txn)
522
523 for x in range(500):
524 key = '%04d' % x # and now some in forward order
525 data = self.makeData(key)
526 d.put(key, data, txn)
527
528 txn.commit()
529
530 num = len(d)
531 if verbose:
532 print "created %d records" % num
533
534 self.txn = self.env.txn_begin()
535
536
537
538 def test06_Transactions(self):
539 d = self.d
540 if verbose:
541 print '\n', '-=' * 30
542 print "Running %s.test06_Transactions..." % self.__class__.__name__
543
544 assert d.get('new rec', txn=self.txn) == None
545 d.put('new rec', 'this is a new record', self.txn)
546 assert d.get('new rec', txn=self.txn) == 'this is a new record'
547 self.txn.abort()
548 assert d.get('new rec') == None
549
550 self.txn = self.env.txn_begin()
551
552 assert d.get('new rec', txn=self.txn) == None
553 d.put('new rec', 'this is a new record', self.txn)
554 assert d.get('new rec', txn=self.txn) == 'this is a new record'
555 self.txn.commit()
556 assert d.get('new rec') == 'this is a new record'
557
558 self.txn = self.env.txn_begin()
559 c = d.cursor(self.txn)
560 rec = c.first()
561 count = 0
562 while rec is not None:
563 count = count + 1
564 if verbose and count % 100 == 0:
565 print rec
566 rec = c.next()
567 assert count == 1001
568
569 c.close() # Cursors *MUST* be closed before commit!
570 self.txn.commit()
571
572 # flush pending updates
573 try:
574 self.env.txn_checkpoint (0, 0, 0)
575 except db.DBIncompleteError:
576 pass
577
578 # must have at least one log file present:
579 logs = self.env.log_archive(db.DB_ARCH_ABS | db.DB_ARCH_LOG)
580 assert logs != None
581 for log in logs:
582 if verbose:
583 print 'log file: ' + log
584
585 self.txn = self.env.txn_begin()
586
587 #----------------------------------------
588
589 def test07_TxnTruncate(self):
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000590 if db.version() < (3,3):
591 # truncate is a feature of BerkeleyDB 3.3 and above
592 return
593
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000594 d = self.d
595 if verbose:
596 print '\n', '-=' * 30
597 print "Running %s.test07_TxnTruncate..." % self.__class__.__name__
598
599 d.put("abcde", "ABCDE");
600 txn = self.env.txn_begin()
601 num = d.truncate(txn)
602 assert num >= 1, "truncate returned <= 0 on non-empty database"
603 num = d.truncate(txn)
604 assert num == 0, "truncate on empty DB returned nonzero (%s)" % `num`
605 txn.commit()
606
Gregory P. Smithc25fd3f2003-01-17 07:52:59 +0000607 #----------------------------------------
608
609 def test08_TxnLateUse(self):
610 txn = self.env.txn_begin()
611 txn.abort()
612 try:
613 txn.abort()
614 except db.DBError, e:
615 pass
616 else:
617 raise RuntimeError, "DBTxn.abort() called after DB_TXN no longer valid w/o an exception"
618
619 txn = self.env.txn_begin()
620 txn.commit()
621 try:
622 txn.commit()
623 except db.DBError, e:
624 pass
625 else:
626 raise RuntimeError, "DBTxn.commit() called after DB_TXN no longer valid w/o an exception"
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000627
628
629class BTreeTransactionTestCase(BasicTransactionTestCase):
630 dbtype = db.DB_BTREE
631
632class HashTransactionTestCase(BasicTransactionTestCase):
633 dbtype = db.DB_HASH
634
635
636
637#----------------------------------------------------------------------
638
639class BTreeRecnoTestCase(BasicTestCase):
640 dbtype = db.DB_BTREE
641 dbsetflags = db.DB_RECNUM
642
643 def test07_RecnoInBTree(self):
644 d = self.d
645 if verbose:
646 print '\n', '-=' * 30
647 print "Running %s.test07_RecnoInBTree..." % self.__class__.__name__
648
649 rec = d.get(200)
650 assert type(rec) == type(())
651 assert len(rec) == 2
652 if verbose:
653 print "Record #200 is ", rec
654
655 c = d.cursor()
656 c.set('0200')
657 num = c.get_recno()
658 assert type(num) == type(1)
659 if verbose:
660 print "recno of d['0200'] is ", num
661
662 rec = c.current()
663 assert c.set_recno(num) == rec
664
665 c.close()
666
667
668
669class BTreeRecnoWithThreadFlagTestCase(BTreeRecnoTestCase):
670 dbopenflags = db.DB_THREAD
671
672#----------------------------------------------------------------------
673
674class BasicDUPTestCase(BasicTestCase):
675 dbsetflags = db.DB_DUP
676
677 def test08_DuplicateKeys(self):
678 d = self.d
679 if verbose:
680 print '\n', '-=' * 30
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000681 print "Running %s.test08_DuplicateKeys..." % \
682 self.__class__.__name__
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000683
684 d.put("dup0", "before")
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000685 for x in "The quick brown fox jumped over the lazy dog.".split():
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000686 d.put("dup1", x)
687 d.put("dup2", "after")
688
689 data = d.get("dup1")
690 assert data == "The"
691 if verbose:
692 print data
693
694 c = d.cursor()
695 rec = c.set("dup1")
696 assert rec == ('dup1', 'The')
697
698 next = c.next()
699 assert next == ('dup1', 'quick')
700
701 rec = c.set("dup1")
702 count = c.count()
703 assert count == 9
704
705 next_dup = c.next_dup()
706 assert next_dup == ('dup1', 'quick')
707
708 rec = c.set('dup1')
709 while rec is not None:
710 if verbose:
711 print rec
712 rec = c.next_dup()
713
714 c.set('dup1')
715 rec = c.next_nodup()
716 assert rec[0] != 'dup1'
717 if verbose:
718 print rec
719
720 c.close()
721
722
723
724class BTreeDUPTestCase(BasicDUPTestCase):
725 dbtype = db.DB_BTREE
726
727class HashDUPTestCase(BasicDUPTestCase):
728 dbtype = db.DB_HASH
729
730class BTreeDUPWithThreadTestCase(BasicDUPTestCase):
731 dbtype = db.DB_BTREE
732 dbopenflags = db.DB_THREAD
733
734class HashDUPWithThreadTestCase(BasicDUPTestCase):
735 dbtype = db.DB_HASH
736 dbopenflags = db.DB_THREAD
737
738
739#----------------------------------------------------------------------
740
741class BasicMultiDBTestCase(BasicTestCase):
742 dbname = 'first'
743
744 def otherType(self):
745 if self.dbtype == db.DB_BTREE:
746 return db.DB_HASH
747 else:
748 return db.DB_BTREE
749
750 def test09_MultiDB(self):
751 d1 = self.d
752 if verbose:
753 print '\n', '-=' * 30
754 print "Running %s.test09_MultiDB..." % self.__class__.__name__
755
756 d2 = db.DB(self.env)
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000757 d2.open(self.filename, "second", self.dbtype,
758 self.dbopenflags|db.DB_CREATE)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000759 d3 = db.DB(self.env)
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000760 d3.open(self.filename, "third", self.otherType(),
761 self.dbopenflags|db.DB_CREATE)
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000762
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000763 for x in "The quick brown fox jumped over the lazy dog".split():
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000764 d2.put(x, self.makeData(x))
765
766 for x in string.letters:
767 d3.put(x, x*70)
768
769 d1.sync()
770 d2.sync()
771 d3.sync()
772 d1.close()
773 d2.close()
774 d3.close()
775
776 self.d = d1 = d2 = d3 = None
777
778 self.d = d1 = db.DB(self.env)
779 d1.open(self.filename, self.dbname, flags = self.dbopenflags)
780 d2 = db.DB(self.env)
781 d2.open(self.filename, "second", flags = self.dbopenflags)
782 d3 = db.DB(self.env)
783 d3.open(self.filename, "third", flags = self.dbopenflags)
784
785 c1 = d1.cursor()
786 c2 = d2.cursor()
787 c3 = d3.cursor()
788
789 count = 0
790 rec = c1.first()
791 while rec is not None:
792 count = count + 1
793 if verbose and (count % 50) == 0:
794 print rec
795 rec = c1.next()
796 assert count == 1000
797
798 count = 0
799 rec = c2.first()
800 while rec is not None:
801 count = count + 1
802 if verbose:
803 print rec
804 rec = c2.next()
805 assert count == 9
806
807 count = 0
808 rec = c3.first()
809 while rec is not None:
810 count = count + 1
811 if verbose:
812 print rec
813 rec = c3.next()
814 assert count == 52
815
816
817 c1.close()
818 c2.close()
819 c3.close()
820
821 d2.close()
822 d3.close()
823
824
825
826# Strange things happen if you try to use Multiple DBs per file without a
827# DBEnv with MPOOL and LOCKing...
828
829class BTreeMultiDBTestCase(BasicMultiDBTestCase):
830 dbtype = db.DB_BTREE
831 dbopenflags = db.DB_THREAD
832 useEnv = 1
833 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
834
835class HashMultiDBTestCase(BasicMultiDBTestCase):
836 dbtype = db.DB_HASH
837 dbopenflags = db.DB_THREAD
838 useEnv = 1
839 envflags = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK
840
841
842#----------------------------------------------------------------------
843#----------------------------------------------------------------------
844
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000845def test_suite():
846 suite = unittest.TestSuite()
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000847
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000848 suite.addTest(unittest.makeSuite(VersionTestCase))
849 suite.addTest(unittest.makeSuite(BasicBTreeTestCase))
850 suite.addTest(unittest.makeSuite(BasicHashTestCase))
851 suite.addTest(unittest.makeSuite(BasicBTreeWithThreadFlagTestCase))
852 suite.addTest(unittest.makeSuite(BasicHashWithThreadFlagTestCase))
853 suite.addTest(unittest.makeSuite(BasicBTreeWithEnvTestCase))
854 suite.addTest(unittest.makeSuite(BasicHashWithEnvTestCase))
855 suite.addTest(unittest.makeSuite(BTreeTransactionTestCase))
856 suite.addTest(unittest.makeSuite(HashTransactionTestCase))
857 suite.addTest(unittest.makeSuite(BTreeRecnoTestCase))
858 suite.addTest(unittest.makeSuite(BTreeRecnoWithThreadFlagTestCase))
859 suite.addTest(unittest.makeSuite(BTreeDUPTestCase))
860 suite.addTest(unittest.makeSuite(HashDUPTestCase))
861 suite.addTest(unittest.makeSuite(BTreeDUPWithThreadTestCase))
862 suite.addTest(unittest.makeSuite(HashDUPWithThreadTestCase))
863 suite.addTest(unittest.makeSuite(BTreeMultiDBTestCase))
864 suite.addTest(unittest.makeSuite(HashMultiDBTestCase))
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000865
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000866 return suite
Martin v. Löwis1c6b1a22002-11-19 17:47:07 +0000867
868
869if __name__ == '__main__':
Barry Warsaw9a0d7792002-12-30 20:53:52 +0000870 unittest.main(defaultTest='test_suite')