QUA-002, premiere moitie. **Ce commit ne fait que reformater** : aucun changement de comportement, aucune ligne de logique touchee. 72 fichiers, 4 restaient deja conformes. Il est isole exprès, pour que `git log -p` sur les commits voisins reste lisible. `quote-style = "preserve"` etait deja pose dans pyproject.toml, ce qui evite le brassage guillemets simples / doubles : le diff porte sur les retours a la ligne, l indentation des appels longs et les virgules finales, pas sur le style de chaine. Verification : 263 tests passent avant et apres, ruff check propre. L activation en CI arrive dans le commit suivant, separement, pour que ce diff-ci ne contienne rien d autre. Co-Authored-By: Claude Opus 5 <[email protected]>
97 lines
3.4 KiB
Python
97 lines
3.4 KiB
Python
"""Which PostgreSQL driver the application actually asks for — QUA-001.
|
|
|
|
`postgresql://…` is not "whichever driver is installed". SQLAlchemy reads it
|
|
as psycopg2 and imports that module when the engine is created.
|
|
requirements.txt pins psycopg 3 and no psycopg2, so a clean install against
|
|
the URL Render hands out — the same form docs/database-restore.md documents
|
|
— fails before the first request:
|
|
|
|
ModuleNotFoundError: No module named 'psycopg2'
|
|
|
|
create_app() now names the driver. These tests pin that down, and the last
|
|
one proves the failure is real rather than theoretical.
|
|
"""
|
|
|
|
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%40s[email protected]:5432/tryouts?sslmode=require'
|
|
)
|
|
assert result == ('postgresql+psycopg://u:p%40s[email protected]: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:[email protected]: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 TestTheFailureIsReal:
|
|
"""Not a hypothetical: this is what the deployed configuration did."""
|
|
|
|
def test_psycopg2_is_not_installed(self):
|
|
with pytest.raises(ImportError):
|
|
import psycopg2 # noqa: F401
|
|
|
|
def test_a_driverless_url_cannot_build_an_engine(self):
|
|
with pytest.raises(ModuleNotFoundError):
|
|
create_engine('postgresql://u:p@host/db')
|
|
|
|
def test_the_normalised_url_can(self):
|
|
engine = create_engine(normalise_database_url('postgresql://u:p@host/db'))
|
|
assert engine.dialect.driver == 'psycopg'
|