Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New release #197

Merged
merged 101 commits into from
Sep 27, 2019
Merged
Changes from 1 commit
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
620ab7d
Add roll command
Kileak Aug 18, 2018
936bdbf
Make roll a non-admin command
Kileak Aug 19, 2018
61f185b
Add versions to requirements.txt (#160)
fibonascii Oct 29, 2018
4e93eef
Try reconnect on every error
Kileak Dec 2, 2018
94c03fe
resolved issue 161 (#163)
Dec 16, 2018
d6be21f
Add fallback handling for usernames
Kileak Dec 16, 2018
5156bef
error response will be send as a thread message
ksslng Dec 29, 2018
f0ff277
Merge pull request #164 from ksslng/development
Kileak Dec 29, 2018
13cde23
Add alias support for commands
Kileak Jan 20, 2019
ee9e97a
Remove superfluous command
Kileak Jan 20, 2019
14352dc
Fix all command handlers with timestamp
Kileak Jan 26, 2019
f139dbb
Merge pull request #167 from OpenToAllCTF/fixhandler
Kileak Jan 26, 2019
2894aab
Fix: Missing timestamp argument on reaction handler
Kileak Jan 27, 2019
69e6006
Merged development into alias
Kileak Feb 2, 2019
e3bae99
Merge pull request #166 from OpenToAllCTF/alias
Kileak Feb 2, 2019
d3897b7
Bugfix: Add missing timestamp to rename ctf
Kileak Feb 2, 2019
8d97feb
Add basic test framework
Kileak Feb 9, 2019
064410c
Harmonized testfile ids
Kileak Feb 9, 2019
82ef67c
Add missing newline in testfiles
Kileak Feb 9, 2019
0a5226f
Merge remote-tracking branch 'origin/master' into development
Grazfather Feb 9, 2019
4383f9f
add set topic to slack wrapper
crclark96 Feb 9, 2019
0e86aaf
add set_ctf_topic and call from addcreds function
crclark96 Feb 9, 2019
24b9ca4
conditionally update topic
crclark96 Feb 9, 2019
893d4de
change set_ctf_topic to take arbitrary string
crclark96 Feb 9, 2019
cf91aa4
oneline docstring
crclark96 Feb 9, 2019
e0220f9
Add handler for saving useful links
r00tdaemon Feb 9, 2019
0adfe2f
add backgrounding option to makefile (#177)
crclark96 Feb 9, 2019
a6f51cf
remove unnecessary function
crclark96 Feb 9, 2019
0549e20
remove extra spacing around docstring
crclark96 Feb 9, 2019
b125bab
Add json config for save handler. Add more details to posts
r00tdaemon Feb 10, 2019
c7d1204
Refactoring for removal of botserver_mock
Kileak Feb 10, 2019
45d8062
Replace set_config_option for tests to avoid overwriting original config
Kileak Feb 10, 2019
90ae1d3
Merge branch 'development' into mocking
Kileak Feb 10, 2019
6a7ec60
Dockerfile caching (#178)
crclark96 Feb 10, 2019
a9e9144
add guarantee that image exists for runlocal and lint rules (#171)
crclark96 Feb 10, 2019
82baea0
Add invite cmd (#175)
crclark96 Feb 13, 2019
2735eb0
Merge pull request #174 from OpenToAllCTF/mocking
Kileak Feb 15, 2019
1f48af0
Fix invalid invite command
Kileak Feb 15, 2019
1a59304
Merge pull request #172 from crclark96/set_topic_url
Kileak Feb 15, 2019
36173f7
Remove unused clas
Kileak Feb 15, 2019
2e1d77d
Add category filter for status (ctf / verbose)
Kileak Mar 14, 2019
51a7c0b
Merge pull request #182 from OpenToAllCTF/statusfilter
Kileak Mar 14, 2019
cf49235
Changes to use staticman fork
r00tdaemon Mar 21, 2019
b9bb70f
Check for purpose changes
Kileak Mar 27, 2019
84eb641
Merge pull request #184 from OpenToAllCTF/purpose_check
Kileak Mar 28, 2019
f58013e
Archive main ctf channel
Kileak Mar 28, 2019
b4c74f2
Merge pull request #185 from OpenToAllCTF/archive_ctf_full
Kileak Mar 28, 2019
475ebc0
Add username of saver in posts
r00tdaemon Mar 28, 2019
ca2e4e5
Add allowed_users to config
r00tdaemon Mar 28, 2019
72a9ae6
Merge pull request #179 from ujjwal96/save-link
Kileak Mar 28, 2019
59e8d0f
Minor renaming and hide link saver command if not configured
Kileak Mar 28, 2019
e7443a3
Add showlinkurl and add example to readme
Kileak Mar 28, 2019
236e752
Check for already finished ctf
Kileak Mar 29, 2019
ebaf5f1
Merge pull request #186 from OpenToAllCTF/finishctftwice
Kileak Mar 29, 2019
bbb551f
Fix parsing of user names in status list
Kileak Mar 31, 2019
8231fdb
Merge pull request #188 from OpenToAllCTF/display_names
Kileak Mar 31, 2019
0540d5a
Revert status change
Kileak Mar 31, 2019
8f28522
Fix status message
Kileak Mar 31, 2019
acc75ff
Merge pull request #189 from OpenToAllCTF/fix_status
Kileak Mar 31, 2019
8adfdef
Resolve username for show_admins
Kileak Mar 31, 2019
b197ac1
Refactoring / Cleanup code
Kileak Mar 31, 2019
4013e33
Add pylintrc
Kileak Mar 31, 2019
91a7a43
Remove URL from creds to get more space in purpose
Kileak Apr 1, 2019
248c014
Cleanup
Kileak Apr 2, 2019
8ace1a2
Merge pull request #190 from OpenToAllCTF/refactoring
Kileak Apr 2, 2019
c503107
Reactivated some pylint warnings
Kileak Apr 2, 2019
e8e8590
Merge pull request #191 from OpenToAllCTF/addpylintrc
Kileak Apr 2, 2019
f0c251b
Merge pull request #192 from OpenToAllCTF/remove_url
Kileak Apr 2, 2019
a7352be
Fix test mock
Kileak Apr 2, 2019
38da8fd
Add config for circle ci
Grazfather Apr 3, 2019
5c969ae
Add lint step to ci
Grazfather Apr 3, 2019
f373396
ci: pylint -E
Grazfather Apr 3, 2019
1af2824
ci: cleanup template comments
Grazfather Apr 3, 2019
df7f17d
Merge pull request #193 from OpenToAllCTF/circle
Kileak Apr 3, 2019
8186813
Cleanup
Kileak Apr 3, 2019
897e19c
Fix parsing of mail addresses in !showcreds
Kileak Apr 3, 2019
16eaec8
Merge pull request #194 from OpenToAllCTF/cleanup
Kileak Apr 3, 2019
9f9720f
Remove usage of urlembed service
r00tdaemon Apr 3, 2019
be078f5
Merge pull request #195 from ujjwal96/save-link
Kileak Apr 22, 2019
040359e
Add max len for wolfram non verbose response
Kileak May 3, 2019
861f291
Don't allow links in ctf long name
Kileak May 5, 2019
d552458
Add sysinfo admin command
Kileak May 9, 2019
c81db56
Add sysinfo admin command
Kileak May 9, 2019
63b23b2
Merge pull request #203 from OpenToAllCTF/sysinfo
Kileak May 9, 2019
9682497
Fix sleep in main loop to be nicer to cpu
Kileak May 9, 2019
757c9ac
Make reload an admin command
Kileak May 23, 2019
7ee93da
Fix ctf reload unit test (admin command now)
Kileak May 28, 2019
fd16c4e
Ignore unparsable channels on init
Kileak May 28, 2019
f9f0909
Remove bot console
Kileak May 28, 2019
ee832fb
Merge pull request #201 from OpenToAllCTF/fixurllongname
Kileak Jun 3, 2019
40b4bb8
Don't execute commands triggered by bot himself
Kileak Jun 3, 2019
bab4af2
Fixes #204 Change regex to capture complete URL
r00tdaemon Jun 6, 2019
14db84e
Merge pull request #205 from ujjwal96/save-link
Kileak Jun 6, 2019
de443b3
Add "finished since" to ctf status
Kileak Jun 19, 2019
82058a7
Clean up finish on display
Kileak Jun 19, 2019
8b2c954
Add archive reminder handling
Kileak Jun 19, 2019
0e7cf89
Add deletion logging by specific keywords
Kileak Jun 19, 2019
2d74571
Allow longer ctf and challenge names
Grazfather Aug 28, 2019
d1ca226
Truncate finished time to an int
Grazfather Sep 11, 2019
b6f892f
Release 0.1.0
Grazfather Sep 11, 2019
6901a4f
Merge pull request #210 from OpenToAllCTF/longer_chal_names
Kileak Sep 26, 2019
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
Prev Previous commit
Next Next commit
Add basic test framework
Kileak committed Feb 9, 2019

Verified

This commit was signed with the committer’s verified signature.
joshcooper Josh Cooper
commit 8d97feb83ea5671962bbca5ffe3ee023304f8c0a
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -11,3 +11,6 @@ run: image

runlocal:
docker run --rm -it -v ${PWD}/:/src/ otabot

test:
docker run --rm -v ${PWD}/:/src/ otabot python3 runtests.py
213 changes: 213 additions & 0 deletions runtests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#!/usr/bin/env python3
from unittest import TestCase
from unittest.mock import patch
from tests.botserver_mock import BotServerMock
import unittest
from util.loghandler import log, logging


class TestSyscallsHandler(TestCase):
def setUp(self):
self.botserver = BotServerMock()

def test_available(self):
self.botserver.test_command("!syscalls available")
self.assertTrue(self.botserver.check_for_response("Available architectures"),
msg="Available architectures didn't respond correct.")

def test_show_x86_execve(self):
self.botserver.test_command("!syscalls show x86 execve")
self.assertTrue(self.botserver.check_for_response("execve"), msg="Didn't receive execve syscall from bot")
self.assertTrue(self.botserver.check_for_response("0x0b"),
msg="Didn't receive correct execve syscall no for x86 from bot")

def test_show_amd64_execve(self):
self.botserver.test_command("!syscalls show x64 execve")
self.assertTrue(self.botserver.check_for_response("execve"), msg="Didn't receive execve syscall from bot")
self.assertTrue(self.botserver.check_for_response("0x3b"),
msg="Didn't receive correct execve syscall no for x64 from bot")

def test_syscall_not_found(self):
self.botserver.test_command("!syscalls show x64 notexist")
self.assertTrue(self.botserver.check_for_response("Specified syscall not found"),
msg="Bot didn't respond with expected response on non-existing syscall")


class TestBotHandler(TestCase):
def setUp(self):
self.botserver = BotServerMock()

def test_ping(self):
self.botserver.test_command("!bot ping")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertTrue(self.botserver.check_for_response("Pong!"), msg="Ping command didn't reply with pong.")

def test_intro(self):
self.botserver.test_command("!bot intro")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="Intro didn't execute properly.")

def test_version(self):
self.botserver.test_command("!bot version")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="Version didn't execute properly.")


class TestAdminHandler(TestCase):
def setUp(self):
self.botserver = BotServerMock()

def test_show_admins(self):
self.botserver.test_command("!admin show_admins", "admin_user")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="ShowAdmins didn't execute properly.")
self.assertTrue(self.botserver.check_for_response("Administrators"), msg="ShowAdmins didn't reply with expected result.")

def test_add_admin(self):
self.botserver.test_command("!admin add_admin test", "admin_user")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="AddAdmin didn't execute properly.")

def test_remove_admin(self):
self.botserver.test_command("!admin remove_admin test", "admin_user")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="RemoveAdmin didn't execute properly.")

def test_as(self):
self.botserver.test_command("!admin as @unittest_user1 addchallenge test pwn", "admin_user")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="As didn't execute properly.")


