Exemplo n.º 1
0
    def prepare_database_template(self):

        # --- Check template database cache ---
        current_mhash = checksumdir.dirhash('./scripts/migrations')
        cache_connector = db_connector(self.template_cache_name)
        try:
            latest_mhash = self.read_migrations_hash(cache_connector)
            if latest_mhash == current_mhash:
                logger.info("Using template database cache.")
                # Cache is still valid, copy it to the template database
                # NOTE: In theory, 'get_migrations_hash:create_database'
                # should form one transaction. If another execution interrupts
                # us at this point, we will be lost ... 😨
                self.create_database(self.template_name,
                                     self.template_cache_name)
                return
        except psycopg2.OperationalError:
            pass  # Database does not exist
        except psycopg2.errors.UndefinedObject:
            pass  # No hash specified for historical reasons

        # --- Cache invalidation, recreating template database ---
        logger.info("Recreating template database ...")
        _perform_query(f'CREATE DATABASE {self.template_name}')
        connector = db_connector(self.template_name)
        # Apply migrations
        sp.run('./scripts/migrations/migrate.sh',
               check=True,
               env=dict(os.environ, POSTGRES_DB=self.template_name))
        # Seal template
        self.store_migrations_hash(connector, current_mhash)
        connector.execute(f'''
            UPDATE pg_database SET datistemplate = TRUE
            WHERE datname = '{self.template_name}'
        ''')
        logger.info("Template database was recreated.")

        # --- Update cache database ---
        # NOTE: In theory, this block should form one transaction. If another
        # execution interrupts us at this point, we will be lost ... 😨
        self.drop_database(self.template_cache_name)
        self.create_database(self.template_cache_name, self.template_name)
        # Copy the hash manually (not done automatically by Postgres)
        self.store_migrations_hash(cache_connector, current_mhash)
        logger.info("Template database was stored into cache.")
    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)

        # Set db connection parameters using env vars
        self.db_connector = _utils.db_connector()
        self.host = self.db_connector.host
        self.database = self.db_connector.database
        self.user = self.db_connector.user
        self.password = self.db_connector.password

        # lazy properties
        self._columns = None
        self._primary_constraint_name = None
Exemplo n.º 3
0
    def setup_database(self):
        """
        Provide throw-away database during the execution of the test case.

        The database instance is created from the template which was prepared
        in DatabaseTestSuite.setup_database_template().
        """
        # Generate "unique" database name
        outer_db = os.getenv('POSTGRES_DB')
        os.environ['POSTGRES_DB'] = self.str_id
        self.addCleanup(os.environ.update, POSTGRES_DB=outer_db)
        # Create database
        _perform_query(f'''
                CREATE DATABASE {os.environ['POSTGRES_DB']}
                TEMPLATE {os.environ['POSTGRES_DB_TEMPLATE']}
            ''')
        # Instantiate connector
        self.db_connector = db_connector()

        # Register cleanup
        self.addCleanup(_perform_query,
                        f'DROP DATABASE {self.db_connector.database}')
Exemplo n.º 4
0
#!/usr/bin/env python3
"""
Truncate facebook posts (#213).

We want to do this because in the past, we have collected a number of old
posts that are not necessarily authored by the museum itself. To avoid wrong
is_from_museum attributions, we are going to drop all posts so that posts that
are indeed by the museum will be fetched again automatically (see #184).
"""

import logging
import os
import subprocess as sp

from _utils import db_connector, logger
CONNECTOR = db_connector()

logging.basicConfig(level=logging.INFO)

REFERENCING_TABLES = ['fb_post_comment', 'fb_post_performance']

# Are there any existing data to preserve?
if not any(
        CONNECTOR.exists(f'SELECT * FROM {table}')
        for table in REFERENCING_TABLES):
    # Nothing to preserve, get into the fast lane
    logger.info("Truncating fb_post in the fast line")
    CONNECTOR.execute('''
        TRUNCATE TABLE fb_post CASCADE
    ''')
    exit(0)
    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)
        self.db_connector = _utils.db_connector()