Skip to main content
Glama
test_unified_discover.py9.89 kB
""" Tests for unified dune_discover tool. """ from __future__ import annotations from dataclasses import dataclass from spice_mcp.core.models import SchemaMatch, TableColumn, TableDescription, TableSummary from spice_mcp.mcp import server class StubDuneExplorer: """Stub explorer for Dune API discovery (returns SchemaMatch objects).""" schemas: list[str] tables: list[str] description: TableDescription def __init__(self): self.schemas = ["sui_base"] self.tables = ["events", "transactions"] self.description = TableDescription("sui_base.events", []) def find_schemas(self, keyword: str): if keyword == "sui": return [SchemaMatch(schema=s) for s in self.schemas] return [] def list_tables(self, schema: str, limit: int | None = None): if schema == "sui_base": summaries = [TableSummary(schema=schema, table=t) for t in self.tables] if limit: return summaries[:limit] return summaries return [] def describe_table(self, schema: str, table: str): return self.description class StubSpellbookExplorer: """Stub for Spellbook explorer.""" def __init__(self): # Mock models cache structure matching real SpellbookExplorer self._models_cache = { "daily_spellbook": [ { "name": "layerzero_send", "schema": "daily_spellbook", "dune_schema": "layerzero", "dune_alias": "send", "dune_table": "layerzero.send", }, { "name": "layerzero_chain_list", "schema": "daily_spellbook", "dune_schema": "layerzero", "dune_alias": "chain_list", "dune_table": "layerzero.chain_list", }, ] } def find_schemas(self, keyword: str): if "layerzero" in keyword.lower(): return [SchemaMatch(schema="daily_spellbook")] return [] def list_tables(self, schema: str, limit: int | None = None): if schema == "daily_spellbook": tables = ["layerzero_send", "layerzero_chain_list"] summaries = [TableSummary(schema=schema, table=t) for t in tables] if limit: return summaries[:limit] return summaries return [] def describe_table(self, schema: str, table: str): if schema == "daily_spellbook" and table == "layerzero_send": return TableDescription( "daily_spellbook.layerzero_send", columns=[ TableColumn(name="block_time", dune_type="TIMESTAMP"), TableColumn(name="tx_hash", dune_type="VARCHAR"), ], ) raise ValueError(f"Table {schema}.{table} not found") def _load_models(self): """Return mock models cache matching real SpellbookExplorer structure.""" return self._models_cache class StubVerificationService: """Stub verification service that always returns True (all tables verified).""" def verify_tables_batch(self, tables): """Return True for all tables.""" return {f"{schema}.{table}": True for schema, table in tables} def test_unified_discover_spellbook_only(monkeypatch, tmp_path): """Test unified discover with spellbook source only.""" monkeypatch.setenv("DUNE_API_KEY", "test-key") monkeypatch.setenv("SPICE_QUERY_HISTORY", str(tmp_path / "history.jsonl")) server._ensure_initialized() server.SPELLBOOK_EXPLORER = StubSpellbookExplorer() server.VERIFICATION_SERVICE = StubVerificationService() result = server._unified_discover_impl(keyword="layerzero", source="spellbook", include_columns=False) assert result["source"] == "spellbook" assert "daily_spellbook" in result["schemas"] assert len(result["tables"]) > 0 assert all(t["source"] == "spellbook" for t in result["tables"]) assert all("fully_qualified_name" in t for t in result["tables"]) def test_unified_discover_dune_only(monkeypatch, tmp_path): """Test unified discover with dune source only.""" monkeypatch.setenv("DUNE_API_KEY", "test-key") monkeypatch.setenv("SPICE_QUERY_HISTORY", str(tmp_path / "history.jsonl")) server._ensure_initialized() stub_explorer = StubDuneExplorer() # Replace the explorer on the discovery service from spice_mcp.service_layer.discovery_service import DiscoveryService server.DISCOVERY_SERVICE = DiscoveryService(stub_explorer) result = server._unified_discover_impl(keyword="sui", source="dune") assert result["source"] == "dune" assert "sui_base" in result["schemas"] assert len(result["tables"]) == 0 # No schema specified, so no tables listed def test_unified_discover_both_sources(monkeypatch, tmp_path): """Test unified discover with both sources.""" monkeypatch.setenv("DUNE_API_KEY", "test-key") monkeypatch.setenv("SPICE_QUERY_HISTORY", str(tmp_path / "history.jsonl")) server._ensure_initialized() server.SPELLBOOK_EXPLORER = StubSpellbookExplorer() server.VERIFICATION_SERVICE = StubVerificationService() stub_explorer = StubDuneExplorer() from spice_mcp.service_layer.discovery_service import DiscoveryService server.DISCOVERY_SERVICE = DiscoveryService(stub_explorer) result = server._unified_discover_impl(keyword="layerzero", source="both", include_columns=False) assert result["source"] == "both" assert len(result["schemas"]) > 0 assert len(result["tables"]) > 0 # Should have spellbook tables spellbook_tables = [t for t in result["tables"] if t["source"] == "spellbook"] assert len(spellbook_tables) > 0 def test_unified_discover_multiple_keywords(monkeypatch, tmp_path): """Test unified discover with multiple keywords.""" monkeypatch.setenv("DUNE_API_KEY", "test-key") monkeypatch.setenv("SPICE_QUERY_HISTORY", str(tmp_path / "history.jsonl")) server._ensure_initialized() server.SPELLBOOK_EXPLORER = StubSpellbookExplorer() server.VERIFICATION_SERVICE = StubVerificationService() result = server._unified_discover_impl(keyword=["layerzero", "bridge"], source="spellbook", include_columns=False) assert len(result["tables"]) > 0 # Should find models matching either keyword table_names = [t["table"] for t in result["tables"]] assert any("layerzero" in name.lower() for name in table_names) or any("bridge" in name.lower() for name in table_names) def test_unified_discover_with_schema(monkeypatch, tmp_path): """Test unified discover with schema specified.""" monkeypatch.setenv("DUNE_API_KEY", "test-key") monkeypatch.setenv("SPICE_QUERY_HISTORY", str(tmp_path / "history.jsonl")) server._ensure_initialized() server.SPELLBOOK_EXPLORER = StubSpellbookExplorer() server.VERIFICATION_SERVICE = StubVerificationService() result = server._unified_discover_impl(schema="daily_spellbook", source="spellbook", limit=10, include_columns=True) assert len(result["tables"]) > 0 assert all(t["schema"] == "daily_spellbook" for t in result["tables"]) # With include_columns=True, should have columns if result["tables"]: first_table = result["tables"][0] assert "columns" in first_table def test_unified_discover_response_format(monkeypatch, tmp_path): """Test that unified discover returns consistent format.""" monkeypatch.setenv("DUNE_API_KEY", "test-key") monkeypatch.setenv("SPICE_QUERY_HISTORY", str(tmp_path / "history.jsonl")) server._ensure_initialized() server.SPELLBOOK_EXPLORER = StubSpellbookExplorer() server.VERIFICATION_SERVICE = StubVerificationService() result = server._unified_discover_impl(keyword="layerzero", source="spellbook") # Verify response structure assert "schemas" in result assert "tables" in result assert "source" in result assert isinstance(result["schemas"], list) assert isinstance(result["tables"], list) # Verify table structure if result["tables"]: table = result["tables"][0] assert "schema" in table assert "table" in table assert "fully_qualified_name" in table assert "source" in table assert table["source"] in ("dune", "spellbook") # Verify new fields for Spellbook models if table["source"] == "spellbook": assert "dune_schema" in table assert "dune_alias" in table assert "dune_table" in table assert "verified" in table assert table["verified"] is True def test_unified_discover_dune_tables_have_verified_fields(monkeypatch, tmp_path): """Test that Dune tables include dune_table and verified fields.""" monkeypatch.setenv("DUNE_API_KEY", "test-key") monkeypatch.setenv("SPICE_QUERY_HISTORY", str(tmp_path / "history.jsonl")) server._ensure_initialized() stub_explorer = StubDuneExplorer() from spice_mcp.service_layer.discovery_service import DiscoveryService server.DISCOVERY_SERVICE = DiscoveryService(stub_explorer) # Use schema to get actual tables (not just schemas) result = server._unified_discover_impl(schema="sui_base", source="dune") assert result["source"] == "dune" assert len(result["tables"]) > 0 # Verify all Dune tables have dune_table and verified fields for table in result["tables"]: assert table["source"] == "dune" assert "dune_table" in table assert table["dune_table"] == f"{table['schema']}.{table['table']}" assert "verified" in table assert table["verified"] is True

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/spice-mcp'

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