from datetime import datetime, timedelta import pytest from core.edges import EntityEdge from core.nodes import EntityNode from core.utils.maintenance.temporal_operations import ( prepare_edges_for_invalidation, prepare_invalidation_context, ) # Helper function to create test data def create_test_data(): now = datetime.now() # Create nodes node1 = EntityNode(uuid="1", name="Node1", labels=["Person"], created_at=now) node2 = EntityNode(uuid="2", name="Node2", labels=["Person"], created_at=now) node3 = EntityNode(uuid="3", name="Node3", labels=["Person"], created_at=now) # Create edges existing_edge1 = EntityEdge( uuid="e1", source_node_uuid="1", target_node_uuid="2", name="KNOWS", fact="Node1 knows Node2", created_at=now, ) existing_edge2 = EntityEdge( uuid="e2", source_node_uuid="2", target_node_uuid="3", name="LIKES", fact="Node2 likes Node3", created_at=now, ) new_edge1 = EntityEdge( uuid="e3", source_node_uuid="1", target_node_uuid="3", name="WORKS_WITH", fact="Node1 works with Node3", created_at=now, ) new_edge2 = EntityEdge( uuid="e4", source_node_uuid="1", target_node_uuid="2", name="DISLIKES", fact="Node1 dislikes Node2", created_at=now, ) return { "nodes": [node1, node2, node3], "existing_edges": [existing_edge1, existing_edge2], "new_edges": [new_edge1, new_edge2], } def test_prepare_edges_for_invalidation_basic(): test_data = create_test_data() existing_edges_pending_invalidation, new_edges_with_nodes = ( prepare_edges_for_invalidation( test_data["existing_edges"], test_data["new_edges"], test_data["nodes"] ) ) assert len(existing_edges_pending_invalidation) == 2 assert len(new_edges_with_nodes) == 2 # Check if the edges are correctly associated with nodes for edge_with_nodes in existing_edges_pending_invalidation + new_edges_with_nodes: assert isinstance(edge_with_nodes[0], EntityNode) assert isinstance(edge_with_nodes[1], EntityEdge) assert isinstance(edge_with_nodes[2], EntityNode) def test_prepare_edges_for_invalidation_no_existing_edges(): test_data = create_test_data() existing_edges_pending_invalidation, new_edges_with_nodes = ( prepare_edges_for_invalidation([], test_data["new_edges"], test_data["nodes"]) ) assert len(existing_edges_pending_invalidation) == 0 assert len(new_edges_with_nodes) == 2 def test_prepare_edges_for_invalidation_no_new_edges(): test_data = create_test_data() existing_edges_pending_invalidation, new_edges_with_nodes = ( prepare_edges_for_invalidation( test_data["existing_edges"], [], test_data["nodes"] ) ) assert len(existing_edges_pending_invalidation) == 2 assert len(new_edges_with_nodes) == 0 def test_prepare_edges_for_invalidation_missing_nodes(): test_data = create_test_data() # Remove one node to simulate a missing node scenario nodes = test_data["nodes"][:-1] existing_edges_pending_invalidation, new_edges_with_nodes = ( prepare_edges_for_invalidation( test_data["existing_edges"], test_data["new_edges"], nodes ) ) assert len(existing_edges_pending_invalidation) == 1 assert len(new_edges_with_nodes) == 1 def test_prepare_invalidation_context(): # Create test data now = datetime.now() # Create nodes node1 = EntityNode(uuid="1", name="Node1", labels=["Person"], created_at=now) node2 = EntityNode(uuid="2", name="Node2", labels=["Person"], created_at=now) node3 = EntityNode(uuid="3", name="Node3", labels=["Person"], created_at=now) # Create edges edge1 = EntityEdge( uuid="e1", source_node_uuid="1", target_node_uuid="2", name="KNOWS", fact="Node1 knows Node2", created_at=now, ) edge2 = EntityEdge( uuid="e2", source_node_uuid="2", target_node_uuid="3", name="LIKES", fact="Node2 likes Node3", created_at=now, ) # Create NodeEdgeNodeTriplet objects existing_edge = (node1, edge1, node2) new_edge = (node2, edge2, node3) # Prepare test input existing_edges = [existing_edge] new_edges = [new_edge] # Call the function result = prepare_invalidation_context(existing_edges, new_edges) # Assert the result assert isinstance(result, dict) assert "existing_edges" in result assert "new_edges" in result assert len(result["existing_edges"]) == 1 assert len(result["new_edges"]) == 1 # Check the format of the existing edge existing_edge_str = result["existing_edges"][0] assert edge1.uuid in existing_edge_str assert node1.name in existing_edge_str assert edge1.name in existing_edge_str assert node2.name in existing_edge_str assert edge1.created_at.isoformat() in existing_edge_str # Check the format of the new edge new_edge_str = result["new_edges"][0] assert edge2.uuid in new_edge_str assert node2.name in new_edge_str assert edge2.name in new_edge_str assert node3.name in new_edge_str assert edge2.created_at.isoformat() in new_edge_str def test_prepare_invalidation_context_empty_input(): result = prepare_invalidation_context([], []) assert isinstance(result, dict) assert "existing_edges" in result assert "new_edges" in result assert len(result["existing_edges"]) == 0 assert len(result["new_edges"]) == 0 def test_prepare_invalidation_context_sorting(): now = datetime.now() # Create nodes node1 = EntityNode(uuid="1", name="Node1", labels=["Person"], created_at=now) node2 = EntityNode(uuid="2", name="Node2", labels=["Person"], created_at=now) # Create edges with different timestamps edge1 = EntityEdge( uuid="e1", source_node_uuid="1", target_node_uuid="2", name="KNOWS", fact="Node1 knows Node2", created_at=now, ) edge2 = EntityEdge( uuid="e2", source_node_uuid="2", target_node_uuid="1", name="LIKES", fact="Node2 likes Node1", created_at=now + timedelta(hours=1), ) edge_with_nodes1 = (node1, edge1, node2) edge_with_nodes2 = (node2, edge2, node1) # Prepare test input existing_edges = [edge_with_nodes1, edge_with_nodes2] # Call the function result = prepare_invalidation_context(existing_edges, []) # Assert the result assert len(result["existing_edges"]) == 2 assert edge2.uuid in result["existing_edges"][0] # The newer edge should be first assert edge1.uuid in result["existing_edges"][1] # The older edge should be second # Run the tests if __name__ == "__main__": pytest.main([__file__])