blob: 3a10fab404ffb39558e8100f12bd801d44b5394c [file] [log] [blame]
Roger E. Masse352e1861997-01-16 22:04:10 +00001#! /usr/bin/env python
Raymond Hettingerd55111f2003-09-13 05:51:09 +00002"""Test script for the bsddb C module by Roger E. Masse
3 Adapted to unittest format and expanded scope by Raymond Hettinger
Roger E. Masse352e1861997-01-16 22:04:10 +00004"""
Gregory P. Smithdc113a82003-11-02 09:10:16 +00005import os, sys
Raymond Hettingerd55111f2003-09-13 05:51:09 +00006import unittest
7from test import test_support
Roger E. Masse352e1861997-01-16 22:04:10 +00008
R. David Murray597ebab2009-03-31 18:32:17 +00009# Skip test if _bsddb wasn't built.
10test_support.import_module('_bsddb')
11
Ezio Melottia2d46532010-01-30 07:22:54 +000012bsddb = test_support.import_module('bsddb', deprecated=True)
13# Just so we know it's imported:
14test_support.import_module('dbhash', deprecated=True)
R. David Murray597ebab2009-03-31 18:32:17 +000015
16
Raymond Hettingerd55111f2003-09-13 05:51:09 +000017class TestBSDDB(unittest.TestCase):
Gregory P. Smith14c6b462006-04-12 20:16:56 +000018 openflag = 'c'
Roger E. Masse352e1861997-01-16 22:04:10 +000019
Raymond Hettingerd55111f2003-09-13 05:51:09 +000020 def setUp(self):
Gregory P. Smith64029982006-04-12 20:35:02 +000021 self.f = self.openmethod[0](self.fname, self.openflag, cachesize=32768)
Raymond Hettingerd55111f2003-09-13 05:51:09 +000022 self.d = dict(q='Guido', w='van', e='Rossum', r='invented', t='Python', y='')
23 for k, v in self.d.iteritems():
24 self.f[k] = v
Fred Drake004d5e62000-10-23 17:22:08 +000025
Raymond Hettingerd55111f2003-09-13 05:51:09 +000026 def tearDown(self):
27 self.f.sync()
28 self.f.close()
29 if self.fname is None:
30 return
Anthony Baxter83888952002-04-23 02:11:05 +000031 try:
Raymond Hettingerd55111f2003-09-13 05:51:09 +000032 os.remove(self.fname)
Anthony Baxter83888952002-04-23 02:11:05 +000033 except os.error:
34 pass
Roger E. Masse352e1861997-01-16 22:04:10 +000035
Raymond Hettingerd55111f2003-09-13 05:51:09 +000036 def test_getitem(self):
37 for k, v in self.d.iteritems():
38 self.assertEqual(self.f[k], v)
Roger E. Masse352e1861997-01-16 22:04:10 +000039
Raymond Hettingerd55111f2003-09-13 05:51:09 +000040 def test_len(self):
41 self.assertEqual(len(self.f), len(self.d))
42
43 def test_change(self):
44 self.f['r'] = 'discovered'
45 self.assertEqual(self.f['r'], 'discovered')
Ezio Melottiaa980582010-01-23 23:04:36 +000046 self.assertIn('r', self.f.keys())
47 self.assertIn('discovered', self.f.values())
Raymond Hettingerd55111f2003-09-13 05:51:09 +000048
49 def test_close_and_reopen(self):
Zachary Ware1f702212013-12-10 14:09:20 -060050 self.assertIsNotNone(self.fname)
Raymond Hettingerd55111f2003-09-13 05:51:09 +000051 self.f.close()
52 self.f = self.openmethod[0](self.fname, 'w')
53 for k, v in self.d.iteritems():
54 self.assertEqual(self.f[k], v)
55
56 def assertSetEquals(self, seqn1, seqn2):
Georg Brandl7b71bf32006-07-17 13:23:46 +000057 self.assertEqual(set(seqn1), set(seqn2))
Raymond Hettingerd55111f2003-09-13 05:51:09 +000058
59 def test_mapping_iteration_methods(self):
60 f = self.f
61 d = self.d
62 self.assertSetEquals(d, f)
63 self.assertSetEquals(d.keys(), f.keys())
64 self.assertSetEquals(d.values(), f.values())
65 self.assertSetEquals(d.items(), f.items())
66 self.assertSetEquals(d.iterkeys(), f.iterkeys())
67 self.assertSetEquals(d.itervalues(), f.itervalues())
68 self.assertSetEquals(d.iteritems(), f.iteritems())
69
Gregory P. Smitha703a212003-11-03 01:04:41 +000070 def test_iter_while_modifying_values(self):
Gregory P. Smitha703a212003-11-03 01:04:41 +000071 di = iter(self.d)
72 while 1:
73 try:
74 key = di.next()
75 self.d[key] = 'modified '+key
76 except StopIteration:
77 break
78
79 # it should behave the same as a dict. modifying values
80 # of existing keys should not break iteration. (adding
81 # or removing keys should)
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000082 loops_left = len(self.f)
Gregory P. Smitha703a212003-11-03 01:04:41 +000083 fi = iter(self.f)
84 while 1:
85 try:
86 key = fi.next()
87 self.f[key] = 'modified '+key
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000088 loops_left -= 1
Gregory P. Smitha703a212003-11-03 01:04:41 +000089 except StopIteration:
90 break
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000091 self.assertEqual(loops_left, 0)
Gregory P. Smitha703a212003-11-03 01:04:41 +000092
93 self.test_mapping_iteration_methods()
94
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000095 def test_iter_abort_on_changed_size(self):
96 def DictIterAbort():
97 di = iter(self.d)
98 while 1:
99 try:
100 di.next()
101 self.d['newkey'] = 'SPAM'
102 except StopIteration:
103 break
104 self.assertRaises(RuntimeError, DictIterAbort)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000105
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000106 def DbIterAbort():
107 fi = iter(self.f)
108 while 1:
109 try:
110 fi.next()
111 self.f['newkey'] = 'SPAM'
112 except StopIteration:
113 break
114 self.assertRaises(RuntimeError, DbIterAbort)
115
116 def test_iteritems_abort_on_changed_size(self):
117 def DictIteritemsAbort():
118 di = self.d.iteritems()
119 while 1:
120 try:
121 di.next()
122 self.d['newkey'] = 'SPAM'
123 except StopIteration:
124 break
125 self.assertRaises(RuntimeError, DictIteritemsAbort)
126
127 def DbIteritemsAbort():
128 fi = self.f.iteritems()
129 while 1:
130 try:
131 key, value = fi.next()
132 del self.f[key]
133 except StopIteration:
134 break
135 self.assertRaises(RuntimeError, DbIteritemsAbort)
136
137 def test_iteritems_while_modifying_values(self):
Gregory P. Smitha703a212003-11-03 01:04:41 +0000138 di = self.d.iteritems()
139 while 1:
140 try:
141 k, v = di.next()
142 self.d[k] = 'modified '+v
143 except StopIteration:
144 break
145
146 # it should behave the same as a dict. modifying values
147 # of existing keys should not break iteration. (adding
148 # or removing keys should)
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000149 loops_left = len(self.f)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000150 fi = self.f.iteritems()
151 while 1:
152 try:
153 k, v = fi.next()
154 self.f[k] = 'modified '+v
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000155 loops_left -= 1
Gregory P. Smitha703a212003-11-03 01:04:41 +0000156 except StopIteration:
157 break
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000158 self.assertEqual(loops_left, 0)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000159
160 self.test_mapping_iteration_methods()
161
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000162 def test_first_next_looping(self):
163 items = [self.f.first()]
164 for i in xrange(1, len(self.f)):
165 items.append(self.f.next())
166 self.assertSetEquals(items, self.d.items())
167
168 def test_previous_last_looping(self):
169 items = [self.f.last()]
170 for i in xrange(1, len(self.f)):
171 items.append(self.f.previous())
172 self.assertSetEquals(items, self.d.items())
173
Gregory P. Smith1042a4d2007-08-24 05:11:38 +0000174 def test_first_while_deleting(self):
175 # Test for bug 1725856
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000176 self.assertTrue(len(self.d) >= 2, "test requires >=2 items")
Gregory P. Smith1042a4d2007-08-24 05:11:38 +0000177 for _ in self.d:
178 key = self.f.first()[0]
179 del self.f[key]
180 self.assertEqual([], self.f.items(), "expected empty db after test")
181
182 def test_last_while_deleting(self):
183 # Test for bug 1725856's evil twin
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000184 self.assertTrue(len(self.d) >= 2, "test requires >=2 items")
Gregory P. Smith1042a4d2007-08-24 05:11:38 +0000185 for _ in self.d:
186 key = self.f.last()[0]
187 del self.f[key]
188 self.assertEqual([], self.f.items(), "expected empty db after test")
189
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000190 def test_set_location(self):
191 self.assertEqual(self.f.set_location('e'), ('e', self.d['e']))
192
193 def test_contains(self):
194 for k in self.d:
Ezio Melottiaa980582010-01-23 23:04:36 +0000195 self.assertIn(k, self.f)
196 self.assertNotIn('not here', self.f)
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000197
198 def test_has_key(self):
199 for k in self.d:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000200 self.assertTrue(self.f.has_key(k))
201 self.assertTrue(not self.f.has_key('not here'))
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000202
203 def test_clear(self):
204 self.f.clear()
205 self.assertEqual(len(self.f), 0)
206
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000207 def test__no_deadlock_first(self, debug=0):
208 # do this so that testers can see what function we're in in
209 # verbose mode when we deadlock.
210 sys.stdout.flush()
211
212 # in pybsddb's _DBWithCursor this causes an internal DBCursor
213 # object is created. Other test_ methods in this class could
214 # inadvertently cause the deadlock but an explicit test is needed.
215 if debug: print "A"
216 k,v = self.f.first()
217 if debug: print "B", k
218 self.f[k] = "deadlock. do not pass go. do not collect $200."
219 if debug: print "C"
220 # if the bsddb implementation leaves the DBCursor open during
221 # the database write and locking+threading support is enabled
222 # the cursor's read lock will deadlock the write lock request..
223
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000224 # test the iterator interface
225 if True:
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000226 if debug: print "D"
Gregory P. Smitha703a212003-11-03 01:04:41 +0000227 i = self.f.iteritems()
228 k,v = i.next()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000229 if debug: print "E"
230 self.f[k] = "please don't deadlock"
231 if debug: print "F"
232 while 1:
233 try:
Gregory P. Smitha703a212003-11-03 01:04:41 +0000234 k,v = i.next()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000235 except StopIteration:
236 break
237 if debug: print "F2"
238
239 i = iter(self.f)
240 if debug: print "G"
241 while i:
242 try:
243 if debug: print "H"
244 k = i.next()
245 if debug: print "I"
246 self.f[k] = "deadlocks-r-us"
247 if debug: print "J"
248 except StopIteration:
249 i = None
250 if debug: print "K"
251
252 # test the legacy cursor interface mixed with writes
Ezio Melottiaa980582010-01-23 23:04:36 +0000253 self.assertIn(self.f.first()[0], self.d)
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000254 k = self.f.next()[0]
Ezio Melottiaa980582010-01-23 23:04:36 +0000255 self.assertIn(k, self.d)
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000256 self.f[k] = "be gone with ye deadlocks"
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000257 self.assertTrue(self.f[k], "be gone with ye deadlocks")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000258
Gregory P. Smitha703a212003-11-03 01:04:41 +0000259 def test_for_cursor_memleak(self):
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000260 # do the bsddb._DBWithCursor iterator internals leak cursors?
Gregory P. Smitha703a212003-11-03 01:04:41 +0000261 nc1 = len(self.f._cursor_refs)
262 # create iterator
263 i = self.f.iteritems()
264 nc2 = len(self.f._cursor_refs)
Neal Norwitz764cf7e2007-02-23 00:22:39 +0000265 # use the iterator (should run to the first yield, creating the cursor)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000266 k, v = i.next()
267 nc3 = len(self.f._cursor_refs)
268 # destroy the iterator; this should cause the weakref callback
269 # to remove the cursor object from self.f._cursor_refs
270 del i
271 nc4 = len(self.f._cursor_refs)
272
273 self.assertEqual(nc1, nc2)
274 self.assertEqual(nc1, nc4)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000275 self.assertTrue(nc3 == nc1+1)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000276
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000277 def test_popitem(self):
278 k, v = self.f.popitem()
Ezio Melottiaa980582010-01-23 23:04:36 +0000279 self.assertIn(k, self.d)
280 self.assertIn(v, self.d.values())
281 self.assertNotIn(k, self.f)
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000282 self.assertEqual(len(self.d)-1, len(self.f))
283
284 def test_pop(self):
285 k = 'w'
286 v = self.f.pop(k)
287 self.assertEqual(v, self.d[k])
Ezio Melottiaa980582010-01-23 23:04:36 +0000288 self.assertNotIn(k, self.f)
289 self.assertNotIn(v, self.f.values())
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000290 self.assertEqual(len(self.d)-1, len(self.f))
291
292 def test_get(self):
293 self.assertEqual(self.f.get('NotHere'), None)
294 self.assertEqual(self.f.get('NotHere', 'Default'), 'Default')
295 self.assertEqual(self.f.get('q', 'Default'), self.d['q'])
296
297 def test_setdefault(self):
298 self.assertEqual(self.f.setdefault('new', 'dog'), 'dog')
299 self.assertEqual(self.f.setdefault('r', 'cat'), self.d['r'])
300
301 def test_update(self):
302 new = dict(y='life', u='of', i='brian')
303 self.f.update(new)
304 self.d.update(new)
305 for k, v in self.d.iteritems():
306 self.assertEqual(self.f[k], v)
307
308 def test_keyordering(self):
Zachary Ware1f702212013-12-10 14:09:20 -0600309 self.assertIs(self.openmethod[0], bsddb.btopen)
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000310 keys = self.d.keys()
311 keys.sort()
312 self.assertEqual(self.f.first()[0], keys[0])
313 self.assertEqual(self.f.next()[0], keys[1])
314 self.assertEqual(self.f.last()[0], keys[-1])
315 self.assertEqual(self.f.previous()[0], keys[-2])
316 self.assertEqual(list(self.f), keys)
317
318class TestBTree(TestBSDDB):
319 fname = test_support.TESTFN
320 openmethod = [bsddb.btopen]
321
322class TestBTree_InMemory(TestBSDDB):
323 fname = None
324 openmethod = [bsddb.btopen]
325
Zachary Ware1f702212013-12-10 14:09:20 -0600326 # if we're using an in-memory only db, we can't reopen it
327 test_close_and_reopen = None
328
Gregory P. Smith14c6b462006-04-12 20:16:56 +0000329class TestBTree_InMemory_Truncate(TestBSDDB):
330 fname = None
331 openflag = 'n'
332 openmethod = [bsddb.btopen]
333
Zachary Ware1f702212013-12-10 14:09:20 -0600334 # if we're using an in-memory only db, we can't reopen it
335 test_close_and_reopen = None
336
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000337class TestHashTable(TestBSDDB):
338 fname = test_support.TESTFN
339 openmethod = [bsddb.hashopen]
340
Zachary Ware1f702212013-12-10 14:09:20 -0600341 # keyordering is specific to btopen method
342 test_keyordering = None
343
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000344class TestHashTable_InMemory(TestBSDDB):
345 fname = None
346 openmethod = [bsddb.hashopen]
347
Zachary Ware1f702212013-12-10 14:09:20 -0600348 # if we're using an in-memory only db, we can't reopen it
349 test_close_and_reopen = None
350
351 # keyordering is specific to btopen method
352 test_keyordering = None
353
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000354## # (bsddb.rnopen,'Record Numbers'), 'put' for RECNO for bsddb 1.85
355## # appears broken... at least on
356## # Solaris Intel - rmasse 1/97
357
358def test_main(verbose=None):
359 test_support.run_unittest(
360 TestBTree,
361 TestHashTable,
362 TestBTree_InMemory,
363 TestHashTable_InMemory,
Gregory P. Smith14c6b462006-04-12 20:16:56 +0000364 TestBTree_InMemory_Truncate,
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000365 )
366
367if __name__ == "__main__":
368 test_main(verbose=True)