Code

- Fixed retirement of items in rdbms imports (sf bug 841355)
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 14 Nov 2003 00:11:19 +0000 (00:11 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 14 Nov 2003 00:11:19 +0000 (00:11 +0000)
- Fixed bug in looking up journal of newly-created items in *dbm backends

git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1988 57a73879-2fb5-44c3-a270-3262357dd7e2

15 files changed:
CHANGES.txt
roundup/backends/back_anydbm.py
roundup/backends/back_bsddb.py
roundup/backends/back_bsddb3.py
roundup/backends/back_metakit.py
roundup/backends/back_postgresql.py
roundup/backends/rdbms_common.py
test/db_test_base.py
test/test_anydbm.py
test/test_bsddb.py
test/test_bsddb3.py
test/test_metakit.py
test/test_mysql.py
test/test_postgresql.py
test/test_sqlite.py

index 0f35bd00154d315b7046ee655c34edc5076d3b72..8c1c0077f2a08cf7b84bf991a539f9adf3905632 100644 (file)
@@ -61,6 +61,8 @@ Fixed:
   Date +/- Interval now works, and Date - Date also works (produces
   an Interval.
 - Handle socket timeout exception (thanks Marcus Priesch)
+- Fixed retirement of items in rdbms imports (sf bug 841355)
+- Fixed bug in looking up journal of newly-created items in *dbm backends
 
 
 2003-09-29 0.6.2
index 61f2226b86717dfd919b15e3050c9cc05cb37249..d2897addf497c0f019d6cd5bbae4bf8edf6d6eff 100644 (file)
@@ -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.130 2003-11-10 03:56:39 richard Exp $
+#$Id: back_anydbm.py,v 1.131 2003-11-14 00:11:18 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
@@ -516,7 +516,11 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
             if str(error) == "need 'c' or 'n' flag to open new db":
                 raise IndexError, 'no such %s %s'%(classname, nodeid)
             elif error.args[0] != 2:
+                # this isn't a "not found" error, be alarmed!
                 raise
+            if res:
+                # we have unsaved journal entries, return them
+                return res
             raise IndexError, 'no such %s %s'%(classname, nodeid)
         try:
             journal = marshal.loads(db[nodeid])
@@ -936,7 +940,7 @@ class Class(hyperdb.Class):
             l.append(repr(value))
 
         # append retired flag
-        l.append(self.is_retired(nodeid))
+        l.append(repr(self.is_retired(nodeid)))
 
         return l
 
index 2b2a5046ee20faa26db1afbefecae7e287fe075d..37abdd88cb838a753c1c484ba9f9c96254e67c1f 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-#$Id: back_bsddb.py,v 1.27 2003-09-08 20:39:18 jlgijsbers Exp $
+#$Id: back_bsddb.py,v 1.28 2003-11-14 00:11:18 richard Exp $
 '''
 This module defines a backend that saves the hyperdatabase in BSDDB.
 '''
@@ -105,7 +105,12 @@ class Database(Database):
             db = bsddb.btopen(os.path.join(self.dir, 'journals.%s'%classname),
                 'r')
         except bsddb.error, error:
-            if error.args[0] != 2: raise
+            if error.args[0] != 2:
+                # this isn't a "not found" error, be alarmed!
+                raise
+            if res:
+                # we have unsaved journal entries, return them
+                return res
             raise IndexError, 'no such %s %s'%(classname, nodeid)
         # more handling of bad journals
         if not db.has_key(nodeid):
index 2c01d57e881eb31ffebca3e6a970c202be10a961..444fe65d1f5d38504fe8751cd0f4d08faffd8593 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-#$Id: back_bsddb3.py,v 1.20 2003-09-08 20:39:18 jlgijsbers Exp $
+#$Id: back_bsddb3.py,v 1.21 2003-11-14 00:11:18 richard Exp $
 '''
 This module defines a backend that saves the hyperdatabase in BSDDB3.
 '''
@@ -105,6 +105,9 @@ class Database(Database):
             db = bsddb3.btopen(os.path.join(self.dir, 'journals.%s'%classname),
                 'r')
         except bsddb3._db.DBNoSuchFileError:
+            if res:
+                # we have unsaved journal entries, return them
+                return res
             raise IndexError, 'no such %s %s'%(classname, nodeid)
         # more handling of bad journals
         if not db.has_key(nodeid):
index a612f8b145598c1fb39c779f2ff801e7591dd569..53035262a8680d71847f6d43090373e667b30d6e 100755 (executable)
@@ -1,4 +1,4 @@
-# $Id: back_metakit.py,v 1.52 2003-11-12 03:42:12 richard Exp $
+# $Id: back_metakit.py,v 1.53 2003-11-14 00:11:18 richard Exp $
 '''
    Metakit backend for Roundup, originally by Gordon McMillan.
 
@@ -1173,7 +1173,7 @@ class Class:
             l.append(repr(value))
 
         # append retired flag
-        l.append(self.is_retired(nodeid))
+        l.append(repr(self.is_retired(nodeid)))
 
         return l
         
index 9559ee4eac4e02f0187549d28f6f406eec4d9f04..5a28fa7c0010a4906d98cd305c84018f79ada76a 100644 (file)
@@ -21,7 +21,7 @@ class Database(rdbms_common.Database):
         try:
             self.conn = psycopg.connect(**db)
         except psycopg.OperationalError, message:
-            raise DatabaseError, message
+            raise hyperdb.DatabaseError, message
 
         self.cursor = self.conn.cursor()
 
index 1e7db1914849d97c13af7234ca9833e0dd28c81a..627ecec929f590d4121b52b072cffd98803e9634 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: rdbms_common.py,v 1.69 2003-11-12 03:42:12 richard Exp $
+# $Id: rdbms_common.py,v 1.70 2003-11-14 00:11:19 richard Exp $
 ''' Relational database (SQL) backend common code.
 
 Basics:
@@ -1236,7 +1236,7 @@ class Class(hyperdb.Class):
             elif isinstance(proptype, hyperdb.Password):
                 value = str(value)
             l.append(repr(value))
-        l.append(self.is_retired(nodeid))
+        l.append(repr(self.is_retired(nodeid)))
         return l
 
     def import_list(self, propnames, proplist):
@@ -1293,6 +1293,9 @@ class Class(hyperdb.Class):
         if newid is None:
             newid = self.db.newid(self.classname)
 
+        # add the node and journal
+        self.db.addnode(self.classname, newid, d)
+
         # retire?
         if retire:
             # use the arg for __retired__ to cope with any odd database type
@@ -1303,9 +1306,6 @@ class Class(hyperdb.Class):
                 print >>hyperdb.DEBUG, 'retire', (self, sql, newid)
             self.db.cursor.execute(sql, (1, newid))
 
-        # add the node and journal
-        self.db.addnode(self.classname, newid, d)
-
         # extract the extraneous journalling gumpf and nuke it
         if d.has_key('creator'):
             creator = d['creator']
index 97c01cb7c6d921517a92691b828bef26b7d2119c..57d6e2bc02c8a6799376d7058e72efd803fbadaf 100644 (file)
@@ -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.7 2003-11-12 03:42:13 richard Exp $ 
+# $Id: db_test_base.py,v 1.8 2003-11-14 00:11:19 richard Exp $ 
 
 import unittest, os, shutil, errno, imp, sys, time, pprint
 
@@ -744,6 +744,59 @@ class DBTest(MyTestCase):
 # XXX add sorting tests for other types
 # XXX test auditors and reactors
 
+    def testImportExport(self):
+        # use the filtering setup to create a bunch of items
+        ae, filt = self.filteringSetup()
+        self.db.user.retire('3')
+        self.db.issue.retire('2')
+
+        # grab snapshot of the current database
+        orig = {}
+        for cn,klass in self.db.classes.items():
+            cl = orig[cn] = {}
+            for id in klass.list():
+                it = cl[id] = {}
+                for name in klass.getprops().keys():
+                    it[name] = klass.get(id, name)
+
+        # grab the export
+        export = {}
+        for cn,klass in self.db.classes.items():
+            names = klass.getprops().keys()
+            cl = export[cn] = [names+['is retired']]
+            for id in klass.getnodeids():
+                cl.append(klass.export_list(names, id))
+
+        # shut down this db and nuke it
+        self.db.close()
+        self.nuke_database()
+
+        # open a new, empty database
+        os.makedirs(config.DATABASE + '/files')
+        self.db = self.module.Database(config, 'admin')
+        setupSchema(self.db, 0, self.module)
+
+        # import
+        for cn, items in export.items():
+            klass = self.db.classes[cn]
+            names = items[0]
+            for itemprops in items[1:]:
+                klass.import_list(names, itemprops)
+
+        # grab snapshot of the current database
+        for cn, items in orig.items():
+            klass = self.db.classes[cn]
+            # ensure retired items are retired :)
+            l = items.keys(); l.sort()
+            m = klass.list(); m.sort()
+            ae(l, m)
+            for id, props in items.items():
+                for name, value in props.items():
+                    ae(klass.get(id, name), value)
+
+        # make sure the retired items are actually imported
+        ae(self.db.user.get('3', 'username'), 'blop')
+        ae(self.db.issue.get('2', 'title'), 'issue two')
 
 class ROTest(MyTestCase):
     def setUp(self):
index 84d3108d1c317f1521568a5ecb7544ee5e3def31..77c57b8744cf965da4ed77c292f9c1b6ba72c746 100644 (file)
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: test_anydbm.py,v 1.1 2003-10-25 22:53:26 richard Exp $ 
+# $Id: test_anydbm.py,v 1.2 2003-11-14 00:11:19 richard Exp $ 
 
 import unittest, os, shutil, time
 
-from db_test_base import DBTest, ROTest, SchemaTest, ClassicInitTest
+from db_test_base import DBTest, ROTest, SchemaTest, ClassicInitTest, config
 
 class anydbmOpener:
     from roundup.backends import anydbm as module
 
+    def nuke_database(self):
+        shutil.rmtree(config.DATABASE)
+
 class anydbmDBTest(anydbmOpener, DBTest):
     pass
 
index 45059b9edcb8fbc6db457a27136b70e90b249eea..24cde202a96188b731a79e3af630a2924cfab477 100644 (file)
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: test_bsddb.py,v 1.1 2003-10-25 22:53:26 richard Exp $ 
+# $Id: test_bsddb.py,v 1.2 2003-11-14 00:11:19 richard Exp $ 
 
 import unittest, os, shutil, time
 
-from db_test_base import DBTest, ROTest, SchemaTest, \
-    ClassicInitTest
+from db_test_base import DBTest, ROTest, SchemaTest, ClassicInitTest, config
 from roundup import backends
 
 class bsddbOpener:
     if hasattr(backends, 'bsddb'):
         from roundup.backends import bsddb as module
 
+    def nuke_database(self):
+        shutil.rmtree(config.DATABASE)
+
 class bsddbDBTest(bsddbOpener, DBTest):
     pass
 
index 16f55e72e9110ad4ae1b589ba420e4bdd305ab09..2387cda04aa6aec674b09becb3b3904146060a7d 100644 (file)
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: test_bsddb3.py,v 1.1 2003-10-25 22:53:26 richard Exp $ 
+# $Id: test_bsddb3.py,v 1.2 2003-11-14 00:11:19 richard Exp $ 
 
 import unittest, os, shutil, time
 
-from db_test_base import DBTest, ROTest, SchemaTest, \
-    ClassicInitTest
+from db_test_base import DBTest, ROTest, SchemaTest, ClassicInitTest, config
 from roundup import backends
 
 class bsddb3Opener:
     if hasattr(backends, 'bsddb3'):
         from roundup.backends import bsddb3 as module
 
+    def nuke_database(self):
+        shutil.rmtree(config.DATABASE)
+
 class bsddb3DBTest(bsddb3Opener, DBTest):
     pass
 
index 4d3964226a436fb37e050151d598a344a7e96854..85961545f6f5ecb7eabcd715aabf20a8a1c2b1a6 100644 (file)
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: test_metakit.py,v 1.1 2003-10-25 22:53:26 richard Exp $ 
+# $Id: test_metakit.py,v 1.2 2003-11-14 00:11:19 richard Exp $ 
 
 import unittest, os, shutil, time, weakref
 
-from db_test_base import DBTest, ROTest, SchemaTest, \
-    ClassicInitTest
+from db_test_base import DBTest, ROTest, SchemaTest, ClassicInitTest, config
 
 from roundup import backends
 
@@ -29,6 +28,9 @@ class metakitOpener:
         from roundup.backends import metakit as module
         module._instances = weakref.WeakValueDictionary()
 
+    def nuke_database(self):
+        shutil.rmtree(config.DATABASE)
+
 class metakitDBTest(metakitOpener, DBTest):
     def testTransactions(self):
         # remember the number of items we started
index 724eefc408f40661d081321d6a74be74222ce1ba..1388d47e8df0401009eaa265dc871169da67c5f0 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: test_mysql.py,v 1.5 2003-11-11 11:19:18 richard Exp $ 
+# $Id: test_mysql.py,v 1.6 2003-11-14 00:11:19 richard Exp $ 
 
 import unittest, os, shutil, time, imp
 
@@ -42,6 +42,9 @@ class mysqlOpener:
 
     def tearDown(self):
         self.db.close()
+        self.nuke_database()
+
+    def nuke_database(self):
         self.module.db_nuke(config)
 
 class mysqlDBTest(mysqlOpener, DBTest):
@@ -53,7 +56,7 @@ class mysqlROTest(mysqlOpener, ROTest):
 class mysqlSchemaTest(mysqlOpener, SchemaTest):
     pass
 
-class mysqlClassicInitTest(ClassicInitTest):
+class mysqlClassicInitTest(mysqlOpener, ClassicInitTest):
     backend = 'mysql'
     extra_config = '''
 MYSQL_DBHOST = 'localhost'
@@ -66,7 +69,7 @@ MYSQL_DATABASE = (MYSQL_DBHOST, MYSQL_DBUSER, MYSQL_DBPASSWORD, MYSQL_DBNAME)
         from roundup.backends import mysql as module
     def tearDown(self):
         ClassicInitTest.tearDown(self)
-        self.module.db_nuke(config)
+        self.nuke_database()
 
 def test_suite():
     suite = unittest.TestSuite()
index c7a957d0f9950b561c0edd37c4e06157e4cccc2e..5841f8419e2fa9add8c1d1aefc662bc8dc1f33f0 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: test_postgresql.py,v 1.3 2003-11-11 11:19:18 richard Exp $ 
+# $Id: test_postgresql.py,v 1.4 2003-11-14 00:11:19 richard Exp $ 
 
 import sys, unittest, os, shutil, time, popen2
 
@@ -68,7 +68,12 @@ class postgresqlOpener:
         db_create()
 
     def tearDown(self):
+        self.nuke_database()
+
+    def nuke_database(self):
+        # clear out the database - easiest way is to nuke and re-created it
         db_nuke()
+        db_create()
 
 class postgresqlDBTest(postgresqlOpener, DBTest):
     def setUp(self):
index bf0cc2225393c4880a45ee1199593d69388514da..19e4277459ce349160ae44857ec6edd8c651cf59 100644 (file)
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: test_sqlite.py,v 1.2 2003-11-02 08:44:17 richard Exp $ 
+# $Id: test_sqlite.py,v 1.3 2003-11-14 00:11:19 richard Exp $ 
 
 import unittest, os, shutil, time
 
-from db_test_base import DBTest, ROTest, SchemaTest, \
-    ClassicInitTest
+from db_test_base import DBTest, ROTest, SchemaTest, ClassicInitTest, config
 
 class sqliteOpener:
     from roundup import backends
     if hasattr(backends, 'sqlite'):
         from roundup.backends import sqlite as module
 
+    def nuke_database(self):
+        shutil.rmtree(config.DATABASE)
+
 class sqliteDBTest(sqliteOpener, DBTest):
     pass