"""Tests for the MCP endpoint, token and bot-tag resolver.""" from __future__ import annotations import pytest from cerbero_bite.config.mcp_endpoints import ( DEFAULT_BOT_TAG, DEFAULT_ENDPOINTS, MCP_SERVICES, load_bot_tag, load_endpoints, load_token, ) def test_defaults_match_known_docker_dns() -> None: assert DEFAULT_ENDPOINTS["deribit"] == "http://mcp-deribit:9011" assert DEFAULT_ENDPOINTS["sentiment"] == "http://mcp-sentiment:9014" def test_load_endpoints_uses_defaults_when_env_empty() -> None: endpoints = load_endpoints(env={}) for name, url in DEFAULT_ENDPOINTS.items(): assert endpoints.for_service(name) == url def test_per_service_env_var_override() -> None: endpoints = load_endpoints( env={"CERBERO_BITE_MCP_DERIBIT_URL": "http://localhost:9911"} ) assert endpoints.deribit == "http://localhost:9911" assert endpoints.macro == DEFAULT_ENDPOINTS["macro"] def test_per_service_env_var_strips_trailing_slash() -> None: endpoints = load_endpoints( env={"CERBERO_BITE_MCP_DERIBIT_URL": "http://localhost:9911///"} ) assert endpoints.deribit == "http://localhost:9911" def test_for_service_unknown_raises_key_error() -> None: endpoints = load_endpoints(env={}) with pytest.raises(KeyError, match="unknown MCP service"): endpoints.for_service("nope") def test_load_token_uses_explicit_value() -> None: assert load_token(value="abcdef") == "abcdef" def test_load_token_strips_whitespace_in_explicit_value() -> None: assert load_token(value=" abcdef\n") == "abcdef" def test_load_token_uses_env_var() -> None: token = load_token(env={"CERBERO_BITE_MCP_TOKEN": "xyz"}) assert token == "xyz" def test_load_token_strips_whitespace_in_env_var() -> None: token = load_token(env={"CERBERO_BITE_MCP_TOKEN": " xyz\n"}) assert token == "xyz" def test_load_token_raises_when_missing() -> None: with pytest.raises(ValueError, match="CERBERO_BITE_MCP_TOKEN"): load_token(env={}) def test_load_token_raises_when_empty() -> None: with pytest.raises(ValueError, match="CERBERO_BITE_MCP_TOKEN"): load_token(env={"CERBERO_BITE_MCP_TOKEN": " "}) def test_load_token_raises_when_explicit_value_blank() -> None: with pytest.raises(ValueError, match="empty"): load_token(value=" ") def test_load_bot_tag_default_when_unset() -> None: assert load_bot_tag(env={}) == DEFAULT_BOT_TAG def test_load_bot_tag_explicit_value_overrides_env() -> None: tag = load_bot_tag(value="BOT__CUSTOM", env={"CERBERO_BITE_MCP_BOT_TAG": "x"}) assert tag == "BOT__CUSTOM" def test_load_bot_tag_uses_env_when_set() -> None: tag = load_bot_tag(env={"CERBERO_BITE_MCP_BOT_TAG": "BOT__SHADOW"}) assert tag == "BOT__SHADOW" def test_load_bot_tag_strips_whitespace() -> None: tag = load_bot_tag(env={"CERBERO_BITE_MCP_BOT_TAG": " BOT__X\n"}) assert tag == "BOT__X" def test_load_bot_tag_falls_back_to_default_when_blank_env() -> None: tag = load_bot_tag(env={"CERBERO_BITE_MCP_BOT_TAG": " "}) assert tag == DEFAULT_BOT_TAG def test_load_bot_tag_rejects_too_long() -> None: with pytest.raises(ValueError, match="exceeds 64"): load_bot_tag(value="x" * 65) def test_mcp_services_table_is_complete() -> None: # Telegram and Portfolio are now in-process and must NOT be listed # as shared MCP services. expected = {"deribit", "hyperliquid", "macro", "sentiment"} assert set(MCP_SERVICES) == expected