Files
2026-06-29 10:08:59 -07:00

188 lines
6.3 KiB
Python

from __future__ import annotations
import pytest
from helpers import seed_state
from slack_mock.models import SlackChannel
from slack_mock.server import (
archive_channel,
create_channel,
list_dms,
open_dm,
open_mpim,
rename_channel,
send_dm,
send_mpim,
)
from slack_mock.state import get_state
def setup_function() -> None:
seed_state(
{
"channels": {"C001": {"id": "C001", "name": "general", "is_im": False, "context_team_id": "T_MOCK"}},
"messages": {"C001": []},
"users": {
"U001": {
"id": "U001",
"name": "alice",
"real_name": "Alice Smith",
"profile": {"display_name": "alice"},
},
"U002": {"id": "U002", "name": "bob", "real_name": "Bob Jones", "profile": {"display_name": "bob"}},
"U003": {
"id": "U003",
"name": "charlie",
"real_name": "Charlie Day",
"profile": {"display_name": "charlie"},
},
},
}
)
@pytest.mark.asyncio
async def test_open_dm() -> None:
result = await open_dm("U001")
assert result["ok"] is True
assert result["channel"]["is_im"] is True
assert result["channel"]["user"] == "U001"
assert result["channel"]["is_private"] is True
assert result["channel"]["is_channel"] is False
assert get_state().messages[result["channel"]["id"]] == []
@pytest.mark.asyncio
async def test_open_dm_reuses_existing_and_separates_users() -> None:
first = await open_dm("U001")
second = await open_dm("U001")
other = await open_dm("U002")
assert second["channel"]["id"] == first["channel"]["id"]
assert other["channel"]["id"] != first["channel"]["id"]
assert (await open_dm("NONEXISTENT"))["error"] == "user_not_found"
@pytest.mark.asyncio
async def test_list_dms() -> None:
assert (await list_dms())["channels"] == []
await open_dm("U001")
await open_dm("U002")
result = await list_dms()
assert len(result["channels"]) == 2
assert all(channel["is_im"] for channel in result["channels"])
assert all(channel["id"] != "C001" for channel in result["channels"])
assert len((await list_dms(limit=1))["channels"]) == 1
@pytest.mark.asyncio
async def test_direct_conversations_cannot_be_archived_or_renamed() -> None:
dm_id = (await open_dm("U001"))["channel"]["id"]
state = get_state()
state.channels["GMP001"] = SlackChannel.model_validate(
{
"id": "GMP001",
"name": "mpdm-alice--bob-1",
"is_channel": False,
"is_group": False,
"is_im": False,
"is_mpim": True,
"is_private": True,
"context_team_id": "T_MOCK",
}
)
state.messages["GMP001"] = []
for channel_id in (dm_id, "GMP001"):
archived = await archive_channel(channel_id)
renamed = await rename_channel(channel_id, "new-name")
assert archived == {"ok": False, "error": "method_not_supported_for_channel_type"}
assert renamed == {"ok": False, "error": "method_not_supported_for_channel_type", "channel": {}}
assert state.channels[dm_id].is_archived is False
assert state.channels[dm_id].name == "alice"
assert state.channels["GMP001"].is_archived is False
assert state.channels["GMP001"].name == "mpdm-alice--bob-1"
@pytest.mark.asyncio
async def test_list_dms_includes_multi_party_direct_conversations() -> None:
state = get_state()
state.channels["GMP001"] = SlackChannel.model_validate(
{
"id": "GMP001",
"name": "mpdm-alice--bob-1",
"is_channel": False,
"is_group": False,
"is_im": False,
"is_mpim": True,
"is_private": True,
"context_team_id": "T_MOCK",
}
)
state.messages["GMP001"] = []
result = await list_dms()
assert [channel["id"] for channel in result["channels"]] == ["GMP001"]
assert result["channels"][0]["is_mpim"] is True
@pytest.mark.asyncio
async def test_open_mpim_reuses_existing_conversation_by_members() -> None:
first = await open_mpim(["U002", "U001"])
second = await open_mpim(["U001", "U002"])
assert first["ok"] is True
assert first["channel"]["is_mpim"] is True
assert first["channel"]["is_private"] is True
assert first["channel"]["members"] == ["U_MOCK_BOT", "U001", "U002"]
assert second["channel"]["id"] == first["channel"]["id"]
assert [channel["id"] for channel in (await list_dms())["channels"]] == [first["channel"]["id"]]
@pytest.mark.asyncio
async def test_open_mpim_validates_user_list() -> None:
assert await open_mpim(["U001"]) == {"ok": False, "error": "not_enough_users", "channel": {}}
assert await open_mpim(["U001", "U001"]) == {"ok": False, "error": "not_enough_users", "channel": {}}
assert await open_mpim(["U001", "U404"]) == {"ok": False, "error": "user_not_found", "channel": {}}
@pytest.mark.asyncio
async def test_send_mpim_posts_and_reuses_conversation() -> None:
sent = await send_mpim(["U001", "U002"], "Hello group")
second = await send_mpim(["U002", "U001"], "Second group note")
assert sent["ok"] is True
assert sent["message"]["text"] == "Hello group"
assert second["channel"] == sent["channel"]
assert [message.text for message in get_state().messages[sent["channel"]]] == ["Hello group", "Second group note"]
assert (await send_mpim(["U001", "U404"], "Hi"))["ok"] is False
@pytest.mark.asyncio
async def test_dm_names_do_not_reserve_channel_names() -> None:
opened = await open_dm("U001")
created = await create_channel(opened["channel"]["name"])
assert created["ok"] is True
assert created["channel"]["name"] == "alice"
assert created["channel"]["is_im"] is False
@pytest.mark.asyncio
async def test_send_dm() -> None:
result = await send_dm("U001", "Hello Alice!")
assert result["ok"] is True
assert result["message"]["text"] == "Hello Alice!"
assert result["channel"]
assert result["ts"]
assert len((await list_dms())["channels"]) == 1
await send_dm("U001", "Second")
assert len((await list_dms())["channels"]) == 1
assert get_state().messages[result["channel"]][0].text == "Hello Alice!"
assert (await send_dm("NONEXISTENT", "Hi"))["ok"] is False