Fix SQLite UUID and server_default incompatibilities in test fixtures
CI / lint (pull_request) Failing after 7s
CI / typecheck (pull_request) Failing after 48s
CI / test (pull_request) Failing after 1m35s
CI / build-and-push (pull_request) Has been skipped

Adds SQLiteCompatibleUUID TypeDecorator and _StringUUID fallback to handle
PostgreSQL UUID and Text PK columns when using SQLite test database.

- SQLiteCompatibleUUID: converts uuid.UUID to CHAR(32) hex string for bind,
  returns uuid.UUID on result fetch
- _StringUUID: handles Text PK/FK columns that tests bind UUID values into
- _adapt_uuid_columns_for_sqlite: replaces PostgresUUID column types
- _adapt_text_pk_columns_for_uuid: replaces Text PK types
- _adapt_fk_columns_for_uuid: replaces Text FK types
- _strip_postgres_server_defaults: removes gen_random_uuid/gen_random_bytes
  server_defaults that SQLite can't evaluate

Updates test_encrypted_json.py fixtures to use shared conftest engine
and pass explicit UUID for User records.

Fixes CAR-1111.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Flea Flicker
2026-06-01 11:37:05 +00:00
parent 84c143c4e7
commit 8c78fde48d
4 changed files with 940 additions and 76 deletions
+7 -20
View File
@@ -1,11 +1,12 @@
"""Tests for EncryptedJSON TypeDecorator and session_data encryption."""
import json
import uuid as uuid_lib
import pytest
from cryptography.fernet import Fernet
from pydantic import ValidationError
from sqlalchemy import column, create_engine, table, text
from sqlalchemy import column, table, text
from sqlalchemy.orm import sessionmaker
from cartsnitch_api.config import settings
@@ -15,27 +16,13 @@ from cartsnitch_api.models.user import User, UserStoreAccount
@pytest.fixture
def engine():
eng = create_engine("sqlite:///:memory:")
for table in Base.metadata.tables.values():
for col in table.columns.values():
sd = col.server_default
if sd is not None:
expr_str = str(sd.expression).lower()
if "gen_random_uuid" in expr_str or "gen_random_bytes" in expr_str:
col.server_default = None
Base.metadata.create_all(eng)
yield eng
eng.dispose()
def engine(engine):
yield engine
@pytest.fixture
def session(engine):
factory = sessionmaker(bind=engine)
with factory() as sess:
yield sess
def session(session):
yield session
@pytest.fixture
@@ -49,7 +36,7 @@ def store(session):
@pytest.fixture
def user(session):
u = User(email="alice@example.com", hashed_password="fakehash")
u = User(id=uuid_lib.uuid4(), email="alice@example.com", hashed_password="fakehash")
session.add(u)
session.commit()
session.refresh(u)