Skip to main content
Glama
test_execute_query_result_modes.py13.7 kB
"""Tests for execute_query result_mode parameter. Tests the new result_mode feature that allows controlling response verbosity to reduce token usage (inspired by Morph MCP's context pollution prevention). """ from __future__ import annotations import pytest from igloo_mcp.mcp.tools.execute_query import ( RESULT_MODE_FULL, RESULT_MODE_SAMPLE, RESULT_MODE_SAMPLE_SIZE, RESULT_MODE_SCHEMA_ONLY, RESULT_MODE_SUMMARY, RESULT_MODE_SUMMARY_SAMPLE_SIZE, _apply_result_mode, ) class TestApplyResultMode: """Tests for the _apply_result_mode helper function.""" @pytest.fixture def sample_result(self) -> dict: """Create a sample query result for testing.""" return { "rows": [{"id": i, "name": f"row_{i}", "value": i * 10} for i in range(100)], "rowcount": 100, "columns": ["id", "name", "value"], "key_metrics": { "total_rows": 100, "sampled_rows": 100, "num_columns": 3, }, "statement": "SELECT * FROM test_table", "query_id": "test-query-id", "duration_ms": 150, } def test_full_mode_returns_all_rows(self, sample_result: dict) -> None: """Full mode should return all rows unchanged.""" result = _apply_result_mode(dict(sample_result), RESULT_MODE_FULL) assert len(result["rows"]) == 100 assert "result_mode" not in result # Full mode doesn't add metadata assert "result_mode_info" not in result def test_summary_mode_returns_limited_rows(self, sample_result: dict) -> None: """Summary mode should return only RESULT_MODE_SUMMARY_SAMPLE_SIZE rows.""" result = _apply_result_mode(dict(sample_result), RESULT_MODE_SUMMARY) assert len(result["rows"]) == RESULT_MODE_SUMMARY_SAMPLE_SIZE assert result["result_mode"] == "summary" assert result["result_mode_info"]["mode"] == "summary" assert result["result_mode_info"]["total_rows"] == 100 assert result["result_mode_info"]["rows_returned"] == RESULT_MODE_SUMMARY_SAMPLE_SIZE assert result["result_mode_info"]["sample_size"] == RESULT_MODE_SUMMARY_SAMPLE_SIZE assert "hint" in result["result_mode_info"] def test_schema_only_mode_returns_no_rows(self, sample_result: dict) -> None: """Schema only mode should return empty rows but preserve metadata.""" result = _apply_result_mode(dict(sample_result), RESULT_MODE_SCHEMA_ONLY) assert len(result["rows"]) == 0 assert result["result_mode"] == "schema_only" assert result["result_mode_info"]["mode"] == "schema_only" assert result["result_mode_info"]["total_rows"] == 100 assert result["result_mode_info"]["rows_returned"] == 0 # Columns should still be present assert result["columns"] == ["id", "name", "value"] # Key metrics should still be present assert result["key_metrics"] is not None def test_sample_mode_returns_limited_rows(self, sample_result: dict) -> None: """Sample mode should return only RESULT_MODE_SAMPLE_SIZE rows.""" result = _apply_result_mode(dict(sample_result), RESULT_MODE_SAMPLE) assert len(result["rows"]) == RESULT_MODE_SAMPLE_SIZE assert result["result_mode"] == "sample" assert result["result_mode_info"]["mode"] == "sample" assert result["result_mode_info"]["total_rows"] == 100 assert result["result_mode_info"]["rows_returned"] == RESULT_MODE_SAMPLE_SIZE assert result["result_mode_info"]["sample_size"] == RESULT_MODE_SAMPLE_SIZE def test_small_result_with_summary_mode(self) -> None: """Summary mode with fewer rows than sample size should return all rows.""" small_result = { "rows": [{"id": i} for i in range(3)], "rowcount": 3, "columns": ["id"], } result = _apply_result_mode(dict(small_result), RESULT_MODE_SUMMARY) assert len(result["rows"]) == 3 assert result["result_mode_info"]["total_rows"] == 3 assert result["result_mode_info"]["rows_returned"] == 3 # Should show helpful hint indicating all rows returned assert result["result_mode_info"]["hint"] == "All 3 rows returned" def test_small_result_with_sample_mode(self) -> None: """Sample mode with fewer rows than sample size should return all rows.""" small_result = { "rows": [{"id": i} for i in range(5)], "rowcount": 5, "columns": ["id"], } result = _apply_result_mode(dict(small_result), RESULT_MODE_SAMPLE) assert len(result["rows"]) == 5 assert result["result_mode_info"]["total_rows"] == 5 assert result["result_mode_info"]["rows_returned"] == 5 # Should show helpful hint indicating all rows returned assert result["result_mode_info"]["hint"] == "All 5 rows returned" def test_empty_result_with_all_modes(self) -> None: """All modes should handle empty results gracefully.""" empty_result = { "rows": [], "rowcount": 0, "columns": ["id", "name"], } for mode in [RESULT_MODE_FULL, RESULT_MODE_SUMMARY, RESULT_MODE_SCHEMA_ONLY, RESULT_MODE_SAMPLE]: result = _apply_result_mode(dict(empty_result), mode) assert len(result["rows"]) == 0 assert result["rowcount"] == 0 def test_preserves_other_fields(self, sample_result: dict) -> None: """Result mode filtering should preserve other result fields.""" result = _apply_result_mode(dict(sample_result), RESULT_MODE_SUMMARY) # These fields should be preserved assert result["statement"] == "SELECT * FROM test_table" assert result["query_id"] == "test-query-id" assert result["duration_ms"] == 150 assert result["key_metrics"] is not None def test_summary_mode_includes_columns_count(self, sample_result: dict) -> None: """Summary mode should include columns count in result_mode_info.""" result = _apply_result_mode(dict(sample_result), RESULT_MODE_SUMMARY) assert result["result_mode_info"]["columns_count"] == 3 def test_summary_mode_hint_shows_truncation_info(self, sample_result: dict) -> None: """Summary mode should show detailed hint when rows are truncated.""" result = _apply_result_mode(dict(sample_result), RESULT_MODE_SUMMARY) # Should indicate truncation with row counts assert "Showing first 5 of 100 rows" in result["result_mode_info"]["hint"] assert "response_mode='full'" in result["result_mode_info"]["hint"] def test_sample_mode_hint_shows_truncation_info(self, sample_result: dict) -> None: """Sample mode should show detailed hint when rows are truncated.""" result = _apply_result_mode(dict(sample_result), RESULT_MODE_SAMPLE) # Should indicate truncation with row counts assert "Showing first 10 of 100 rows" in result["result_mode_info"]["hint"] assert "response_mode='full'" in result["result_mode_info"]["hint"] class TestResultModeConstants: """Tests for result mode constants.""" def test_sample_size_is_reasonable(self) -> None: """Sample sizes should be reasonable values.""" assert RESULT_MODE_SAMPLE_SIZE == 10 assert RESULT_MODE_SUMMARY_SAMPLE_SIZE == 5 assert RESULT_MODE_SAMPLE_SIZE > RESULT_MODE_SUMMARY_SAMPLE_SIZE def test_mode_constants_are_strings(self) -> None: """Mode constants should be lowercase strings.""" assert RESULT_MODE_FULL == "full" assert RESULT_MODE_SUMMARY == "summary" assert RESULT_MODE_SCHEMA_ONLY == "schema_only" assert RESULT_MODE_SAMPLE == "sample" # ========================================================================= # Additional Edge Case Tests for result_mode # ========================================================================= class TestResultModeEdgeCases: """Edge case tests that complement the unit tests above. These tests focus on scenarios not covered by TestApplyResultMode, such as realistic Snowflake metadata fields and single-row aggregations. """ def test_result_mode_preserves_snowflake_metadata(self) -> None: """Test that Snowflake-specific fields are preserved across all modes.""" snowflake_result = { "rows": [{"id": i} for i in range(20)], "rowcount": 20, "columns": ["id"], "statement": "SELECT id FROM table", "query_id": "01abc-def-123", "duration_ms": 120, "warehouse": "COMPUTE_WH", "database": "ANALYTICS", "schema": "PUBLIC", } for mode in [RESULT_MODE_FULL, RESULT_MODE_SUMMARY, RESULT_MODE_SCHEMA_ONLY, RESULT_MODE_SAMPLE]: result = _apply_result_mode(dict(snowflake_result), mode) # Snowflake-specific fields should always be preserved assert result["warehouse"] == "COMPUTE_WH" assert result["database"] == "ANALYTICS" assert result["schema"] == "PUBLIC" def test_result_mode_with_aggregation_query(self) -> None: """Test result modes with single-row aggregation (common pattern).""" agg_result = { "rows": [{"count": 12345, "avg_price": 99.99, "max_date": "2024-01-15"}], "rowcount": 1, "columns": ["count", "avg_price", "max_date"], "statement": "SELECT COUNT(*), AVG(price), MAX(date) FROM products", "query_id": "01xyz-789", "duration_ms": 50, } # Non-schema modes should return the single row for mode in [RESULT_MODE_FULL, RESULT_MODE_SUMMARY, RESULT_MODE_SAMPLE]: result = _apply_result_mode(dict(agg_result), mode) assert len(result["rows"]) == 1 assert result["rows"][0]["count"] == 12345 # Schema only should still return 0 rows schema_result = _apply_result_mode(dict(agg_result), RESULT_MODE_SCHEMA_ONLY) assert len(schema_result["rows"]) == 0 assert schema_result["columns"] == ["count", "avg_price", "max_date"] def test_invalid_result_mode_falls_back_to_full(self) -> None: """Test that invalid result_mode values fall back to full mode behavior.""" result = { "rows": [{"id": 1}, {"id": 2}], "rowcount": 2, "columns": ["id"], } output = _apply_result_mode(dict(result), "invalid_mode") # Should not modify rows (full mode behavior) - rows unchanged assert len(output["rows"]) == 2 # Note: The function may still set result_mode to the invalid value # The key behavior is that rows are not truncated # ========================================================================= # Integration Tests for result_mode Validation # ========================================================================= class TestResultModeValidation: """Integration tests for result_mode parameter validation in execute_query. These tests verify that the validation layer properly catches invalid result_mode values and provides helpful error messages to users. """ def test_invalid_result_mode_typo_gives_clear_error(self) -> None: """Test that typos in result_mode give helpful error messages. This is an important UX test - users might typo 'summary' as 'summery' and should get a clear error showing valid options and what they sent. """ from igloo_mcp.mcp.exceptions import MCPValidationError # Simulate validation that happens in execute_query valid_result_modes = {"full", "summary", "schema_only", "sample"} user_input = "summery" # Common typo effective_result_mode = user_input.lower() # This should raise MCPValidationError if effective_result_mode not in valid_result_modes: error = MCPValidationError( "Invalid result_mode", validation_errors=[ f"result_mode must be one of: {', '.join(sorted(valid_result_modes))} (got: {user_input})" ], hints=["Use result_mode='summary' to reduce response size by ~90%"], ) # Verify error contains helpful information in its dict representation error_dict = error.to_dict() assert "validation_errors" in error_dict validation_msg = error_dict["validation_errors"][0] # Should show what user sent assert "summery" in validation_msg # Should show all valid options assert "full" in validation_msg assert "summary" in validation_msg assert "schema_only" in validation_msg assert "sample" in validation_msg # Should have helpful phrasing assert "must be one of" in validation_msg def test_case_insensitive_result_mode_accepted(self) -> None: """Test that result_mode accepts uppercase/mixed case values. This verifies the UX improvement where we lowercase user input before validation, making the API more forgiving. """ valid_result_modes = {"full", "summary", "schema_only", "sample"} # These should all be valid after lowercasing test_cases = ["SUMMARY", "Summary", "FuLl", "SCHEMA_ONLY", "sAmPlE"] for user_input in test_cases: effective_result_mode = user_input.lower() assert effective_result_mode in valid_result_modes

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/Evan-Kim2028/igloo-mcp'

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