[Checkins] SVN: relstorage/trunk/ Added tests of the zodbconvert utility and removed the verbose option

Shane Hathaway shane at hathawaymix.org
Fri Oct 30 03:20:28 EDT 2009


Log message for revision 105379:
  Added tests of the zodbconvert utility and removed the verbose option
  since it was violating an API.
  

Changed:
  U   relstorage/trunk/README.txt
  A   relstorage/trunk/relstorage/tests/test_zodbconvert.py
  U   relstorage/trunk/relstorage/zodbconvert.py

-=-
Modified: relstorage/trunk/README.txt
===================================================================
--- relstorage/trunk/README.txt	2009-10-29 21:16:07 UTC (rev 105378)
+++ relstorage/trunk/README.txt	2009-10-30 07:20:27 UTC (rev 105379)
@@ -141,7 +141,7 @@
     END relstorage_util;
     /
 
-Here are some sample SQL statements for creating the user::
+Here are some sample SQL statements for creating the database user::
 
     CREATE USER zodb IDENTIFIED BY mypassword;
     GRANT CONNECT, RESOURCE, CREATE TABLE, CREATE SEQUENCE TO zodb;
@@ -317,16 +317,13 @@
   ``--clear``
     Clears all data from the destination storage before copying. Use
     this only if you are certain the destination has no useful data.
+    Currently only works when the destination is a RelStorage instance.
 
   ``--dry-run``
     Opens both storages and analyzes what would be copied, but does not
     actually copy.
 
-  ``--verbose``
-    List the transactions and objects as they are copied. This is very
-    verbose.
 
-
 Migrating to a new version of RelStorage
 ----------------------------------------
 

Added: relstorage/trunk/relstorage/tests/test_zodbconvert.py
===================================================================
--- relstorage/trunk/relstorage/tests/test_zodbconvert.py	                        (rev 0)
+++ relstorage/trunk/relstorage/tests/test_zodbconvert.py	2009-10-30 07:20:27 UTC (rev 105379)
@@ -0,0 +1,130 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import unittest
+
+class ZODBConvertTests(unittest.TestCase):
+
+    def setUp(self):
+        import os
+        import tempfile
+
+        fd, self.srcfile = tempfile.mkstemp()
+        os.close(fd)
+        os.remove(self.srcfile)
+
+        fd, self.destfile = tempfile.mkstemp()
+        os.close(fd)
+        os.remove(self.destfile)
+
+        cfg = """
+        <filestorage source>
+            path %s
+        </filestorage>
+        <filestorage destination>
+            path %s
+        </filestorage>
+        """ % (self.srcfile, self.destfile)
+
+        fd, self.cfgfile = tempfile.mkstemp()
+        os.write(fd, cfg)
+        os.close(fd)
+
+    def tearDown(self):
+        import os
+        if os.path.exists(self.destfile):
+            os.remove(self.destfile)
+        if os.path.exists(self.srcfile):
+            os.remove(self.srcfile)
+
+    def test_storage_has_data(self):
+        from ZODB.DB import DB
+        from relstorage.zodbconvert import storage_has_data
+        from ZODB.FileStorage import FileStorage
+        src = FileStorage(self.srcfile, create=True)
+        self.assertFalse(storage_has_data(src))
+        db = DB(src)  # add the root object
+        db.close()
+        self.assertTrue(storage_has_data(src))
+
+    def test_convert(self):
+        from ZODB.DB import DB
+        from ZODB.FileStorage import FileStorage
+        from relstorage.zodbconvert import main
+        from relstorage.zodbconvert import storage_has_data
+        import transaction
+
+        src = FileStorage(self.srcfile)
+        db = DB(src)
+        conn = db.open()
+        conn.root()['x'] = 10
+        transaction.commit()
+        conn.close()
+        db.close()
+
+        main(['', self.cfgfile], write=lambda x: None)
+
+        dest = FileStorage(self.destfile)
+        db2 = DB(dest)
+        conn2 = db2.open()
+        self.assertEqual(conn2.root().get('x'), 10)
+        conn2.close()
+        db2.close()
+
+    def test_dry_run(self):
+        from ZODB.DB import DB
+        from ZODB.FileStorage import FileStorage
+        from relstorage.zodbconvert import main
+        from relstorage.zodbconvert import storage_has_data
+        import transaction
+
+        src = FileStorage(self.srcfile)
+        db = DB(src)
+        conn = db.open()
+        conn.root()['x'] = 10
+        transaction.commit()
+        conn.close()
+        db.close()
+
+        main(['', '--dry-run', self.cfgfile], write=lambda x: None)
+
+        dest = FileStorage(self.destfile)
+        db2 = DB(dest)
+        conn2 = db2.open()
+        self.assertEqual(conn2.root().get('x'), None)
+        conn2.close()
+        db2.close()
+
+    def test_no_overwrite(self):
+        from ZODB.DB import DB
+        from ZODB.FileStorage import FileStorage
+        from relstorage.zodbconvert import main
+        from relstorage.zodbconvert import storage_has_data
+        import transaction
+
+        src = FileStorage(self.srcfile)
+        db = DB(src)  # create the root object
+        db.close()
+
+        dest = FileStorage(self.destfile)
+        db = DB(dest)  # create the root object
+        db.close()
+
+        self.assertRaises(SystemExit, main, ['', self.cfgfile],
+            write=lambda x: None)
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(ZODBConvertTests))
+    return suite

