mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
e0d8aeb149
Signed-off-by: phernandez <paul@basicmachines.co> Signed-off-by: Drew Cain <groksrc@gmail.com> Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Drew Cain <groksrc@gmail.com>
240 lines
8.4 KiB
Python
240 lines
8.4 KiB
Python
"""Tests for datetime serialization in memory schema models."""
|
|
|
|
import json
|
|
from datetime import datetime
|
|
|
|
|
|
from basic_memory.schemas.memory import (
|
|
EntitySummary,
|
|
RelationSummary,
|
|
ObservationSummary,
|
|
MemoryMetadata,
|
|
GraphContext,
|
|
ContextResult,
|
|
)
|
|
|
|
|
|
class TestDateTimeSerialization:
|
|
"""Test datetime serialization for MCP schema compliance."""
|
|
|
|
def test_entity_summary_datetime_serialization(self):
|
|
"""Test EntitySummary serializes datetime as ISO format string."""
|
|
test_datetime = datetime(2023, 12, 8, 10, 30, 0)
|
|
|
|
entity = EntitySummary(
|
|
permalink="test/entity",
|
|
title="Test Entity",
|
|
file_path="test/entity.md",
|
|
created_at=test_datetime,
|
|
)
|
|
|
|
# Test model_dump_json() produces ISO format
|
|
json_str = entity.model_dump_json()
|
|
data = json.loads(json_str)
|
|
|
|
assert data["created_at"] == "2023-12-08T10:30:00"
|
|
assert data["type"] == "entity"
|
|
assert data["title"] == "Test Entity"
|
|
|
|
def test_relation_summary_datetime_serialization(self):
|
|
"""Test RelationSummary serializes datetime as ISO format string."""
|
|
test_datetime = datetime(2023, 12, 8, 15, 45, 30)
|
|
|
|
relation = RelationSummary(
|
|
title="Test Relation",
|
|
file_path="test/relation.md",
|
|
permalink="test/relation",
|
|
relation_type="relates_to",
|
|
from_entity="entity1",
|
|
to_entity="entity2",
|
|
created_at=test_datetime,
|
|
)
|
|
|
|
# Test model_dump_json() produces ISO format
|
|
json_str = relation.model_dump_json()
|
|
data = json.loads(json_str)
|
|
|
|
assert data["created_at"] == "2023-12-08T15:45:30"
|
|
assert data["type"] == "relation"
|
|
assert data["relation_type"] == "relates_to"
|
|
|
|
def test_observation_summary_datetime_serialization(self):
|
|
"""Test ObservationSummary serializes datetime as ISO format string."""
|
|
test_datetime = datetime(2023, 12, 8, 20, 15, 45)
|
|
|
|
observation = ObservationSummary(
|
|
title="Test Observation",
|
|
file_path="test/observation.md",
|
|
permalink="test/observation",
|
|
category="note",
|
|
content="Test content",
|
|
created_at=test_datetime,
|
|
)
|
|
|
|
# Test model_dump_json() produces ISO format
|
|
json_str = observation.model_dump_json()
|
|
data = json.loads(json_str)
|
|
|
|
assert data["created_at"] == "2023-12-08T20:15:45"
|
|
assert data["type"] == "observation"
|
|
assert data["category"] == "note"
|
|
|
|
def test_memory_metadata_datetime_serialization(self):
|
|
"""Test MemoryMetadata serializes datetime as ISO format string."""
|
|
test_datetime = datetime(2023, 12, 8, 12, 0, 0)
|
|
|
|
metadata = MemoryMetadata(
|
|
depth=2, generated_at=test_datetime, primary_count=5, related_count=3
|
|
)
|
|
|
|
# Test model_dump_json() produces ISO format
|
|
json_str = metadata.model_dump_json()
|
|
data = json.loads(json_str)
|
|
|
|
assert data["generated_at"] == "2023-12-08T12:00:00"
|
|
assert data["depth"] == 2
|
|
assert data["primary_count"] == 5
|
|
|
|
def test_context_result_with_datetime_serialization(self):
|
|
"""Test ContextResult with nested models serializes datetime correctly."""
|
|
test_datetime = datetime(2023, 12, 8, 9, 30, 15)
|
|
|
|
entity = EntitySummary(
|
|
permalink="test/entity",
|
|
title="Test Entity",
|
|
file_path="test/entity.md",
|
|
created_at=test_datetime,
|
|
)
|
|
|
|
observation = ObservationSummary(
|
|
title="Test Observation",
|
|
file_path="test/observation.md",
|
|
permalink="test/observation",
|
|
category="note",
|
|
content="Test content",
|
|
created_at=test_datetime,
|
|
)
|
|
|
|
context_result = ContextResult(
|
|
primary_result=entity, observations=[observation], related_results=[]
|
|
)
|
|
|
|
# Test model_dump_json() produces ISO format for nested models
|
|
json_str = context_result.model_dump_json()
|
|
data = json.loads(json_str)
|
|
|
|
assert data["primary_result"]["created_at"] == "2023-12-08T09:30:15"
|
|
assert data["observations"][0]["created_at"] == "2023-12-08T09:30:15"
|
|
|
|
def test_graph_context_full_serialization(self):
|
|
"""Test full GraphContext serialization with all datetime fields."""
|
|
test_datetime = datetime(2023, 12, 8, 14, 20, 10)
|
|
|
|
entity = EntitySummary(
|
|
permalink="test/entity",
|
|
title="Test Entity",
|
|
file_path="test/entity.md",
|
|
created_at=test_datetime,
|
|
)
|
|
|
|
metadata = MemoryMetadata(
|
|
depth=1, generated_at=test_datetime, primary_count=1, related_count=0
|
|
)
|
|
|
|
context_result = ContextResult(primary_result=entity, observations=[], related_results=[])
|
|
|
|
graph_context = GraphContext(
|
|
results=[context_result], metadata=metadata, page=1, page_size=10
|
|
)
|
|
|
|
# Test full serialization
|
|
json_str = graph_context.model_dump_json()
|
|
data = json.loads(json_str)
|
|
|
|
assert data["metadata"]["generated_at"] == "2023-12-08T14:20:10"
|
|
assert data["results"][0]["primary_result"]["created_at"] == "2023-12-08T14:20:10"
|
|
|
|
def test_datetime_with_microseconds_serialization(self):
|
|
"""Test datetime with microseconds serializes correctly."""
|
|
test_datetime = datetime(2023, 12, 8, 10, 30, 0, 123456)
|
|
|
|
entity = EntitySummary(
|
|
permalink="test/entity",
|
|
title="Test Entity",
|
|
file_path="test/entity.md",
|
|
created_at=test_datetime,
|
|
)
|
|
|
|
json_str = entity.model_dump_json()
|
|
data = json.loads(json_str)
|
|
|
|
# Should include microseconds in ISO format
|
|
assert data["created_at"] == "2023-12-08T10:30:00.123456"
|
|
|
|
def test_mcp_schema_validation_compatibility(self):
|
|
"""Test that serialized datetime format is compatible with MCP schema validation."""
|
|
test_datetime = datetime(2023, 12, 8, 10, 30, 0)
|
|
|
|
entity = EntitySummary(
|
|
permalink="test/entity",
|
|
title="Test Entity",
|
|
file_path="test/entity.md",
|
|
created_at=test_datetime,
|
|
)
|
|
|
|
# Serialize to JSON
|
|
json_str = entity.model_dump_json()
|
|
data = json.loads(json_str)
|
|
|
|
# Verify the format matches expected MCP "date-time" format
|
|
datetime_str = data["created_at"]
|
|
|
|
# Should be parseable back to datetime (ISO format validation)
|
|
parsed_datetime = datetime.fromisoformat(datetime_str)
|
|
assert parsed_datetime == test_datetime
|
|
|
|
# Should match the expected ISO format pattern
|
|
assert "T" in datetime_str # Contains date-time separator
|
|
assert len(datetime_str) >= 19 # At least YYYY-MM-DDTHH:MM:SS format
|
|
|
|
def test_all_models_have_datetime_serializers_configured(self):
|
|
"""Test that all memory schema models have datetime field serializers configured."""
|
|
models_to_test = [
|
|
(EntitySummary, "created_at"),
|
|
(RelationSummary, "created_at"),
|
|
(ObservationSummary, "created_at"),
|
|
(MemoryMetadata, "generated_at"),
|
|
]
|
|
|
|
for model_class, datetime_field in models_to_test:
|
|
# Create a test instance with a datetime field
|
|
test_datetime = datetime(2023, 12, 8, 10, 30, 0)
|
|
|
|
if model_class == EntitySummary:
|
|
instance = model_class(
|
|
permalink="test", title="Test", file_path="test.md", created_at=test_datetime
|
|
)
|
|
elif model_class == RelationSummary:
|
|
instance = model_class(
|
|
title="Test",
|
|
file_path="test.md",
|
|
permalink="test",
|
|
relation_type="test",
|
|
created_at=test_datetime,
|
|
)
|
|
elif model_class == ObservationSummary:
|
|
instance = model_class(
|
|
title="Test",
|
|
file_path="test.md",
|
|
permalink="test",
|
|
category="test",
|
|
content="Test",
|
|
created_at=test_datetime,
|
|
)
|
|
elif model_class == MemoryMetadata:
|
|
instance = model_class(depth=1, generated_at=test_datetime)
|
|
|
|
# Test that model_dump produces ISO format for datetime field
|
|
data = instance.model_dump()
|
|
assert data[datetime_field] == "2023-12-08T10:30:00"
|