#!/usr/bin/env python3 """ This allows running Django tests using a temporary postgres db (set up by tesing.postgresql) instead of using the stock config in settings.py. Run as script to start postgres instance, returns PID to allow stopping it after use. To use this in Django tests, run: '.../manage.py test lsmrapp --testrunner=postgres_testrunner.PostgresqlTestRunner' """ import testing.postgresql from django.test.runner import DiscoverRunner import psycopg2 from lofar.sas.lsmr.lsmr.settings import DATABASES # todo: consider switching from testing.postgresql to pyembedpg to allow easy testing on specific versions. That may be slower, though. try: import testing.postgresql except ImportError as e: print(str(e)) print('Please install python package testing.postgresql: sudo pip3 install testing.postgresql') exit(3) # special lofar test exit code: skipped test def execute_query(pg, query): """ Run a raw SQL query on the given database :param pg: A testing.postgresql.Postgresql instance :param query: The query to execute """ # connect to Postgres as root connection = psycopg2.connect(**pg.dsn()) connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) cursor = connection.cursor() # create user role cursor.execute(query) cursor.close() connection.commit() connection.close() def create_admin_role(pg, user, passw): """ Adds a superuser to the provided Postgres instance :param pg: A testing.postgresql.Postgresql instance :return: """ query = "CREATE ROLE %s WITH SUPERUSER LOGIN PASSWORD '%s';" % (user, passw) execute_query(pg, query) def create_project_db(pg, name): """ Creates a new database in the provided Postgres instance :param pg: A testing.postgresql.Postgresql instance :param name: The name of the database to create """ name = DATABASES['default']['NAME'] query = "CREATE DATABASE %s;" % (name) execute_query(pg, query) def create_test_postgres(host, port, user, passw): """ Fires up a non-persistent Postgresql database with superuser for the provided details :return: A testing.postgresql.Postgresql instance """ postgresql = testing.postgresql.Postgresql(host=host, port=port) create_admin_role(postgresql, user, passw) return postgresql def create_test_Postgres_from_django_settings(): """ Reads default connection details from settings.py and creates an according Postgres instance :return: A testing.postgresql.Postgresql instance """ host = DATABASES['default']['HOST'] port = DATABASES['default']['PORT'] user = DATABASES['default']['USER'] passw = DATABASES['default']['PASS'] return create_test_postgres(host, port, user, passw) class PostgresqlTestRunner(DiscoverRunner): """ A test runner to pass to manage.py test to start and tear down a database for testing. Uses the connection details as configured in settings.py """ def setup_databases(self, **kwargs): self.postgresql = create_test_Postgres_from_django_settings() return super(PostgresqlTestRunner, self).setup_databases(**kwargs) def teardown_databases(self, old_config, **kwargs): self.postgresql.stop() if __name__ == "__main__": """ Start Django test database and keep it alive until interrupted """ pg = create_test_Postgres_from_django_settings() name = DATABASES['default']['NAME'] create_project_db(pg, name) print("Started Postgres server according to settings.py details with PID %s" % pg.server_pid) print("Waiting for your interrupt to stop it.") import time while True: time.sleep(1)