"""E2E tests for search_processes MCP tool.
Scenarios from E2E Test Plan Section 5.5:
- Scenario 5.5.5: Search Processes with Keyword Match (P1)
- Scenario 5.5.6: Search Processes with No Matches (P1)
- Scenario 5.5.7: Search Processes Respects Result Limit (P1)
- Scenario 5.6.9: Process Search Partial Matching (P2)
"""
from __future__ import annotations
from pathlib import Path
from typing import TYPE_CHECKING
import pytest
from sso_mcp_server.processes.service import ProcessService
if TYPE_CHECKING:
pass
@pytest.mark.e2e
@pytest.mark.regression
@pytest.mark.process
@pytest.mark.search
class TestSearchProcessesE2E:
"""E2E tests for search_processes tool."""
def test_search_processes_keyword_match(
self,
e2e_process_dir: Path,
) -> None:
"""Scenario 5.5.5: Search processes with keyword match.
Given server is authenticated and ready
And multiple process files exist with various content
When client sends MCP request to search_processes with keyword="review"
Then server returns search results including "code-review" process
"""
# Arrange
service = ProcessService(e2e_process_dir)
# Act
result = service.search_processes("review")
# Assert
assert result is not None
assert len(result) > 0, "Should find at least one process with 'review'"
names = [r["name"] for r in result]
assert "Code Review Process" in names
def test_search_processes_matches_title(
self,
e2e_process_dir: Path,
) -> None:
"""Test that search matches process titles.
Given process "deployment" exists
When client searches for "deployment"
Then deployment process is in results
"""
# Arrange
service = ProcessService(e2e_process_dir)
# Act
result = service.search_processes("deployment")
# Assert
names = [r["name"] for r in result]
assert "Deployment Process" in names
def test_search_processes_matches_content(
self,
e2e_process_dir: Path,
) -> None:
"""Test that search matches process content.
Given processes contain specific keywords in content
When client searches for keyword in content
Then matching processes are returned
"""
# Arrange
service = ProcessService(e2e_process_dir)
# Act - search for content keyword
result = service.search_processes("production")
# Assert - "production" appears in deployment process content
names = [r["name"] for r in result]
assert "Deployment Process" in names
def test_search_processes_relevance_ranking(
self,
e2e_process_dir: Path,
) -> None:
"""Test that search results are ranked by relevance.
Given processes with keyword in title vs content
When client searches
Then title matches should rank higher (appear first)
"""
# Arrange
service = ProcessService(e2e_process_dir)
# Add a process with "review" in content but not title
review_content = """---
name: Quality Assurance
description: QA process with code review steps
---
# Quality Assurance
This process includes code review activities.
"""
(e2e_process_dir / "qa.md").write_text(review_content)
# Act
result = service.search_processes("review")
# Assert
assert len(result) >= 2
# Code Review Process (title match) should have higher relevance
# than QA (content match)
code_review_result = next(r for r in result if r["name"] == "Code Review Process")
qa_result = next(r for r in result if r["name"] == "Quality Assurance")
assert code_review_result["relevance_score"] >= qa_result["relevance_score"]
def test_search_processes_no_matches(
self,
e2e_process_dir: Path,
) -> None:
"""Scenario 5.5.6: Search processes with no matches.
Given server is authenticated and ready
And no process contains the keyword "xyznonexistent"
When client sends MCP request to search_processes with keyword="xyznonexistent"
Then server returns empty results array
"""
# Arrange
service = ProcessService(e2e_process_dir)
# Act
result = service.search_processes("xyznonexistent")
# Assert
assert result == [], "Non-matching search should return empty list"
def test_search_processes_partial_matching(
self,
e2e_process_dir: Path,
) -> None:
"""Scenario 5.6.9: Process search partial matching.
Given process "deployment.md" exists with content "production deployment steps"
When client searches with keyword="deploy"
Then "deployment.md" is included in results (partial match)
"""
# Arrange
service = ProcessService(e2e_process_dir)
# Act - partial keyword
result = service.search_processes("deploy")
# Assert
names = [r["name"] for r in result]
assert "Deployment Process" in names
def test_search_processes_case_insensitive(
self,
e2e_process_dir: Path,
) -> None:
"""Test that search is case-insensitive.
Given processes exist
When client searches with mixed case keyword
Then matching processes are returned regardless of case
"""
# Arrange
service = ProcessService(e2e_process_dir)
# Act
result_lower = service.search_processes("review")
result_upper = service.search_processes("REVIEW")
result_mixed = service.search_processes("ReViEw")
# Assert - all should return same results
assert len(result_lower) == len(result_upper) == len(result_mixed)
def test_search_processes_includes_metadata(
self,
e2e_process_dir: Path,
) -> None:
"""Test that search results include process metadata.
Given processes match search query
When search is performed
Then results include name, description, relevance_score, and snippet
"""
# Arrange
service = ProcessService(e2e_process_dir)
# Act
result = service.search_processes("review")
# Assert
for item in result:
assert "name" in item
assert "description" in item
assert "relevance_score" in item
assert "snippet" in item
@pytest.mark.e2e
@pytest.mark.regression
@pytest.mark.process
@pytest.mark.search
class TestSearchProcessesLimitE2E:
"""E2E tests for search result limit."""
def test_search_processes_respects_max_limit(
self,
e2e_temp_dir: Path,
) -> None:
"""Scenario 5.5.7: Search processes respects result limit.
Given process directory contains 100+ files all containing "process"
When client sends MCP request to search_processes with keyword="process"
Then server returns at most 50 results
"""
# Arrange - create many process files
process_dir = e2e_temp_dir / "many_processes"
process_dir.mkdir(parents=True)
for i in range(60):
content = f"""---
name: Process {i}
description: Test process {i} for limit testing
---
# Process {i}
This is process number {i}.
"""
(process_dir / f"process-{i}.md").write_text(content)
service = ProcessService(process_dir)
# Act
result = service.search_processes("process")
# Assert
assert len(result) <= 50, f"Should return at most 50 results, got {len(result)}"
assert len(result) == 50, "Should return exactly 50 when more available"