1+ """Tests for datetime serialization in memory schema models."""
2+
3+ import json
4+ from datetime import datetime
5+
6+ import pytest
7+
8+ from basic_memory .schemas .memory import (
9+ EntitySummary ,
10+ RelationSummary ,
11+ ObservationSummary ,
12+ MemoryMetadata ,
13+ GraphContext ,
14+ ContextResult
15+ )
16+
17+
18+ class TestDateTimeSerialization :
19+ """Test datetime serialization for MCP schema compliance."""
20+
21+ def test_entity_summary_datetime_serialization (self ):
22+ """Test EntitySummary serializes datetime as ISO format string."""
23+ test_datetime = datetime (2023 , 12 , 8 , 10 , 30 , 0 )
24+
25+ entity = EntitySummary (
26+ permalink = "test/entity" ,
27+ title = "Test Entity" ,
28+ file_path = "test/entity.md" ,
29+ created_at = test_datetime
30+ )
31+
32+ # Test model_dump_json() produces ISO format
33+ json_str = entity .model_dump_json ()
34+ data = json .loads (json_str )
35+
36+ assert data ["created_at" ] == "2023-12-08T10:30:00"
37+ assert data ["type" ] == "entity"
38+ assert data ["title" ] == "Test Entity"
39+
40+ def test_relation_summary_datetime_serialization (self ):
41+ """Test RelationSummary serializes datetime as ISO format string."""
42+ test_datetime = datetime (2023 , 12 , 8 , 15 , 45 , 30 )
43+
44+ relation = RelationSummary (
45+ title = "Test Relation" ,
46+ file_path = "test/relation.md" ,
47+ permalink = "test/relation" ,
48+ relation_type = "relates_to" ,
49+ from_entity = "entity1" ,
50+ to_entity = "entity2" ,
51+ created_at = test_datetime
52+ )
53+
54+ # Test model_dump_json() produces ISO format
55+ json_str = relation .model_dump_json ()
56+ data = json .loads (json_str )
57+
58+ assert data ["created_at" ] == "2023-12-08T15:45:30"
59+ assert data ["type" ] == "relation"
60+ assert data ["relation_type" ] == "relates_to"
61+
62+ def test_observation_summary_datetime_serialization (self ):
63+ """Test ObservationSummary serializes datetime as ISO format string."""
64+ test_datetime = datetime (2023 , 12 , 8 , 20 , 15 , 45 )
65+
66+ observation = ObservationSummary (
67+ title = "Test Observation" ,
68+ file_path = "test/observation.md" ,
69+ permalink = "test/observation" ,
70+ category = "note" ,
71+ content = "Test content" ,
72+ created_at = test_datetime
73+ )
74+
75+ # Test model_dump_json() produces ISO format
76+ json_str = observation .model_dump_json ()
77+ data = json .loads (json_str )
78+
79+ assert data ["created_at" ] == "2023-12-08T20:15:45"
80+ assert data ["type" ] == "observation"
81+ assert data ["category" ] == "note"
82+
83+ def test_memory_metadata_datetime_serialization (self ):
84+ """Test MemoryMetadata serializes datetime as ISO format string."""
85+ test_datetime = datetime (2023 , 12 , 8 , 12 , 0 , 0 )
86+
87+ metadata = MemoryMetadata (
88+ depth = 2 ,
89+ generated_at = test_datetime ,
90+ primary_count = 5 ,
91+ related_count = 3
92+ )
93+
94+ # Test model_dump_json() produces ISO format
95+ json_str = metadata .model_dump_json ()
96+ data = json .loads (json_str )
97+
98+ assert data ["generated_at" ] == "2023-12-08T12:00:00"
99+ assert data ["depth" ] == 2
100+ assert data ["primary_count" ] == 5
101+
102+ def test_context_result_with_datetime_serialization (self ):
103+ """Test ContextResult with nested models serializes datetime correctly."""
104+ test_datetime = datetime (2023 , 12 , 8 , 9 , 30 , 15 )
105+
106+ entity = EntitySummary (
107+ permalink = "test/entity" ,
108+ title = "Test Entity" ,
109+ file_path = "test/entity.md" ,
110+ created_at = test_datetime
111+ )
112+
113+ observation = ObservationSummary (
114+ title = "Test Observation" ,
115+ file_path = "test/observation.md" ,
116+ permalink = "test/observation" ,
117+ category = "note" ,
118+ content = "Test content" ,
119+ created_at = test_datetime
120+ )
121+
122+ context_result = ContextResult (
123+ primary_result = entity ,
124+ observations = [observation ],
125+ related_results = []
126+ )
127+
128+ # Test model_dump_json() produces ISO format for nested models
129+ json_str = context_result .model_dump_json ()
130+ data = json .loads (json_str )
131+
132+ assert data ["primary_result" ]["created_at" ] == "2023-12-08T09:30:15"
133+ assert data ["observations" ][0 ]["created_at" ] == "2023-12-08T09:30:15"
134+
135+ def test_graph_context_full_serialization (self ):
136+ """Test full GraphContext serialization with all datetime fields."""
137+ test_datetime = datetime (2023 , 12 , 8 , 14 , 20 , 10 )
138+
139+ entity = EntitySummary (
140+ permalink = "test/entity" ,
141+ title = "Test Entity" ,
142+ file_path = "test/entity.md" ,
143+ created_at = test_datetime
144+ )
145+
146+ metadata = MemoryMetadata (
147+ depth = 1 ,
148+ generated_at = test_datetime ,
149+ primary_count = 1 ,
150+ related_count = 0
151+ )
152+
153+ context_result = ContextResult (
154+ primary_result = entity ,
155+ observations = [],
156+ related_results = []
157+ )
158+
159+ graph_context = GraphContext (
160+ results = [context_result ],
161+ metadata = metadata ,
162+ page = 1 ,
163+ page_size = 10
164+ )
165+
166+ # Test full serialization
167+ json_str = graph_context .model_dump_json ()
168+ data = json .loads (json_str )
169+
170+ assert data ["metadata" ]["generated_at" ] == "2023-12-08T14:20:10"
171+ assert data ["results" ][0 ]["primary_result" ]["created_at" ] == "2023-12-08T14:20:10"
172+
173+ def test_datetime_with_microseconds_serialization (self ):
174+ """Test datetime with microseconds serializes correctly."""
175+ test_datetime = datetime (2023 , 12 , 8 , 10 , 30 , 0 , 123456 )
176+
177+ entity = EntitySummary (
178+ permalink = "test/entity" ,
179+ title = "Test Entity" ,
180+ file_path = "test/entity.md" ,
181+ created_at = test_datetime
182+ )
183+
184+ json_str = entity .model_dump_json ()
185+ data = json .loads (json_str )
186+
187+ # Should include microseconds in ISO format
188+ assert data ["created_at" ] == "2023-12-08T10:30:00.123456"
189+
190+ def test_mcp_schema_validation_compatibility (self ):
191+ """Test that serialized datetime format is compatible with MCP schema validation."""
192+ test_datetime = datetime (2023 , 12 , 8 , 10 , 30 , 0 )
193+
194+ entity = EntitySummary (
195+ permalink = "test/entity" ,
196+ title = "Test Entity" ,
197+ file_path = "test/entity.md" ,
198+ created_at = test_datetime
199+ )
200+
201+ # Serialize to JSON
202+ json_str = entity .model_dump_json ()
203+ data = json .loads (json_str )
204+
205+ # Verify the format matches expected MCP "date-time" format
206+ datetime_str = data ["created_at" ]
207+
208+ # Should be parseable back to datetime (ISO format validation)
209+ parsed_datetime = datetime .fromisoformat (datetime_str )
210+ assert parsed_datetime == test_datetime
211+
212+ # Should match the expected ISO format pattern
213+ assert "T" in datetime_str # Contains date-time separator
214+ assert len (datetime_str ) >= 19 # At least YYYY-MM-DDTHH:MM:SS format
215+
216+ def test_all_models_have_json_encoders_configured (self ):
217+ """Test that all memory schema models have datetime json_encoders configured."""
218+ models_to_test = [
219+ EntitySummary ,
220+ RelationSummary ,
221+ ObservationSummary ,
222+ MemoryMetadata
223+ ]
224+
225+ for model_class in models_to_test :
226+ # Check that ConfigDict with json_encoders is configured
227+ assert hasattr (model_class , 'model_config' )
228+ assert 'json_encoders' in model_class .model_config
229+ assert datetime in model_class .model_config ['json_encoders' ]
230+
231+ # Verify the encoder function produces ISO format
232+ encoder = model_class .model_config ['json_encoders' ][datetime ]
233+ test_datetime = datetime (2023 , 12 , 8 , 10 , 30 , 0 )
234+ result = encoder (test_datetime )
235+ assert result == "2023-12-08T10:30:00"
0 commit comments