Files
Aetheel/test_slack.py
Tanmay Karande ec8bd80a3d first commit
2026-02-13 23:56:09 -05:00

245 lines
8.1 KiB
Python

#!/usr/bin/env python3
"""
Aetheel Slack Adapter — Integration Test
==========================================
Tests the Slack adapter by:
1. Connecting to Slack via Socket Mode
2. Sending a test message to a specified channel
3. Verifying the bot can send and receive
Usage:
python test_slack.py # Interactive — prompts for channel
python test_slack.py --channel C0123456789 # Send to a specific channel
python test_slack.py --dm U0123456789 # Send a DM to a user
python test_slack.py --send-only # Just send, don't listen
Requirements:
- SLACK_BOT_TOKEN and SLACK_APP_TOKEN set in .env
- Bot must be invited to the target channel
"""
import argparse
import logging
import os
import sys
import time
import threading
from dotenv import load_dotenv
load_dotenv()
from adapters.slack_adapter import SlackAdapter, SlackMessage
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger("aetheel.test")
# ---------------------------------------------------------------------------
# Test 1: Send a message
# ---------------------------------------------------------------------------
def test_send_message(adapter: SlackAdapter, target: str) -> bool:
"""Test sending a message to a channel or user."""
print("\n" + "=" * 60)
print(" TEST 1: Send Message")
print("=" * 60)
try:
result = adapter.send_message(
channel=target,
text=(
"🧪 *Aetheel Slack Test*\n\n"
"If you can see this message, the Slack adapter is working!\n\n"
f"• Bot ID: `{adapter._bot_user_id}`\n"
f"• Bot Name: `@{adapter._bot_user_name}`\n"
f"• Timestamp: `{time.strftime('%Y-%m-%d %H:%M:%S')}`\n"
f"• Mode: Socket Mode\n\n"
"_Reply to this message to test receiving._"
),
)
print(f" ✅ Message sent successfully!")
print(f" Channel: {result.channel_id}")
print(f" Message ID: {result.message_id}")
return True
except Exception as e:
print(f" ❌ Failed to send: {e}")
return False
# ---------------------------------------------------------------------------
# Test 2: Send a threaded reply
# ---------------------------------------------------------------------------
def test_threaded_reply(adapter: SlackAdapter, target: str) -> bool:
"""Test sending a message and then replying in a thread."""
print("\n" + "=" * 60)
print(" TEST 2: Threaded Reply")
print("=" * 60)
try:
# Send parent message
parent = adapter.send_message(
channel=target,
text="🧵 *Thread Test* — This is the parent message.",
)
print(f" ✅ Parent message sent (ts={parent.message_id})")
time.sleep(1)
# Send threaded reply
reply = adapter.send_message(
channel=target,
text="↳ This is a threaded reply! Thread isolation is working.",
thread_ts=parent.message_id,
)
print(f" ✅ Thread reply sent (ts={reply.message_id})")
return True
except Exception as e:
print(f" ❌ Failed: {e}")
return False
# ---------------------------------------------------------------------------
# Test 3: Long message chunking
# ---------------------------------------------------------------------------
def test_long_message(adapter: SlackAdapter, target: str) -> bool:
"""Test that long messages are properly chunked."""
print("\n" + "=" * 60)
print(" TEST 3: Long Message Chunking")
print("=" * 60)
try:
# Create a message that exceeds 4000 chars
long_text = "📜 *Long Message Test*\n\n"
for i in range(1, 101):
long_text += f"{i}. This is line number {i} of the long message test. " \
f"It contains enough text to test the chunking behavior.\n"
result = adapter.send_message(channel=target, text=long_text)
print(f" ✅ Long message sent (length={len(long_text)}, id={result.message_id})")
return True
except Exception as e:
print(f" ❌ Failed: {e}")
return False
# ---------------------------------------------------------------------------
# Test 4: Receive messages (interactive)
# ---------------------------------------------------------------------------
def test_receive_messages(adapter: SlackAdapter, duration: int = 30) -> bool:
"""
Test receiving messages by listening for a specified duration.
The bot will echo back any messages it receives.
"""
print("\n" + "=" * 60)
print(" TEST 4: Receive Messages (Interactive)")
print("=" * 60)
print(f" Listening for {duration} seconds...")
print(f" Send a message to @{adapter._bot_user_name} to test receiving.")
print(f" Press Ctrl+C to stop early.\n")
received = []
def test_handler(msg: SlackMessage) -> str:
received.append(msg)
print(f" 📨 Received: '{msg.text}' from @{msg.user_name}")
return f"✅ Got it! You said: _{msg.text}_"
adapter.on_message(test_handler)
try:
adapter.start_async()
time.sleep(duration)
except KeyboardInterrupt:
print("\n Stopped by user.")
finally:
adapter.stop()
print(f"\n Messages received: {len(received)}")
if received:
print(" ✅ Receive test PASSED")
return True
else:
print(" ⚠️ No messages received (send a message to the bot to test)")
return True # Not a failure — just no one sent a message
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main():
parser = argparse.ArgumentParser(description="Test the Aetheel Slack Adapter")
group = parser.add_mutually_exclusive_group()
group.add_argument("--channel", help="Channel ID to send test messages to (C...)")
group.add_argument("--dm", help="User ID to DM for testing (U...)")
parser.add_argument(
"--send-only",
action="store_true",
help="Only run send tests (don't listen for messages)",
)
parser.add_argument(
"--duration",
type=int,
default=30,
help="How long to listen for messages in seconds (default: 30)",
)
args = parser.parse_args()
# Validate tokens
if not os.environ.get("SLACK_BOT_TOKEN") or not os.environ.get("SLACK_APP_TOKEN"):
print("❌ Missing SLACK_BOT_TOKEN or SLACK_APP_TOKEN in environment.")
print(" Copy .env.example to .env and fill in your tokens.")
sys.exit(1)
# Get target
target = args.channel or args.dm
if not target:
print("You need to specify a target for send tests.")
print(" --channel C0123456789 (channel ID)")
print(" --dm U0123456789 (user ID for DM)")
target = input("\nEnter a channel or user ID (or press Enter to skip send tests): ").strip()
# Create adapter
adapter = SlackAdapter(log_level="INFO")
# Resolve identity first
adapter._resolve_identity()
# Run tests
results = {}
if target:
results["send"] = test_send_message(adapter, target)
results["thread"] = test_threaded_reply(adapter, target)
results["chunking"] = test_long_message(adapter, target)
else:
print("\n⏭️ Skipping send tests (no target specified)")
if not args.send_only:
results["receive"] = test_receive_messages(adapter, duration=args.duration)
# Summary
print("\n" + "=" * 60)
print(" TEST RESULTS")
print("=" * 60)
for test_name, passed in results.items():
icon = "" if passed else ""
print(f" {icon} {test_name}")
total = len(results)
passed = sum(1 for v in results.values() if v)
print(f"\n {passed}/{total} tests passed")
print("=" * 60)
return 0 if all(results.values()) else 1
if __name__ == "__main__":
sys.exit(main())