class TestChallengeHandler(TestCase):
def setUp(self):
self.botserver = BotServerMock()

def test_addctf_name_too_long(self):
self.botserver.test_command("!ctf addctf unittest_ctf unittest_ctf")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertTrue(self.botserver.check_for_response("CTF name must be <= 10 characters."), msg="Challenge handler didn't respond with expected result for name_too_long.")

def test_addctf_success(self):
self.botserver.test_command("!ctf addctf test_ctf test_ctf")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertTrue(self.botserver.check_for_response("Created channel #test_ctf"), msg="Challenge handler failed on creating ctf channel.")

def test_addchallenge(self):
self.botserver.test_command("!ctf addchall testchall pwn")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="AddChallenge command didn't execute properly.")

def test_workon(self):
self.botserver.test_command("!ctf workon test_challenge")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="Workon command didn't execute properly.")

def test_status(self):
self.botserver.test_command("!ctf status")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="Status command didn't execute properly.")

def test_solve(self):
self.botserver.test_command("!ctf solve testchall")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="Solve command didn't execute properly.")

def test_solve_support(self):
self.botserver.test_command("!ctf solve testchall supporter")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="Solve with supporter didn't execute properly.")

def test_rename_challenge_name(self):
self.botserver.test_command("!ctf renamechallenge testchall test1")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="RenameChallenge didn't execute properly.")

