litellm/tests/unit/proxy/test_db_schema_changes.py
joshua-berri 49f56e8b23
refactor(proxy)!: drop the unused accounting event tables (#49923)
LiteLLM_AccountingEvent and LiteLLM_AccountingDelivery have had no reader since
the SpendLogs projection replaced them, so the migration drops them with their
enums. AccountingDeliveryState stays because LiteLLM_SpendLogDelivery uses it

The schema now spells the delivery_id default the way Postgres stores it, which
ends the drift Prisma reported against the ledger migration. The schema check
compares base types only, so an attribute-only change is no longer reported as
a type change

Co-authored-by: Joshua Valluru <326636767+joshua-berri@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 20:23:30 -08:00

62 lines
2.7 KiB
Python

from typing import Final
import pytest
from scripts.check_schema_compatibility import check_breaking_changes, parse_model_fields
ORIGINAL: Final = "model Item {\n id String @id\n label String?\n}\n"
def test_aaaaaschema_compatibility() -> None:
added: Final = "model Item {\n id String @id\n label String?\n count Int?\n}\nmodel Extra {\n id String @id\n}\n"
assert check_breaking_changes(parse_model_fields(ORIGINAL), parse_model_fields(added)) == ()
def test_changing_only_a_field_attribute_is_not_breaking() -> None:
previous: Final = parse_model_fields('model Item {\n id String @id @default(dbgenerated("a()::text"))\n}\n')
current: Final = parse_model_fields('model Item {\n id String @id @default(dbgenerated("(a())::text"))\n}\n')
assert check_breaking_changes(previous, current) == ()
def test_parse_model_fields_retains_types_and_attributes() -> None:
assert parse_model_fields(ORIGINAL) == {"Item": {"id": "String @id", "label": "String?"}}
def test_parse_model_fields_keeps_json_defaults_and_empty_models() -> None:
schema: Final = 'model Item {\n data Json @default("{}")\n}\nmodel Empty {\n}\n'
assert parse_model_fields(schema) == {"Item": {"data": 'Json @default("{}")'}, "Empty": {}}
@pytest.mark.parametrize(
("schema", "expected"),
(
("", ("Breaking: Model Item was removed",)),
("model Item {\n id String @id\n}\n", ("Breaking: Field Item.label was removed",)),
(
"model Item {\n id String @id\n label String\n}\n",
("Breaking: Field Item.label changed from optional to required",),
),
(
"model Item {\n id String @id\n label Int?\n}\n",
("Breaking: Field Item.label changed type from String? to Int?",),
),
),
)
def test_schema_compatibility_rejects_removed_models_fields_and_narrowed_types(
schema: str, expected: tuple[str, ...]
) -> None:
assert check_breaking_changes(parse_model_fields(ORIGINAL), parse_model_fields(schema)) == expected
def test_only_the_dropped_accounting_models_may_be_removed() -> None:
accounting: Final = (
"model LiteLLM_AccountingEvent {\n event_id String @id\n}\n"
"model LiteLLM_AccountingDelivery {\n event_id String\n note String?\n}\n"
)
previous: Final = parse_model_fields(ORIGINAL + accounting)
assert check_breaking_changes(previous, parse_model_fields(ORIGINAL)) == ()
assert check_breaking_changes(previous, parse_model_fields("")) == ("Breaking: Model Item was removed",)
assert check_breaking_changes(
previous, parse_model_fields(ORIGINAL + "model LiteLLM_AccountingDelivery {\n event_id String\n}\n")
) == ("Breaking: Field LiteLLM_AccountingDelivery.note was removed",)