Skip to main content
Glama

MCP-Airflow-API

test_prompt_template.py12.1 kB
import pytest from mcp_airflow_api.mcp_main import get_prompt_template from mcp_airflow_api.functions import read_prompt_template, parse_prompt_sections from .config import TEMPLATE_CONFIG import os class TestPromptTemplate: """ Prompt template functionality tests. These tests are designed to be resilient to template content changes. """ @pytest.fixture def template_data(self): """Template data fixture - loads once per test class""" template = get_prompt_template() headings, sections = parse_prompt_sections(template) return { "template": template, "headings": headings, "sections": sections } # ============================================================================ # 반영구적 테스트들 (템플릿 변경과 무관하게 계속 유효) # ============================================================================ def test_template_loading_basic(self): """Test that template loads without errors""" template = get_prompt_template() assert template is not None assert len(template) > 0 assert isinstance(template, str) def test_full_template_mode(self): """Test full template mode returns complete content""" template_full = get_prompt_template() template_explicit = get_prompt_template(mode="full") # Both should return the same content assert template_full == template_explicit assert TEMPLATE_CONFIG["title_marker"] in template_full assert len(template_full) > TEMPLATE_CONFIG["min_template_length"] def test_headings_mode_structure(self): """Test headings mode returns proper structure""" headings = get_prompt_template(mode="headings") assert TEMPLATE_CONFIG["section_headings_marker"] in headings lines = headings.split("\n") # Should have at least the header line plus minimum sections assert len(lines) >= TEMPLATE_CONFIG["min_sections"] + 1 def test_case_insensitive_search(self): """Test case insensitive keyword search""" # Test with a keyword that should exist test_keyword = TEMPLATE_CONFIG["expected_keywords"][0] # "overview" # Test different cases result_upper = get_prompt_template(section=test_keyword.upper()) result_lower = get_prompt_template(section=test_keyword.lower()) result_title = get_prompt_template(section=test_keyword.title()) # At least one should work (case insensitive) results = [result_upper, result_lower, result_title] valid_results = [r for r in results if "not found" not in r.lower()] assert len(valid_results) > 0, f"Keyword '{test_keyword}' not found in any case variation" def test_invalid_inputs_handling(self): """Test handling of invalid inputs""" # Test invalid section numbers invalid_numbers = ["999", "0", "-1", "abc"] for num in invalid_numbers: result = get_prompt_template(section=num) if num == "0" or num == "-1": # These might be handled differently, so just check they don't crash assert isinstance(result, str) elif not num.isdigit(): # Non-numeric should be treated as keyword search assert isinstance(result, str) else: # High numbers should return "not found" assert "not found" in result.lower() # Test completely invalid keywords result = get_prompt_template(section="nonexistent_keyword_xyz_123") assert "not found" in result.lower() def test_empty_and_none_inputs(self): """Test handling of empty and None inputs""" full_template = get_prompt_template() # These should all return the full template empty_string = get_prompt_template(section="") none_section = get_prompt_template(section=None) assert full_template == empty_string assert full_template == none_section # ============================================================================ # 유연성을 높인 적응형 테스트들 # ============================================================================ def test_section_by_number_flexible(self, template_data): """Test section retrieval by number (flexible approach)""" headings = template_data["headings"] num_sections = len(headings) # Test first section if it exists if num_sections > 0: first_section = get_prompt_template(section="1") assert len(first_section) > 0 assert "not found" not in first_section.lower() # Should contain the first heading assert headings[0] in first_section # Test middle section if there are enough sections if num_sections >= 3: middle_section = get_prompt_template(section="2") assert len(middle_section) > 0 assert "not found" not in middle_section.lower() def test_keyword_search_expected_keywords(self, template_data): """Test keyword search with expected keywords""" headings = template_data["headings"] template = template_data["template"] for keyword in TEMPLATE_CONFIG["expected_keywords"]: # Check if keyword appears in template or headings keyword_in_template = keyword.lower() in template.lower() keyword_in_headings = any(keyword.lower() in heading.lower() for heading in headings) if keyword_in_template or keyword_in_headings: # If keyword exists, search should work result = get_prompt_template(section=keyword) assert "not found" not in result.lower(), f"Keyword '{keyword}' should be findable" assert len(result) > 0 else: # If keyword doesn't exist, that's OK, just log it print(f"Info: Expected keyword '{keyword}' not found in current template") def test_boundary_conditions_dynamic(self, template_data): """Test boundary conditions dynamically based on current template""" headings = template_data["headings"] num_sections = len(headings) if num_sections > 0: # Test first section first = get_prompt_template(section="1") assert "not found" not in first.lower() assert len(first) > 0 # Test last valid section last = get_prompt_template(section=str(num_sections)) assert "not found" not in last.lower() assert len(last) > 0 # Test beyond range beyond_range = get_prompt_template(section=str(num_sections + 1)) assert "not found" in beyond_range.lower() def test_template_structure_integrity(self, template_data): """Test that template maintains expected structure""" template = template_data["template"] headings = template_data["headings"] sections = template_data["sections"] # Basic structure validation assert TEMPLATE_CONFIG["title_marker"] in template assert len(headings) >= TEMPLATE_CONFIG["min_sections"] # Sections should match headings count (+1 for title section) expected_sections = len(headings) + 1 actual_sections = len(sections) assert actual_sections == expected_sections, f"Expected {expected_sections} sections, got {actual_sections}" # Each heading section should not be empty for i, section in enumerate(sections[1:], 1): # Skip title section assert len(section.strip()) > 10, f"Section {i} is too short or empty: {len(section.strip())} chars" def test_headings_format_consistency(self, template_data): """Test that headings follow expected format""" headings = template_data["headings"] for i, heading in enumerate(headings, 1): # Basic validation assert len(heading.strip()) > 0, f"Heading {i} is empty" assert len(heading.strip()) > 3, f"Heading {i} too short: '{heading}'" # Most headings should contain some alphanumeric content assert any(c.isalnum() for c in heading), f"Heading {i} contains no alphanumeric characters: '{heading}'" def test_section_retrieval_consistency(self, template_data): """Test that section retrieval is consistent""" headings = template_data["headings"] # Test first few sections for consistency test_range = min(3, len(headings)) for i in range(1, test_range + 1): # Get section by number section_by_number = get_prompt_template(section=str(i)) assert "not found" not in section_by_number.lower() # Section should contain its own heading expected_heading = headings[i-1] assert expected_heading in section_by_number, f"Section {i} doesn't contain its heading: {expected_heading}" # ============================================================================ # 레거시 호환성 테스트들 (기존 기능 유지 확인) # ============================================================================ def test_legacy_airflow_tools_references(self): """Test that template still contains key Airflow tool references""" template = get_prompt_template() # These should generally be present in an Airflow API template expected_tools = ["list_dags", "get_health", "get_version"] found_tools = [] for tool in expected_tools: if tool in template: found_tools.append(tool) # At least some tools should be present assert len(found_tools) > 0, f"No expected Airflow tools found. Looking for: {expected_tools}" def test_legacy_important_sections_exist(self): """Test that important sections still exist (flexible check)""" headings = get_prompt_template(mode="headings") # These concepts should generally be present important_concepts = ["overview", "tool", "example"] found_concepts = [] for concept in important_concepts: if any(concept.lower() in heading.lower() for heading in headings.split('\n')): found_concepts.append(concept) # At least some important concepts should be present assert len(found_concepts) >= 2, f"Too few important concepts found. Expected some of: {important_concepts}, found: {found_concepts}" # ============================================================================ # 성능 및 안정성 테스트들 # ============================================================================ def test_template_loading_performance(self): """Test that template loading is reasonably fast""" import time start_time = time.time() for _ in range(10): get_prompt_template() end_time = time.time() avg_time = (end_time - start_time) / 10 # Should load in reasonable time (less than 0.1 seconds per call) assert avg_time < 0.1, f"Template loading too slow: {avg_time:.3f}s per call" def test_template_memory_usage(self): """Test that template doesn't consume excessive memory""" template = get_prompt_template() # Template shouldn't be excessively large (less than 1MB) template_size = len(template.encode('utf-8')) max_size = 1024 * 1024 # 1MB assert template_size < max_size, f"Template too large: {template_size} bytes (max: {max_size})"

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/call518/MCP-Airflow-API'

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