def test_renamectf(self):
self.botserver.test_command("!ctf renamectf testctf test2")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="RenameCTF didn't execute properly.")

def test_reload(self):
self.botserver.test_command("!ctf reload")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertTrue(self.botserver.check_for_response("Updating CTFs and challenges"), msg="Reload didn't execute properly.")

def test_addcreds(self):
self.botserver.test_command("!ctf addcreds user pw url")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="RenameCTF didn't execute properly.")

def test_endctf(self):
self.botserver.test_command("!ctf endctf", "admin_user")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="EndCTF didn't execute properly.")

def test_showcreds(self):
self.botserver.test_command("!ctf showcreds")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="RenameCTF didn't execute properly.")

def test_unsolve(self):
self.botserver.test_command("!ctf unsolve testchall")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="RenameCTF didn't execute properly.")

def test_removechallenge(self):
self.botserver.test_command("!ctf removechallenge testchall", "admin_user")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="RenameCTF didn't execute properly.")

def test_roll(self):
self.botserver.test_command("!ctf roll")

self.assertTrue(self.botserver.check_for_response_available(), msg="Bot didn't react on unit test. Check for possible exceptions.")
self.assertFalse(self.botserver.check_for_response("Unknown handler or command"), msg="RenameCTF didn't execute properly.")


