Add test suite for database upgrades
authorPatrick Uiterwijk <puiterwijk@redhat.com>
Mon, 31 Aug 2015 23:33:02 +0000 (01:33 +0200)
committerPatrick Uiterwijk <puiterwijk@redhat.com>
Wed, 2 Sep 2015 15:19:23 +0000 (17:19 +0200)
Signed-off-by: Patrick Uiterwijk <puiterwijk@redhat.com>
Reviewed-by: Rob Crittenden <rcritten@redhat.com>
Makefile
tests/blobs/old_dbs/v1/adminconfig.sqlite.dump [new file with mode: 0644]
tests/blobs/old_dbs/v1/openid.sqlite.dump [new file with mode: 0644]
tests/blobs/old_dbs/v1/saml2.sessions.db.sqlite.dump [new file with mode: 0644]
tests/blobs/old_dbs/v1/transactions.sqlite.dump [new file with mode: 0644]
tests/blobs/old_dbs/v1/userprefs.sqlite.dump [new file with mode: 0644]
tests/dbupgrades.py [new file with mode: 0755]
tests/helpers/common.py

index d15ca4d..ddfdf14 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -104,6 +104,7 @@ tests: wrappers
        PYTHONPATH=./ ./tests/tests.py --test=ldap
        PYTHONPATH=./ ./tests/tests.py --test=ldapdown
        PYTHONPATH=./ ./tests/tests.py --test=openid
+       PYTHONPATH=./ ./tests/tests.py --test=dbupgrades
 
 test: lp-test unittests tests
 
