Esempio n. 1
0
def core_config_mock(request):
    """
    Fixture to allow having per-test core.config tables without affecting the other parallel tests.

    This override works only in tests which use core function calls directly, not in the ones working
    via the API, because the normal config table is not touched and the rucio instance answering API
    calls is not aware of this mock.

    This fixture acts by creating a new copy of the "config" sql table using the :memory: sqlite engine.
    Accesses to the "models.Config" table are then redirected to this temporary table via mock.patch().
    """
    from unittest import mock
    from rucio.common.utils import generate_uuid
    from sqlalchemy.pool import StaticPool
    from rucio.db.sqla.models import ModelBase, BASE, Column, String, PrimaryKeyConstraint
    from rucio.db.sqla.session import get_session, get_maker, get_engine, create_engine, declarative_base

    # Get the fixture parameters
    table_content = []
    params = __get_fixture_param(request)
    if params:
        table_content = params.get("table_content", table_content)

    # Create an in-memory dropdown replacement table for the "models.Config" table
    engine = create_engine('sqlite://',
                           connect_args={'check_same_thread': False},
                           poolclass=StaticPool)
    InMemoryBase = declarative_base(bind=engine)

    class InMemoryConfig(InMemoryBase, ModelBase):
        __tablename__ = 'configs_' + generate_uuid()
        section = Column(String(128))
        opt = Column(String(128))
        value = Column(String(4000))
        _table_args = (PrimaryKeyConstraint('section',
                                            'opt',
                                            name='CONFIGS_PK'), )

    InMemoryBase.metadata.create_all()

    # Register the new table with the associated engine into the sqlalchemy sessionmaker
    # In theory, this code must be protected by rucio.db.scla.session._LOCK, but this code will be executed
    # during test case initialization, so there is no risk here to have concurrent calls from within the
    # same process
    current_engine = get_engine()
    get_maker().configure(binds={BASE: current_engine, InMemoryBase: engine})

    # Fill the table with the requested mock data
    session = get_session()()
    for section, option, value in (table_content or []):
        InMemoryConfig(section=section, opt=option,
                       value=value).save(flush=True, session=session)
    session.commit()

    with mock.patch('rucio.core.config.models.Config', new=InMemoryConfig):
        yield
Esempio n. 2
0
def __create_in_memory_db_table(name, *columns, **kwargs):
    """
    Create an in-memory temporary table using the sqlite memory driver.
    Make sqlalchemy  aware of that table by registering it via a
    declarative base.
    """
    import datetime
    from sqlalchemy import Column, DateTime, CheckConstraint
    from sqlalchemy.pool import StaticPool
    from sqlalchemy.schema import Table
    from sqlalchemy.orm import registry
    from rucio.db.sqla.models import ModelBase
    from rucio.db.sqla.session import get_maker, create_engine

    engine = create_engine('sqlite://',
                           connect_args={'check_same_thread': False},
                           poolclass=StaticPool)

    # Create a class which inherits from ModelBase. This will allow us to use the rucio-specific methods like .save()
    DeclarativeObj = type('DeclarativeObj{}'.format(name), (ModelBase, ), {})
    # Create a new declarative base and map the previously created object into the base
    mapper_registry = registry()
    InMemoryBase = mapper_registry.generate_base(
        name='InMemoryBase{}'.format(name))
    table_args = tuple(columns) + tuple(kwargs.get('table_args', ())) + (
        Column("created_at", DateTime, default=datetime.datetime.utcnow),
        Column("updated_at",
               DateTime,
               default=datetime.datetime.utcnow,
               onupdate=datetime.datetime.utcnow),
        CheckConstraint('CREATED_AT IS NOT NULL',
                        name=name.upper() + '_CREATED_NN'),
        CheckConstraint('UPDATED_AT IS NOT NULL',
                        name=name.upper() + '_UPDATED_NN'),
    )
    table = Table(name, InMemoryBase.metadata, *table_args)
    mapper_registry.map_imperatively(DeclarativeObj, table)
    # Performa actual creation of the in-memory table
    InMemoryBase.metadata.create_all(engine)

    # Register the new table with the associated engine into the sqlalchemy sessionmaker
    # In theory, this code must be protected by rucio.db.scla.session._LOCK, but this code will be executed
    # during test case initialization, so there is no risk here to have concurrent calls from within the
    # same process
    senssionmaker = get_maker()
    senssionmaker.kw.setdefault('binds', {}).update({DeclarativeObj: engine})
    return DeclarativeObj