def run_tests():
# borrowed from gef test suite (https://github.com/hugsy/gef/blob/dev/tests/runtests.py)
test_instances = [
TestSyscallsHandler,
TestBotHandler,
TestAdminHandler,
TestChallengeHandler
]

# don't show bot debug messages for running tests
log.setLevel(logging.ERROR)

runner = unittest.TextTestRunner(verbosity=3)
total_failures = 0

for test in [unittest.TestLoader().loadTestsFromTestCase(x) for x in test_instances]:
res = runner.run(test)
total_failures += len(res.errors) + len(res.failures)

return total_failures


if __name__ == "__main__":
run_tests()
4 changes: 4 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
__all__ = [
"botserver_mock",
"slackwrapper_mock"
]
170 changes: 170 additions & 0 deletions tests/botserver_mock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import json
import threading
import time
import websocket

import handlers.handler_factory as handler_factory
from handlers import *
from util.loghandler import *
from tests.slackwrapper_mock import SlackWrapperMock
from bottypes.invalid_console_command import *
from slackclient.server import SlackConnectionError


class BotServerMock():
user_list = {}

def __init__(self):
log.debug("Parse config file and initialize threading...")
self.running = False
self.config = {}
self.bot_name = "unittest_bot"
self.bot_id = "unittest_botid"
self.bot_at = "@unittest_bot"
self.slack_wrapper = SlackWrapperMock("unittest_apikey")

def quit(self):
"""Inform the application that it is quitting."""
self.running = False

def load_config(self):
"""Load configuration file."""
self.config = {
"bot_name": "unittest_bot",
"api_key": "unittest_apikey",
"send_help_as_dm": "1",
"admin_users": [
"admin_user"
],
"auto_invite": [],
"wolfram_app_id": "wolfram_dummyapi"
}

def get_config_option(self, option):
"""Get configuration option."""
result = self.config.get(option)

return result

def set_config_option(self, option, value):
"""Set configuration option."""

if option in self.config:
self.config[option] = value
log.info("Updated configuration: {} => {}".format(option, value))
else:
raise InvalidConsoleCommand("The specified configuration option doesn't exist: {}".format(option))