Modified: relstorage/trunk/relstorage/zodbconvert.py
===================================================================
--- relstorage/trunk/relstorage/zodbconvert.py	2009-10-29 21:16:07 UTC (rev 105378)
+++ relstorage/trunk/relstorage/zodbconvert.py	2009-10-30 07:20:27 UTC (rev 105379)
@@ -14,10 +14,9 @@
 ##############################################################################
 """ZODB storage conversion utility.
 
-See http://wiki.zope.org/ZODB/ZODBConvert for details.
+See README.txt for details.
 """
 
-import logging
 import optparse
 from persistent.TimeStamp import TimeStamp
 from StringIO import StringIO
@@ -40,15 +39,18 @@
 def storage_has_data(storage):
     i = storage.iterator()
     try:
-        i[0]
-    except IndexError:
+        if hasattr(i, 'next'):
+            # New iterator API
+            i.next()
+        else:
+            # Old index lookup API
+            i[0]
+    except (IndexError, StopIteration):
         return False
     return True
 
 
-def main():
-    logging.basicConfig()
-
+def main(argv=sys.argv, write=sys.stdout.write):
     parser = optparse.OptionParser(description=__doc__,
         usage="%prog [options] config_file")
     parser.add_option(
@@ -57,11 +59,8 @@
     parser.add_option(
         "--clear", dest="clear", action="store_true",
         help="Clear the contents of the destination storage before copying")
-    parser.add_option(
-        "-v", "--verbose", dest="verbose", action="store_true",
-        help="Show verbose information while copying")
-    parser.set_defaults(dry_run=False, clear=False, verbose=False)
-    options, args = parser.parse_args()
+    parser.set_defaults(dry_run=False, clear=False)
+    options, args = parser.parse_args(argv[1:])
 
     if len(args) != 1:
         parser.error("The name of one configuration file is required.")
@@ -71,42 +70,39 @@
     source = config.source.open()
     destination = config.destination.open()
 
-    print "Storages opened successfully."
+    write("Storages opened successfully.\n")
 
     if options.dry_run:
-        print "Dry run mode: not changing the destination."
+        write("Dry run mode: not changing the destination.\n")
         if storage_has_data(destination):
-            print "Warning: the destination storage has data"
+            write("Warning: the destination storage has data\n")
         count = 0
         for txn in source.iterator():
-            print '%s user=%s description=%s' % (
-                TimeStamp(txn.tid), txn.user, txn.description)
-            for rec in txn:
-                print '  oid=%s length=%d' % (oid_repr(rec.oid), len(rec.data))
+            write('%s user=%s description=%s\n' % (
+                TimeStamp(txn.tid), txn.user, txn.description))
             count += 1
-        print "Would copy %d transactions." % count
-        sys.exit(0)
+        write("Would copy %d transactions.\n" % count)
 
-    if options.clear:
-        if hasattr(destination, 'zap_all'):
-            destination.zap_all()
-        else:
-            msg = ("Error: no API is known for clearing this type of storage."
-                " Use another method.")
+    else:
+        if options.clear:
+            if hasattr(destination, 'zap_all'):
+                destination.zap_all()
+            else:
+                msg = ("Error: no API is known for clearing this type "
+                       "of storage. Use another method.")
+                sys.exit(msg)
+
+        if storage_has_data(destination):
+            msg = "Error: the destination storage has data.  Try --clear."
             sys.exit(msg)
 
-    if storage_has_data(destination):
-        msg = "Error: the destination storage has data.  Try --clear."
-        sys.exit(msg)
+        destination.copyTransactionsFrom(source)
 
-    destination.copyTransactionsFrom(source, verbose=options.verbose)
+        source.close()
+        destination.close()
 
-    source.close()
-    destination.close()
+        write('All transactions copied successfully.\n')
 
-    print 'All transactions copied successfully.'
 
-
 if __name__ == '__main__':
     main()
-



More information about the checkins mailing list