diff --git a/src/wormhole/server/database.py b/src/wormhole/server/database.py index 7cd09f9..d2589ad 100644 --- a/src/wormhole/server/database.py +++ b/src/wormhole/server/database.py @@ -64,3 +64,12 @@ def get_db(dbfile, target_version=TARGET_VERSION, stderr=sys.stderr): raise DBError("Unable to handle db version %s" % version) return db + +def dump_db(db): + # to let _iterdump work, we need to restore the original row factory + orig = db.row_factory + try: + db.row_factory = sqlite3.Row + return "".join(db.iterdump()) + finally: + db.row_factory = orig diff --git a/src/wormhole/test/test_database.py b/src/wormhole/test/test_database.py new file mode 100644 index 0000000..460508e --- /dev/null +++ b/src/wormhole/test/test_database.py @@ -0,0 +1,53 @@ +from __future__ import print_function, unicode_literals +import os +from twisted.trial import unittest +from ..server.database import get_db, TARGET_VERSION, dump_db + +class DB(unittest.TestCase): + def test_create_default(self): + db_url = ":memory:" + db = get_db(db_url) + rows = db.execute("SELECT * FROM version").fetchall() + self.assertEqual(len(rows), 1) + self.assertEqual(rows[0]["version"], TARGET_VERSION) + + def test_upgrade(self): + basedir = self.mktemp() + os.mkdir(basedir) + fn = os.path.join(basedir, "upgrade.db") + self.assertNotEqual(TARGET_VERSION, 2) + + # create an old-version DB in a file + db = get_db(fn, 2) + rows = db.execute("SELECT * FROM version").fetchall() + self.assertEqual(len(rows), 1) + self.assertEqual(rows[0]["version"], 2) + del db + + # then upgrade the file to the latest version + dbA = get_db(fn, TARGET_VERSION) + rows = dbA.execute("SELECT * FROM version").fetchall() + self.assertEqual(len(rows), 1) + self.assertEqual(rows[0]["version"], TARGET_VERSION) + dbA_text = dump_db(dbA) + del dbA + + # make sure the upgrades got committed to disk + dbB = get_db(fn, TARGET_VERSION) + dbB_text = dump_db(dbB) + del dbB + self.assertEqual(dbA_text, dbB_text) + + # The upgraded schema should be equivalent to that of a new DB. + # However a text dump will differ because ALTER TABLE always appends + # the new column to the end of a table, whereas our schema puts it + # somewhere in the middle (wherever it fits naturally). Also ALTER + # TABLE doesn't include comments. + if False: + latest_db = get_db(":memory:", TARGET_VERSION) + latest_text = dump_db(latest_db) + with open("up.sql","w") as f: f.write(dbA_text) + with open("new.sql","w") as f: f.write(latest_text) + # check with "diff -u _trial_temp/up.sql _trial_temp/new.sql" + self.assertEqual(dbA_text, latest_text) + test_upgrade.skip = "disabled until at least one upgrader is written"