Skip to content

Commit

Permalink
Make postgres_cluster and config_psql_dos fixtures configurable (#…
Browse files Browse the repository at this point in the history
…6254)

The `postgres_cluster` and `config_psql_dos` fixtures are made available
publicly in order to help plugin packages with unit testing.
Particularly, these fixtures should make it easy to generate test
profiles using the `core.psql_dos` storage plugin, generating the
postgres database in a test cluster that is created on-the-fly.

The problem was that the interface did not actually allow to configure
anything, such as the database name, but this was hardcoded. This would
work fine in case it was used just once, but the fixtures could not be
used to create a second profile, as the database name would already
exist.

The `postgres_cluster` fixture is turned into a factory, allowing the
database name, username and password to be customized. The unbound
method `create_database` is added to the `PGTest` instance that it
returns to easily create a new database.

The `config_psql_dos` fixture now actually forwards the relevant part of
the `custom_configuration` to the `postgres_cluster.create_database`
call.

Finally, the `aiida_profile_factory` fixture factory now makes the
`custom_configuration` argument actually optional, as originally was
intended.
  • Loading branch information
sphuber committed Jan 31, 2024
1 parent d724965 commit 35d7ca6
Showing 1 changed file with 35 additions and 19 deletions.
54 changes: 35 additions & 19 deletions src/aiida/manage/tests/pytest_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ def aiida_caplog(caplog):


@pytest.fixture(scope='session')
def postgres_cluster(
database_name: str | None = None, database_username: str | None = None, database_password: str | None = None
) -> t.Generator[dict[str, str], None, None]:
def postgres_cluster():
"""Create a temporary and isolated PostgreSQL cluster using ``pgtest`` and cleanup after the yield.
:param database_name: Name of the database.
Expand All @@ -82,27 +80,35 @@ def postgres_cluster(
"""
from pgtest.pgtest import PGTest

from aiida.manage.external.postgres import Postgres
def create_database(
database_name: str | None = None, database_username: str | None = None, database_password: str | None = None
) -> t.Generator[dict[str, str], None, None]:
from aiida.manage.external.postgres import Postgres

postgres_config = {
'database_engine': 'postgresql_psycopg2',
'database_name': database_name or str(uuid.uuid4()),
'database_username': database_username or 'guest',
'database_password': database_password or 'guest',
}

cluster = None
try:
cluster = PGTest()
postgres_config = {
'database_engine': 'postgresql_psycopg2',
'database_name': database_name or str(uuid.uuid4()),
'database_username': database_username or 'guest',
'database_password': database_password or 'guest',
}

postgres = Postgres(interactive=False, quiet=True, dbinfo=cluster.dsn)
postgres.create_dbuser(postgres_config['database_username'], postgres_config['database_password'], 'CREATEDB')
if not postgres.dbuser_exists(postgres_config['database_username']):
postgres.create_dbuser(
postgres_config['database_username'], postgres_config['database_password'], 'CREATEDB'
)
postgres.create_db(postgres_config['database_username'], postgres_config['database_name'])

postgres_config['database_hostname'] = postgres.host_for_psycopg2
postgres_config['database_port'] = postgres.port_for_psycopg2

yield postgres_config
return postgres_config

cluster = None
try:
cluster = PGTest()
cluster.create_database = create_database
yield cluster
finally:
if cluster is not None:
cluster.close()
Expand Down Expand Up @@ -194,16 +200,26 @@ def factory(custom_configuration: dict[str, t.Any] | None = None) -> dict[str, t
:param custom_configuration: Custom configuration to override default profile configuration.
:returns: The profile configuration.
"""
custom_configuration = custom_configuration or {}
custom_configuration.setdefault('storage', {}).setdefault('config', {})
custom_storage_config = custom_configuration['storage']['config']

storage_config = postgres_cluster.create_database(
database_name=custom_storage_config.get('database_name'),
database_username=custom_storage_config.get('database_username'),
database_password=custom_storage_config.get('database_password'),
)
recursive_merge(custom_storage_config, storage_config)

configuration = {
'storage': {
'backend': 'core.psql_dos',
'config': {
**postgres_cluster,
'repository_uri': f'file://{tmp_path_factory.mktemp("repository")}',
},
}
}
recursive_merge(configuration, custom_configuration or {})
recursive_merge(configuration, custom_configuration)
return configuration

return factory
Expand Down Expand Up @@ -242,7 +258,7 @@ def aiida_profile_factory(
contains and recreate the default user, making the profile ready for use.
"""

def factory(custom_configuration: dict[str, t.Any]) -> Profile:
def factory(custom_configuration: dict[str, t.Any] | None = None) -> Profile:
"""Create an isolated AiiDA instance with a temporary and fully loaded profile.
:param custom_configuration: Custom configuration to override default profile configuration.
Expand Down

0 comments on commit 35d7ca6

Please sign in to comment.