Code

Very close now. The cgi and mailgw now use the new security API. The two
[roundup.git] / test / test_db.py
1 #
2 # Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
3 # This module is free software, and you may redistribute it and/or modify
4 # under the same terms as Python, so long as this copyright message and
5 # disclaimer are retained in their original form.
6 #
7 # IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
8 # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
9 # OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
10 # POSSIBILITY OF SUCH DAMAGE.
11 #
12 # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17
18 # $Id: test_db.py,v 1.38 2002-07-26 08:27:00 richard Exp $ 
20 import unittest, os, shutil, time
22 from roundup.hyperdb import String, Password, Link, Multilink, Date, \
23     Interval, DatabaseError, Boolean, Number
24 from roundup import date, password
25 from roundup.indexer import Indexer
27 def setupSchema(db, create, module):
28     status = module.Class(db, "status", name=String())
29     status.setkey("name")
30     user = module.Class(db, "user", username=String(), password=Password(),
31         assignable=Boolean(), age=Number(), roles=String())
32     user.setkey("username")
33     file = module.FileClass(db, "file", name=String(), type=String(),
34         comment=String(indexme="yes"))
35     issue = module.IssueClass(db, "issue", title=String(indexme="yes"),
36         status=Link("status"), nosy=Multilink("user"), deadline=Date(),
37         foo=Interval(), files=Multilink("file"), assignedto=Link('user'))
38     session = module.Class(db, 'session', title=String())
39     session.disableJournalling()
40     db.post_init()
41     if create:
42         status.create(name="unread")
43         status.create(name="in-progress")
44         status.create(name="testing")
45         status.create(name="resolved")
46     db.commit()
48 class MyTestCase(unittest.TestCase):
49     def tearDown(self):
50         if os.path.exists('_test_dir'):
51             shutil.rmtree('_test_dir')
53 class config:
54     DATABASE='_test_dir'
55     MAILHOST = 'localhost'
56     MAIL_DOMAIN = 'fill.me.in.'
57     INSTANCE_NAME = 'Roundup issue tracker'
58     ISSUE_TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN
59     ISSUE_TRACKER_WEB = 'http://some.useful.url/'
60     ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
61     FILTER_POSITION = 'bottom'      # one of 'top', 'bottom', 'top and bottom'
62     ANONYMOUS_ACCESS = 'deny'       # either 'deny' or 'allow'
63     ANONYMOUS_REGISTER = 'deny'     # either 'deny' or 'allow'
64     MESSAGES_TO_AUTHOR = 'no'       # either 'yes' or 'no'
65     EMAIL_SIGNATURE_POSITION = 'bottom'
67 class anydbmDBTestCase(MyTestCase):
68     def setUp(self):
69         from roundup.backends import anydbm
70         # remove previous test, ignore errors
71         if os.path.exists(config.DATABASE):
72             shutil.rmtree(config.DATABASE)
73         os.makedirs(config.DATABASE + '/files')
74         self.db = anydbm.Database(config, 'test')
75         setupSchema(self.db, 1, anydbm)
76         self.db2 = anydbm.Database(config, 'test')
77         setupSchema(self.db2, 0, anydbm)
79     def testStringChange(self):
80         self.db.issue.create(title="spam", status='1')
81         self.assertEqual(self.db.issue.get('1', 'title'), 'spam')
82         self.db.issue.set('1', title='eggs')
83         self.assertEqual(self.db.issue.get('1', 'title'), 'eggs')
84         self.db.commit()
85         self.assertEqual(self.db.issue.get('1', 'title'), 'eggs')
86         self.db.issue.create(title="spam", status='1')
87         self.db.commit()
88         self.assertEqual(self.db.issue.get('2', 'title'), 'spam')
89         self.db.issue.set('2', title='ham')
90         self.assertEqual(self.db.issue.get('2', 'title'), 'ham')
91         self.db.commit()
92         self.assertEqual(self.db.issue.get('2', 'title'), 'ham')
94     def testLinkChange(self):
95         self.db.issue.create(title="spam", status='1')
96         self.assertEqual(self.db.issue.get('1', "status"), '1')
97         self.db.issue.set('1', status='2')
98         self.assertEqual(self.db.issue.get('1', "status"), '2')
100     def testDateChange(self):
101         self.db.issue.create(title="spam", status='1')
102         a = self.db.issue.get('1', "deadline")
103         self.db.issue.set('1', deadline=date.Date())
104         b = self.db.issue.get('1', "deadline")
105         self.db.commit()
106         self.assertNotEqual(a, b)
107         self.assertNotEqual(b, date.Date('1970-1-1 00:00:00'))
108         self.db.issue.set('1', deadline=date.Date())
110     def testIntervalChange(self):
111         self.db.issue.create(title="spam", status='1')
112         a = self.db.issue.get('1', "foo")
113         self.db.issue.set('1', foo=date.Interval('-1d'))
114         self.assertNotEqual(self.db.issue.get('1', "foo"), a)
116     def testBooleanChange(self):
117         userid = self.db.user.create(username='foo', assignable=1)
118         self.db.user.create(username='foo2', assignable=0)
119         a = self.db.user.get(userid, 'assignable')
120         self.db.user.set(userid, assignable=0)
121         self.assertNotEqual(self.db.user.get(userid, 'assignable'), a)
122         self.db.user.set(userid, assignable=0)
123         self.db.user.set(userid, assignable=1)
125     def testNumberChange(self):
126         self.db.user.create(username='foo', age='1')
127         a = self.db.user.get('1', 'age')
128         self.db.user.set('1', age='3')
129         self.assertNotEqual(self.db.user.get('1', 'age'), a)
130         self.db.user.set('1', age='1.0')
132     def testNewProperty(self):
133         self.db.issue.create(title="spam", status='1')
134         self.db.issue.addprop(fixer=Link("user"))
135         props = self.db.issue.getprops()
136         keys = props.keys()
137         keys.sort()
138         self.assertEqual(keys, ['activity', 'assignedto', 'creation',
139             'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages',
140             'nosy', 'status', 'superseder', 'title'])
141         self.assertEqual(self.db.issue.get('1', "fixer"), None)
143     def testRetire(self):
144         self.db.issue.create(title="spam", status='1')
145         b = self.db.status.get('1', 'name')
146         a = self.db.status.list()
147         self.db.status.retire('1')
148         # make sure the list is different 
149         self.assertNotEqual(a, self.db.status.list())
150         # can still access the node if necessary
151         self.assertEqual(self.db.status.get('1', 'name'), b)
152         self.db.commit()
153         self.assertEqual(self.db.status.get('1', 'name'), b)
154         self.assertNotEqual(a, self.db.status.list())
156     def testSerialisation(self):
157         self.db.issue.create(title="spam", status='1',
158             deadline=date.Date(), foo=date.Interval('-1d'))
159         self.db.commit()
160         assert isinstance(self.db.issue.get('1', 'deadline'), date.Date)
161         assert isinstance(self.db.issue.get('1', 'foo'), date.Interval)
162         self.db.user.create(username="fozzy",
163             password=password.Password('t. bear'))
164         self.db.commit()
165         assert isinstance(self.db.user.get('1', 'password'), password.Password)
167     def testTransactions(self):
168         # remember the number of items we started
169         num_issues = len(self.db.issue.list())
170         num_files = self.db.numfiles()
171         self.db.issue.create(title="don't commit me!", status='1')
172         self.assertNotEqual(num_issues, len(self.db.issue.list()))
173         self.db.rollback()
174         self.assertEqual(num_issues, len(self.db.issue.list()))
175         self.db.issue.create(title="please commit me!", status='1')
176         self.assertNotEqual(num_issues, len(self.db.issue.list()))
177         self.db.commit()
178         self.assertNotEqual(num_issues, len(self.db.issue.list()))
179         self.db.rollback()
180         self.assertNotEqual(num_issues, len(self.db.issue.list()))
181         self.db.file.create(name="test", type="text/plain", content="hi")
182         self.db.rollback()
183         self.assertEqual(num_files, self.db.numfiles())
184         for i in range(10):
185             self.db.file.create(name="test", type="text/plain", 
186                     content="hi %d"%(i))
187             self.db.commit()
188         num_files2 = self.db.numfiles()
189         self.assertNotEqual(num_files, num_files2)
190         self.db.file.create(name="test", type="text/plain", content="hi")
191         self.db.rollback()
192         self.assertNotEqual(num_files, self.db.numfiles())
193         self.assertEqual(num_files2, self.db.numfiles())
195     def testDestroyNoJournalling(self):
196         self.innerTestDestroy(klass=self.db.session)
198     def testDestroyJournalling(self):
199         self.innerTestDestroy(klass=self.db.issue)
201     def innerTestDestroy(self, klass):
202         newid = klass.create(title='Mr Friendly')
203         n = len(klass.list())
204         self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly')
205         klass.destroy(newid)
206         self.assertRaises(IndexError, klass.get, newid, 'title')
207         self.assertNotEqual(len(klass.list()), n)
208         if klass.do_journal:
209             self.assertRaises(IndexError, klass.history, newid)
211         # now with a commit
212         newid = klass.create(title='Mr Friendly')
213         n = len(klass.list())
214         self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly')
215         self.db.commit()
216         klass.destroy(newid)
217         self.assertRaises(IndexError, klass.get, newid, 'title')
218         self.db.commit()
219         self.assertRaises(IndexError, klass.get, newid, 'title')
220         self.assertNotEqual(len(klass.list()), n)
221         if klass.do_journal:
222             self.assertRaises(IndexError, klass.history, newid)
224         # now with a rollback
225         newid = klass.create(title='Mr Friendly')
226         n = len(klass.list())
227         self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly')
228         self.db.commit()
229         klass.destroy(newid)
230         self.assertNotEqual(len(klass.list()), n)
231         self.assertRaises(IndexError, klass.get, newid, 'title')
232         self.db.rollback()
233         self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly')
234         self.assertEqual(len(klass.list()), n)
235         if klass.do_journal:
236             self.assertNotEqual(klass.history(newid), [])
238     def testExceptions(self):
239         # this tests the exceptions that should be raised
240         ar = self.assertRaises
242         #
243         # class create
244         #
245         # string property
246         ar(TypeError, self.db.status.create, name=1)
247         # invalid property name
248         ar(KeyError, self.db.status.create, foo='foo')
249         # key name clash
250         ar(ValueError, self.db.status.create, name='unread')
251         # invalid link index
252         ar(IndexError, self.db.issue.create, title='foo', status='bar')
253         # invalid link value
254         ar(ValueError, self.db.issue.create, title='foo', status=1)
255         # invalid multilink type
256         ar(TypeError, self.db.issue.create, title='foo', status='1',
257             nosy='hello')
258         # invalid multilink index type
259         ar(ValueError, self.db.issue.create, title='foo', status='1',
260             nosy=[1])
261         # invalid multilink index
262         ar(IndexError, self.db.issue.create, title='foo', status='1',
263             nosy=['10'])
265         #
266         # key property
267         # 
268         # key must be a String
269         ar(TypeError, self.db.user.setkey, 'password')
270         # key must exist
271         ar(KeyError, self.db.user.setkey, 'fubar')
273         #
274         # class get
275         #
276         # invalid node id
277         ar(IndexError, self.db.issue.get, '1', 'title')
278         # invalid property name
279         ar(KeyError, self.db.status.get, '2', 'foo')
281         #
282         # class set
283         #
284         # invalid node id
285         ar(IndexError, self.db.issue.set, '1', title='foo')
286         # invalid property name
287         ar(KeyError, self.db.status.set, '1', foo='foo')
288         # string property
289         ar(TypeError, self.db.status.set, '1', name=1)
290         # key name clash
291         ar(ValueError, self.db.status.set, '2', name='unread')
292         # set up a valid issue for me to work on
293         self.db.issue.create(title="spam", status='1')
294         # invalid link index
295         ar(IndexError, self.db.issue.set, '6', title='foo', status='bar')
296         # invalid link value
297         ar(ValueError, self.db.issue.set, '6', title='foo', status=1)
298         # invalid multilink type
299         ar(TypeError, self.db.issue.set, '6', title='foo', status='1',
300             nosy='hello')
301         # invalid multilink index type
302         ar(ValueError, self.db.issue.set, '6', title='foo', status='1',
303             nosy=[1])
304         # invalid multilink index
305         ar(IndexError, self.db.issue.set, '6', title='foo', status='1',
306             nosy=['10'])
307         # invalid number value
308         ar(TypeError, self.db.user.create, username='foo', age='a')
309         # invalid boolean value
310         ar(TypeError, self.db.user.create, username='foo', assignable='true')
311         self.db.user.create(username='foo')
312         # invalid number value
313         ar(TypeError, self.db.user.set, '3', username='foo', age='a')
314         # invalid boolean value
315         ar(TypeError, self.db.user.set, '3', username='foo', assignable='true')
317     def testJournals(self):
318         self.db.issue.addprop(fixer=Link("user", do_journal='yes'))
319         self.db.user.create(username="mary")
320         self.db.user.create(username="pete")
321         self.db.issue.create(title="spam", status='1')
322         self.db.commit()
324         # journal entry for issue create
325         journal = self.db.getjournal('issue', '1')
326         self.assertEqual(1, len(journal))
327         (nodeid, date_stamp, journaltag, action, params) = journal[0]
328         self.assertEqual(nodeid, '1')
329         self.assertEqual(journaltag, 'test')
330         self.assertEqual(action, 'create')
331         keys = params.keys()
332         keys.sort()
333         self.assertEqual(keys, ['assignedto', 'deadline', 'files', 'fixer',
334             'foo', 'messages', 'nosy', 'status', 'superseder', 'title'])
335         self.assertEqual(None,params['deadline'])
336         self.assertEqual(None,params['fixer'])
337         self.assertEqual(None,params['foo'])
338         self.assertEqual([],params['nosy'])
339         self.assertEqual('1',params['status'])
340         self.assertEqual('spam',params['title'])
342         # journal entry for link
343         journal = self.db.getjournal('user', '1')
344         self.assertEqual(1, len(journal))
345         self.db.issue.set('1', fixer='1')
346         self.db.commit()
347         journal = self.db.getjournal('user', '1')
348         self.assertEqual(2, len(journal))
349         (nodeid, date_stamp, journaltag, action, params) = journal[1]
350         self.assertEqual('1', nodeid)
351         self.assertEqual('test', journaltag)
352         self.assertEqual('link', action)
353         self.assertEqual(('issue', '1', 'fixer'), params)
355         # journal entry for unlink
356         self.db.issue.set('1', fixer='2')
357         self.db.commit()
358         journal = self.db.getjournal('user', '1')
359         self.assertEqual(3, len(journal))
360         (nodeid, date_stamp, journaltag, action, params) = journal[2]
361         self.assertEqual('1', nodeid)
362         self.assertEqual('test', journaltag)
363         self.assertEqual('unlink', action)
364         self.assertEqual(('issue', '1', 'fixer'), params)
366         # test disabling journalling
367         # ... get the last entry
368         time.sleep(1)
369         entry = self.db.getjournal('issue', '1')[-1]
370         (x, date_stamp, x, x, x) = entry
371         self.db.issue.disableJournalling()
372         self.db.issue.set('1', title='hello world')
373         self.db.commit()
374         entry = self.db.getjournal('issue', '1')[-1]
375         (x, date_stamp2, x, x, x) = entry
376         # see if the change was journalled when it shouldn't have been
377         self.assertEqual(date_stamp, date_stamp2)
378         self.db.issue.enableJournalling()
379         self.db.issue.set('1', title='hello world 2')
380         self.db.commit()
381         entry = self.db.getjournal('issue', '1')[-1]
382         (x, date_stamp2, x, x, x) = entry
383         # see if the change was journalled
384         self.assertNotEqual(date_stamp, date_stamp2)
386     def testPack(self):
387         self.db.issue.create(title="spam", status='1')
388         self.db.commit()
389         self.db.issue.set('1', status='2')
390         self.db.commit()
391         self.db.issue.set('1', status='3')
392         self.db.commit()
393         pack_before = date.Date(". + 1d")
394         self.db.pack(pack_before)
395         journal = self.db.getjournal('issue', '1')
396         self.assertEqual(2, len(journal))
398     def testIDGeneration(self):
399         id1 = self.db.issue.create(title="spam", status='1')
400         id2 = self.db2.issue.create(title="eggs", status='2')
401         self.assertNotEqual(id1, id2)
403     def testSearching(self):
404         self.db.file.create(content='hello', type="text/plain")
405         self.db.file.create(content='world', type="text/frozz",
406             comment='blah blah')
407         self.db.issue.create(files=['1', '2'], title="flebble plop")
408         self.db.issue.create(title="flebble frooz")
409         self.db.commit()
410         self.assertEquals(self.db.indexer.search(['hello'], self.db.issue),
411             {'1': {'files': ['1']}})
412         self.assertEquals(self.db.indexer.search(['world'], self.db.issue), {})
413         self.assertEquals(self.db.indexer.search(['frooz'], self.db.issue),
414             {'2': {}})
415         self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue),
416             {'2': {}, '1': {}})
418     def testReindexing(self):
419         self.db.issue.create(title="frooz")
420         self.db.commit()
421         self.assertEquals(self.db.indexer.search(['frooz'], self.db.issue),
422             {'1': {}})
423         self.db.issue.set('1', title="dooble")
424         self.db.commit()
425         self.assertEquals(self.db.indexer.search(['dooble'], self.db.issue),
426             {'1': {}})
427         self.assertEquals(self.db.indexer.search(['frooz'], self.db.issue), {})
429     def testForcedReindexing(self):
430         self.db.issue.create(title="flebble frooz")
431         self.db.commit()
432         self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue),
433             {'1': {}})
434         self.db.indexer.quiet = 1
435         self.db.indexer.force_reindex()
436         self.db.post_init()
437         self.db.indexer.quiet = 9
438         self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue),
439             {'1': {}})
441 class anydbmReadOnlyDBTestCase(MyTestCase):
442     def setUp(self):
443         from roundup.backends import anydbm
444         # remove previous test, ignore errors
445         if os.path.exists(config.DATABASE):
446             shutil.rmtree(config.DATABASE)
447         os.makedirs(config.DATABASE + '/files')
448         db = anydbm.Database(config, 'test')
449         setupSchema(db, 1, anydbm)
450         self.db = anydbm.Database(config)
451         setupSchema(self.db, 0, anydbm)
452         self.db2 = anydbm.Database(config, 'test')
453         setupSchema(self.db2, 0, anydbm)
455     def testExceptions(self):
456         # this tests the exceptions that should be raised
457         ar = self.assertRaises
459         # this tests the exceptions that should be raised
460         ar(DatabaseError, self.db.status.create, name="foo")
461         ar(DatabaseError, self.db.status.set, '1', name="foo")
462         ar(DatabaseError, self.db.status.retire, '1')
465 class bsddbDBTestCase(anydbmDBTestCase):
466     def setUp(self):
467         from roundup.backends import bsddb
468         # remove previous test, ignore errors
469         if os.path.exists(config.DATABASE):
470             shutil.rmtree(config.DATABASE)
471         os.makedirs(config.DATABASE + '/files')
472         self.db = bsddb.Database(config, 'test')
473         setupSchema(self.db, 1, bsddb)
474         self.db2 = bsddb.Database(config, 'test')
475         setupSchema(self.db2, 0, bsddb)
477 class bsddbReadOnlyDBTestCase(anydbmReadOnlyDBTestCase):
478     def setUp(self):
479         from roundup.backends import bsddb
480         # remove previous test, ignore errors
481         if os.path.exists(config.DATABASE):
482             shutil.rmtree(config.DATABASE)
483         os.makedirs(config.DATABASE + '/files')
484         db = bsddb.Database(config, 'test')
485         setupSchema(db, 1, bsddb)
486         self.db = bsddb.Database(config)
487         setupSchema(self.db, 0, bsddb)
488         self.db2 = bsddb.Database(config, 'test')
489         setupSchema(self.db2, 0, bsddb)
492 class bsddb3DBTestCase(anydbmDBTestCase):
493     def setUp(self):
494         from roundup.backends import bsddb3
495         # remove previous test, ignore errors
496         if os.path.exists(config.DATABASE):
497             shutil.rmtree(config.DATABASE)
498         os.makedirs(config.DATABASE + '/files')
499         self.db = bsddb3.Database(config, 'test')
500         setupSchema(self.db, 1, bsddb3)
501         self.db2 = bsddb3.Database(config, 'test')
502         setupSchema(self.db2, 0, bsddb3)
504 class bsddb3ReadOnlyDBTestCase(anydbmReadOnlyDBTestCase):
505     def setUp(self):
506         from roundup.backends import bsddb3
507         # remove previous test, ignore errors
508         if os.path.exists(config.DATABASE):
509             shutil.rmtree(config.DATABASE)
510         os.makedirs(config.DATABASE + '/files')
511         db = bsddb3.Database(config, 'test')
512         setupSchema(db, 1, bsddb3)
513         self.db = bsddb3.Database(config)
514         setupSchema(self.db, 0, bsddb3)
515         self.db2 = bsddb3.Database(config, 'test')
516         setupSchema(self.db2, 0, bsddb3)
519 class metakitDBTestCase(anydbmDBTestCase):
520     def setUp(self):
521         from roundup.backends import metakit
522         import weakref
523         metakit._instances = weakref.WeakValueDictionary()
524         # remove previous test, ignore errors
525         if os.path.exists(config.DATABASE):
526             shutil.rmtree(config.DATABASE)
527         os.makedirs(config.DATABASE + '/files')
528         self.db = metakit.Database(config, 'test')
529         setupSchema(self.db, 1, metakit)
530         self.db2 = metakit.Database(config, 'test')
531         setupSchema(self.db2, 0, metakit)
533     def testTransactions(self):
534         # remember the number of items we started
535         num_issues = len(self.db.issue.list())
536         self.db.issue.create(title="don't commit me!", status='1')
537         self.assertNotEqual(num_issues, len(self.db.issue.list()))
538         self.db.rollback()
539         self.assertEqual(num_issues, len(self.db.issue.list()))
540         self.db.issue.create(title="please commit me!", status='1')
541         self.assertNotEqual(num_issues, len(self.db.issue.list()))
542         self.db.commit()
543         self.assertNotEqual(num_issues, len(self.db.issue.list()))
544         self.db.rollback()
545         self.assertNotEqual(num_issues, len(self.db.issue.list()))
546         self.db.file.create(name="test", type="text/plain", content="hi")
547         self.db.rollback()
548         for i in range(10):
549             self.db.file.create(name="test", type="text/plain", 
550                     content="hi %d"%(i))
551             self.db.commit()
552         # TODO: would be good to be able to ensure the file is not on disk after
553         # a rollback...
554         self.assertNotEqual(num_files, num_files2)
555         self.db.file.create(name="test", type="text/plain", content="hi")
556         self.db.rollback()
558 class metakitReadOnlyDBTestCase(anydbmReadOnlyDBTestCase):
559     def setUp(self):
560         from roundup.backends import metakit
561         import weakref
562         metakit._instances = weakref.WeakValueDictionary()
563         # remove previous test, ignore errors
564         if os.path.exists(config.DATABASE):
565             shutil.rmtree(config.DATABASE)
566         os.makedirs(config.DATABASE + '/files')
567         db = metakit.Database(config, 'test')
568         setupSchema(db, 1, metakit)
569         self.db = metakit.Database(config)
570         setupSchema(self.db, 0, metakit)
571         self.db2 = metakit.Database(config, 'test')
572         setupSchema(self.db2, 0, metakit)
574 def suite():
575     l = [
576          unittest.makeSuite(anydbmDBTestCase, 'test'),
577          unittest.makeSuite(anydbmReadOnlyDBTestCase, 'test')
578     ]
579 #    return unittest.TestSuite(l)
581     try:
582         import bsddb
583         l.append(unittest.makeSuite(bsddbDBTestCase, 'test'))
584         l.append(unittest.makeSuite(bsddbReadOnlyDBTestCase, 'test'))
585     except:
586         print 'bsddb module not found, skipping bsddb DBTestCase'
588     try:
589         import bsddb3
590         l.append(unittest.makeSuite(bsddb3DBTestCase, 'test'))
591         l.append(unittest.makeSuite(bsddb3ReadOnlyDBTestCase, 'test'))
592     except:
593         print 'bsddb3 module not found, skipping bsddb3 DBTestCase'
595     try:
596         import metakit
597         l.append(unittest.makeSuite(metakitDBTestCase, 'test'))
598         l.append(unittest.makeSuite(metakitReadOnlyDBTestCase, 'test'))
599     except:
600         print 'metakit module not found, skipping metakit DBTestCase'
602     return unittest.TestSuite(l)
605 # $Log: not supported by cvs2svn $
606 # Revision 1.37  2002/07/25 07:14:06  richard
607 # Bugger it. Here's the current shape of the new security implementation.
608 # Still to do:
609 #  . call the security funcs from cgi and mailgw
610 #  . change shipped templates to include correct initialisation and remove
611 #    the old config vars
612 # ... that seems like a lot. The bulk of the work has been done though. Honest :)
614 # Revision 1.36  2002/07/19 03:36:34  richard
615 # Implemented the destroy() method needed by the session database (and possibly
616 # others). At the same time, I removed the leading underscores from the hyperdb
617 # methods that Really Didn't Need Them.
618 # The journal also raises IndexError now for all situations where there is a
619 # request for the journal of a node that doesn't have one. It used to return
620 # [] in _some_ situations, but not all. This _may_ break code, but the tests
621 # pass...
623 # Revision 1.35  2002/07/18 23:07:08  richard
624 # Unit tests and a few fixes.
626 # Revision 1.34  2002/07/18 11:52:00  richard
627 # oops
629 # Revision 1.33  2002/07/18 11:50:58  richard
630 # added tests for number type too
632 # Revision 1.32  2002/07/18 11:41:10  richard
633 # added tests for boolean type, and fixes to anydbm backend
635 # Revision 1.31  2002/07/14 23:17:45  richard
636 # minor change to make testing easier
638 # Revision 1.30  2002/07/14 06:06:34  richard
639 # Did some old TODOs
641 # Revision 1.29  2002/07/14 04:03:15  richard
642 # Implemented a switch to disable journalling for a Class. CGI session
643 # database now uses it.
645 # Revision 1.28  2002/07/14 02:16:29  richard
646 # Fixes for the metakit backend (removed the cut-n-paste IssueClass, removed
647 # a special case for it in testing)
649 # Revision 1.27  2002/07/14 02:05:54  richard
650 # . all storage-specific code (ie. backend) is now implemented by the backends
652 # Revision 1.26  2002/07/11 01:11:03  richard
653 # Added metakit backend to the db tests and fixed the more easily fixable test
654 # failures.
656 # Revision 1.25  2002/07/09 04:19:09  richard
657 # Added reindex command to roundup-admin.
658 # Fixed reindex on first access.
659 # Also fixed reindexing of entries that change.
661 # Revision 1.24  2002/07/09 03:02:53  richard
662 # More indexer work:
663 # - all String properties may now be indexed too. Currently there's a bit of
664 #   "issue" specific code in the actual searching which needs to be
665 #   addressed. In a nutshell:
666 #   + pass 'indexme="yes"' as a String() property initialisation arg, eg:
667 #         file = FileClass(db, "file", name=String(), type=String(),
668 #             comment=String(indexme="yes"))
669 #   + the comment will then be indexed and be searchable, with the results
670 #     related back to the issue that the file is linked to
671 # - as a result of this work, the FileClass has a default MIME type that may
672 #   be overridden in a subclass, or by the use of a "type" property as is
673 #   done in the default templates.
674 # - the regeneration of the indexes (if necessary) is done once the schema is
675 #   set up in the dbinit.
677 # Revision 1.23  2002/06/20 23:51:48  richard
678 # Cleaned up the hyperdb tests
680 # Revision 1.22  2002/05/21 05:52:11  richard
681 # Well whadya know, bsddb3 works again.
682 # The backend is implemented _exactly_ the same as bsddb - so there's no
683 # using its transaction or locking support. It'd be nice to use those some
684 # day I suppose.
686 # Revision 1.21  2002/04/15 23:25:15  richard
687 # . node ids are now generated from a lockable store - no more race conditions
689 # We're using the portalocker code by Jonathan Feinberg that was contributed
690 # to the ASPN Python cookbook. This gives us locking across Unix and Windows.
692 # Revision 1.20  2002/04/03 05:54:31  richard
693 # Fixed serialisation problem by moving the serialisation step out of the
694 # hyperdb.Class (get, set) into the hyperdb.Database.
696 # Also fixed htmltemplate after the showid changes I made yesterday.
698 # Unit tests for all of the above written.
700 # Revision 1.19  2002/02/25 14:34:31  grubert
701 #  . use blobfiles in back_anydbm which is used in back_bsddb.
702 #    change test_db as dirlist does not work for subdirectories.
703 #    ATTENTION: blobfiles now creates subdirectories for files.
705 # Revision 1.18  2002/01/22 07:21:13  richard
706 # . fixed back_bsddb so it passed the journal tests
708 # ... it didn't seem happy using the back_anydbm _open method, which is odd.
709 # Yet another occurrance of whichdb not being able to recognise older bsddb
710 # databases. Yadda yadda. Made the HYPERDBDEBUG stuff more sane in the
711 # process.
713 # Revision 1.17  2002/01/22 05:06:09  rochecompaan
714 # We need to keep the last 'set' entry in the journal to preserve
715 # information on 'activity' for nodes.
717 # Revision 1.16  2002/01/21 16:33:20  rochecompaan
718 # You can now use the roundup-admin tool to pack the database
720 # Revision 1.15  2002/01/19 13:16:04  rochecompaan
721 # Journal entries for link and multilink properties can now be switched on
722 # or off.
724 # Revision 1.14  2002/01/16 07:02:57  richard
725 #  . lots of date/interval related changes:
726 #    - more relaxed date format for input
728 # Revision 1.13  2002/01/14 02:20:15  richard
729 #  . changed all config accesses so they access either the instance or the
730 #    config attriubute on the db. This means that all config is obtained from
731 #    instance_config instead of the mish-mash of classes. This will make
732 #    switching to a ConfigParser setup easier too, I hope.
734 # At a minimum, this makes migration a _little_ easier (a lot easier in the
735 # 0.5.0 switch, I hope!)
737 # Revision 1.12  2001/12/17 03:52:48  richard
738 # Implemented file store rollback. As a bonus, the hyperdb is now capable of
739 # storing more than one file per node - if a property name is supplied,
740 # the file is called designator.property.
741 # I decided not to migrate the existing files stored over to the new naming
742 # scheme - the FileClass just doesn't specify the property name.
744 # Revision 1.11  2001/12/10 23:17:20  richard
745 # Added transaction tests to test_db
747 # Revision 1.10  2001/12/03 21:33:39  richard
748 # Fixes so the tests use commit and not close
750 # Revision 1.9  2001/12/02 05:06:16  richard
751 # . We now use weakrefs in the Classes to keep the database reference, so
752 #   the close() method on the database is no longer needed.
753 #   I bumped the minimum python requirement up to 2.1 accordingly.
754 # . #487480 ] roundup-server
755 # . #487476 ] INSTALL.txt
757 # I also cleaned up the change message / post-edit stuff in the cgi client.
758 # There's now a clearly marked "TODO: append the change note" where I believe
759 # the change note should be added there. The "changes" list will obviously
760 # have to be modified to be a dict of the changes, or somesuch.
762 # More testing needed.
764 # Revision 1.8  2001/10/09 07:25:59  richard
765 # Added the Password property type. See "pydoc roundup.password" for
766 # implementation details. Have updated some of the documentation too.
768 # Revision 1.7  2001/08/29 06:23:59  richard
769 # Disabled the bsddb3 module entirely in the unit testing. See CHANGES for
770 # details.
772 # Revision 1.6  2001/08/07 00:24:43  richard
773 # stupid typo
775 # Revision 1.5  2001/08/07 00:15:51  richard
776 # Added the copyright/license notice to (nearly) all files at request of
777 # Bizar Software.
779 # Revision 1.4  2001/07/30 03:45:56  richard
780 # Added more DB to test_db. Can skip tests where imports fail.
782 # Revision 1.3  2001/07/29 07:01:39  richard
783 # Added vim command to all source so that we don't get no steenkin' tabs :)
785 # Revision 1.2  2001/07/29 04:09:20  richard
786 # Added the fabricated property "id" to all hyperdb classes.
788 # Revision 1.1  2001/07/27 06:55:07  richard
789 # moving tests -> test
791 # Revision 1.7  2001/07/27 06:26:43  richard
792 # oops - wasn't deleting the test dir after the read-only tests
794 # Revision 1.6  2001/07/27 06:23:59  richard
795 # consistency
797 # Revision 1.5  2001/07/27 06:23:09  richard
798 # Added some new hyperdb tests to make sure we raise the right exceptions.
800 # Revision 1.4  2001/07/25 04:34:31  richard
801 # Added id and log to tests files...
804 # vim: set filetype=python ts=4 sw=4 et si