blob: dfee3dcb11436e1d3b94fca782b9c2bd6180093d [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
Raymond Hettingerd55111f2003-09-13 05:51:09 +000012class TestBSDDB(unittest.TestCase):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000013 openflag = 'c'
Roger E. Masse352e1861997-01-16 22:04:10 +000014
Martin v. Löwis64ce5052007-08-05 15:39:16 +000015 def do_open(self, *args, **kw):
16 # openmethod is a list so that it's not mistaken as an instance method
17 return bsddb.StringValues(bsddb.StringKeys(self.openmethod[0](*args, **kw)))
18
Raymond Hettingerd55111f2003-09-13 05:51:09 +000019 def setUp(self):
Martin v. Löwis64ce5052007-08-05 15:39:16 +000020 self.f = self.do_open(self.fname, self.openflag, cachesize=32768)
Raymond Hettingerd55111f2003-09-13 05:51:09 +000021 self.d = dict(q='Guido', w='van', e='Rossum', r='invented', t='Python', y='')
Guido van Rossumcc2b0162007-02-11 06:12:03 +000022 for k, v in self.d.items():
Raymond Hettingerd55111f2003-09-13 05:51:09 +000023 self.f[k] = v
Fred Drake004d5e62000-10-23 17:22:08 +000024
Raymond Hettingerd55111f2003-09-13 05:51:09 +000025 def tearDown(self):
26 self.f.sync()
27 self.f.close()
28 if self.fname is None:
29 return
Anthony Baxter83888952002-04-23 02:11:05 +000030 try:
Raymond Hettingerd55111f2003-09-13 05:51:09 +000031 os.remove(self.fname)
Anthony Baxter83888952002-04-23 02:11:05 +000032 except os.error:
33 pass
Roger E. Masse352e1861997-01-16 22:04:10 +000034
Raymond Hettingerd55111f2003-09-13 05:51:09 +000035 def test_getitem(self):
Guido van Rossumcc2b0162007-02-11 06:12:03 +000036 for k, v in self.d.items():
Raymond Hettingerd55111f2003-09-13 05:51:09 +000037 self.assertEqual(self.f[k], v)
Roger E. Masse352e1861997-01-16 22:04:10 +000038
Raymond Hettingerd55111f2003-09-13 05:51:09 +000039 def test_len(self):
40 self.assertEqual(len(self.f), len(self.d))
41
42 def test_change(self):
43 self.f['r'] = 'discovered'
44 self.assertEqual(self.f['r'], 'discovered')
45 self.assert_('r' in self.f.keys())
46 self.assert_('discovered' in self.f.values())
47
48 def test_close_and_reopen(self):
49 if self.fname is None:
50 # if we're using an in-memory only db, we can't reopen it
51 # so finish here.
52 return
53 self.f.close()
Martin v. Löwis64ce5052007-08-05 15:39:16 +000054 self.f = self.do_open(self.fname, 'w')
Guido van Rossumcc2b0162007-02-11 06:12:03 +000055 for k, v in self.d.items():
Raymond Hettingerd55111f2003-09-13 05:51:09 +000056 self.assertEqual(self.f[k], v)
57
58 def assertSetEquals(self, seqn1, seqn2):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000059 self.assertEqual(set(seqn1), set(seqn2))
Raymond Hettingerd55111f2003-09-13 05:51:09 +000060
61 def test_mapping_iteration_methods(self):
62 f = self.f
63 d = self.d
64 self.assertSetEquals(d, f)
65 self.assertSetEquals(d.keys(), f.keys())
66 self.assertSetEquals(d.values(), f.values())
67 self.assertSetEquals(d.items(), f.items())
Guido van Rossumcc2b0162007-02-11 06:12:03 +000068 self.assertSetEquals(d.keys(), f.keys())
69 self.assertSetEquals(d.values(), f.values())
70 self.assertSetEquals(d.items(), f.items())
Raymond Hettingerd55111f2003-09-13 05:51:09 +000071
Gregory P. Smitha703a212003-11-03 01:04:41 +000072 def test_iter_while_modifying_values(self):
73 if not hasattr(self.f, '__iter__'):
74 return
75
76 di = iter(self.d)
77 while 1:
78 try:
Georg Brandla18af4e2007-04-21 15:47:16 +000079 key = next(di)
Gregory P. Smitha703a212003-11-03 01:04:41 +000080 self.d[key] = 'modified '+key
81 except StopIteration:
82 break
83
84 # it should behave the same as a dict. modifying values
85 # of existing keys should not break iteration. (adding
86 # or removing keys should)
87 fi = iter(self.f)
88 while 1:
89 try:
Georg Brandla18af4e2007-04-21 15:47:16 +000090 key = next(fi)
Gregory P. Smitha703a212003-11-03 01:04:41 +000091 self.f[key] = 'modified '+key
92 except StopIteration:
93 break
94
95 self.test_mapping_iteration_methods()
96
97 def test_iteritems_while_modifying_values(self):
98 if not hasattr(self.f, 'iteritems'):
99 return
100
Brett Cannon5b8d24a2007-02-22 06:12:19 +0000101 di = iter(self.d.items())
Gregory P. Smitha703a212003-11-03 01:04:41 +0000102 while 1:
103 try:
Georg Brandla18af4e2007-04-21 15:47:16 +0000104 k, v = next(di)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000105 self.d[k] = 'modified '+v
106 except StopIteration:
107 break
108
109 # it should behave the same as a dict. modifying values
110 # of existing keys should not break iteration. (adding
111 # or removing keys should)
Brett Cannon5b8d24a2007-02-22 06:12:19 +0000112 fi = iter(self.f.items())
Gregory P. Smitha703a212003-11-03 01:04:41 +0000113 while 1:
114 try:
Georg Brandla18af4e2007-04-21 15:47:16 +0000115 k, v = next(fi)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000116 self.f[k] = 'modified '+v
117 except StopIteration:
118 break
119
120 self.test_mapping_iteration_methods()
121
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000122 def test_first_next_looping(self):
123 items = [self.f.first()]
Guido van Rossum805365e2007-05-07 22:24:25 +0000124 for i in range(1, len(self.f)):
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000125 items.append(self.f.next())
126 self.assertSetEquals(items, self.d.items())
127
128 def test_previous_last_looping(self):
129 items = [self.f.last()]
Guido van Rossum805365e2007-05-07 22:24:25 +0000130 for i in range(1, len(self.f)):
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000131 items.append(self.f.previous())
132 self.assertSetEquals(items, self.d.items())
133
Gregory P. Smith07aec082007-08-24 05:32:10 +0000134 def test_first_while_deleting(self):
135 # Test for bug 1725856
136 self.assert_(len(self.d) >= 2, "test requires >=2 items")
137 for _ in self.d:
138 key = self.f.first()[0]
139 del self.f[key]
140 self.assertEqual(0, len(self.f), "expected empty db after test")
141
142 def test_last_while_deleting(self):
143 # Test for bug 1725856's evil twin
144 self.assert_(len(self.d) >= 2, "test requires >=2 items")
145 for _ in self.d:
146 key = self.f.last()[0]
147 del self.f[key]
148 self.assertEqual(0, len(self.f), "expected empty db after test")
149
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000150 def test_set_location(self):
151 self.assertEqual(self.f.set_location('e'), ('e', self.d['e']))
152
153 def test_contains(self):
154 for k in self.d:
155 self.assert_(k in self.f)
156 self.assert_('not here' not in self.f)
157
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000158 def test_clear(self):
159 self.f.clear()
160 self.assertEqual(len(self.f), 0)
161
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000162 def test__no_deadlock_first(self, debug=0):
163 # do this so that testers can see what function we're in in
164 # verbose mode when we deadlock.
165 sys.stdout.flush()
166
167 # in pybsddb's _DBWithCursor this causes an internal DBCursor
168 # object is created. Other test_ methods in this class could
169 # inadvertently cause the deadlock but an explicit test is needed.
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000170 if debug: print("A")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000171 k,v = self.f.first()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000172 if debug: print("B", k)
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000173 self.f[k] = "deadlock. do not pass go. do not collect $200."
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000174 if debug: print("C")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000175 # if the bsddb implementation leaves the DBCursor open during
176 # the database write and locking+threading support is enabled
177 # the cursor's read lock will deadlock the write lock request..
178
179 # test the iterator interface (if present)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000180 if hasattr(self.f, 'iteritems'):
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000181 if debug: print("D")
Brett Cannon5b8d24a2007-02-22 06:12:19 +0000182 i = iter(self.f.items())
Georg Brandla18af4e2007-04-21 15:47:16 +0000183 k,v = next(i)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000184 if debug: print("E")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000185 self.f[k] = "please don't deadlock"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000186 if debug: print("F")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000187 while 1:
188 try:
Georg Brandla18af4e2007-04-21 15:47:16 +0000189 k,v = next(i)
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000190 except StopIteration:
191 break
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000192 if debug: print("F2")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000193
194 i = iter(self.f)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000195 if debug: print("G")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000196 while i:
197 try:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000198 if debug: print("H")
Georg Brandla18af4e2007-04-21 15:47:16 +0000199 k = next(i)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000200 if debug: print("I")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000201 self.f[k] = "deadlocks-r-us"
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000202 if debug: print("J")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000203 except StopIteration:
204 i = None
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000205 if debug: print("K")
Gregory P. Smithdc113a82003-11-02 09:10:16 +0000206
207 # test the legacy cursor interface mixed with writes
208 self.assert_(self.f.first()[0] in self.d)
209 k = self.f.next()[0]
210 self.assert_(k in self.d)
211 self.f[k] = "be gone with ye deadlocks"
212 self.assert_(self.f[k], "be gone with ye deadlocks")
213
Gregory P. Smitha703a212003-11-03 01:04:41 +0000214 def test_for_cursor_memleak(self):
215 if not hasattr(self.f, 'iteritems'):
216 return
217
218 # do the bsddb._DBWithCursor _iter_mixin internals leak cursors?
219 nc1 = len(self.f._cursor_refs)
220 # create iterator
Guido van Rossum63eecc72007-02-22 23:55:25 +0000221 i = iter(self.f.iteritems())
Gregory P. Smitha703a212003-11-03 01:04:41 +0000222 nc2 = len(self.f._cursor_refs)
Guido van Rossum63eecc72007-02-22 23:55:25 +0000223 # use the iterator (should run to the first yield, creating the cursor)
Georg Brandla18af4e2007-04-21 15:47:16 +0000224 k, v = next(i)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000225 nc3 = len(self.f._cursor_refs)
226 # destroy the iterator; this should cause the weakref callback
227 # to remove the cursor object from self.f._cursor_refs
228 del i
229 nc4 = len(self.f._cursor_refs)
230
231 self.assertEqual(nc1, nc2)
232 self.assertEqual(nc1, nc4)
Guido van Rossum63eecc72007-02-22 23:55:25 +0000233 self.assertEqual(nc3, nc1+1)
Gregory P. Smitha703a212003-11-03 01:04:41 +0000234
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000235 def test_popitem(self):
236 k, v = self.f.popitem()
237 self.assert_(k in self.d)
238 self.assert_(v in self.d.values())
239 self.assert_(k not in self.f)
240 self.assertEqual(len(self.d)-1, len(self.f))
241
242 def test_pop(self):
243 k = 'w'
244 v = self.f.pop(k)
245 self.assertEqual(v, self.d[k])
246 self.assert_(k not in self.f)
247 self.assert_(v not in self.f.values())
248 self.assertEqual(len(self.d)-1, len(self.f))
249
250 def test_get(self):
251 self.assertEqual(self.f.get('NotHere'), None)
252 self.assertEqual(self.f.get('NotHere', 'Default'), 'Default')
253 self.assertEqual(self.f.get('q', 'Default'), self.d['q'])
254
255 def test_setdefault(self):
256 self.assertEqual(self.f.setdefault('new', 'dog'), 'dog')
257 self.assertEqual(self.f.setdefault('r', 'cat'), self.d['r'])
258
259 def test_update(self):
260 new = dict(y='life', u='of', i='brian')
261 self.f.update(new)
262 self.d.update(new)
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000263 for k, v in self.d.items():
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000264 self.assertEqual(self.f[k], v)
265
266 def test_keyordering(self):
267 if self.openmethod[0] is not bsddb.btopen:
268 return
Brett Cannon5b8d24a2007-02-22 06:12:19 +0000269 keys = sorted(self.d.keys())
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000270 self.assertEqual(self.f.first()[0], keys[0])
271 self.assertEqual(self.f.next()[0], keys[1])
272 self.assertEqual(self.f.last()[0], keys[-1])
273 self.assertEqual(self.f.previous()[0], keys[-2])
274 self.assertEqual(list(self.f), keys)
275
276class TestBTree(TestBSDDB):
277 fname = test_support.TESTFN
278 openmethod = [bsddb.btopen]
279
280class TestBTree_InMemory(TestBSDDB):
281 fname = None
282 openmethod = [bsddb.btopen]
283
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000284class TestBTree_InMemory_Truncate(TestBSDDB):
285 fname = None
286 openflag = 'n'
287 openmethod = [bsddb.btopen]
288
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000289class TestHashTable(TestBSDDB):
290 fname = test_support.TESTFN
291 openmethod = [bsddb.hashopen]
292
293class TestHashTable_InMemory(TestBSDDB):
294 fname = None
295 openmethod = [bsddb.hashopen]
296
297## # (bsddb.rnopen,'Record Numbers'), 'put' for RECNO for bsddb 1.85
298## # appears broken... at least on
299## # Solaris Intel - rmasse 1/97
300
301def test_main(verbose=None):
302 test_support.run_unittest(
303 TestBTree,
304 TestHashTable,
305 TestBTree_InMemory,
306 TestHashTable_InMemory,
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000307 TestBTree_InMemory_Truncate,
Raymond Hettingerd55111f2003-09-13 05:51:09 +0000308 )
309
310if __name__ == "__main__":
311 test_main(verbose=True)