Skip to main content
Glama
test_action_manager.py30.9 kB
"""Tests for ActionManager.""" import json from datetime import date from pathlib import Path import pytest from execution_system_mcp.action_manager import ActionManager from execution_system_mcp.config import ConfigManager class TestActionManagerAddAction: """Test ActionManager add_action functionality.""" def test_adds_action_to_context_file(self, tmp_path): """ Test adding action to context file. Given: Context file exists with YAML header When: Adding action with text, context, project Then: Action is added to top of file with today's date """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- - [ ] 2025-10-20 Existing action @macbook +existing-project """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) # Create a dummy project so validation passes projects_dir = repo_path / "docs" / "execution_system" / "10k-projects" / "active" / "health" projects_dir.mkdir(parents=True) project_file = projects_dir / "test-project.md" project_file.write_text("""--- area: Health title: Test Project --- """) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_action( text="New action to add", context="@macbook", project="test-project" ) # Then assert "✓ Successfully added action" in result content = macbook_file.read_text() lines = content.strip().split('\n') # Check action is added after YAML header today = date.today().strftime("%Y-%m-%d") expected_action = f"- [ ] {today} New action to add @macbook +test-project" assert expected_action in content # Should be added at top (after YAML) assert lines[4] == expected_action def test_adds_action_with_due_date(self, tmp_path): """ Test adding action with due date. Given: Context file exists When: Adding action with due date Then: Action includes due:YYYY-MM-DD tag """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_action( text="Action with deadline", context="@macbook", due="2025-12-31" ) # Then assert "✓ Successfully added action" in result content = macbook_file.read_text() assert "due:2025-12-31" in content def test_adds_action_with_custom_date(self, tmp_path): """ Test adding action with custom creation date. Given: Context file exists When: Adding action with specific date Then: Action uses provided date instead of today """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_action( text="Action from past", context="@macbook", action_date="2025-09-15" ) # Then content = macbook_file.read_text() assert "- [ ] 2025-09-15 Action from past @macbook" in content def test_validates_project_exists(self, tmp_path): """ Test project validation when adding action. Given: Project does not exist When: Adding action with +project tag Then: Returns error about invalid project """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- """) # Create projects dir but no project file projects_dir = repo_path / "docs" / "execution_system" / "10k-projects" / "active" projects_dir.mkdir(parents=True) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_action( text="Action for nonexistent project", context="@macbook", project="nonexistent-project" ) # Then assert "Error" in result assert "Project 'nonexistent-project' does not exist" in result def test_returns_error_for_invalid_context(self, tmp_path): """ Test error when context file doesn't exist. Given: Context file does not exist When: Adding action to that context Then: Returns error about missing context """ # Given repo_path = tmp_path / "repo" config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_action( text="Action for missing context", context="@nonexistent" ) # Then assert "Error" in result assert "Context file" in result assert "@nonexistent.md" in result def test_action_without_project_tag(self, tmp_path): """ Test adding action without project tag. Given: Context file exists When: Adding action without project parameter Then: Action added successfully without +project tag """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) phone_file = contexts_dir / "@phone.md" phone_file.write_text("""--- title: Phone last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_action( text="Call dentist", context="@phone" ) # Then assert "✓ Successfully added action" in result content = phone_file.read_text() assert "Call dentist @phone" in content assert "+" not in content # No project tag def test_no_blank_line_after_yaml(self, tmp_path): """ Test that no blank line exists after YAML when adding action. Given: Context file with blank line after YAML When: Adding action Then: New action is placed immediately after YAML, no blank lines """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- - [ ] 2025-10-20 Existing action @macbook """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_action( text="New action", context="@macbook" ) # Then assert "✓ Successfully added action" in result content = macbook_file.read_text() lines = content.split('\n') # Line 3 is closing --- assert lines[3] == "---" # Line 4 should be the new action, NO blank line today = date.today().strftime("%Y-%m-%d") assert lines[4] == f"- [ ] {today} New action @macbook" # Line 5 should be the existing action assert lines[5] == "- [ ] 2025-10-20 Existing action @macbook" def test_removes_blank_lines_after_yaml(self, tmp_path): """ Test that blank lines after YAML are removed when adding action. Given: Context file with multiple blank lines after YAML When: Adding action Then: All blank lines removed, action placed immediately after YAML """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" # Two blank lines after YAML macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- - [ ] 2025-10-20 Existing action @macbook """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_action( text="New action", context="@macbook" ) # Then content = macbook_file.read_text() lines = content.split('\n') # Verify no blank lines between YAML and first action assert lines[3] == "---" today = date.today().strftime("%Y-%m-%d") assert lines[4] == f"- [ ] {today} New action @macbook" assert lines[5] == "- [ ] 2025-10-20 Existing action @macbook" class TestActionManagerAddToWaiting: """Test ActionManager add_to_waiting functionality.""" def test_adds_to_waiting_file(self, tmp_path): """ Test adding item to @waiting file. Given: @waiting.md exists When: Adding item with add_to_waiting Then: Item added to top of file with @waiting context """ # Given repo_path = tmp_path / "repo" actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" actions_dir.mkdir(parents=True) waiting_file = actions_dir / "@waiting.md" waiting_file.write_text("""--- title: Waiting For last_reviewed: 2025-10-20 --- - [ ] 2025-10-20 Existing waiting item @waiting +existing-project """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) # Create dummy project for validation projects_dir = repo_path / "docs" / "execution_system" / "10k-projects" / "active" / "health" projects_dir.mkdir(parents=True) (projects_dir / "receive-package.md").write_text("---\narea: Health\n---\n") config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_to_waiting( text="Wait for package delivery", project="receive-package" ) # Then assert "✓ Successfully added to @waiting.md" in result content = waiting_file.read_text() today = date.today().strftime("%Y-%m-%d") expected = f"- [ ] {today} Wait for package delivery @waiting +receive-package" assert expected in content def test_adds_to_waiting_with_defer(self, tmp_path): """ Test adding to waiting with defer date. Given: @waiting.md exists When: Adding item with defer date and project Then: Item includes defer:YYYY-MM-DD tag """ # Given repo_path = tmp_path / "repo" actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" actions_dir.mkdir(parents=True) waiting_file = actions_dir / "@waiting.md" waiting_file.write_text("""--- title: Waiting For last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) # Create dummy project for validation projects_dir = repo_path / "docs" / "execution_system" / "10k-projects" / "active" / "health" projects_dir.mkdir(parents=True) (projects_dir / "shipment-project.md").write_text("---\narea: Health\n---\n") config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_to_waiting( text="Wait for delayed shipment", project="shipment-project", defer="2025-12-01" ) # Then content = waiting_file.read_text() assert "defer:2025-12-01" in content def test_error_when_waiting_missing_project(self, tmp_path): """ Test that adding to waiting without project returns error. Given: @waiting.md exists When: Adding item without project parameter Then: Returns error about missing project """ # Given repo_path = tmp_path / "repo" actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" actions_dir.mkdir(parents=True) waiting_file = actions_dir / "@waiting.md" waiting_file.write_text("""--- title: Waiting For last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_to_waiting( text="Wait for something" ) # Then assert "Error" in result assert "project" in result.lower() assert "required" in result.lower() class TestActionManagerAddToDeferred: """Test ActionManager add_to_deferred functionality.""" def test_adds_to_deferred_file(self, tmp_path): """ Test adding item to @deferred file. Given: @deferred.md exists When: Adding item with add_to_deferred Then: Item added to top of file with @deferred context """ # Given repo_path = tmp_path / "repo" actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" actions_dir.mkdir(parents=True) deferred_file = actions_dir / "@deferred.md" deferred_file.write_text("""--- title: Deferred last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) # Create dummy project for validation projects_dir = repo_path / "docs" / "execution_system" / "10k-projects" / "active" / "health" projects_dir.mkdir(parents=True) (projects_dir / "future-project.md").write_text("---\narea: Health\n---\n") config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_to_deferred( text="Action for later", defer="2025-11-15", project="future-project" ) # Then assert "✓ Successfully added to @deferred.md" in result content = deferred_file.read_text() today = date.today().strftime("%Y-%m-%d") assert f"- [ ] {today} Action for later @deferred +future-project defer:2025-11-15" in content def test_error_when_deferred_missing_project(self, tmp_path): """ Test that adding to deferred without project returns error. Given: @deferred.md exists When: Adding item without project parameter Then: Returns error about missing project """ # Given repo_path = tmp_path / "repo" actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" actions_dir.mkdir(parents=True) deferred_file = actions_dir / "@deferred.md" deferred_file.write_text("""--- title: Deferred last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_to_deferred( text="Deferred action", defer="2025-12-01" ) # Then assert "Error" in result assert "project" in result.lower() assert "required" in result.lower() class TestActionManagerAddToIncubating: """Test ActionManager add_to_incubating functionality.""" def test_adds_to_incubating_file(self, tmp_path): """ Test adding item to @incubating file. Given: @incubating.md exists When: Adding item with add_to_incubating Then: Item added to top of file with @incubating context """ # Given repo_path = tmp_path / "repo" actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" actions_dir.mkdir(parents=True) incubating_file = actions_dir / "@incubating.md" incubating_file.write_text("""--- title: Incubating last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) # Create dummy project for validation projects_dir = repo_path / "docs" / "execution_system" / "10k-projects" / "active" / "health" projects_dir.mkdir(parents=True) (projects_dir / "experimental-idea.md").write_text("---\narea: Health\n---\n") config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.add_to_incubating( text="Maybe someday explore this", project="experimental-idea" ) # Then assert "✓ Successfully added to @incubating.md" in result content = incubating_file.read_text() today = date.today().strftime("%Y-%m-%d") assert f"- [ ] {today} Maybe someday explore this @incubating +experimental-idea" in content class TestActionManagerCompleteAction: """Test ActionManager complete_action functionality.""" def test_completes_action_by_line_number(self, tmp_path): """ Test completing action using line number. Given: Context file with multiple actions When: Completing action at specific line Then: Action marked complete, moved to completed.md, removed from source """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- - [ ] 2025-10-20 First action @macbook +project-one - [ ] 2025-10-21 Second action @macbook +project-two - [ ] 2025-10-22 Third action @macbook +project-three """) actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" completed_file = actions_dir / "completed.md" completed_file.write_text("""--- title: Completed Actions last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When - complete line 6 (second action) result = manager.complete_action( file_path="contexts/@macbook.md", line_number=7 ) # Then assert "✓ Successfully completed action" in result # Source file should have action removed source_content = macbook_file.read_text() assert "Second action" not in source_content assert "First action" in source_content assert "Third action" in source_content # Completed file should have action with completion date completed_content = completed_file.read_text() today = date.today().strftime("%Y-%m-%d") assert f"- [x] {today} 2025-10-21 Second action @macbook +project-two" in completed_content def test_complete_preserves_due_and_defer_dates(self, tmp_path): """ Test that completing action preserves due: and defer: tags. Given: Action with due and defer dates When: Completing action Then: Tags are preserved in completed.md """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- - [ ] 2025-10-15 Action with dates @macbook +project due:2025-11-01 defer:2025-10-20 """) actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" completed_file = actions_dir / "completed.md" completed_file.write_text("""--- title: Completed Actions last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.complete_action( file_path="contexts/@macbook.md", line_number=6 ) # Then completed_content = completed_file.read_text() today = date.today().strftime("%Y-%m-%d") assert f"- [x] {today} 2025-10-15 Action with dates @macbook +project due:2025-11-01 defer:2025-10-20" in completed_content def test_complete_with_custom_completion_date(self, tmp_path): """ Test completing action with custom completion date. Given: Context file with action When: Completing with specific completion date Then: Action uses provided completion date """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- - [ ] 2025-10-15 Action to complete @macbook """) actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" completed_file = actions_dir / "completed.md" completed_file.write_text("""--- title: Completed Actions last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.complete_action( file_path="contexts/@macbook.md", line_number=6, completion_date="2025-10-25" ) # Then completed_content = completed_file.read_text() assert "- [x] 2025-10-25 2025-10-15 Action to complete @macbook" in completed_content def test_complete_action_from_waiting_list(self, tmp_path): """ Test completing action from @waiting list. Given: @waiting.md with action When: Completing action Then: Works correctly for special state files """ # Given repo_path = tmp_path / "repo" actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" actions_dir.mkdir(parents=True) waiting_file = actions_dir / "@waiting.md" waiting_file.write_text("""--- title: Waiting For last_reviewed: 2025-10-20 --- - [ ] 2025-10-18 Waiting for response @waiting +project-x """) completed_file = actions_dir / "completed.md" completed_file.write_text("""--- title: Completed Actions last_reviewed: 2025-10-20 --- """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.complete_action( file_path="@waiting.md", line_number=6 ) # Then assert "✓ Successfully completed action" in result completed_content = completed_file.read_text() today = date.today().strftime("%Y-%m-%d") assert f"- [x] {today} 2025-10-18 Waiting for response @waiting +project-x" in completed_content def test_error_on_invalid_line_number(self, tmp_path): """ Test error when line number doesn't contain an action. Given: Context file When: Completing invalid line number Then: Returns error """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- - [ ] 2025-10-20 Action @macbook """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When - try to complete line 1 (YAML header) result = manager.complete_action( file_path="contexts/@macbook.md", line_number=1 ) # Then assert "Error" in result assert "incomplete" in result.lower() def test_complete_no_blank_line_in_completed_file(self, tmp_path): """ Test that completing action doesn't add blank lines to completed.md. Given: completed.md with blank line after YAML When: Completing an action Then: Completed action is placed immediately after YAML, no blank lines """ # Given repo_path = tmp_path / "repo" contexts_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" / "contexts" contexts_dir.mkdir(parents=True) macbook_file = contexts_dir / "@macbook.md" macbook_file.write_text("""--- title: Macbook last_reviewed: 2025-10-20 --- - [ ] 2025-10-15 Action to complete @macbook """) actions_dir = repo_path / "docs" / "execution_system" / "00k-next-actions" completed_file = actions_dir / "completed.md" # completed.md has blank line after YAML completed_file.write_text("""--- title: Completed Actions last_reviewed: 2025-10-20 --- - [x] 2025-10-19 Old completed action @macbook """) config_file = tmp_path / "config.json" config_file.write_text(json.dumps({ "execution_system_repo_path": str(repo_path), "areas": [{"name": "Health", "kebab": "health"}] })) config = ConfigManager(str(config_file)) manager = ActionManager(config) # When result = manager.complete_action( file_path="contexts/@macbook.md", line_number=5 # Line 5 is the action (no blank line after YAML) ) # Then assert "✓ Successfully completed action" in result content = completed_file.read_text() lines = content.split('\n') # Verify no blank lines between YAML and first action assert lines[3] == "---" today = date.today().strftime("%Y-%m-%d") assert lines[4] == f"- [x] {today} 2025-10-15 Action to complete @macbook" assert lines[5] == "- [x] 2025-10-19 Old completed action @macbook"

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/elinsky/execution-system-mcp'

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