"""Tests for the Slack API client."""
from unittest.mock import AsyncMock, patch
import pytest
from slack_mcp import mcp
from slack_mcp.client import slack
from slack_mcp.exceptions import SlackMCPError, SlackPermissionError
from slack_mcp.lifespan import lifespan
class TestCheckChannelAllowed:
def test_allowed_when_no_whitelist(self, mock_slack_clients):
slack._allowed_channels = None
slack.check_channel_allowed("C123") # should not raise
def test_allowed_when_in_whitelist(self, mock_slack_clients):
slack._allowed_channels = {"C123", "C456"}
slack.check_channel_allowed("C123") # should not raise
def test_blocked_when_not_in_whitelist(self, mock_slack_clients):
slack._allowed_channels = {"C123", "C456"}
with pytest.raises(SlackMCPError) as exc_info:
slack.check_channel_allowed("C999")
assert exc_info.value.error_code == "channel_not_allowed"
class TestCallUser:
async def test_raises_when_no_user_token(self):
slack._user_client = None
try:
with pytest.raises(SlackPermissionError) as exc_info:
await slack.call_user("search_messages", query="test")
assert exc_info.value.error_code == "missing_user_token"
assert "SLACK_USER_TOKEN" in str(exc_info.value)
finally:
slack._user_client = None
@pytest.mark.asyncio
class TestLifespan:
async def test_lifespan_bot_only(self):
mock_bot = AsyncMock()
mock_bot.auth_test.return_value = {"user": "testbot", "team": "testteam"}
import os
os.environ.pop("SLACK_USER_TOKEN", None)
with patch.dict("os.environ", {"SLACK_BOT_TOKEN": "xoxb-test"}, clear=False):
with patch("slack_mcp.client.AsyncWebClient") as MockClient:
MockClient.return_value = mock_bot
async with lifespan(mcp):
assert slack._bot_client is mock_bot
assert slack._user_client is None
assert slack._bot_client is None
async def test_lifespan_with_user_token(self):
mock_bot = AsyncMock()
mock_bot.auth_test.return_value = {"user": "testbot", "team": "testteam"}
mock_user = AsyncMock()
mock_user.auth_test.return_value = {"user": "testuser"}
call_count = 0
def create_client(**kwargs):
nonlocal call_count
call_count += 1
if call_count == 1:
return mock_bot
return mock_user
env = {"SLACK_BOT_TOKEN": "xoxb-test", "SLACK_USER_TOKEN": "xoxp-test"}
with patch.dict("os.environ", env, clear=False):
with patch("slack_mcp.client.AsyncWebClient", side_effect=create_client):
async with lifespan(mcp):
assert slack._bot_client is mock_bot
assert slack._user_client is mock_user
assert slack._bot_client is None
assert slack._user_client is None
async def test_lifespan_missing_bot_token(self):
with patch.dict("os.environ", {}, clear=True), pytest.raises(RuntimeError, match="SLACK_BOT_TOKEN"):
async with lifespan(mcp):
pass
async def test_lifespan_channel_whitelist(self):
mock_bot = AsyncMock()
mock_bot.auth_test.return_value = {"user": "testbot", "team": "testteam"}
import os
os.environ.pop("SLACK_USER_TOKEN", None)
env = {"SLACK_BOT_TOKEN": "xoxb-test", "SLACK_MCP_ALLOWED_CHANNELS": "C123,C456"}
with patch.dict("os.environ", env, clear=False):
with patch("slack_mcp.client.AsyncWebClient") as MockClient:
MockClient.return_value = mock_bot
async with lifespan(mcp):
assert {"C123", "C456"} == slack._allowed_channels