|
| 1 | +import pytest |
| 2 | +from pydantic import BaseModel, Field |
| 3 | +from memstate import MemoryStore, InMemoryStorage |
| 4 | + |
| 5 | + |
| 6 | +class UserProfileV1(BaseModel): |
| 7 | + username: str |
| 8 | + # the `role` field is missing yet |
| 9 | + |
| 10 | + |
| 11 | +class UserProfileV2(BaseModel): |
| 12 | + username: str |
| 13 | + role: str = Field(default="user") |
| 14 | + |
| 15 | + |
| 16 | +class UserProfileV3_Strict(BaseModel): |
| 17 | + username: str |
| 18 | + age: int # a new field without a default value |
| 19 | + |
| 20 | + |
| 21 | +class UserProfileV4(BaseModel): |
| 22 | + username: str |
| 23 | + |
| 24 | + |
| 25 | +@pytest.fixture |
| 26 | +def memory(): |
| 27 | + return MemoryStore(InMemoryStorage()) |
| 28 | + |
| 29 | + |
| 30 | +def test_schema_evolution_adding_field_with_default(memory): |
| 31 | + memory.register_schema("user", UserProfileV1) |
| 32 | + |
| 33 | + id_v1 = memory.commit_model(UserProfileV1(username="legacy_user")) |
| 34 | + |
| 35 | + memory.register_schema("user", UserProfileV2) |
| 36 | + |
| 37 | + fact_data = memory.storage.load(id_v1) |
| 38 | + raw_payload = fact_data["payload"] |
| 39 | + |
| 40 | + user_obj = UserProfileV2(**raw_payload) |
| 41 | + |
| 42 | + assert user_obj.username == "legacy_user" |
| 43 | + assert user_obj.role == "user" |
| 44 | + |
| 45 | + id_v2 = memory.commit_model(UserProfileV2(username="new_user", role="admin")) |
| 46 | + |
| 47 | + raw_payload_v2 = memory.storage.load(id_v2)["payload"] |
| 48 | + assert raw_payload_v2["role"] == "admin" |
| 49 | + |
| 50 | + |
| 51 | +def test_schema_breaking_change(memory): |
| 52 | + memory.register_schema("user", UserProfileV1) |
| 53 | + id_v1 = memory.commit_model(UserProfileV1(username="young_user")) |
| 54 | + |
| 55 | + memory.register_schema("user", UserProfileV3_Strict) |
| 56 | + |
| 57 | + fact_data = memory.storage.load(id_v1) |
| 58 | + |
| 59 | + with pytest.raises(ValueError) as excinfo: |
| 60 | + UserProfileV3_Strict(**fact_data["payload"]) |
| 61 | + |
| 62 | + assert "age" in str(excinfo.value) |
| 63 | + assert "Field required" in str(excinfo.value) |
| 64 | + |
| 65 | + |
| 66 | +def test_loading_rich_data_into_slim_model(memory): |
| 67 | + memory.register_schema("user", UserProfileV2) |
| 68 | + rich_id = memory.commit_model(UserProfileV2(username="rich_user", role="admin")) |
| 69 | + |
| 70 | + memory.register_schema("user", UserProfileV4) |
| 71 | + |
| 72 | + fact_data = memory.storage.load(rich_id) |
| 73 | + |
| 74 | + user_obj = UserProfileV4(**fact_data["payload"]) |
| 75 | + |
| 76 | + assert user_obj.username == "rich_user" |
| 77 | + assert not hasattr(user_obj, "role") |
0 commit comments