From: richard Date: Fri, 5 Dec 2003 09:47:46 +0000 (+0000) Subject: more unit tests to improve coverage (up from 85% to 88% for anydbm! :) X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=4f3a2b3424630f7de584633976f9d29a6f5149c2;p=roundup.git more unit tests to improve coverage (up from 85% to 88% for anydbm! :) git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2018 57a73879-2fb5-44c3-a270-3262357dd7e2 --- diff --git a/roundup/backends/back_anydbm.py b/roundup/backends/back_anydbm.py index d6aebc4..090965e 100644 --- a/roundup/backends/back_anydbm.py +++ b/roundup/backends/back_anydbm.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_anydbm.py,v 1.132 2003-11-16 18:41:40 jlgijsbers Exp $ +#$Id: back_anydbm.py,v 1.133 2003-12-05 09:47:46 richard Exp $ ''' This module defines a backend that saves the hyperdatabase in a database chosen by anydbm. It is guaranteed to always be available in python @@ -310,13 +310,6 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): if db is None: db = self.getclassdb(classname) if not db.has_key(nodeid): - # try the cache - might be a brand-new node - cache_dict = self.cache.setdefault(classname, {}) - if cache_dict.has_key(nodeid): - if __debug__: - print >>hyperdb.TRACE, 'get %s %s cached'%(classname, - nodeid) - return cache_dict[nodeid] raise IndexError, "no such %s %s"%(classname, nodeid) # check the uncommitted, destroyed nodes @@ -1540,7 +1533,7 @@ class Class(hyperdb.Class): ''' for propname in requirements.keys(): prop = self.properties[propname] - if isinstance(not prop, String): + if not isinstance(prop, String): raise TypeError, "'%s' not a String property"%propname requirements[propname] = requirements[propname].lower() l = [] diff --git a/roundup/backends/rdbms_common.py b/roundup/backends/rdbms_common.py index bdb60ac..45078c4 100644 --- a/roundup/backends/rdbms_common.py +++ b/roundup/backends/rdbms_common.py @@ -1,4 +1,4 @@ -# $Id: rdbms_common.py,v 1.71 2003-11-16 18:41:40 jlgijsbers Exp $ +# $Id: rdbms_common.py,v 1.72 2003-12-05 09:47:46 richard Exp $ ''' Relational database (SQL) backend common code. Basics: @@ -155,19 +155,7 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): self.conn.commit() def refresh_database(self): - # now detect changes in the schema - for classname, spec in self.classes.items(): - dbspec = self.database_schema[classname] - self.update_class(spec, dbspec, force=1) - self.database_schema[classname] = spec.schema() - # update the database version of the schema - self.sql('delete from schema') - self.save_dbschema(self.database_schema) - # reindex the db - self.reindex() - # commit - self.conn.commit() - + self.post_init() def reindex(self): for klass in self.classes.values(): @@ -1800,8 +1788,8 @@ class Class(hyperdb.Class): raise TypeError, "'%s' not a Link/Multilink property"%propname # first, links - where = [] - allvalues = () + where = ['__retired__ = %s'] + allvalues = (0,) a = self.db.arg for prop, values in propspec: if not isinstance(props[prop], hyperdb.Link): @@ -1852,14 +1840,16 @@ class Class(hyperdb.Class): args = [] for propname in requirements.keys(): prop = self.properties[propname] - if isinstance(not prop, String): + if not isinstance(prop, String): raise TypeError, "'%s' not a String property"%propname where.append(propname) args.append(requirements[propname].lower()) # generate the where clause s = ' and '.join(['lower(_%s)=%s'%(col, self.db.arg) for col in where]) - sql = 'select id from _%s where %s'%(self.classname, s) + sql = 'select id from _%s where %s and __retired__=%s'%(self.classname, + s, self.db.arg) + args.append(0) self.db.sql(sql, tuple(args)) l = [x[0] for x in self.db.sql_fetchall()] if __debug__: diff --git a/test/db_test_base.py b/test/db_test_base.py index d7b65be..681cf4f 100644 --- a/test/db_test_base.py +++ b/test/db_test_base.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: db_test_base.py,v 1.10 2003-11-16 22:56:46 jlgijsbers Exp $ +# $Id: db_test_base.py,v 1.11 2003-12-05 09:47:46 richard Exp $ import unittest, os, shutil, errno, imp, sys, time, pprint @@ -36,11 +36,13 @@ def setupSchema(db, create, module): issue = module.IssueClass(db, "issue", title=String(indexme="yes"), status=Link("status"), nosy=Multilink("user"), deadline=Date(), foo=Interval(), files=Multilink("file"), assignedto=Link('user')) + stuff = module.Class(db, "stuff", stuff=String()) session = module.Class(db, 'session', title=String()) session.disableJournalling() db.post_init() if create: - user.create(username="admin", roles='Admin') + user.create(username="admin", roles='Admin', + password=password.Password('sekrit')) status.create(name="unread") status.create(name="in-progress") status.create(name="testing") @@ -78,52 +80,8 @@ class DBTest(MyTestCase): self.db = self.module.Database(config, 'admin') setupSchema(self.db, 1, self.module) - # - # schema mutation - # - def testAddProperty(self): - self.db.issue.create(title="spam", status='1') - self.db.commit() - - self.db.issue.addprop(fixer=Link("user")) - # force any post-init stuff to happen - self.db.post_init() - props = self.db.issue.getprops() - keys = props.keys() - keys.sort() - self.assertEqual(keys, ['activity', 'assignedto', 'creation', - 'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages', - 'nosy', 'status', 'superseder', 'title']) - self.assertEqual(self.db.issue.get('1', "fixer"), None) - - def testRemoveProperty(self): - self.db.issue.create(title="spam", status='1') - self.db.commit() - - del self.db.issue.properties['title'] - self.db.post_init() - props = self.db.issue.getprops() - keys = props.keys() - keys.sort() - self.assertEqual(keys, ['activity', 'assignedto', 'creation', - 'creator', 'deadline', 'files', 'foo', 'id', 'messages', - 'nosy', 'status', 'superseder']) - self.assertEqual(self.db.issue.list(), ['1']) - - def testAddRemoveProperty(self): - self.db.issue.create(title="spam", status='1') - self.db.commit() - - self.db.issue.addprop(fixer=Link("user")) - del self.db.issue.properties['title'] - self.db.post_init() - props = self.db.issue.getprops() - keys = props.keys() - keys.sort() - self.assertEqual(keys, ['activity', 'assignedto', 'creation', - 'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages', - 'nosy', 'status', 'superseder']) - self.assertEqual(self.db.issue.list(), ['1']) + def testRefresh(self): + self.db.refresh_database() # # basic operations @@ -133,6 +91,10 @@ class DBTest(MyTestCase): id2 = self.db.issue.create(title="eggs", status='2') self.assertNotEqual(id1, id2) + def testEmptySet(self): + id1 = self.db.issue.create(title="spam", status='1') + self.db.issue.set(id1) + def testStringChange(self): for commit in (0,1): # test set & retrieve @@ -155,6 +117,8 @@ class DBTest(MyTestCase): self.assertEqual(self.db.issue.get(nid, "title"), None) def testLinkChange(self): + self.assertRaises(IndexError, self.db.issue.create, title="spam", + status='100') for commit in (0,1): nid = self.db.issue.create(title="spam", status='1') if commit: self.db.commit() @@ -173,6 +137,8 @@ class DBTest(MyTestCase): def testMultilinkChange(self): for commit in (0,1): + self.assertRaises(IndexError, self.db.issue.create, title="spam", + nosy=['foo%s'%commit]) u1 = self.db.user.create(username='foo%s'%commit) u2 = self.db.user.create(username='bar%s'%commit) nid = self.db.issue.create(title="spam", nosy=[u1]) @@ -186,8 +152,11 @@ class DBTest(MyTestCase): self.assertEqual(self.db.issue.get(nid, "nosy"), [u1,u2]) def testDateChange(self): + self.assertRaises(TypeError, self.db.issue.create, + title='spam', deadline=1) for commit in (0,1): nid = self.db.issue.create(title="spam", status='1') + self.assertRaises(TypeError, self.db.issue.set, nid, deadline=1) a = self.db.issue.get(nid, "deadline") if commit: self.db.commit() self.db.issue.set(nid, deadline=date.Date()) @@ -207,8 +176,11 @@ class DBTest(MyTestCase): self.assertEqual(self.db.issue.get(nid, "deadline"), None) def testIntervalChange(self): + self.assertRaises(TypeError, self.db.issue.create, + title='spam', foo=1) for commit in (0,1): nid = self.db.issue.create(title="spam", status='1') + self.assertRaises(TypeError, self.db.issue.set, nid, foo=1) if commit: self.db.commit() a = self.db.issue.get(nid, "foo") i = date.Interval('-1d') @@ -261,7 +233,27 @@ class DBTest(MyTestCase): self.db.user.set(nid, age=None) self.assertEqual(self.db.user.get(nid, "age"), None) + def testPasswordChange(self): + x = password.Password('x') + userid = self.db.user.create(username='foo', password=x) + self.assertEqual(x, self.db.user.get(userid, 'password')) + self.assertEqual(self.db.user.get(userid, 'password'), 'x') + y = password.Password('y') + self.db.user.set(userid, password=y) + self.assertEqual(self.db.user.get(userid, 'password'), 'y') + self.assertRaises(TypeError, self.db.user.create, userid, + username='bar', password='x') + self.assertRaises(TypeError, self.db.user.set, userid, password='x') + + def testPasswordUnset(self): + x = password.Password('x') + nid = self.db.user.create(username='foo', password=x) + self.db.user.set(nid, assignable=None) + self.assertEqual(self.db.user.get(nid, "assignable"), None) + def testKeyValue(self): + self.assertRaises(ValueError, self.db.user.create) + newid = self.db.user.create(username="spam") self.assertEqual(self.db.user.lookup('spam'), newid) self.db.commit() @@ -275,6 +267,19 @@ class DBTest(MyTestCase): # try to restore old node. this shouldn't succeed! self.assertRaises(KeyError, self.db.user.restore, newid) + self.assertRaises(TypeError, self.db.issue.lookup, 'fubar') + + def testLabelProp(self): + # key prop + self.assertEqual(self.db.status.labelprop(), 'name') + self.assertEqual(self.db.user.labelprop(), 'username') + # title + self.assertEqual(self.db.issue.labelprop(), 'title') + # name + self.assertEqual(self.db.file.labelprop(), 'name') + # id + self.assertEqual(self.db.stuff.labelprop(default_to_id=1), 'id') + def testRetire(self): self.db.issue.create(title="spam", status='1') b = self.db.status.get('1', 'name') @@ -284,6 +289,7 @@ class DBTest(MyTestCase): self.assertNotEqual(a, self.db.status.list()) # can still access the node if necessary self.assertEqual(self.db.status.get('1', 'name'), b) + self.assertRaises(IndexError, self.db.status.set, '1', name='hello') self.db.commit() self.assertEqual(self.db.status.get('1', 'name'), b) self.assertNotEqual(a, self.db.status.list()) @@ -356,7 +362,9 @@ class DBTest(MyTestCase): newid = klass.create(title='Mr Friendly') n = len(klass.list()) self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') + count = klass.count() klass.destroy(newid) + self.assertNotEqual(count, klass.count()) self.assertRaises(IndexError, klass.get, newid, 'title') self.assertNotEqual(len(klass.list()), n) if klass.do_journal: @@ -367,7 +375,9 @@ class DBTest(MyTestCase): n = len(klass.list()) self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') self.db.commit() + count = klass.count() klass.destroy(newid) + self.assertNotEqual(count, klass.count()) self.assertRaises(IndexError, klass.get, newid, 'title') self.db.commit() self.assertRaises(IndexError, klass.get, newid, 'title') @@ -380,10 +390,12 @@ class DBTest(MyTestCase): n = len(klass.list()) self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') self.db.commit() + count = klass.count() klass.destroy(newid) self.assertNotEqual(len(klass.list()), n) self.assertRaises(IndexError, klass.get, newid, 'title') self.db.rollback() + self.assertEqual(count, klass.count()) self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') self.assertEqual(len(klass.list()), n) if klass.do_journal: @@ -393,11 +405,18 @@ class DBTest(MyTestCase): # this tests the exceptions that should be raised ar = self.assertRaises + ar(KeyError, self.db.getclass, 'fubar') + # # class create # # string property ar(TypeError, self.db.status.create, name=1) + # id, creation, creator and activity properties are reserved + ar(KeyError, self.db.status.create, id=1) + ar(KeyError, self.db.status.create, creation=1) + ar(KeyError, self.db.status.create, creator=1) + ar(KeyError, self.db.status.create, activity=1) # invalid property name ar(KeyError, self.db.status.create, foo='foo') # key name clash @@ -603,6 +622,8 @@ class DBTest(MyTestCase): # searching tests follow # def testFind(self): + self.assertRaises(TypeError, self.db.issue.find, title='fubar') + self.db.user.create(username='test') ids = [] ids.append(self.db.issue.create(status="1", nosy=['1'])) @@ -645,7 +666,13 @@ class DBTest(MyTestCase): self.assertEqual(self.db.issue.find(status='4', nosy='3'), []) self.assertEqual(self.db.issue.find(status={'4':1}, nosy={'3':1}), []) + # test retiring a node + self.db.issue.retire(ids[0]) + self.assertEqual(len(self.db.issue.find(status='1', nosy='2')), 2) + def testStringFind(self): + self.assertRaises(TypeError, self.db.issue.stringFind, status='1') + ids = [] ids.append(self.db.issue.create(title="spam")) self.db.issue.create(title="not spam") @@ -656,6 +683,10 @@ class DBTest(MyTestCase): self.assertEqual(got, ids) self.assertEqual(self.db.issue.stringFind(title='fubar'), []) + # test retiring a node + self.db.issue.retire(ids[0]) + self.assertEqual(len(self.db.issue.stringFind(title='spam')), 1) + def filteringSetup(self): for user in ( {'username': 'bleep'}, @@ -780,10 +811,12 @@ class DBTest(MyTestCase): for cn, items in export.items(): klass = self.db.classes[cn] names = items[0] + maxid = 1 for itemprops in items[1:]: - klass.import_list(names, itemprops) + maxid = max(maxid, int(klass.import_list(names, itemprops))) + self.db.setid(cn, str(maxid+1)) - # grab snapshot of the current database + # compare with snapshot of the database for cn, items in orig.items(): klass = self.db.classes[cn] # ensure retired items are retired :) @@ -798,6 +831,11 @@ class DBTest(MyTestCase): ae(self.db.user.get('3', 'username'), 'blop') ae(self.db.issue.get('2', 'title'), 'issue two') + # make sure id counters are set correctly + maxid = max([int(id) for id in self.db.user.list()]) + newid = self.db.user.create(username='testing') + assert newid > maxid + def testSafeGet(self): # existent nodeid, existent property self.assertEqual(self.db.user.safeget('1', 'username'), 'admin') @@ -806,6 +844,50 @@ class DBTest(MyTestCase): # different default self.assertEqual(self.db.issue.safeget('999', 'nosy', []), []) + def testAddProperty(self): + self.db.issue.create(title="spam", status='1') + self.db.commit() + + self.db.issue.addprop(fixer=Link("user")) + # force any post-init stuff to happen + self.db.post_init() + props = self.db.issue.getprops() + keys = props.keys() + keys.sort() + self.assertEqual(keys, ['activity', 'assignedto', 'creation', + 'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages', + 'nosy', 'status', 'superseder', 'title']) + self.assertEqual(self.db.issue.get('1', "fixer"), None) + + def testRemoveProperty(self): + self.db.issue.create(title="spam", status='1') + self.db.commit() + + del self.db.issue.properties['title'] + self.db.post_init() + props = self.db.issue.getprops() + keys = props.keys() + keys.sort() + self.assertEqual(keys, ['activity', 'assignedto', 'creation', + 'creator', 'deadline', 'files', 'foo', 'id', 'messages', + 'nosy', 'status', 'superseder']) + self.assertEqual(self.db.issue.list(), ['1']) + + def testAddRemoveProperty(self): + self.db.issue.create(title="spam", status='1') + self.db.commit() + + self.db.issue.addprop(fixer=Link("user")) + del self.db.issue.properties['title'] + self.db.post_init() + props = self.db.issue.getprops() + keys = props.keys() + keys.sort() + self.assertEqual(keys, ['activity', 'assignedto', 'creation', + 'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages', + 'nosy', 'status', 'superseder']) + self.assertEqual(self.db.issue.list(), ['1']) + class ROTest(MyTestCase): def setUp(self): # remove previous test, ignore errors @@ -836,6 +918,15 @@ class SchemaTest(MyTestCase): shutil.rmtree(config.DATABASE) os.makedirs(config.DATABASE + '/files') + def test_reservedProperties(self): + self.db = self.module.Database(config, 'admin') + self.assertRaises(ValueError, self.module.Class, self.db, "a", + creation=String()) + self.assertRaises(ValueError, self.module.Class, self.db, "a", + activity=String()) + self.assertRaises(ValueError, self.module.Class, self.db, "a", + creator=String()) + def init_a(self): self.db = self.module.Database(config, 'admin') a = self.module.Class(self.db, "a", name=String()) @@ -852,6 +943,10 @@ class SchemaTest(MyTestCase): def test_addNewClass(self): self.init_a() + + self.assertRaises(ValueError, self.module.Class, self.db, "a", + name=String()) + aid = self.db.a.create(name='apple') self.db.commit(); self.db.close() @@ -1010,6 +1105,12 @@ class SchemaTest(MyTestCase): # confirm journal's ok self.db.getjournal('a', aid) +class RDBMSTest: + ''' tests specific to RDBMS backends ''' + def test_indexTest(self): + self.assertEqual(self.db.sql_index_exists('_issue', '_issue_id_idx'), 1) + self.assertEqual(self.db.sql_index_exists('_issue', '_issue_x_idx'), 0) + class ClassicInitTest(unittest.TestCase): count = 0