"""Which PostgreSQL driver the application actually asks for — QUA-001. `postgresql://…` is not "whichever driver is installed". SQLAlchemy reads it as psycopg2 unless the URL names a driver. requirements.txt declares psycopg 3, so create_app() must explicitly select it. The test suite must not assume that psycopg2 is absent: a developer's virtual environment can contain optional packages in addition to the declared dependencies. These tests instead pin the application's selected driver and the dependency contract that production installs use. """ from pathlib import Path import pytest from sqlalchemy import create_engine from app.app import normalise_database_url class TestNormalisation: @pytest.mark.parametrize( 'given', [ 'postgresql://user:pass@host:5432/tryouts', 'postgres://user:pass@host:5432/tryouts', ], ) def test_a_driverless_postgres_url_gets_psycopg(self, given): assert normalise_database_url(given).startswith('postgresql+psycopg://') def test_the_rest_of_the_url_is_untouched(self): result = normalise_database_url( 'postgresql://u:p%40ss@db.internal:5432/tryouts?sslmode=require' ) assert result == ('postgresql+psycopg://u:p%40ss@db.internal:5432/tryouts?sslmode=require') @pytest.mark.parametrize( 'given', [ 'postgresql+psycopg://user:pass@host/db', 'postgresql+psycopg2://user:pass@host/db', ], ) def test_an_explicit_driver_is_left_alone(self, given): """Naming psycopg2 stays possible for an environment that has it.""" assert normalise_database_url(given) == given def test_sqlite_is_left_alone(self): assert normalise_database_url('sqlite:///x.db') == 'sqlite:///x.db' @pytest.mark.parametrize('given', [None, '', 'not-a-url']) def test_nothing_to_normalise(self, given): assert normalise_database_url(given) == given class TestTheFactory: @staticmethod def _config(uri): return { 'SECRET_KEY': 'test-secret-not-used-anywhere-real', 'SQLALCHEMY_DATABASE_URI': uri, 'TESTING': True, 'WTF_CSRF_ENABLED': False, 'FORCE_HTTPS': False, 'SESSION_COOKIE_SECURE': False, 'ENABLE_DISCORD_BOT': False, 'AUTO_CREATE_TABLES': False, 'CORS_ALLOWED_ORIGINS': '', 'RATELIMIT_ENABLED': False, } def test_the_configured_uri_names_a_driver(self): from app.app import create_app app = create_app(self._config('postgresql://u:p@db.internal:5432/tryouts')) assert app.config['SQLALCHEMY_DATABASE_URI'].startswith('postgresql+psycopg://') def test_the_sqlite_suite_is_unaffected(self, app): assert app.config['SQLALCHEMY_DATABASE_URI'].startswith('sqlite:///') class TestDriverContract: def test_production_dependencies_select_psycopg_3(self): requirements = Path(__file__).resolve().parents[1] / 'requirements.txt' declared = requirements.read_text(encoding='utf-8') assert 'psycopg[binary]==' in declared assert 'psycopg2' not in declared def test_the_normalised_url_can(self): engine = create_engine(normalise_database_url('postgresql://u:p@host/db')) assert engine.dialect.driver == 'psycopg'