diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b6fb5cb8..96b55484 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,6 +49,7 @@ jobs: run: | sudo systemctl start postgresql.service sudo -u postgres createuser --createdb $USER + sudo -u postgres psql -c "ALTER USER $USER WITH SUPERUSER" - name: Install dependencies run: | diff --git a/tests/test_database.py b/tests/test_database.py index cb5b54a0..d68e0482 100644 --- a/tests/test_database.py +++ b/tests/test_database.py @@ -492,3 +492,67 @@ def test_db_access_in_test_module(self, django_pytester: DjangoPytester) -> None 'or the "db" or "transactional_db" fixtures to enable it.' ] ) + + +def test_custom_django_db_setup(django_pytester: DjangoPytester) -> None: + pytest.importorskip("xdist") + pytest.importorskip("psycopg") + + django_pytester.makeconftest( + """ + import pytest + import psycopg + from django.conf import settings as django_settings + from django.core.management import call_command + + def run_sql(query, fetch=False, db='default'): + conn = psycopg.connect( + user=django_settings.DATABASES[db]['USER'], + password=django_settings.DATABASES[db]['PASSWORD'], + dbname="postgres", + host=django_settings.DATABASES[db]['HOST'], + port=django_settings.DATABASES['default']['PORT'] + ) + (cur := conn.cursor()).execute(query) + response = cur.fetchone() if fetch else None + conn.close() + return response + + @pytest.fixture(scope='session') + def django_db_createdb(request, django_db_createdb) -> bool: + db_name = f'test_{django_settings.DATABASES["default"]["NAME"]}' + if xdist_suffix := getattr(request.config, 'workerinput', {}).get('workerid'): + db_name = f'{db_name}_{xdist_suffix}' + print(run_sql(query="SELECT * FROM pg_available_extensions;", fetch=True)) + db_exists = (result := run_sql(query=f"SELECT EXISTS (SELECT 1 FROM pg_database WHERE datname='{db_name}')", fetch=True)) and result and result[0] + if django_db_createdb or not db_exists: + run_sql('CREATE EXTENSION IF NOT EXISTS hstore') + return django_db_createdb or not db_exists + + @pytest.fixture(scope='session') + def django_db_setup(django_db_setup, django_db_blocker, django_db_createdb) -> None: + del django_db_setup + if django_db_createdb: + with django_db_blocker.unblock(): + call_command('flush', '--noinput') + """ + ) + + django_pytester.create_test_module( + """ + import pytest + from .app.models import Item + + @pytest.mark.django_db + def test_simple(): + assert Item.objects.count() == 0 + """ + ) + + result = django_pytester.runpytest_subprocess("-vv", "-s", "--reuse-db", "-n", "auto") + assert "Creating test database for alias 'default'" in result.stderr.str() + result.assert_outcomes(passed=1) + + result = django_pytester.runpytest_subprocess("-vv", "-s", "--reuse-db", "-n", "auto") + assert "Got an error creating the test database: database" in result.stderr.str() + result.assert_outcomes(passed=1) diff --git a/tox.ini b/tox.ini index 5ffeeead..ef43a7f7 100644 --- a/tox.ini +++ b/tox.ini @@ -37,7 +37,7 @@ passenv = PYTEST_ADDOPTS,TERM,TEST_DB_USER,TEST_DB_PASSWORD,TEST_DB_HOST usedevelop = True commands = coverage: coverage erase - {env:PYTESTDJANGO_TEST_RUNNER:pytest} {posargs:tests} + {env:PYTESTDJANGO_TEST_RUNNER:pytest} {posargs:tests} tests/test_database.py::test_custom_django_db_setup -vv -s coverage: coverage combine coverage: coverage report coverage: coverage xml