diff --git a/tests/blobs/old_dbs/v1/adminconfig.sqlite.dump b/tests/blobs/old_dbs/v1/adminconfig.sqlite.dump
new file mode 100644 (file)
index 0000000..d8e4d0a
--- /dev/null
@@ -0,0 +1,65 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE dbinfo (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+INSERT INTO "dbinfo" VALUES('AdminStore_schema','version','1');
+CREATE TABLE config (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+CREATE TABLE info_config (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+CREATE TABLE login_config (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+INSERT INTO "login_config" VALUES('global','enabled','testauth');
+CREATE TABLE provider_config (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+INSERT INTO "provider_config" VALUES('openid','endpoint url','http://127.0.0.11:45081/idp_v1/openid/');
+INSERT INTO "provider_config" VALUES('openid','database url','openid.sqlite');
+INSERT INTO "provider_config" VALUES('openid','identity url template','http://127.0.0.11:45081/idp_v1/openid/id/%(username)s');
+INSERT INTO "provider_config" VALUES('openid','enabled extensions','');
+INSERT INTO "provider_config" VALUES('global','enabled','openid,persona,saml2');
+INSERT INTO "provider_config" VALUES('persona','allowed domains','127.0.0.11:45081');
+INSERT INTO "provider_config" VALUES('persona','issuer domain','127.0.0.11:45081');
+INSERT INTO "provider_config" VALUES('persona','idp key file','persona/persona.key');
+INSERT INTO "provider_config" VALUES('saml2','idp nameid salt','6c78ae3b33db4fe4886edb1679490821');
+INSERT INTO "provider_config" VALUES('saml2','idp metadata validity','1825');
+INSERT INTO "provider_config" VALUES('saml2','idp certificate file','saml2/idp.pem');
+INSERT INTO "provider_config" VALUES('saml2','idp key file','saml2/idp.key');
+INSERT INTO "provider_config" VALUES('saml2','session database url','saml2.sessions.db.sqlite');
+INSERT INTO "provider_config" VALUES('saml2','idp metadata file','metadata.xml');
+INSERT INTO "provider_config" VALUES('saml2','idp storage path','saml2');
+CREATE TABLE testauth_data (
+       uuid TEXT NOT NULL, 
+       name TEXT NOT NULL, 
+       value TEXT
+);
+CREATE TABLE openid_data (
+       uuid TEXT NOT NULL, 
+       name TEXT NOT NULL, 
+       value TEXT
+);
+CREATE TABLE persona_data (
+       uuid TEXT NOT NULL, 
+       name TEXT NOT NULL, 
+       value TEXT
+);
+CREATE TABLE saml2_data (
+       uuid TEXT NOT NULL, 
+       name TEXT NOT NULL, 
+       value TEXT
+);
+COMMIT;
diff --git a/tests/blobs/old_dbs/v1/openid.sqlite.dump b/tests/blobs/old_dbs/v1/openid.sqlite.dump
new file mode 100644 (file)
index 0000000..4618785
--- /dev/null
@@ -0,0 +1,14 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE dbinfo (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+INSERT INTO "dbinfo" VALUES('OpenIDStore_schema','version','1');
+CREATE TABLE association (
+       uuid TEXT NOT NULL, 
+       name TEXT NOT NULL, 
+       value TEXT
+);
+COMMIT;
diff --git a/tests/blobs/old_dbs/v1/saml2.sessions.db.sqlite.dump b/tests/blobs/old_dbs/v1/saml2.sessions.db.sqlite.dump
new file mode 100644 (file)
index 0000000..1e8a694
--- /dev/null
@@ -0,0 +1,14 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE saml2_sessions (
+       uuid TEXT NOT NULL, 
+       name TEXT NOT NULL, 
+       value TEXT
+);
+CREATE TABLE dbinfo (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+INSERT INTO "dbinfo" VALUES('SAML2SessionStore_schema','version','1');
+COMMIT;
diff --git a/tests/blobs/old_dbs/v1/transactions.sqlite.dump b/tests/blobs/old_dbs/v1/transactions.sqlite.dump
new file mode 100644 (file)
index 0000000..b803e78
--- /dev/null
@@ -0,0 +1,14 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE dbinfo (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+INSERT INTO "dbinfo" VALUES('TranStore_schema','version','1');
+CREATE TABLE transactions (
+       uuid TEXT NOT NULL, 
+       name TEXT NOT NULL, 
+       value TEXT
+);
+COMMIT;
diff --git a/tests/blobs/old_dbs/v1/userprefs.sqlite.dump b/tests/blobs/old_dbs/v1/userprefs.sqlite.dump
new file mode 100644 (file)
index 0000000..a20af5e
--- /dev/null
@@ -0,0 +1,14 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE dbinfo (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+INSERT INTO "dbinfo" VALUES('UserStore_schema','version','1');
+CREATE TABLE users (
+       name TEXT NOT NULL, 
+       option TEXT NOT NULL, 
+       value TEXT
+);
+COMMIT;
diff --git a/tests/dbupgrades.py b/tests/dbupgrades.py
new file mode 100755 (executable)
index 0000000..73d04fb
--- /dev/null
@@ -0,0 +1,149 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
+
+from helpers.common import IpsilonTestBase  # pylint: disable=relative-import
+from helpers.http import HttpSessions  # pylint: disable=relative-import
+import os
+import pwd
+import sys
+import signal
+import subprocess
+import ipsilon.util.data
+
+idp_g = {'TEMPLATES': '${TESTDIR}/templates/install',
+         'CONFDIR': '${TESTDIR}/etc',
+         'DATADIR': '${TESTDIR}/lib',
+         'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
+         'STATICDIR': '${ROOTDIR}',
+         'BINDIR': '${ROOTDIR}/ipsilon',
+         'WSGI_SOCKET_PREFIX': '${TESTDIR}/${NAME}/logs/wsgi'}
+
+
+idp_a = {'hostname': '${ADDRESS}:${PORT}',
+         'admin_user': '${TEST_USER}',
+         'system_user': '${TEST_USER}',
+         'instance': '${NAME}',
+         'secure': 'no',
+         'testauth': 'yes',
+         'pam': 'no',
+         'gssapi': 'no',
+         'ipa': 'no',
+         'server_debugging': 'True'}
+
+
+class IpsilonTest(IpsilonTestBase):
+
+    def __init__(self):
+        super(IpsilonTest, self).__init__('dbupgrades', __file__)
+
+    def setup_servers(self, env=None):
+        pass
+
+    def test_upgrade_from(self, env, old_version):
+        # Setup IDP Server
+        print "Installing IDP server to test upgrade from %i" % old_version
+        name = 'idp_v%i' % old_version
+        addr = '127.0.0.%i' % (10 + old_version)
+        port = str(45080 + old_version)
+        idp = self.generate_profile(idp_g, idp_a, name, addr, port)
+        conf = self.setup_idp_server(idp, name, addr, port, env)
+
+        # Move database of old_version into place
+        cfgfile = os.path.join(self.testdir, 'etc', name, 'ipsilon.conf')
+        db_indir = os.path.join(self.rootdir, 'tests', 'blobs', 'old_dbs',
+                                'v%i' % old_version)
+        db_outdir = os.path.join(self.testdir, 'lib', name)
+
+        if old_version > 0:
+            for database in ['adminconfig',
+                             'openid',
+                             'saml2.sessions.db',
+                             'transactions',
+                             'userprefs']:
+                db_in = os.path.join(db_indir, '%s.sqlite.dump' % database)
+                db_out = os.path.join(db_outdir, '%s.sqlite' % database)
+                os.unlink(db_out)
+                cmd = ['/bin/sqlite3', db_out, '.read %s' % db_in]
+                subprocess.check_call(cmd)
+
+            # Upgrade that database
+            cmd = [os.path.join(self.rootdir,
+                                'ipsilon/install/ipsilon-upgrade-database'),
+                   cfgfile]
+            subprocess.check_call(cmd,
+                                  cwd=os.path.join(self.testdir, 'lib', name),
+                                  env=env)
+
+        # Check some version-specific changes, to see if the upgrade went OK
+        if old_version == 0:
+            # Check all features in a newly created database
+            # Let's verify if at least one index was created
+            test_db = os.path.join(db_outdir, 'adminconfig.sqlite')
+            p = subprocess.Popen(['/bin/sqlite3', test_db, '.dump'],
+                                 stdout=subprocess.PIPE)
+            output, _ = p.communicate()
+            if p.returncode:
+                print 'Sqlite dump failed'
+                sys.exit(1)
+            if 'CREATE INDEX' not in output:
+                raise Exception('Database upgrade did not introduce index')
+            if 'PRIMARY KEY' not in output:
+                raise Exception('Database upgrade did not introduce primary ' +
+                                'key')
+        elif old_version == 1:
+            # In 1 -> 2, we added indexes and primary keys
+            # Let's verify if at least one index was created
+            test_db = os.path.join(db_outdir, 'adminconfig.sqlite')
+            p = subprocess.Popen(['/bin/sqlite3', test_db, '.dump'],
+                                 stdout=subprocess.PIPE)
+            output, _ = p.communicate()
+            if p.returncode:
+                print 'Sqlite dump failed'
+                sys.exit(1)
+            if 'CREATE INDEX' not in output:
+                raise Exception('Database upgrade did not introduce index')
+            # SQLite did not support creating primary keys, so we can't test
+
+        # Start the httpd server
+        http_server = self.start_http_server(conf, env)
+
+        # Now attempt to use the upgraded database
+        exe = self.execname
+        if exe.endswith('c'):
+            exe = exe[:-1]
+        exe = [exe]
+        exe.append(str(old_version))
+        exe.append(name)
+        exe.append('%s:%s' % (addr, port))
+        exit_code = subprocess.call(exe, env=env)
+        if exit_code:
+            sys.exit(exit_code)
+
+        # Now kill the last http server
+        os.killpg(http_server.pid, signal.SIGTERM)
+        self.processes.remove(http_server)
+
+    def run(self, env):
+        for version in range(ipsilon.util.data.CURRENT_SCHEMA_VERSION):
+            self.test_upgrade_from(env, version)
+
+
+if __name__ == '__main__':
+    from_version = sys.argv[1]
+    idpname = sys.argv[2]
+    url = sys.argv[3]
+
+    user = pwd.getpwuid(os.getuid())[0]
+
+    sess = HttpSessions()
+    sess.add_server(idpname, 'http://%s' % url, user,
+                    'ipsilon')
+
+    print "dbupgrades: From v%s: Authenticate to IDP ..." % from_version,
+    try:
+        sess.auth_to_idp(idpname)
+    except Exception, e:  # pylint: disable=broad-except
+        print >> sys.stderr, " ERROR: %s" % repr(e)
+        sys.exit(1)
+    print " SUCCESS"
index eadfdc3..a7021e2 100755 (executable)
@@ -177,6 +177,7 @@ class IpsilonTestBase(object):
         p = subprocess.Popen(['/usr/sbin/httpd', '-DFOREGROUND', '-f', conf],
                              env=env, preexec_fn=os.setsid)
         self.processes.append(p)
+        return p
 
     def start_pgdb_server(self, datadir, rundir, log, addr, port, env):
         p = subprocess.Popen(['/usr/bin/pg_ctl', 'start', '-D', datadir, '-o',