Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bugzooka/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def main() -> None:
if args.enable_socket_mode:

logger.info("Starting Socket Mode (WebSocket) for responding to @ mentions")
listener = SlackSocketListener(channel_id=SLACK_CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

# Start socket listener in a separate thread
socket_thread = threading.Thread(
Expand Down
4 changes: 2 additions & 2 deletions bugzooka/integrations/slack_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ class SlackClientBase:
Provides common initialization, message formatting, and utility methods.
"""

def __init__(self, channel_id: str, logger: logging.Logger):
def __init__(self, logger: logging.Logger, channel_id: str = None):
"""
Initialize Slack client with common configuration.

:param channel_id: Slack channel ID to monitor/post to
:param logger: Logger instance
:param channel_id: Optional Slack channel ID to monitor/post to
"""
self.slack_bot_token = SLACK_BOT_TOKEN
self.channel_id = channel_id
Expand Down
4 changes: 2 additions & 2 deletions bugzooka/integrations/slack_fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ class SlackMessageFetcher(SlackClientBase):

def __init__(self, channel_id, logger, poll_interval=600):
"""Initialize Slack client and channel details."""
# Initialize base class (handles WebClient, channel_id, logger, running flag, signal handler)
super().__init__(channel_id, logger)
# Initialize base class (handles WebClient, logger, channel_id, running flag, signal handler)
super().__init__(logger, channel_id)

self.poll_interval = poll_interval # How often to fetch messages
self.last_seen_timestamp = None # Track the latest message timestamp
Expand Down
31 changes: 7 additions & 24 deletions bugzooka/integrations/slack_socket_listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,15 @@ class SlackSocketListener(SlackClientBase):
Listens for @ mentions of the bot and processes messages asynchronously in real-time.
"""

def __init__(
self, channel_id: str, logger: logging.Logger, max_workers: int = 5
):
def __init__(self, logger: logging.Logger, max_workers: int = 5):
"""
Initialize Socket Mode client and channel details.
Initialize Socket Mode client.

:param channel_id: Slack channel ID to monitor
:param logger: Logger instance
:param max_workers: Maximum number of concurrent mention handlers (default: 5)
"""
# Initialize base class (handles WebClient, channel_id, logger, running flag, signal handler)
super().__init__(channel_id, logger)
# Initialize base class (handles WebClient, logger, running flag, signal handler)
super().__init__(logger)

self.slack_app_token = SLACK_APP_TOKEN

Expand All @@ -66,7 +63,7 @@ def __init__(
def _should_process_message(self, event: Dict[str, Any]) -> bool:
"""
Determine if a message should be processed.
Only process messages that mention the bot and are in the configured channel.
Only process app_mention events not sent by the bot itself.

:param event: Slack event data
:return: True if message should be processed
Expand All @@ -75,13 +72,6 @@ def _should_process_message(self, event: Dict[str, Any]) -> bool:
if event.get("type") != "app_mention":
return False

# Check if it's in the right channel
if event.get("channel") != self.channel_id:
self.logger.debug(
f"Ignoring mention in different channel: {event.get('channel')}"
)
return False

# Don't process messages from the bot itself
if event.get("user") == JEDI_BOT_SLACK_USER_ID:
self.logger.debug("Ignoring message from bot itself")
Expand Down Expand Up @@ -277,15 +267,8 @@ def run(self, **kwargs) -> None:

:param kwargs: Configuration arguments (not used, for compatibility)
"""
self.logger.info(
f"🚀 Starting Slack Socket Mode Listener for Channel: {self.channel_id}"
)
self.logger.info(
"Bot will respond to @ mentions with a simple greeting message"
)
self.logger.info(
f"Async processing enabled with {self.executor._max_workers} worker threads"
)
self.logger.info("🚀 Starting Slack Socket Mode Listener")
self.logger.info(f"Async processing enabled with {self.executor._max_workers} worker threads")

# Register the event handler
self.socket_client.socket_mode_request_listeners.append(
Expand Down
31 changes: 15 additions & 16 deletions tests/test_slack_socket_listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,20 @@ def test_initialization(self, mock_socket_mode_client, mock_web_client):

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

assert listener.channel_id == CHANNEL_ID
assert listener.logger == logger
assert listener.running is True
mock_socket_mode_client.assert_called_once()
mock_web_client.assert_called_once()

def test_should_process_app_mention(self, mock_socket_mode_client, mock_web_client):
"""Test that app_mention events in the correct channel are processed."""
"""Test that app_mention events are processed."""
logger = logging.getLogger("test")

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

event = create_app_mention_event(
text="<@UBOTID> analyze this failure",
Expand All @@ -102,23 +101,23 @@ def test_should_process_app_mention(self, mock_socket_mode_client, mock_web_clie

assert listener._should_process_message(event) is True

def test_should_not_process_wrong_channel(
def test_should_process_any_channel(
self, mock_socket_mode_client, mock_web_client
):
"""Test that mentions in other channels are ignored."""
"""Test that mentions in any channel are processed."""
logger = logging.getLogger("test")

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

event = create_app_mention_event(
text="<@UBOTID> analyze this failure",
user="U12345",
)
event["channel"] = "C_DIFFERENT_CHANNEL"

assert listener._should_process_message(event) is False
assert listener._should_process_message(event) is True

def test_should_not_process_bot_self_mention(
self, mock_socket_mode_client, mock_web_client
Expand All @@ -129,7 +128,7 @@ def test_should_not_process_bot_self_mention(
with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
with patch("bugzooka.integrations.slack_socket_listener.JEDI_BOT_SLACK_USER_ID", "UBOTID"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

event = create_app_mention_event(
text="<@UBOTID> analyze this failure",
Expand All @@ -146,7 +145,7 @@ def test_process_mention_sends_greeting(

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

event = create_app_mention_event(
text="<@UBOTID> hello",
Expand All @@ -172,7 +171,7 @@ def test_submit_mention_for_processing(

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger, max_workers=2)
listener = SlackSocketListener(logger=logger, max_workers=2)

event = create_app_mention_event(
text="<@UBOTID> async test",
Expand All @@ -197,7 +196,7 @@ def test_submit_mention_prevents_duplicates(

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger, max_workers=2)
listener = SlackSocketListener(logger=logger, max_workers=2)

event = create_app_mention_event(
text="<@UBOTID> duplicate test",
Expand All @@ -222,7 +221,7 @@ def test_process_socket_request_acknowledgement(

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

event = create_app_mention_event(text="<@UBOTID> test", ts="1234567890.123456")
socket_request = create_socket_mode_request(event)
Expand All @@ -246,7 +245,7 @@ def test_process_socket_request_adds_reaction_immediately(

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

event = create_app_mention_event(
text="<@UBOTID> test",
Expand Down Expand Up @@ -275,7 +274,7 @@ def test_process_socket_request_non_app_mention(

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

# Create a different event type
event = {
Expand All @@ -302,7 +301,7 @@ def test_process_mention_error_handling(

with patch("bugzooka.core.config.SLACK_BOT_TOKEN", "xoxb-test-token"):
with patch("bugzooka.core.config.SLACK_APP_TOKEN", "xapp-test-token"):
listener = SlackSocketListener(channel_id=CHANNEL_ID, logger=logger)
listener = SlackSocketListener(logger=logger)

# Mock chat_postMessage to raise an exception
mock_web_client.return_value.chat_postMessage.side_effect = Exception(
Expand Down