Files
xer-mcp/tests/contract/test_list_relationships.py
Bill Ballou af8cdc1d31 feat: add driving flag to relationship query responses
Add computed driving flag to all relationship queries (list_relationships,
get_predecessors, get_successors). A relationship is marked as driving when
the predecessor's early end date plus lag determines the successor's early
start date.

Changes:
- Add early_start_date and early_end_date columns to activities schema
- Parse early dates from TASK table in XER files
- Implement is_driving_relationship() helper with 24hr tolerance for
  calendar gaps
- Update all relationship queries to compute and return driving flag
- Add contract and unit tests for driving flag functionality
- Update spec, contracts, and documentation
2026-01-07 07:21:58 -05:00

97 lines
3.3 KiB
Python

"""Contract tests for list_relationships MCP tool."""
from pathlib import Path
import pytest
from xer_mcp.db import db
@pytest.fixture(autouse=True)
def setup_db():
"""Initialize and clear database for each test."""
db.initialize()
yield
db.clear()
class TestListRelationshipsContract:
"""Contract tests verifying list_relationships tool interface."""
async def test_list_relationships_returns_paginated_results(
self, sample_xer_single_project: Path
) -> None:
"""list_relationships returns relationships with pagination metadata."""
from xer_mcp.tools.list_relationships import list_relationships
from xer_mcp.tools.load_xer import load_xer
await load_xer(file_path=str(sample_xer_single_project))
result = await list_relationships()
assert "relationships" in result
assert "pagination" in result
assert len(result["relationships"]) == 5
assert result["pagination"]["total_count"] == 5
async def test_list_relationships_with_pagination(
self, sample_xer_single_project: Path
) -> None:
"""list_relationships respects limit and offset parameters."""
from xer_mcp.tools.list_relationships import list_relationships
from xer_mcp.tools.load_xer import load_xer
await load_xer(file_path=str(sample_xer_single_project))
result = await list_relationships(limit=2, offset=0)
assert len(result["relationships"]) == 2
assert result["pagination"]["has_more"] is True
async def test_list_relationships_includes_expected_fields(
self, sample_xer_single_project: Path
) -> None:
"""list_relationships returns relationships with all expected fields."""
from xer_mcp.tools.list_relationships import list_relationships
from xer_mcp.tools.load_xer import load_xer
await load_xer(file_path=str(sample_xer_single_project))
result = await list_relationships()
rel = result["relationships"][0]
assert "task_pred_id" in rel
assert "task_id" in rel
assert "pred_task_id" in rel
assert "pred_type" in rel
assert "lag_hr_cnt" in rel
async def test_list_relationships_no_file_loaded_returns_error(self) -> None:
"""list_relationships without loaded file returns NO_FILE_LOADED error."""
from xer_mcp.server import set_file_loaded
from xer_mcp.tools.list_relationships import list_relationships
set_file_loaded(False)
result = await list_relationships()
assert "error" in result
assert result["error"]["code"] == "NO_FILE_LOADED"
async def test_list_relationships_includes_driving_flag(
self, sample_xer_single_project: Path
) -> None:
"""list_relationships returns relationships with driving flag."""
from xer_mcp.tools.list_relationships import list_relationships
from xer_mcp.tools.load_xer import load_xer
await load_xer(file_path=str(sample_xer_single_project))
result = await list_relationships()
assert "relationships" in result
assert len(result["relationships"]) > 0
# All relationships should have a driving flag
for rel in result["relationships"]:
assert "driving" in rel
assert isinstance(rel["driving"], bool)