graphiti/tests/utils/maintenance/test_temporal_operations_int.py
Daniel Chalef 73ec0146ff
ruff action (#17)
* ruff action

* chore: Update Python version to 3.10 in lint.yml workflow

* fix lint and formatting

* cleanup
2024-08-22 13:06:42 -07:00

293 lines
7.1 KiB
Python

import os
from datetime import datetime, timedelta
import pytest
from dotenv import load_dotenv
from core.edges import EntityEdge
from core.llm_client import LLMConfig, OpenAIClient
from core.nodes import EntityNode
from core.utils.maintenance.temporal_operations import (
invalidate_edges,
)
load_dotenv()
def setup_llm_client():
return OpenAIClient(
LLMConfig(
api_key=os.getenv('TEST_OPENAI_API_KEY'),
model=os.getenv('TEST_OPENAI_MODEL'),
base_url='https://api.openai.com/v1',
)
)
# Helper function to create test data
def create_test_data():
now = datetime.now()
# Create nodes
node1 = EntityNode(uuid='1', name='Alice', labels=['Person'], created_at=now)
node2 = EntityNode(uuid='2', name='Bob', labels=['Person'], created_at=now)
# Create edges
edge1 = EntityEdge(
uuid='e1',
source_node_uuid='1',
target_node_uuid='2',
name='LIKES',
fact='Alice likes Bob',
created_at=now - timedelta(days=1),
)
edge2 = EntityEdge(
uuid='e2',
source_node_uuid='1',
target_node_uuid='2',
name='DISLIKES',
fact='Alice dislikes Bob',
created_at=now,
)
existing_edge = (node1, edge1, node2)
new_edge = (node1, edge2, node2)
return existing_edge, new_edge
@pytest.mark.asyncio
@pytest.mark.integration
async def test_invalidate_edges():
existing_edge, new_edge = create_test_data()
invalidated_edges = await invalidate_edges(setup_llm_client(), [existing_edge], [new_edge])
assert len(invalidated_edges) == 1
assert invalidated_edges[0].uuid == existing_edge[1].uuid
assert invalidated_edges[0].expired_at is not None
@pytest.mark.asyncio
@pytest.mark.integration
async def test_invalidate_edges_no_invalidation():
existing_edge, _ = create_test_data()
invalidated_edges = await invalidate_edges(setup_llm_client(), [existing_edge], [])
assert len(invalidated_edges) == 0
@pytest.mark.asyncio
@pytest.mark.integration
async def test_invalidate_edges_multiple_existing():
existing_edge1, new_edge = create_test_data()
existing_edge2, _ = create_test_data()
existing_edge2[1].uuid = 'e3'
existing_edge2[1].name = 'KNOWS'
existing_edge2[1].fact = 'Alice knows Bob'
invalidated_edges = await invalidate_edges(
setup_llm_client(), [existing_edge1, existing_edge2], [new_edge]
)
assert len(invalidated_edges) == 1
assert invalidated_edges[0].uuid == existing_edge1[1].uuid
assert invalidated_edges[0].expired_at is not None
# Helper function to create more complex test data
def create_complex_test_data():
now = datetime.now()
# Create nodes
node1 = EntityNode(uuid='1', name='Alice', labels=['Person'], created_at=now)
node2 = EntityNode(uuid='2', name='Bob', labels=['Person'], created_at=now)
node3 = EntityNode(uuid='3', name='Charlie', labels=['Person'], created_at=now)
node4 = EntityNode(uuid='4', name='Company XYZ', labels=['Organization'], created_at=now)
# Create edges
edge1 = EntityEdge(
uuid='e1',
source_node_uuid='1',
target_node_uuid='2',
name='LIKES',
fact='Alice likes Bob',
created_at=now - timedelta(days=5),
)
edge2 = EntityEdge(
uuid='e2',
source_node_uuid='1',
target_node_uuid='3',
name='FRIENDS_WITH',
fact='Alice is friends with Charlie',
created_at=now - timedelta(days=3),
)
edge3 = EntityEdge(
uuid='e3',
source_node_uuid='2',
target_node_uuid='4',
name='WORKS_FOR',
fact='Bob works for Company XYZ',
created_at=now - timedelta(days=2),
)
existing_edge1 = (node1, edge1, node2)
existing_edge2 = (node1, edge2, node3)
existing_edge3 = (node2, edge3, node4)
return [existing_edge1, existing_edge2, existing_edge3], [
node1,
node2,
node3,
node4,
]
@pytest.mark.asyncio
@pytest.mark.integration
async def test_invalidate_edges_complex():
existing_edges, nodes = create_complex_test_data()
# Create a new edge that contradicts an existing one
new_edge = (
nodes[0],
EntityEdge(
uuid='e4',
source_node_uuid='1',
target_node_uuid='2',
name='DISLIKES',
fact='Alice dislikes Bob',
created_at=datetime.now(),
),
nodes[1],
)
invalidated_edges = await invalidate_edges(setup_llm_client(), existing_edges, [new_edge])
assert len(invalidated_edges) == 1
assert invalidated_edges[0].uuid == 'e1'
assert invalidated_edges[0].expired_at is not None
@pytest.mark.asyncio
@pytest.mark.integration
async def test_invalidate_edges_temporal_update():
existing_edges, nodes = create_complex_test_data()
# Create a new edge that updates an existing one with new information
new_edge = (
nodes[1],
EntityEdge(
uuid='e5',
source_node_uuid='2',
target_node_uuid='4',
name='LEFT_JOB',
fact='Bob left his job at Company XYZ',
created_at=datetime.now(),
),
nodes[3],
)
invalidated_edges = await invalidate_edges(setup_llm_client(), existing_edges, [new_edge])
assert len(invalidated_edges) == 1
assert invalidated_edges[0].uuid == 'e3'
assert invalidated_edges[0].expired_at is not None
@pytest.mark.asyncio
@pytest.mark.integration
async def test_invalidate_edges_multiple_invalidations():
existing_edges, nodes = create_complex_test_data()
# Create new edges that invalidate multiple existing edges
new_edge1 = (
nodes[0],
EntityEdge(
uuid='e6',
source_node_uuid='1',
target_node_uuid='2',
name='ENEMIES_WITH',
fact='Alice and Bob are now enemies',
created_at=datetime.now(),
),
nodes[1],
)
new_edge2 = (
nodes[0],
EntityEdge(
uuid='e7',
source_node_uuid='1',
target_node_uuid='3',
name='ENDED_FRIENDSHIP',
fact='Alice ended her friendship with Charlie',
created_at=datetime.now(),
),
nodes[2],
)
invalidated_edges = await invalidate_edges(
setup_llm_client(), existing_edges, [new_edge1, new_edge2]
)
assert len(invalidated_edges) == 2
assert set(edge.uuid for edge in invalidated_edges) == {'e1', 'e2'}
for edge in invalidated_edges:
assert edge.expired_at is not None
@pytest.mark.asyncio
@pytest.mark.integration
async def test_invalidate_edges_no_effect():
existing_edges, nodes = create_complex_test_data()
# Create a new edge that doesn't invalidate any existing edges
new_edge = (
nodes[2],
EntityEdge(
uuid='e8',
source_node_uuid='3',
target_node_uuid='4',
name='APPLIED_TO',
fact='Charlie applied to Company XYZ',
created_at=datetime.now(),
),
nodes[3],
)
invalidated_edges = await invalidate_edges(setup_llm_client(), existing_edges, [new_edge])
assert len(invalidated_edges) == 0
@pytest.mark.asyncio
@pytest.mark.integration
async def test_invalidate_edges_partial_update():
existing_edges, nodes = create_complex_test_data()
# Create a new edge that partially updates an existing one
new_edge = (
nodes[1],
EntityEdge(
uuid='e9',
source_node_uuid='2',
target_node_uuid='4',
name='CHANGED_POSITION',
fact='Bob changed his position at Company XYZ',
created_at=datetime.now(),
),
nodes[3],
)
invalidated_edges = await invalidate_edges(setup_llm_client(), existing_edges, [new_edge])
assert len(invalidated_edges) == 0 # The existing edge is not invalidated, just updated
@pytest.mark.asyncio
@pytest.mark.integration
async def test_invalidate_edges_empty_inputs():
invalidated_edges = await invalidate_edges(setup_llm_client(), [], [])
assert len(invalidated_edges) == 0