Skip to main content
Glama
test_plan.py7.57 kB
"""Tests for plan tools.""" import pytest from pathfinder_mcp.state import Phase from pathfinder_mcp.tools.plan import save_plan, start_plan, validate_plan_structure class TestValidatePlanStructure: """Tests for plan validation.""" def test_valid_plan_passes(self, sample_plan_content: str) -> None: """Valid plan passes validation.""" is_valid, errors = validate_plan_structure(sample_plan_content) assert is_valid assert len(errors) == 0 def test_missing_frontmatter_fails(self) -> None: """Plan without frontmatter fails.""" content = "# Plan\n\n## Architecture Overview\n" is_valid, errors = validate_plan_structure(content) assert not is_valid assert any("frontmatter" in e.lower() for e in errors) def test_missing_sections_fails(self) -> None: """Plan without required sections fails.""" content = """--- name: Test overview: Test todos: [] --- # Plan ## Phase 1: Test """ is_valid, errors = validate_plan_structure(content) assert not is_valid # Should be missing Architecture Overview, Core Components, etc. assert len(errors) > 0 def test_missing_yaml_fields_fails(self) -> None: """Plan with incomplete YAML fails.""" content = """--- name: Test --- ## Architecture Overview ## Core Components ## Phase 1: Setup ## Implementation Details ## Success Criteria """ is_valid, errors = validate_plan_structure(content) assert not is_valid assert any("overview" in e.lower() for e in errors) class TestStartPlan: """Tests for start_plan tool.""" @pytest.mark.asyncio async def test_transitions_to_plan_phase( self, session_manager, artifact_writer, context_monitor, active_sessions, sample_session_id, research_state, ) -> None: """start_plan transitions from RESEARCH to PLAN.""" session_manager.create_session(sample_session_id) active_sessions[sample_session_id] = research_state artifact_writer.write_research(sample_session_id, "Findings", task="Task") result = await start_plan( session_id=sample_session_id, ctx=None, # Skip elicit session_manager=session_manager, artifact_writer=artifact_writer, context_monitor=context_monitor, sessions=active_sessions, ) assert result["phase"] == "plan" assert active_sessions[sample_session_id].current_phase == Phase.PLAN @pytest.mark.asyncio async def test_creates_plan_template( self, session_manager, artifact_writer, context_monitor, active_sessions, sample_session_id, research_state, ) -> None: """start_plan creates plan.md template.""" session_manager.create_session(sample_session_id) active_sessions[sample_session_id] = research_state artifact_writer.write_research(sample_session_id, "Findings", task="Task") await start_plan( session_id=sample_session_id, ctx=None, session_manager=session_manager, artifact_writer=artifact_writer, context_monitor=context_monitor, sessions=active_sessions, ) content = artifact_writer.read_artifact(sample_session_id, "plan.md") assert content is not None assert "---" in content # YAML frontmatter @pytest.mark.asyncio async def test_requires_research_artifact( self, session_manager, artifact_writer, context_monitor, active_sessions, sample_session_id, research_state, ) -> None: """start_plan fails without research.md.""" session_manager.create_session(sample_session_id) active_sessions[sample_session_id] = research_state # Don't create research artifact result = await start_plan( session_id=sample_session_id, ctx=None, session_manager=session_manager, artifact_writer=artifact_writer, context_monitor=context_monitor, sessions=active_sessions, ) assert result["code"] == "MISSING_RESEARCH" @pytest.mark.asyncio async def test_fails_from_wrong_phase( self, session_manager, artifact_writer, context_monitor, active_sessions, sample_session_id, plan_state, ) -> None: """start_plan fails when not in RESEARCH phase.""" session_manager.create_session(sample_session_id) active_sessions[sample_session_id] = plan_state result = await start_plan( session_id=sample_session_id, ctx=None, session_manager=session_manager, artifact_writer=artifact_writer, context_monitor=context_monitor, sessions=active_sessions, ) assert result["code"] == "INVALID_PHASE" class TestSavePlan: """Tests for save_plan tool.""" def test_saves_valid_plan( self, session_manager, artifact_writer, context_monitor, active_sessions, sample_session_id, plan_state, sample_plan_content, ) -> None: """save_plan saves valid plan content.""" session_manager.create_session(sample_session_id) active_sessions[sample_session_id] = plan_state result = save_plan( session_id=sample_session_id, plan_content=sample_plan_content, session_manager=session_manager, artifact_writer=artifact_writer, context_monitor=context_monitor, sessions=active_sessions, ) assert result["validated"] is True content = artifact_writer.read_artifact(sample_session_id, "plan.md") assert "Test Implementation Plan" in content def test_rejects_invalid_plan( self, session_manager, artifact_writer, context_monitor, active_sessions, sample_session_id, plan_state, ) -> None: """save_plan rejects invalid plan format.""" session_manager.create_session(sample_session_id) active_sessions[sample_session_id] = plan_state result = save_plan( session_id=sample_session_id, plan_content="# Invalid plan\n\nNo structure", session_manager=session_manager, artifact_writer=artifact_writer, context_monitor=context_monitor, sessions=active_sessions, ) assert result["code"] == "INVALID_PLAN_FORMAT" assert "validation_errors" in result def test_fails_from_wrong_phase( self, session_manager, artifact_writer, context_monitor, active_sessions, sample_session_id, research_state, sample_plan_content, ) -> None: """save_plan fails when not in PLAN phase.""" session_manager.create_session(sample_session_id) active_sessions[sample_session_id] = research_state result = save_plan( session_id=sample_session_id, plan_content=sample_plan_content, session_manager=session_manager, artifact_writer=artifact_writer, context_monitor=context_monitor, sessions=active_sessions, ) assert result["code"] == "INVALID_PHASE"

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jamesctucker/pathfinder-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server