blob: fa88f565b33c5dd236b62baa197e961ad420b9c5 [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
Roger E. Masse352e1861997-01-16 22:04:10 +00007import bsddb
Guido van Rossuma35e2ce2001-12-07 16:43:19 +00008import dbhash # Just so we know it's imported
Raymond Hettingerd55111f2003-09-13 05:51:09 +00009import unittest
10from test import test_support
Roger E. Masse352e1861997-01-16 22:04:10 +000011
Ezio Melotti3897a442010-08-02 01:33:30 +000012# Skip test if _bsddb wasn't built.
13test_support.import_module('_bsddb')
14
15bsddb = test_support.import_module('bsddb', deprecated=True)
16# Just so we know it's imported:
17test_support.import_module('dbhash', deprecated=True)
18
19
Raymond Hettingerd55111f2003-09-13 05:51:09 +000020class TestBSDDB(unittest.TestCase):
Gregory P. Smith14c6b462006-04-12 20:16:56 +000021 openflag = 'c'
Roger E. Masse352e1861997-01-16 22:04:10 +000022
Raymond Hettingerd55111f2003-09-13 05:51:09 +000023 def setUp(self):
Gregory P. Smith64029982006-04-12 20:35:02 +000024 self.f = self.openmethod[0](self.fname, self.openflag, cachesize=32768)
Raymond Hettingerd55111f2003-09-13 05:51:09 +000025 self.d = dict(q='Guido', w='van', e='Rossum', r='invented', t='Python', y='')
26 for k, v in self.d.iteritems():
27 self.f[k] = v
Fred Drake004d5e62000-10-23 17:22:08 +000028
Raymond Hettingerd55111f2003-09-13 05:51:09 +000029 def tearDown(self):
30 self.f.sync()
31 self.f.close()
32 if self.fname is None:
33 return
Anthony Baxter83888952002-04-23 02:11:05 +000034 try:
Raymond Hettingerd55111f2003-09-13 05:51:09 +000035 os.remove(self.fname)
Anthony Baxter83888952002-04-23 02:11:05 +000036 except os.error:
37 pass
Roger E. Masse352e1861997-01-16 22:04:10 +000038
Raymond Hettingerd55111f2003-09-13 05:51:09 +000039 def test_getitem(self):
40 for k, v in self.d.iteritems():
41 self.assertEqual(self.f[k], v)
Roger E. Masse352e1861997-01-16 22:04:10 +000042
Raymond Hettingerd55111f2003-09-13 05:51:09 +000043 def test_len(self):
44 self.assertEqual(len(self.f), len(self.d))
45
46 def test_change(self):
47 self.f['r'] = 'discovered'
48 self.assertEqual(self.f['r'], 'discovered')
49 self.assert_('r' in self.f.keys())
50 self.assert_('discovered' in self.f.values())
51
52 def test_close_and_reopen(self):
53 if self.fname is None:
54 # if we're using an in-memory only db, we can't reopen it
55 # so finish here.
56 return
57 self.f.close()
58 self.f = self.openmethod[0](self.fname, 'w')
59 for k, v in self.d.iteritems():
60 self.assertEqual(self.f[k], v)
61
62 def assertSetEquals(self, seqn1, seqn2):
Georg Brandl7b71bf32006-07-17 13:23:46 +000063 self.assertEqual(set(seqn1), set(seqn2))
Raymond Hettingerd55111f2003-09-13 05:51:09 +000064
65 def test_mapping_iteration_methods(self):
66 f = self.f
67 d = self.d
68 self.assertSetEquals(d, f)
69 self.assertSetEquals(d.keys(), f.keys())
70 self.assertSetEquals(d.values(), f.values())
71 self.assertSetEquals(d.items(), f.items())
72 self.assertSetEquals(d.iterkeys(), f.iterkeys())
73 self.assertSetEquals(d.itervalues(), f.itervalues())
74 self.assertSetEquals(d.iteritems(), f.iteritems())
75
Gregory P. Smitha703a212003-11-03 01:04:41 +000076 def test_iter_while_modifying_values(self):
Gregory P. Smitha703a212003-11-03 01:04:41 +000077 di = iter(self.d)
78 while 1:
79 try:
80 key = di.next()
81 self.d[key] = 'modified '+key
82 except StopIteration:
83 break
84
85 # it should behave the same as a dict. modifying values
86 # of existing keys should not break iteration. (adding
87 # or removing keys should)
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000088 loops_left = len(self.f)
Gregory P. Smitha703a212003-11-03 01:04:41 +000089 fi = iter(self.f)
90 while 1:
91 try:
92 key = fi.next()
93 self.f[key] = 'modified '+key
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000094 loops_left -= 1
Gregory P. Smitha703a212003-11-03 01:04:41 +000095 except StopIteration:
96 break
Gregory P. Smith9e6468b2008-05-25 08:28:29 +000097 self.assertEqual(loops_left, 0)
Gregory P. Smitha703a212003-11-03 01:04:41 +000098
99 self.test_mapping_iteration_methods()
100
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000101 def test_iter_abort_on_changed_size(self):
102 def DictIterAbort():
103 di = iter(self.d)
104 while 1:
105 try:
106 di.next()
107 self.d['newkey'] = 'SPAM'
108 except StopIteration:
109 break
110 self.assertRaises(RuntimeError, DictIterAbort)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000111
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000112 def DbIterAbort():
113 fi = iter(self.f)
114 while 1:
115 try:
116 fi.next()
117 self.f['newkey'] = 'SPAM'
118 except StopIteration:
119 break
120 self.assertRaises(RuntimeError, DbIterAbort)
121
122 def test_iteritems_abort_on_changed_size(self):
123 def DictIteritemsAbort():
124 di = self.d.iteritems()
125 while 1:
126 try:
127 di.next()
128 self.d['newkey'] = 'SPAM'
129 except StopIteration:
130 break
131 self.assertRaises(RuntimeError, DictIteritemsAbort)
132
133 def DbIteritemsAbort():
134 fi = self.f.iteritems()
135 while 1:
136 try:
137 key, value = fi.next()
138 del self.f[key]
139 except StopIteration:
140 break
141 self.assertRaises(RuntimeError, DbIteritemsAbort)
142
143 def test_iteritems_while_modifying_values(self):
Gregory P. Smitha703a212003-11-03 01:04:41 +0000144 di = self.d.iteritems()
145 while 1:
146 try:
147 k, v = di.next()
148 self.d[k] = 'modified '+v
149 except StopIteration:
150 break
151
152 # it should behave the same as a dict. modifying values
153 # of existing keys should not break iteration. (adding
154 # or removing keys should)
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000155 loops_left = len(self.f)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000156 fi = self.f.iteritems()
157 while 1:
158 try:
159 k, v = fi.next()
160 self.f[k] = 'modified '+v
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000161 loops_left -= 1
Gregory P. Smitha703a212003-11-03 01:04:41 +0000162 except StopIteration:
163 break
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000164 self.assertEqual(loops_left, 0)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000165
166 self.test_mapping_iteration_methods()
167
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000168 def test_first_next_looping(self):
169 items = [self.f.first()]
170 for i in xrange(1, len(self.f)):
171 items.append(self.f.next())
172 self.assertSetEquals(items, self.d.items())
173
174 def test_previous_last_looping(self):
175 items = [self.f.last()]
176 for i in xrange(1, len(self.f)):
177 items.append(self.f.previous())
178 self.assertSetEquals(items, self.d.items())
179
Gregory P. Smith1042a4d2007-08-24 05:11:38 +0000180 def test_first_while_deleting(self):
181 # Test for bug 1725856
182 self.assert_(len(self.d) >= 2, "test requires >=2 items")
183 for _ in self.d:
184 key = self.f.first()[0]
185 del self.f[key]
186 self.assertEqual([], self.f.items(), "expected empty db after test")
187
188 def test_last_while_deleting(self):
189 # Test for bug 1725856's evil twin
190 self.assert_(len(self.d) >= 2, "test requires >=2 items")
191 for _ in self.d:
192 key = self.f.last()[0]
193 del self.f[key]
194 self.assertEqual([], self.f.items(), "expected empty db after test")
195
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000196 def test_set_location(self):
197 self.assertEqual(self.f.set_location('e'), ('e', self.d['e']))
198
199 def test_contains(self):
200 for k in self.d:
201 self.assert_(k in self.f)
202 self.assert_('not here' not in self.f)
203
204 def test_has_key(self):
205 for k in self.d:
206 self.assert_(self.f.has_key(k))
207 self.assert_(not self.f.has_key('not here'))
208
209 def test_clear(self):
210 self.f.clear()
211 self.assertEqual(len(self.f), 0)
212
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000213 def test__no_deadlock_first(self, debug=0):
214 # do this so that testers can see what function we're in in
215 # verbose mode when we deadlock.
216 sys.stdout.flush()
217
218 # in pybsddb's _DBWithCursor this causes an internal DBCursor
219 # object is created. Other test_ methods in this class could
220 # inadvertently cause the deadlock but an explicit test is needed.
221 if debug: print "A"
222 k,v = self.f.first()
223 if debug: print "B", k
224 self.f[k] = "deadlock. do not pass go. do not collect $200."
225 if debug: print "C"
226 # if the bsddb implementation leaves the DBCursor open during
227 # the database write and locking+threading support is enabled
228 # the cursor's read lock will deadlock the write lock request..
229
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000230 # test the iterator interface
231 if True:
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000232 if debug: print "D"
Gregory P. Smitha703a212003-11-03 01:04:41 +0000233 i = self.f.iteritems()
234 k,v = i.next()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000235 if debug: print "E"
236 self.f[k] = "please don't deadlock"
237 if debug: print "F"
238 while 1:
239 try:
Gregory P. Smitha703a212003-11-03 01:04:41 +0000240 k,v = i.next()
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000241 except StopIteration:
242 break
243 if debug: print "F2"
244
245 i = iter(self.f)
246 if debug: print "G"
247 while i:
248 try:
249 if debug: print "H"
250 k = i.next()
251 if debug: print "I"
252 self.f[k] = "deadlocks-r-us"
253 if debug: print "J"
254 except StopIteration:
255 i = None
256 if debug: print "K"
257
258 # test the legacy cursor interface mixed with writes
259 self.assert_(self.f.first()[0] in self.d)
260 k = self.f.next()[0]
261 self.assert_(k in self.d)
262 self.f[k] = "be gone with ye deadlocks"
263 self.assert_(self.f[k], "be gone with ye deadlocks")
264
Gregory P. Smitha703a212003-11-03 01:04:41 +0000265 def test_for_cursor_memleak(self):
Gregory P. Smith9e6468b2008-05-25 08:28:29 +0000266 # do the bsddb._DBWithCursor iterator internals leak cursors?
Gregory P. Smitha703a212003-11-03 01:04:41 +0000267 nc1 = len(self.f._cursor_refs)
268 # create iterator
269 i = self.f.iteritems()
270 nc2 = len(self.f._cursor_refs)
Neal Norwitz764cf7e2007-02-23 00:22:39 +0000271 # use the iterator (should run to the first yield, creating the cursor)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000272 k, v = i.next()
273 nc3 = len(self.f._cursor_refs)
274 # destroy the iterator; this should cause the weakref callback
275 # to remove the cursor object from self.f._cursor_refs
276 del i
277 nc4 = len(self.f._cursor_refs)
278
279 self.assertEqual(nc1, nc2)
280 self.assertEqual(nc1, nc4)
281 self.assert_(nc3 == nc1+1)
282
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000283 def test_popitem(self):
284 k, v = self.f.popitem()
285 self.assert_(k in self.d)
286 self.assert_(v in self.d.values())
287 self.assert_(k not in self.f)
288 self.assertEqual(len(self.d)-1, len(self.f))
289
290 def test_pop(self):
291 k = 'w'
292 v = self.f.pop(k)
293 self.assertEqual(v, self.d[k])
294 self.assert_(k not in self.f)
295 self.assert_(v not in self.f.values())
296 self.assertEqual(len(self.d)-1, len(self.f))
297
298 def test_get(self):
299 self.assertEqual(self.f.get('NotHere'), None)
300 self.assertEqual(self.f.get('NotHere', 'Default'), 'Default')
301 self.assertEqual(self.f.get('q', 'Default'), self.d['q'])
302
303 def test_setdefault(self):
304 self.assertEqual(self.f.setdefault('new', 'dog'), 'dog')
305 self.assertEqual(self.f.setdefault('r', 'cat'), self.d['r'])
306
307 def test_update(self):
308 new = dict(y='life', u='of', i='brian')
309 self.f.update(new)
310 self.d.update(new)
311 for k, v in self.d.iteritems():
312 self.assertEqual(self.f[k], v)
313
314 def test_keyordering(self):
315 if self.openmethod[0] is not bsddb.btopen:
316 return
317 keys = self.d.keys()
318 keys.sort()
319 self.assertEqual(self.f.first()[0], keys[0])
320 self.assertEqual(self.f.next()[0], keys[1])
321 self.assertEqual(self.f.last()[0], keys[-1])
322 self.assertEqual(self.f.previous()[0], keys[-2])
323 self.assertEqual(list(self.f), keys)
324
325class TestBTree(TestBSDDB):
326 fname = test_support.TESTFN
327 openmethod = [bsddb.btopen]
328
329class TestBTree_InMemory(TestBSDDB):
330 fname = None
331 openmethod = [bsddb.btopen]
332
Gregory P. Smith14c6b462006-04-12 20:16:56 +0000333class TestBTree_InMemory_Truncate(TestBSDDB):
334 fname = None
335 openflag = 'n'
336 openmethod = [bsddb.btopen]
337
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000338class TestHashTable(TestBSDDB):
339 fname = test_support.TESTFN
340 openmethod = [bsddb.hashopen]
341
342class TestHashTable_InMemory(TestBSDDB):
343 fname = None
344 openmethod = [bsddb.hashopen]
345
346## # (bsddb.rnopen,'Record Numbers'), 'put' for RECNO for bsddb 1.85
347## # appears broken... at least on
348## # Solaris Intel - rmasse 1/97
349
350def test_main(verbose=None):
351 test_support.run_unittest(
352 TestBTree,
353 TestHashTable,
354 TestBTree_InMemory,
355 TestHashTable_InMemory,
Gregory P. Smith14c6b462006-04-12 20:16:56 +0000356 TestBTree_InMemory_Truncate,
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000357 )
358
359if __name__ == "__main__":
360 test_main(verbose=True)