94 lines
3.3 KiB
Python
94 lines
3.3 KiB
Python
"""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%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 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'
|