blob: a5fa494401f3667d8f16b4e2451cc6405bf4c9ad [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
Gregory P. Smitha703a212003-11-03 01:04:41 +00006import copy
Raymond Hettingerd55111f2003-09-13 05:51:09 +00007import unittest
8from test import test_support
Roger E. Masse352e1861997-01-16 22:04:10 +00009
R. David Murray597ebab2009-03-31 18:32:17 +000010# Skip test if _bsddb wasn't built.
11test_support.import_module('_bsddb')
12
Ezio Melottia2d46532010-01-30 07:22:54 +000013bsddb = test_support.import_module('bsddb', deprecated=True)
14# Just so we know it's imported:
15test_support.import_module('dbhash', deprecated=True)
R. David Murray597ebab2009-03-31 18:32:17 +000016
17
Raymond Hettingerd55111f2003-09-13 05:51:09 +000018class TestBSDDB(unittest.TestCase):
Gregory P. Smith14c6b462006-04-12 20:16:56 +000019 openflag = 'c'
Roger E. Masse352e1861997-01-16 22:04:10 +000020
Raymond Hettingerd55111f2003-09-13 05:51:09 +000021 def setUp(self):
Gregory P. Smith64029982006-04-12 20:35:02 +000022 self.f = self.openmethod[0](self.fname, self.openflag, cachesize=32768)
Raymond Hettingerd55111f2003-09-13 05:51:09 +000023 self.d = dict(q='Guido', w='van', e='Rossum', r='invented', t='Python', y='')
24 for k, v in self.d.iteritems():
25 self.f[k] = v
Fred Drake004d5e62000-10-23 17:22:08 +000026
Raymond Hettingerd55111f2003-09-13 05:51:09 +000027 def tearDown(self):
28 self.f.sync()
29 self.f.close()
30 if self.fname is None:
31 return
Anthony Baxter83888952002-04-23 02:11:05 +000032 try:
Raymond Hettingerd55111f2003-09-13 05:51:09 +000033 os.remove(self.fname)
Anthony Baxter83888952002-04-23 02:11:05 +000034 except os.error:
35 pass
Roger E. Masse352e1861997-01-16 22:04:10 +000036
Raymond Hettingerd55111f2003-09-13 05:51:09 +000037 def test_getitem(self):
38 for k, v in self.d.iteritems():
39 self.assertEqual(self.f[k], v)
Roger E. Masse352e1861997-01-16 22:04:10 +000040
Raymond Hettingerd55111f2003-09-13 05:51:09 +000041 def test_len(self):
42 self.assertEqual(len(self.f), len(self.d))
43
44 def test_change(self):
45 self.f['r'] = 'discovered'
46 self.assertEqual(self.f['r'], 'discovered')
Ezio Melottiaa980582010-01-23 23:04:36 +000047 self.assertIn('r', self.f.keys())
48 self.assertIn('discovered', self.f.values())
Raymond Hettingerd55111f2003-09-13 05:51:09 +000049
50 def test_close_and_reopen(self):
51 if self.fname is None:
52 # if we're using an in-memory only db, we can't reopen it
53 # so finish here.
54 return
55 self.f.close()
56 self.f = self.openmethod[0](self.fname, 'w')
57 for k, v in self.d.iteritems():
58 self.assertEqual(self.f[k], v)
59
60 def assertSetEquals(self, seqn1, seqn2):
Georg Brandl7b71bf32006-07-17 13:23:46 +000061 self.assertEqual(set(seqn1), set(seqn2))
Raymond Hettingerd55111f2003-09-13 05:51:09 +000062
63 def test_mapping_iteration_methods(self):
64 f = self.f
65 d = self.d
66 self.assertSetEquals(d, f)
67 self.assertSetEquals(d.keys(), f.keys())
68 self.assertSetEquals(d.values(), f.values())
69 self.assertSetEquals(d.items(), f.items())
70 self.assertSetEquals(d.iterkeys(), f.iterkeys())
71 self.assertSetEquals(d.itervalues(), f.itervalues())
72 self.assertSetEquals(d.iteritems(), f.iteritems())
73
Gregory P. Smitha703a212003-11-03 01:04:41 +000074 def test_iter_while_modifying_values(self):
Gregory P. Smitha703a212003-11-03 01:04:41 +000075 di = iter(self.d)
76 while 1:
77 try:
78 key = di.next()
79 self.d[key] = 'modified '+key
80 except StopIteration:
81 break
82
83 # it should behave the same as a dict. modifying values
84 # of existing keys should not break iteration. (adding
85 # or removing keys should)
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000086 loops_left = len(self.f)
Gregory P. Smitha703a212003-11-03 01:04:41 +000087 fi = iter(self.f)
88 while 1:
89 try:
90 key = fi.next()
91 self.f[key] = 'modified '+key
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000092 loops_left -= 1
Gregory P. Smitha703a212003-11-03 01:04:41 +000093 except StopIteration:
94 break
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000095 self.assertEqual(loops_left, 0)
Gregory P. Smitha703a212003-11-03 01:04:41 +000096
97 self.test_mapping_iteration_methods()
98
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000099 def test_iter_abort_on_changed_size(self):
100 def DictIterAbort():
101 di = iter(self.d)
102 while 1:
103 try:
104 di.next()
105 self.d['newkey'] = 'SPAM'
106 except StopIteration:
107 break
108 self.assertRaises(RuntimeError, DictIterAbort)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000109
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000110 def DbIterAbort():
111 fi = iter(self.f)
112 while 1:
113 try:
114 fi.next()
115 self.f['newkey'] = 'SPAM'
116 except StopIteration:
117 break
118 self.assertRaises(RuntimeError, DbIterAbort)
119
120 def test_iteritems_abort_on_changed_size(self):
121 def DictIteritemsAbort():
122 di = self.d.iteritems()
123 while 1:
124 try:
125 di.next()
126 self.d['newkey'] = 'SPAM'
127 except StopIteration:
128 break
129 self.assertRaises(RuntimeError, DictIteritemsAbort)
130
131 def DbIteritemsAbort():
132 fi = self.f.iteritems()
133 while 1:
134 try:
135 key, value = fi.next()
136 del self.f[key]
137 except StopIteration:
138 break
139 self.assertRaises(RuntimeError, DbIteritemsAbort)
140
141 def test_iteritems_while_modifying_values(self):
Gregory P. Smitha703a212003-11-03 01:04:41 +0000142 di = self.d.iteritems()
143 while 1:
144 try:
145 k, v = di.next()
146 self.d[k] = 'modified '+v
147 except StopIteration:
148 break
149
150 # it should behave the same as a dict. modifying values
151 # of existing keys should not break iteration. (adding
152 # or removing keys should)
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000153 loops_left = len(self.f)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000154 fi = self.f.iteritems()
155 while 1:
156 try:
157 k, v = fi.next()
158 self.f[k] = 'modified '+v
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000159 loops_left -= 1
Gregory P. Smitha703a212003-11-03 01:04:41 +0000160 except StopIteration:
161 break
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000162 self.assertEqual(loops_left, 0)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000163
164 self.test_mapping_iteration_methods()
165
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000166 def test_first_next_looping(self):
167 items = [self.f.first()]
168 for i in xrange(1, len(self.f)):
169 items.append(self.f.next())
170 self.assertSetEquals(items, self.d.items())
171
172 def test_previous_last_looping(self):
173 items = [self.f.last()]
174 for i in xrange(1, len(self.f)):
175 items.append(self.f.previous())
176 self.assertSetEquals(items, self.d.items())
177
Gregory P. Smith1042a4d2007-08-24 05:11:38 +0000178 def test_first_while_deleting(self):
179 # Test for bug 1725856
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000180 self.assertTrue(len(self.d) >= 2, "test requires >=2 items")
Gregory P. Smith1042a4d2007-08-24 05:11:38 +0000181 for _ in self.d:
182 key = self.f.first()[0]
183 del self.f[key]
184 self.assertEqual([], self.f.items(), "expected empty db after test")
185
186 def test_last_while_deleting(self):
187 # Test for bug 1725856's evil twin
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000188 self.assertTrue(len(self.d) >= 2, "test requires >=2 items")
Gregory P. Smith1042a4d2007-08-24 05:11:38 +0000189 for _ in self.d:
190 key = self.f.last()[0]
191 del self.f[key]
192 self.assertEqual([], self.f.items(), "expected empty db after test")
193
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000194 def test_set_location(self):
195 self.assertEqual(self.f.set_location('e'), ('e', self.d['e']))
196
197 def test_contains(self):
198 for k in self.d:
Ezio Melottiaa980582010-01-23 23:04:36 +0000199 self.assertIn(k, self.f)
200 self.assertNotIn('not here', self.f)
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000201
202 def test_has_key(self):
203 for k in self.d:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000204 self.assertTrue(self.f.has_key(k))
205 self.assertTrue(not self.f.has_key('not here'))
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000206
207 def test_clear(self):
208 self.f.clear()
209 self.assertEqual(len(self.f), 0)
210
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000211 def test__no_deadlock_first(self, debug=0):
212 # do this so that testers can see what function we're in in
213 # verbose mode when we deadlock.
214 sys.stdout.flush()
215
216 # in pybsddb's _DBWithCursor this causes an internal DBCursor
217 # object is created. Other test_ methods in this class could
218 # inadvertently cause the deadlock but an explicit test is needed.
219 if debug: print "A"
220 k,v = self.f.first()
221 if debug: print "B", k
222 self.f[k] = "deadlock. do not pass go. do not collect $200."
223 if debug: print "C"
224 # if the bsddb implementation leaves the DBCursor open during
225 # the database write and locking+threading support is enabled
226 # the cursor's read lock will deadlock the write lock request..
227
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000228 # test the iterator interface
229 if True:
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000230 if debug: print "D"
Gregory P. Smitha703a212003-11-03 01:04:41 +0000231 i = self.f.iteritems()
232 k,v = i.next()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000233 if debug: print "E"
234 self.f[k] = "please don't deadlock"
235 if debug: print "F"
236 while 1:
237 try:
Gregory P. Smitha703a212003-11-03 01:04:41 +0000238 k,v = i.next()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000239 except StopIteration:
240 break
241 if debug: print "F2"
242
243 i = iter(self.f)
244 if debug: print "G"
245 while i:
246 try:
247 if debug: print "H"
248 k = i.next()
249 if debug: print "I"
250 self.f[k] = "deadlocks-r-us"
251 if debug: print "J"
252 except StopIteration:
253 i = None
254 if debug: print "K"
255
256 # test the legacy cursor interface mixed with writes
Ezio Melottiaa980582010-01-23 23:04:36 +0000257 self.assertIn(self.f.first()[0], self.d)
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000258 k = self.f.next()[0]
Ezio Melottiaa980582010-01-23 23:04:36 +0000259 self.assertIn(k, self.d)
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000260 self.f[k] = "be gone with ye deadlocks"
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000261 self.assertTrue(self.f[k], "be gone with ye deadlocks")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000262
Gregory P. Smitha703a212003-11-03 01:04:41 +0000263 def test_for_cursor_memleak(self):
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000264 # do the bsddb._DBWithCursor iterator internals leak cursors?
Gregory P. Smitha703a212003-11-03 01:04:41 +0000265 nc1 = len(self.f._cursor_refs)
266 # create iterator
267 i = self.f.iteritems()
268 nc2 = len(self.f._cursor_refs)
Neal Norwitz764cf7e2007-02-23 00:22:39 +0000269 # use the iterator (should run to the first yield, creating the cursor)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000270 k, v = i.next()
271 nc3 = len(self.f._cursor_refs)
272 # destroy the iterator; this should cause the weakref callback
273 # to remove the cursor object from self.f._cursor_refs
274 del i
275 nc4 = len(self.f._cursor_refs)
276
277 self.assertEqual(nc1, nc2)
278 self.assertEqual(nc1, nc4)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000279 self.assertTrue(nc3 == nc1+1)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000280
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000281 def test_popitem(self):
282 k, v = self.f.popitem()
Ezio Melottiaa980582010-01-23 23:04:36 +0000283 self.assertIn(k, self.d)
284 self.assertIn(v, self.d.values())
285 self.assertNotIn(k, self.f)
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000286 self.assertEqual(len(self.d)-1, len(self.f))
287
288 def test_pop(self):
289 k = 'w'
290 v = self.f.pop(k)
291 self.assertEqual(v, self.d[k])
Ezio Melottiaa980582010-01-23 23:04:36 +0000292 self.assertNotIn(k, self.f)
293 self.assertNotIn(v, self.f.values())
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000294 self.assertEqual(len(self.d)-1, len(self.f))
295
296 def test_get(self):
297 self.assertEqual(self.f.get('NotHere'), None)
298 self.assertEqual(self.f.get('NotHere', 'Default'), 'Default')
299 self.assertEqual(self.f.get('q', 'Default'), self.d['q'])
300
301 def test_setdefault(self):
302 self.assertEqual(self.f.setdefault('new', 'dog'), 'dog')
303 self.assertEqual(self.f.setdefault('r', 'cat'), self.d['r'])
304
305 def test_update(self):
306 new = dict(y='life', u='of', i='brian')
307 self.f.update(new)
308 self.d.update(new)
309 for k, v in self.d.iteritems():
310 self.assertEqual(self.f[k], v)
311
312 def test_keyordering(self):
313 if self.openmethod[0] is not bsddb.btopen:
314 return
315 keys = self.d.keys()
316 keys.sort()
317 self.assertEqual(self.f.first()[0], keys[0])
318 self.assertEqual(self.f.next()[0], keys[1])
319 self.assertEqual(self.f.last()[0], keys[-1])
320 self.assertEqual(self.f.previous()[0], keys[-2])
321 self.assertEqual(list(self.f), keys)
322
323class TestBTree(TestBSDDB):
324 fname = test_support.TESTFN
325 openmethod = [bsddb.btopen]
326
327class TestBTree_InMemory(TestBSDDB):
328 fname = None
329 openmethod = [bsddb.btopen]
330
Gregory P. Smith14c6b462006-04-12 20:16:56 +0000331class TestBTree_InMemory_Truncate(TestBSDDB):
332 fname = None
333 openflag = 'n'
334 openmethod = [bsddb.btopen]
335
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000336class TestHashTable(TestBSDDB):
337 fname = test_support.TESTFN
338 openmethod = [bsddb.hashopen]
339
340class TestHashTable_InMemory(TestBSDDB):
341 fname = None
342 openmethod = [bsddb.hashopen]
343
344## # (bsddb.rnopen,'Record Numbers'), 'put' for RECNO for bsddb 1.85
345## # appears broken... at least on
346## # Solaris Intel - rmasse 1/97
347
348def test_main(verbose=None):
349 test_support.run_unittest(
350 TestBTree,
351 TestHashTable,
352 TestBTree_InMemory,
353 TestHashTable_InMemory,
Gregory P. Smith14c6b462006-04-12 20:16:56 +0000354 TestBTree_InMemory_Truncate,
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000355 )
356
357if __name__ == "__main__":
358 test_main(verbose=True)