def parse_slack_message(self, message_list):
"""
The Slack Real Time Messaging API is an events firehose.
Return (message, channel, ts, user) if the message is directed at the bot,
otherwise return (None, None, None, None).
"""
for msg in message_list:
if msg.get("type") == "message" and "subtype" not in msg:
if self.bot_at in msg.get("text", ""):
# Return text after the @ mention, whitespace removed
return msg['text'].split(self.bot_at)[1].strip(), msg['channel'], msg['thread_ts'] if 'thread_ts' in msg else msg['ts'], msg['user']
elif msg.get("text", "").startswith("!"):
# Return text after the !
return msg['text'][1:].strip(), msg['channel'], msg['thread_ts'] if 'thread_ts' in msg else msg['ts'], msg['user']

return None, None, None, None

def parse_slack_reaction(self, message_list):
for msg in message_list:
msgtype = msg.get("type")

if msgtype == "reaction_removed" or msgtype == "reaction_added":
# Ignore reactions from the bot itself
if msg["user"] == self.bot_id:
continue

if msg["item"]:
return msg["reaction"], msg["item"]["channel"], msg["item"]["ts"], msg["user"]

return None, None, None, None

def load_bot_data(self):
"""
Fetches the bot user information such as
bot_name, bot_id and bot_at.
"""
self.bot_name = self.slack_wrapper.username
self.bot_id = self.slack_wrapper.user_id
self.bot_at = "<@{}>".format(self.bot_id)
self.running = True

def test_command(self, msg, exec_user="normal_user"):
"""Run the command as the specified user in the test environment."""
testmsg = [{'type': 'message', 'user': exec_user, 'text': msg, 'client_msg_id': '738e4beb-d50e-42a4-a60e-3fafd4bd71da',
'team': 'UNITTESTTEAMID', 'channel': 'UNITTESTCHANNELID', 'event_ts': '1549715670.002000', 'ts': '1549715670.002000'}]
self.exec_message(testmsg)

def test_reaction(self, reaction, exec_user="normal_user"):
"""Run the specified reaction as the specified user in the test environment."""
testmsg = [{'type': 'reaction_added', 'user': exec_user, 'item': {'type': 'message', 'channel': 'UNITTESTCHANNELID', 'ts': '1549117537.000500'},
'reaction': reaction, 'item_user': 'UNITTESTUSERID', 'event_ts': '1549715822.000800', 'ts': '1549715822.000800'}]

self.exec_message(testmsg)

def check_for_response_available(self):
return len(self.slack_wrapper.message_list) > 0

def check_for_response(self, expected_result):
""" Check if the simulated slack responses contain an expected result. """
for msg in self.slack_wrapper.message_list:
if expected_result in msg.message:
return True

return False

def exec_message(self, testmsg):
self.running = True

while self.running:
try:
self.load_config()
self.slack_wrapper = SlackWrapperMock("testapikey")

if self.slack_wrapper.connected:
self.load_bot_data()
READ_WEBSOCKET_DELAY = 1 # 1 second delay between reading from firehose

# Might even pass the bot server for handlers?
handler_factory.initialize(self.slack_wrapper, self.bot_id, self)

# Main loop
while self.running:
message = testmsg
if message:
reaction, channel, ts, reaction_user = self.parse_slack_reaction(message)

if reaction:
log.debug("Received reaction : {} ({})".format(reaction, channel))
handler_factory.process_reaction(
self.slack_wrapper, reaction, ts, channel, reaction_user)

command, channel, ts, user = self.parse_slack_message(message)

if command:
log.debug("Received bot command : {} ({})".format(command, channel))
handler_factory.process(self.slack_wrapper, self,
command, ts, channel, user)

# We're in test context, immediately stop
self.running = False
else:
log.error("Connection failed. Invalid slack token or bot id?")
self.running = False
except websocket._exceptions.WebSocketConnectionClosedException:
log.exception("Web socket error. Executing reconnect...")
except SlackConnectionError:
# Try to reconnect if slackclient auto_reconnect didn't work out. Keep an eye on the logfiles,
# and remove the superfluous exception handling if auto_reconnect works.
log.exception("Slack connection error. Trying manual reconnect in 5 seconds...")
time.sleep(5)
except:
log.exception("Unhandled error. Try reconnect...")
time.sleep(5)
Loading