Mercurial > p > roundup > code
comparison test/test_db.py @ 1356:83f33642d220 maint-0.5
[[Metadata associated with this commit was garbled during conversion from CVS
to Subversion.]]
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Thu, 09 Jan 2003 22:59:22 +0000 |
| parents | |
| children | 31cc79f966ac |
comparison
equal
deleted
inserted
replaced
| 1242:3d0158c8c32b | 1356:83f33642d220 |
|---|---|
| 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.63 2002-12-12 09:31:04 richard Exp $ | |
| 19 | |
| 20 import unittest, os, shutil, time | |
| 21 | |
| 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 | |
| 26 | |
| 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"), fooz=Password()) | |
| 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 user.create(username="admin", roles='Admin') | |
| 43 status.create(name="unread") | |
| 44 status.create(name="in-progress") | |
| 45 status.create(name="testing") | |
| 46 status.create(name="resolved") | |
| 47 db.commit() | |
| 48 | |
| 49 class MyTestCase(unittest.TestCase): | |
| 50 def tearDown(self): | |
| 51 self.db.close() | |
| 52 if os.path.exists('_test_dir'): | |
| 53 shutil.rmtree('_test_dir') | |
| 54 | |
| 55 class config: | |
| 56 DATABASE='_test_dir' | |
| 57 MAILHOST = 'localhost' | |
| 58 MAIL_DOMAIN = 'fill.me.in.' | |
| 59 TRACKER_NAME = 'Roundup issue tracker' | |
| 60 TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN | |
| 61 TRACKER_WEB = 'http://some.useful.url/' | |
| 62 ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN | |
| 63 FILTER_POSITION = 'bottom' # one of 'top', 'bottom', 'top and bottom' | |
| 64 ANONYMOUS_ACCESS = 'deny' # either 'deny' or 'allow' | |
| 65 ANONYMOUS_REGISTER = 'deny' # either 'deny' or 'allow' | |
| 66 MESSAGES_TO_AUTHOR = 'no' # either 'yes' or 'no' | |
| 67 EMAIL_SIGNATURE_POSITION = 'bottom' | |
| 68 | |
| 69 class anydbmDBTestCase(MyTestCase): | |
| 70 def setUp(self): | |
| 71 from roundup.backends import anydbm | |
| 72 # remove previous test, ignore errors | |
| 73 if os.path.exists(config.DATABASE): | |
| 74 shutil.rmtree(config.DATABASE) | |
| 75 os.makedirs(config.DATABASE + '/files') | |
| 76 self.db = anydbm.Database(config, 'admin') | |
| 77 setupSchema(self.db, 1, anydbm) | |
| 78 | |
| 79 def testIDGeneration(self): | |
| 80 id1 = self.db.issue.create(title="spam", status='1') | |
| 81 id2 = self.db.issue.create(title="eggs", status='2') | |
| 82 self.assertNotEqual(id1, id2) | |
| 83 | |
| 84 def testStringChange(self): | |
| 85 for commit in (0,1): | |
| 86 # test set & retrieve | |
| 87 nid = self.db.issue.create(title="spam", status='1') | |
| 88 self.assertEqual(self.db.issue.get(nid, 'title'), 'spam') | |
| 89 | |
| 90 # change and make sure we retrieve the correct value | |
| 91 self.db.issue.set(nid, title='eggs') | |
| 92 if commit: self.db.commit() | |
| 93 self.assertEqual(self.db.issue.get(nid, 'title'), 'eggs') | |
| 94 | |
| 95 def testStringUnset(self): | |
| 96 for commit in (0,1): | |
| 97 nid = self.db.issue.create(title="spam", status='1') | |
| 98 if commit: self.db.commit() | |
| 99 self.assertEqual(self.db.issue.get(nid, 'title'), 'spam') | |
| 100 # make sure we can unset | |
| 101 self.db.issue.set(nid, title=None) | |
| 102 if commit: self.db.commit() | |
| 103 self.assertEqual(self.db.issue.get(nid, "title"), None) | |
| 104 | |
| 105 def testLinkChange(self): | |
| 106 for commit in (0,1): | |
| 107 nid = self.db.issue.create(title="spam", status='1') | |
| 108 if commit: self.db.commit() | |
| 109 self.assertEqual(self.db.issue.get(nid, "status"), '1') | |
| 110 self.db.issue.set(nid, status='2') | |
| 111 if commit: self.db.commit() | |
| 112 self.assertEqual(self.db.issue.get(nid, "status"), '2') | |
| 113 | |
| 114 def testLinkUnset(self): | |
| 115 for commit in (0,1): | |
| 116 nid = self.db.issue.create(title="spam", status='1') | |
| 117 if commit: self.db.commit() | |
| 118 self.db.issue.set(nid, status=None) | |
| 119 if commit: self.db.commit() | |
| 120 self.assertEqual(self.db.issue.get(nid, "status"), None) | |
| 121 | |
| 122 def testMultilinkChange(self): | |
| 123 for commit in (0,1): | |
| 124 u1 = self.db.user.create(username='foo%s'%commit) | |
| 125 u2 = self.db.user.create(username='bar%s'%commit) | |
| 126 nid = self.db.issue.create(title="spam", nosy=[u1]) | |
| 127 if commit: self.db.commit() | |
| 128 self.assertEqual(self.db.issue.get(nid, "nosy"), [u1]) | |
| 129 self.db.issue.set(nid, nosy=[]) | |
| 130 if commit: self.db.commit() | |
| 131 self.assertEqual(self.db.issue.get(nid, "nosy"), []) | |
| 132 self.db.issue.set(nid, nosy=[u1,u2]) | |
| 133 if commit: self.db.commit() | |
| 134 self.assertEqual(self.db.issue.get(nid, "nosy"), [u1,u2]) | |
| 135 | |
| 136 def testDateChange(self): | |
| 137 for commit in (0,1): | |
| 138 nid = self.db.issue.create(title="spam", status='1') | |
| 139 a = self.db.issue.get(nid, "deadline") | |
| 140 if commit: self.db.commit() | |
| 141 self.db.issue.set(nid, deadline=date.Date()) | |
| 142 b = self.db.issue.get(nid, "deadline") | |
| 143 if commit: self.db.commit() | |
| 144 self.assertNotEqual(a, b) | |
| 145 self.assertNotEqual(b, date.Date('1970-1-1 00:00:00')) | |
| 146 | |
| 147 def testDateUnset(self): | |
| 148 for commit in (0,1): | |
| 149 nid = self.db.issue.create(title="spam", status='1') | |
| 150 self.db.issue.set(nid, deadline=date.Date()) | |
| 151 if commit: self.db.commit() | |
| 152 self.assertNotEqual(self.db.issue.get(nid, "deadline"), None) | |
| 153 self.db.issue.set(nid, deadline=None) | |
| 154 if commit: self.db.commit() | |
| 155 self.assertEqual(self.db.issue.get(nid, "deadline"), None) | |
| 156 | |
| 157 def testIntervalChange(self): | |
| 158 for commit in (0,1): | |
| 159 nid = self.db.issue.create(title="spam", status='1') | |
| 160 if commit: self.db.commit() | |
| 161 a = self.db.issue.get(nid, "foo") | |
| 162 i = date.Interval('-1d') | |
| 163 self.db.issue.set(nid, foo=i) | |
| 164 if commit: self.db.commit() | |
| 165 self.assertNotEqual(self.db.issue.get(nid, "foo"), a) | |
| 166 self.assertEqual(i, self.db.issue.get(nid, "foo")) | |
| 167 j = date.Interval('1y') | |
| 168 self.db.issue.set(nid, foo=j) | |
| 169 if commit: self.db.commit() | |
| 170 self.assertNotEqual(self.db.issue.get(nid, "foo"), i) | |
| 171 self.assertEqual(j, self.db.issue.get(nid, "foo")) | |
| 172 | |
| 173 def testIntervalUnset(self): | |
| 174 for commit in (0,1): | |
| 175 nid = self.db.issue.create(title="spam", status='1') | |
| 176 self.db.issue.set(nid, foo=date.Interval('-1d')) | |
| 177 if commit: self.db.commit() | |
| 178 self.assertNotEqual(self.db.issue.get(nid, "foo"), None) | |
| 179 self.db.issue.set(nid, foo=None) | |
| 180 if commit: self.db.commit() | |
| 181 self.assertEqual(self.db.issue.get(nid, "foo"), None) | |
| 182 | |
| 183 def testBooleanChange(self): | |
| 184 userid = self.db.user.create(username='foo', assignable=1) | |
| 185 self.assertEqual(1, self.db.user.get(userid, 'assignable')) | |
| 186 self.db.user.set(userid, assignable=0) | |
| 187 self.assertEqual(self.db.user.get(userid, 'assignable'), 0) | |
| 188 self.db.user.set(userid, assignable=None) | |
| 189 self.assertEqual(self.db.user.get('1', "assignable"), None) | |
| 190 | |
| 191 def testNumberChange(self): | |
| 192 nid = self.db.user.create(username='foo', age=1) | |
| 193 self.assertEqual(1, self.db.user.get(nid, 'age')) | |
| 194 self.db.user.set('1', age=3) | |
| 195 self.assertNotEqual(self.db.user.get('1', 'age'), 1) | |
| 196 self.db.user.set('1', age=1.0) | |
| 197 self.db.user.set('1', age=None) | |
| 198 self.assertEqual(self.db.user.get('1', "age"), None) | |
| 199 | |
| 200 def testKeyValue(self): | |
| 201 newid = self.db.user.create(username="spam") | |
| 202 self.assertEqual(self.db.user.lookup('spam'), newid) | |
| 203 self.db.commit() | |
| 204 self.assertEqual(self.db.user.lookup('spam'), newid) | |
| 205 self.db.user.retire(newid) | |
| 206 self.assertRaises(KeyError, self.db.user.lookup, 'spam') | |
| 207 | |
| 208 def testNewProperty(self): | |
| 209 self.db.issue.create(title="spam", status='1') | |
| 210 self.db.issue.addprop(fixer=Link("user")) | |
| 211 # force any post-init stuff to happen | |
| 212 self.db.post_init() | |
| 213 props = self.db.issue.getprops() | |
| 214 keys = props.keys() | |
| 215 keys.sort() | |
| 216 self.assertEqual(keys, ['activity', 'assignedto', 'creation', | |
| 217 'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages', | |
| 218 'nosy', 'status', 'superseder', 'title']) | |
| 219 self.assertEqual(self.db.issue.get('1', "fixer"), None) | |
| 220 | |
| 221 def testRetire(self): | |
| 222 self.db.issue.create(title="spam", status='1') | |
| 223 b = self.db.status.get('1', 'name') | |
| 224 a = self.db.status.list() | |
| 225 self.db.status.retire('1') | |
| 226 # make sure the list is different | |
| 227 self.assertNotEqual(a, self.db.status.list()) | |
| 228 # can still access the node if necessary | |
| 229 self.assertEqual(self.db.status.get('1', 'name'), b) | |
| 230 self.db.commit() | |
| 231 self.assertEqual(self.db.status.get('1', 'name'), b) | |
| 232 self.assertNotEqual(a, self.db.status.list()) | |
| 233 | |
| 234 def testSerialisation(self): | |
| 235 nid = self.db.issue.create(title="spam", status='1', | |
| 236 deadline=date.Date(), foo=date.Interval('-1d')) | |
| 237 self.db.commit() | |
| 238 assert isinstance(self.db.issue.get(nid, 'deadline'), date.Date) | |
| 239 assert isinstance(self.db.issue.get(nid, 'foo'), date.Interval) | |
| 240 uid = self.db.user.create(username="fozzy", | |
| 241 password=password.Password('t. bear')) | |
| 242 self.db.commit() | |
| 243 assert isinstance(self.db.user.get(uid, 'password'), password.Password) | |
| 244 | |
| 245 def testTransactions(self): | |
| 246 # remember the number of items we started | |
| 247 num_issues = len(self.db.issue.list()) | |
| 248 num_files = self.db.numfiles() | |
| 249 self.db.issue.create(title="don't commit me!", status='1') | |
| 250 self.assertNotEqual(num_issues, len(self.db.issue.list())) | |
| 251 self.db.rollback() | |
| 252 self.assertEqual(num_issues, len(self.db.issue.list())) | |
| 253 self.db.issue.create(title="please commit me!", status='1') | |
| 254 self.assertNotEqual(num_issues, len(self.db.issue.list())) | |
| 255 self.db.commit() | |
| 256 self.assertNotEqual(num_issues, len(self.db.issue.list())) | |
| 257 self.db.rollback() | |
| 258 self.assertNotEqual(num_issues, len(self.db.issue.list())) | |
| 259 self.db.file.create(name="test", type="text/plain", content="hi") | |
| 260 self.db.rollback() | |
| 261 self.assertEqual(num_files, self.db.numfiles()) | |
| 262 for i in range(10): | |
| 263 self.db.file.create(name="test", type="text/plain", | |
| 264 content="hi %d"%(i)) | |
| 265 self.db.commit() | |
| 266 num_files2 = self.db.numfiles() | |
| 267 self.assertNotEqual(num_files, num_files2) | |
| 268 self.db.file.create(name="test", type="text/plain", content="hi") | |
| 269 self.db.rollback() | |
| 270 self.assertNotEqual(num_files, self.db.numfiles()) | |
| 271 self.assertEqual(num_files2, self.db.numfiles()) | |
| 272 | |
| 273 def testDestroyNoJournalling(self): | |
| 274 self.innerTestDestroy(klass=self.db.session) | |
| 275 | |
| 276 def testDestroyJournalling(self): | |
| 277 self.innerTestDestroy(klass=self.db.issue) | |
| 278 | |
| 279 def innerTestDestroy(self, klass): | |
| 280 newid = klass.create(title='Mr Friendly') | |
| 281 n = len(klass.list()) | |
| 282 self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') | |
| 283 klass.destroy(newid) | |
| 284 self.assertRaises(IndexError, klass.get, newid, 'title') | |
| 285 self.assertNotEqual(len(klass.list()), n) | |
| 286 if klass.do_journal: | |
| 287 self.assertRaises(IndexError, klass.history, newid) | |
| 288 | |
| 289 # now with a commit | |
| 290 newid = klass.create(title='Mr Friendly') | |
| 291 n = len(klass.list()) | |
| 292 self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') | |
| 293 self.db.commit() | |
| 294 klass.destroy(newid) | |
| 295 self.assertRaises(IndexError, klass.get, newid, 'title') | |
| 296 self.db.commit() | |
| 297 self.assertRaises(IndexError, klass.get, newid, 'title') | |
| 298 self.assertNotEqual(len(klass.list()), n) | |
| 299 if klass.do_journal: | |
| 300 self.assertRaises(IndexError, klass.history, newid) | |
| 301 | |
| 302 # now with a rollback | |
| 303 newid = klass.create(title='Mr Friendly') | |
| 304 n = len(klass.list()) | |
| 305 self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') | |
| 306 self.db.commit() | |
| 307 klass.destroy(newid) | |
| 308 self.assertNotEqual(len(klass.list()), n) | |
| 309 self.assertRaises(IndexError, klass.get, newid, 'title') | |
| 310 self.db.rollback() | |
| 311 self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') | |
| 312 self.assertEqual(len(klass.list()), n) | |
| 313 if klass.do_journal: | |
| 314 self.assertNotEqual(klass.history(newid), []) | |
| 315 | |
| 316 def testExceptions(self): | |
| 317 # this tests the exceptions that should be raised | |
| 318 ar = self.assertRaises | |
| 319 | |
| 320 # | |
| 321 # class create | |
| 322 # | |
| 323 # string property | |
| 324 ar(TypeError, self.db.status.create, name=1) | |
| 325 # invalid property name | |
| 326 ar(KeyError, self.db.status.create, foo='foo') | |
| 327 # key name clash | |
| 328 ar(ValueError, self.db.status.create, name='unread') | |
| 329 # invalid link index | |
| 330 ar(IndexError, self.db.issue.create, title='foo', status='bar') | |
| 331 # invalid link value | |
| 332 ar(ValueError, self.db.issue.create, title='foo', status=1) | |
| 333 # invalid multilink type | |
| 334 ar(TypeError, self.db.issue.create, title='foo', status='1', | |
| 335 nosy='hello') | |
| 336 # invalid multilink index type | |
| 337 ar(ValueError, self.db.issue.create, title='foo', status='1', | |
| 338 nosy=[1]) | |
| 339 # invalid multilink index | |
| 340 ar(IndexError, self.db.issue.create, title='foo', status='1', | |
| 341 nosy=['10']) | |
| 342 | |
| 343 # | |
| 344 # key property | |
| 345 # | |
| 346 # key must be a String | |
| 347 ar(TypeError, self.db.file.setkey, 'fooz') | |
| 348 # key must exist | |
| 349 ar(KeyError, self.db.file.setkey, 'fubar') | |
| 350 | |
| 351 # | |
| 352 # class get | |
| 353 # | |
| 354 # invalid node id | |
| 355 ar(IndexError, self.db.issue.get, '99', 'title') | |
| 356 # invalid property name | |
| 357 ar(KeyError, self.db.status.get, '2', 'foo') | |
| 358 | |
| 359 # | |
| 360 # class set | |
| 361 # | |
| 362 # invalid node id | |
| 363 ar(IndexError, self.db.issue.set, '99', title='foo') | |
| 364 # invalid property name | |
| 365 ar(KeyError, self.db.status.set, '1', foo='foo') | |
| 366 # string property | |
| 367 ar(TypeError, self.db.status.set, '1', name=1) | |
| 368 # key name clash | |
| 369 ar(ValueError, self.db.status.set, '2', name='unread') | |
| 370 # set up a valid issue for me to work on | |
| 371 id = self.db.issue.create(title="spam", status='1') | |
| 372 # invalid link index | |
| 373 ar(IndexError, self.db.issue.set, id, title='foo', status='bar') | |
| 374 # invalid link value | |
| 375 ar(ValueError, self.db.issue.set, id, title='foo', status=1) | |
| 376 # invalid multilink type | |
| 377 ar(TypeError, self.db.issue.set, id, title='foo', status='1', | |
| 378 nosy='hello') | |
| 379 # invalid multilink index type | |
| 380 ar(ValueError, self.db.issue.set, id, title='foo', status='1', | |
| 381 nosy=[1]) | |
| 382 # invalid multilink index | |
| 383 ar(IndexError, self.db.issue.set, id, title='foo', status='1', | |
| 384 nosy=['10']) | |
| 385 # invalid number value | |
| 386 ar(TypeError, self.db.user.create, username='foo', age='a') | |
| 387 # invalid boolean value | |
| 388 ar(TypeError, self.db.user.create, username='foo', assignable='true') | |
| 389 nid = self.db.user.create(username='foo') | |
| 390 # invalid number value | |
| 391 ar(TypeError, self.db.user.set, nid, username='foo', age='a') | |
| 392 # invalid boolean value | |
| 393 ar(TypeError, self.db.user.set, nid, username='foo', assignable='true') | |
| 394 | |
| 395 def testJournals(self): | |
| 396 self.db.user.create(username="mary") | |
| 397 self.db.user.create(username="pete") | |
| 398 self.db.issue.create(title="spam", status='1') | |
| 399 self.db.commit() | |
| 400 | |
| 401 # journal entry for issue create | |
| 402 journal = self.db.getjournal('issue', '1') | |
| 403 self.assertEqual(1, len(journal)) | |
| 404 (nodeid, date_stamp, journaltag, action, params) = journal[0] | |
| 405 self.assertEqual(nodeid, '1') | |
| 406 self.assertEqual(journaltag, self.db.user.lookup('admin')) | |
| 407 self.assertEqual(action, 'create') | |
| 408 keys = params.keys() | |
| 409 keys.sort() | |
| 410 self.assertEqual(keys, []) | |
| 411 | |
| 412 # journal entry for link | |
| 413 journal = self.db.getjournal('user', '1') | |
| 414 self.assertEqual(1, len(journal)) | |
| 415 self.db.issue.set('1', assignedto='1') | |
| 416 self.db.commit() | |
| 417 journal = self.db.getjournal('user', '1') | |
| 418 self.assertEqual(2, len(journal)) | |
| 419 (nodeid, date_stamp, journaltag, action, params) = journal[1] | |
| 420 self.assertEqual('1', nodeid) | |
| 421 self.assertEqual('1', journaltag) | |
| 422 self.assertEqual('link', action) | |
| 423 self.assertEqual(('issue', '1', 'assignedto'), params) | |
| 424 | |
| 425 # journal entry for unlink | |
| 426 self.db.issue.set('1', assignedto='2') | |
| 427 self.db.commit() | |
| 428 journal = self.db.getjournal('user', '1') | |
| 429 self.assertEqual(3, len(journal)) | |
| 430 (nodeid, date_stamp, journaltag, action, params) = journal[2] | |
| 431 self.assertEqual('1', nodeid) | |
| 432 self.assertEqual('1', journaltag) | |
| 433 self.assertEqual('unlink', action) | |
| 434 self.assertEqual(('issue', '1', 'assignedto'), params) | |
| 435 | |
| 436 # test disabling journalling | |
| 437 # ... get the last entry | |
| 438 time.sleep(1) | |
| 439 entry = self.db.getjournal('issue', '1')[-1] | |
| 440 (x, date_stamp, x, x, x) = entry | |
| 441 self.db.issue.disableJournalling() | |
| 442 self.db.issue.set('1', title='hello world') | |
| 443 self.db.commit() | |
| 444 entry = self.db.getjournal('issue', '1')[-1] | |
| 445 (x, date_stamp2, x, x, x) = entry | |
| 446 # see if the change was journalled when it shouldn't have been | |
| 447 self.assertEqual(date_stamp, date_stamp2) | |
| 448 time.sleep(1) | |
| 449 self.db.issue.enableJournalling() | |
| 450 self.db.issue.set('1', title='hello world 2') | |
| 451 self.db.commit() | |
| 452 entry = self.db.getjournal('issue', '1')[-1] | |
| 453 (x, date_stamp2, x, x, x) = entry | |
| 454 # see if the change was journalled | |
| 455 self.assertNotEqual(date_stamp, date_stamp2) | |
| 456 | |
| 457 def testPack(self): | |
| 458 id = self.db.issue.create(title="spam", status='1') | |
| 459 self.db.commit() | |
| 460 self.db.issue.set(id, status='2') | |
| 461 self.db.commit() | |
| 462 | |
| 463 # sleep for at least a second, then get a date to pack at | |
| 464 time.sleep(1) | |
| 465 pack_before = date.Date('.') | |
| 466 | |
| 467 # wait another second and add one more entry | |
| 468 time.sleep(1) | |
| 469 self.db.issue.set(id, status='3') | |
| 470 self.db.commit() | |
| 471 jlen = len(self.db.getjournal('issue', id)) | |
| 472 | |
| 473 # pack | |
| 474 self.db.pack(pack_before) | |
| 475 | |
| 476 # we should have the create and last set entries now | |
| 477 self.assertEqual(jlen-1, len(self.db.getjournal('issue', id))) | |
| 478 | |
| 479 def testSearching(self): | |
| 480 self.db.file.create(content='hello', type="text/plain") | |
| 481 self.db.file.create(content='world', type="text/frozz", | |
| 482 comment='blah blah') | |
| 483 self.db.issue.create(files=['1', '2'], title="flebble plop") | |
| 484 self.db.issue.create(title="flebble frooz") | |
| 485 self.db.commit() | |
| 486 self.assertEquals(self.db.indexer.search(['hello'], self.db.issue), | |
| 487 {'1': {'files': ['1']}}) | |
| 488 self.assertEquals(self.db.indexer.search(['world'], self.db.issue), {}) | |
| 489 self.assertEquals(self.db.indexer.search(['frooz'], self.db.issue), | |
| 490 {'2': {}}) | |
| 491 self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue), | |
| 492 {'2': {}, '1': {}}) | |
| 493 | |
| 494 def testReindexing(self): | |
| 495 self.db.issue.create(title="frooz") | |
| 496 self.db.commit() | |
| 497 self.assertEquals(self.db.indexer.search(['frooz'], self.db.issue), | |
| 498 {'1': {}}) | |
| 499 self.db.issue.set('1', title="dooble") | |
| 500 self.db.commit() | |
| 501 self.assertEquals(self.db.indexer.search(['dooble'], self.db.issue), | |
| 502 {'1': {}}) | |
| 503 self.assertEquals(self.db.indexer.search(['frooz'], self.db.issue), {}) | |
| 504 | |
| 505 def testForcedReindexing(self): | |
| 506 self.db.issue.create(title="flebble frooz") | |
| 507 self.db.commit() | |
| 508 self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue), | |
| 509 {'1': {}}) | |
| 510 self.db.indexer.quiet = 1 | |
| 511 self.db.indexer.force_reindex() | |
| 512 self.db.post_init() | |
| 513 self.db.indexer.quiet = 9 | |
| 514 self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue), | |
| 515 {'1': {}}) | |
| 516 | |
| 517 # | |
| 518 # searching tests follow | |
| 519 # | |
| 520 def testFind(self): | |
| 521 self.db.user.create(username='test') | |
| 522 ids = [] | |
| 523 ids.append(self.db.issue.create(status="1", nosy=['1'])) | |
| 524 oddid = self.db.issue.create(status="2", nosy=['2']) | |
| 525 ids.append(self.db.issue.create(status="1", nosy=['1','2'])) | |
| 526 self.db.issue.create(status="3", nosy=['1']) | |
| 527 ids.sort() | |
| 528 | |
| 529 # should match first and third | |
| 530 got = self.db.issue.find(status='1') | |
| 531 got.sort() | |
| 532 self.assertEqual(got, ids) | |
| 533 | |
| 534 # none | |
| 535 self.assertEqual(self.db.issue.find(status='4'), []) | |
| 536 | |
| 537 # should match first three | |
| 538 got = self.db.issue.find(status='1', nosy='2') | |
| 539 got.sort() | |
| 540 ids.append(oddid) | |
| 541 ids.sort() | |
| 542 self.assertEqual(got, ids) | |
| 543 | |
| 544 # none | |
| 545 self.assertEqual(self.db.issue.find(status='4', nosy='3'), []) | |
| 546 | |
| 547 def testStringFind(self): | |
| 548 ids = [] | |
| 549 ids.append(self.db.issue.create(title="spam")) | |
| 550 self.db.issue.create(title="not spam") | |
| 551 ids.append(self.db.issue.create(title="spam")) | |
| 552 ids.sort() | |
| 553 got = self.db.issue.stringFind(title='spam') | |
| 554 got.sort() | |
| 555 self.assertEqual(got, ids) | |
| 556 self.assertEqual(self.db.issue.stringFind(title='fubar'), []) | |
| 557 | |
| 558 def filteringSetup(self): | |
| 559 for user in ( | |
| 560 {'username': 'bleep'}, | |
| 561 {'username': 'blop'}, | |
| 562 {'username': 'blorp'}): | |
| 563 self.db.user.create(**user) | |
| 564 iss = self.db.issue | |
| 565 for issue in ( | |
| 566 {'title': 'issue one', 'status': '2'}, | |
| 567 {'title': 'issue two', 'status': '1'}, | |
| 568 {'title': 'issue three', 'status': '1', 'nosy': ['1','2']}): | |
| 569 self.db.issue.create(**issue) | |
| 570 self.db.commit() | |
| 571 return self.assertEqual, self.db.issue.filter | |
| 572 | |
| 573 def testFilteringString(self): | |
| 574 ae, filt = self.filteringSetup() | |
| 575 ae(filt(None, {'title': 'issue one'}, ('+','id'), (None,None)), ['1']) | |
| 576 ae(filt(None, {'title': 'issue'}, ('+','id'), (None,None)), | |
| 577 ['1','2','3']) | |
| 578 | |
| 579 def testFilteringLink(self): | |
| 580 ae, filt = self.filteringSetup() | |
| 581 ae(filt(None, {'status': '1'}, ('+','id'), (None,None)), ['2','3']) | |
| 582 | |
| 583 def testFilteringMultilink(self): | |
| 584 ae, filt = self.filteringSetup() | |
| 585 ae(filt(None, {'nosy': '2'}, ('+','id'), (None,None)), ['3']) | |
| 586 | |
| 587 def testFilteringMany(self): | |
| 588 ae, filt = self.filteringSetup() | |
| 589 ae(filt(None, {'nosy': '2', 'status': '1'}, ('+','id'), (None,None)), | |
| 590 ['3']) | |
| 591 | |
| 592 class anydbmReadOnlyDBTestCase(MyTestCase): | |
| 593 def setUp(self): | |
| 594 from roundup.backends import anydbm | |
| 595 # remove previous test, ignore errors | |
| 596 if os.path.exists(config.DATABASE): | |
| 597 shutil.rmtree(config.DATABASE) | |
| 598 os.makedirs(config.DATABASE + '/files') | |
| 599 db = anydbm.Database(config, 'admin') | |
| 600 setupSchema(db, 1, anydbm) | |
| 601 db.close() | |
| 602 self.db = anydbm.Database(config) | |
| 603 setupSchema(self.db, 0, anydbm) | |
| 604 | |
| 605 def testExceptions(self): | |
| 606 # this tests the exceptions that should be raised | |
| 607 ar = self.assertRaises | |
| 608 | |
| 609 # this tests the exceptions that should be raised | |
| 610 ar(DatabaseError, self.db.status.create, name="foo") | |
| 611 ar(DatabaseError, self.db.status.set, '1', name="foo") | |
| 612 ar(DatabaseError, self.db.status.retire, '1') | |
| 613 | |
| 614 | |
| 615 class bsddbDBTestCase(anydbmDBTestCase): | |
| 616 def setUp(self): | |
| 617 from roundup.backends import bsddb | |
| 618 # remove previous test, ignore errors | |
| 619 if os.path.exists(config.DATABASE): | |
| 620 shutil.rmtree(config.DATABASE) | |
| 621 os.makedirs(config.DATABASE + '/files') | |
| 622 self.db = bsddb.Database(config, 'admin') | |
| 623 setupSchema(self.db, 1, bsddb) | |
| 624 | |
| 625 class bsddbReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): | |
| 626 def setUp(self): | |
| 627 from roundup.backends import bsddb | |
| 628 # remove previous test, ignore errors | |
| 629 if os.path.exists(config.DATABASE): | |
| 630 shutil.rmtree(config.DATABASE) | |
| 631 os.makedirs(config.DATABASE + '/files') | |
| 632 db = bsddb.Database(config, 'admin') | |
| 633 setupSchema(db, 1, bsddb) | |
| 634 db.close() | |
| 635 self.db = bsddb.Database(config) | |
| 636 setupSchema(self.db, 0, bsddb) | |
| 637 | |
| 638 | |
| 639 class bsddb3DBTestCase(anydbmDBTestCase): | |
| 640 def setUp(self): | |
| 641 from roundup.backends import bsddb3 | |
| 642 # remove previous test, ignore errors | |
| 643 if os.path.exists(config.DATABASE): | |
| 644 shutil.rmtree(config.DATABASE) | |
| 645 os.makedirs(config.DATABASE + '/files') | |
| 646 self.db = bsddb3.Database(config, 'admin') | |
| 647 setupSchema(self.db, 1, bsddb3) | |
| 648 | |
| 649 class bsddb3ReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): | |
| 650 def setUp(self): | |
| 651 from roundup.backends import bsddb3 | |
| 652 # remove previous test, ignore errors | |
| 653 if os.path.exists(config.DATABASE): | |
| 654 shutil.rmtree(config.DATABASE) | |
| 655 os.makedirs(config.DATABASE + '/files') | |
| 656 db = bsddb3.Database(config, 'admin') | |
| 657 setupSchema(db, 1, bsddb3) | |
| 658 db.close() | |
| 659 self.db = bsddb3.Database(config) | |
| 660 setupSchema(self.db, 0, bsddb3) | |
| 661 | |
| 662 | |
| 663 class gadflyDBTestCase(anydbmDBTestCase): | |
| 664 ''' Gadfly doesn't support multiple connections to the one local | |
| 665 database | |
| 666 ''' | |
| 667 def setUp(self): | |
| 668 from roundup.backends import gadfly | |
| 669 # remove previous test, ignore errors | |
| 670 if os.path.exists(config.DATABASE): | |
| 671 shutil.rmtree(config.DATABASE) | |
| 672 config.GADFLY_DATABASE = ('test', config.DATABASE) | |
| 673 os.makedirs(config.DATABASE + '/files') | |
| 674 self.db = gadfly.Database(config, 'admin') | |
| 675 setupSchema(self.db, 1, gadfly) | |
| 676 | |
| 677 def testFilteringString(self): | |
| 678 ae, filt = self.filteringSetup() | |
| 679 ae(filt(None, {'title': 'issue one'}, ('+','id'), (None,None)), ['1']) | |
| 680 # XXX gadfly can't do substring LIKE searches | |
| 681 #ae(filt(None, {'title': 'issue'}, ('+','id'), (None,None)), | |
| 682 # ['1','2','3']) | |
| 683 | |
| 684 class gadflyReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): | |
| 685 def setUp(self): | |
| 686 from roundup.backends import gadfly | |
| 687 # remove previous test, ignore errors | |
| 688 if os.path.exists(config.DATABASE): | |
| 689 shutil.rmtree(config.DATABASE) | |
| 690 config.GADFLY_DATABASE = ('test', config.DATABASE) | |
| 691 os.makedirs(config.DATABASE + '/files') | |
| 692 db = gadfly.Database(config, 'admin') | |
| 693 setupSchema(db, 1, gadfly) | |
| 694 db.close() | |
| 695 self.db = gadfly.Database(config) | |
| 696 setupSchema(self.db, 0, gadfly) | |
| 697 | |
| 698 | |
| 699 class sqliteDBTestCase(anydbmDBTestCase): | |
| 700 def setUp(self): | |
| 701 from roundup.backends import sqlite | |
| 702 # remove previous test, ignore errors | |
| 703 if os.path.exists(config.DATABASE): | |
| 704 shutil.rmtree(config.DATABASE) | |
| 705 os.makedirs(config.DATABASE + '/files') | |
| 706 self.db = sqlite.Database(config, 'admin') | |
| 707 setupSchema(self.db, 1, sqlite) | |
| 708 | |
| 709 def testIDGeneration(self): | |
| 710 pass | |
| 711 | |
| 712 class sqliteReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): | |
| 713 def setUp(self): | |
| 714 from roundup.backends import sqlite | |
| 715 # remove previous test, ignore errors | |
| 716 if os.path.exists(config.DATABASE): | |
| 717 shutil.rmtree(config.DATABASE) | |
| 718 os.makedirs(config.DATABASE + '/files') | |
| 719 db = sqlite.Database(config, 'admin') | |
| 720 setupSchema(db, 1, sqlite) | |
| 721 db.close() | |
| 722 self.db = sqlite.Database(config) | |
| 723 setupSchema(self.db, 0, sqlite) | |
| 724 | |
| 725 | |
| 726 class metakitDBTestCase(anydbmDBTestCase): | |
| 727 def setUp(self): | |
| 728 from roundup.backends import metakit | |
| 729 import weakref | |
| 730 metakit._instances = weakref.WeakValueDictionary() | |
| 731 # remove previous test, ignore errors | |
| 732 if os.path.exists(config.DATABASE): | |
| 733 shutil.rmtree(config.DATABASE) | |
| 734 os.makedirs(config.DATABASE + '/files') | |
| 735 self.db = metakit.Database(config, 'admin') | |
| 736 setupSchema(self.db, 1, metakit) | |
| 737 | |
| 738 def testTransactions(self): | |
| 739 # remember the number of items we started | |
| 740 num_issues = len(self.db.issue.list()) | |
| 741 self.db.issue.create(title="don't commit me!", status='1') | |
| 742 self.assertNotEqual(num_issues, len(self.db.issue.list())) | |
| 743 self.db.rollback() | |
| 744 self.assertEqual(num_issues, len(self.db.issue.list())) | |
| 745 self.db.issue.create(title="please commit me!", status='1') | |
| 746 self.assertNotEqual(num_issues, len(self.db.issue.list())) | |
| 747 self.db.commit() | |
| 748 self.assertNotEqual(num_issues, len(self.db.issue.list())) | |
| 749 self.db.rollback() | |
| 750 self.assertNotEqual(num_issues, len(self.db.issue.list())) | |
| 751 self.db.file.create(name="test", type="text/plain", content="hi") | |
| 752 self.db.rollback() | |
| 753 num_files = len(self.db.file.list()) | |
| 754 for i in range(10): | |
| 755 self.db.file.create(name="test", type="text/plain", | |
| 756 content="hi %d"%(i)) | |
| 757 self.db.commit() | |
| 758 # TODO: would be good to be able to ensure the file is not on disk after | |
| 759 # a rollback... | |
| 760 num_files2 = len(self.db.file.list()) | |
| 761 self.assertNotEqual(num_files, num_files2) | |
| 762 self.db.file.create(name="test", type="text/plain", content="hi") | |
| 763 num_rfiles = len(os.listdir(self.db.config.DATABASE + '/files/file/0')) | |
| 764 self.db.rollback() | |
| 765 num_rfiles2 = len(os.listdir(self.db.config.DATABASE + '/files/file/0')) | |
| 766 self.assertEqual(num_files2, len(self.db.file.list())) | |
| 767 self.assertEqual(num_rfiles2, num_rfiles-1) | |
| 768 | |
| 769 class metakitReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): | |
| 770 def setUp(self): | |
| 771 from roundup.backends import metakit | |
| 772 import weakref | |
| 773 metakit._instances = weakref.WeakValueDictionary() | |
| 774 # remove previous test, ignore errors | |
| 775 if os.path.exists(config.DATABASE): | |
| 776 shutil.rmtree(config.DATABASE) | |
| 777 os.makedirs(config.DATABASE + '/files') | |
| 778 db = metakit.Database(config, 'admin') | |
| 779 setupSchema(db, 1, metakit) | |
| 780 db.close() | |
| 781 self.db = metakit.Database(config) | |
| 782 setupSchema(self.db, 0, metakit) | |
| 783 | |
| 784 def suite(): | |
| 785 l = [ | |
| 786 unittest.makeSuite(anydbmDBTestCase, 'test'), | |
| 787 unittest.makeSuite(anydbmReadOnlyDBTestCase, 'test') | |
| 788 ] | |
| 789 # return unittest.TestSuite(l) | |
| 790 | |
| 791 from roundup import backends | |
| 792 if hasattr(backends, 'gadfly'): | |
| 793 l.append(unittest.makeSuite(gadflyDBTestCase, 'test')) | |
| 794 l.append(unittest.makeSuite(gadflyReadOnlyDBTestCase, 'test')) | |
| 795 | |
| 796 if hasattr(backends, 'sqlite'): | |
| 797 l.append(unittest.makeSuite(sqliteDBTestCase, 'test')) | |
| 798 l.append(unittest.makeSuite(sqliteReadOnlyDBTestCase, 'test')) | |
| 799 | |
| 800 if hasattr(backends, 'bsddb'): | |
| 801 l.append(unittest.makeSuite(bsddbDBTestCase, 'test')) | |
| 802 l.append(unittest.makeSuite(bsddbReadOnlyDBTestCase, 'test')) | |
| 803 | |
| 804 if hasattr(backends, 'bsddb3'): | |
| 805 l.append(unittest.makeSuite(bsddb3DBTestCase, 'test')) | |
| 806 l.append(unittest.makeSuite(bsddb3ReadOnlyDBTestCase, 'test')) | |
| 807 | |
| 808 if hasattr(backends, 'metakit'): | |
| 809 l.append(unittest.makeSuite(metakitDBTestCase, 'test')) | |
| 810 l.append(unittest.makeSuite(metakitReadOnlyDBTestCase, 'test')) | |
| 811 | |
| 812 return unittest.TestSuite(l) | |
| 813 | |
| 814 # vim: set filetype=python ts=4 sw=4 et si |
