Skip to content
Open
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: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ filterwarnings = [
"ignore:slack.* package is deprecated. Please use slack_sdk.* package instead.*:UserWarning",
]
asyncio_mode = "auto"
timeout = 180
timeout_method = "thread"


[tool.mypy]
Expand Down
4 changes: 4 additions & 0 deletions requirements/testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ pytest>=9.1.1,<10; python_version >= "3.10"
# Note: for async.
pytest-asyncio<2

# pytest-timeout
# Note: per-test timeout so a hung test fails fast with a thread dump instead of stalling CI.
pytest-timeout>=2.2,<3

# pytest-cov
# Note: pytest-cov 7.1+ requires Python >=3.9; cap older interpreters below it.
pytest-cov>=4,<7.1.0; python_version < "3.9"
Expand Down
12 changes: 9 additions & 3 deletions tests/mock_web_api_server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ def setup_mock_web_api_server(test: TestCase, handler: Type[SimpleHTTPRequestHan
test.received_requests = ReceivedRequests(Queue())
test.thread = MockServerThread(queue=test.received_requests.queue, test=test, handler=handler, port=port)
test.thread.start()
test.server_started.wait()
if not test.server_started.wait(timeout=5):
raise RuntimeError(
f"Mock web API server failed to start on port {test.thread.port} within 5s (port already in use?)"
)


def cleanup_mock_web_api_server(test: TestCase):
Expand Down Expand Up @@ -56,11 +59,14 @@ def setup_mock_web_api_server_async(test: TestCase, handler: Type[SimpleHTTPRequ
test.received_requests = ReceivedRequests(asyncio.Queue())
test.thread = MockServerThread(queue=test.received_requests.queue, test=test, handler=handler, port=port)
test.thread.start()
test.server_started.wait()
if not test.server_started.wait(timeout=5):
raise RuntimeError(
f"Mock web API server failed to start on port {test.thread.port} within 5s (port already in use?)"
)


def cleanup_mock_web_api_server_async(test: TestCase):
test.thread.stop_unsafe()
test.thread.stop()
test.thread = None


Expand Down
37 changes: 21 additions & 16 deletions tests/mock_web_api_server/mock_server_thread.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
from asyncio import Queue
import asyncio
from http.server import HTTPServer, SimpleHTTPRequestHandler
import logging
import threading
from typing import Type, Union
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from queue import Queue
from typing import Optional, Type, Union
from unittest import TestCase

logger = logging.getLogger(__name__)


class MockServerThread(threading.Thread):
def __init__(
self, queue: Union[Queue, asyncio.Queue], test: TestCase, handler: Type[SimpleHTTPRequestHandler], port: int = 8888
self,
test: TestCase,
handler: Type[SimpleHTTPRequestHandler],
queue: Optional[Union[Queue, asyncio.Queue]] = None,
port: int = 8888,
):
threading.Thread.__init__(self)
threading.Thread.__init__(self, daemon=True)
self.handler = handler
self.test = test
self.queue = queue
self.port = port

def run(self):
self.server = HTTPServer(("localhost", self.port), self.handler)
self.server.queue = self.queue
self.test.server_url = f"http://localhost:{str(self.port)}"
self.server = ThreadingHTTPServer(("localhost", self.port), self.handler)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ThreadingHTTPServer is only available in python 3.7+, this is why we were using HTTPServer

if self.queue is not None:
self.server.queue = self.queue
self.test.server_url = f"http://localhost:{self.port}"
self.test.host, self.test.port = self.server.socket.getsockname()
self.test.server_started.set() # threading.Event()

Expand All @@ -30,12 +38,9 @@ def run(self):
self.server.server_close()

def stop(self):
with self.server.queue.mutex:
del self.server.queue
self.server.shutdown()
self.join()

def stop_unsafe(self):
del self.server.queue
self.server.shutdown()
self.join()
self.join(timeout=5)
if self.is_alive():
logger.warning(f"Mock web API server thread on port {self.port} did not stop within 5s")
if getattr(self.server, "queue", None) is not None:
del self.server.queue
35 changes: 8 additions & 27 deletions tests/rtm/mock_web_api_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import logging
import threading
from http import HTTPStatus
from http.server import HTTPServer, SimpleHTTPRequestHandler
from typing import Type
from http.server import SimpleHTTPRequestHandler
from unittest import TestCase

from tests.mock_web_api_server.mock_server_thread import MockServerThread


class MockHandler(SimpleHTTPRequestHandler):
protocol_version = "HTTP/1.1"
Expand Down Expand Up @@ -62,34 +63,14 @@ def do_POST(self):
self._handle()


class MockServerThread(threading.Thread):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeps implementation DRY

def __init__(self, test: TestCase, handler: Type[SimpleHTTPRequestHandler] = MockHandler):
threading.Thread.__init__(self)
self.handler = handler
self.test = test

def run(self):
self.server = HTTPServer(("localhost", 8888), self.handler)
self.test.server_url = "http://localhost:8888"
self.test.host, self.test.port = self.server.socket.getsockname()
self.test.server_started.set() # threading.Event()

self.test = None
try:
self.server.serve_forever(0.05)
finally:
self.server.server_close()

def stop(self):
self.server.shutdown()
self.join()


def setup_mock_web_api_server(test: TestCase):
test.server_started = threading.Event()
test.thread = MockServerThread(test)
test.thread = MockServerThread(test=test, handler=MockHandler)
test.thread.start()
test.server_started.wait()
if not test.server_started.wait(timeout=5):
raise RuntimeError(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fails with noise

f"Mock web API server failed to start on port {test.thread.port} within 5s (port already in use?)"
)


def cleanup_mock_web_api_server(test: TestCase):
Expand Down
4 changes: 1 addition & 3 deletions tests/slack_sdk/socket_mode/test_interactions_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,12 @@ def socket_mode_request_handler(client: BaseSocketModeClient, request: SocketMod

self.assertEqual(len(socket_mode_envelopes), len(received_socket_mode_requests))
finally:
pass
# client.close()
client.close()
self.logger.info(f"Passed with buffer size: {buffer_size}")

finally:
# Restore the default value
sys.setrecursionlimit(default_recursion_limit)
client.close()

self.logger.info(f"Passed with buffer size: {buffer_size_list}")

Expand Down
41 changes: 1 addition & 40 deletions tests/slack_sdk/web/mock_web_api_handler.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import asyncio
import json
import logging
from queue import Queue
import re
import threading
import time
from http import HTTPStatus
from http.server import HTTPServer, SimpleHTTPRequestHandler
from typing import Type, Union
from unittest import TestCase
from http.server import SimpleHTTPRequestHandler
from urllib.parse import urlparse, parse_qs


Expand Down Expand Up @@ -258,37 +253,3 @@ def do_GET(self):

def do_POST(self):
self._handle()


class MockServerThread(threading.Thread):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeps implementations DRY

def __init__(
self, queue: Union[Queue, asyncio.Queue], test: TestCase, handler: Type[SimpleHTTPRequestHandler] = MockHandler
):
threading.Thread.__init__(self)
self.handler = handler
self.test = test
self.queue = queue

def run(self):
self.server = HTTPServer(("localhost", 8888), self.handler)
self.server.queue = self.queue
self.test.server_url = "http://localhost:8888"
self.test.host, self.test.port = self.server.socket.getsockname()
self.test.server_started.set() # threading.Event()

self.test = None
try:
self.server.serve_forever(0.05)
finally:
self.server.server_close()

def stop(self):
with self.server.queue.mutex:
del self.server.queue
self.server.shutdown()
self.join()

def stop_unsafe(self):
del self.server.queue
self.server.shutdown()
self.join()
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
start_socket_mode_server,
socket_mode_envelopes,
socket_mode_hello_message,
stop_socket_mode_server,
)
from tests.slack_sdk.socket_mode.mock_web_api_handler import MockHandler
from tests.mock_web_api_server import setup_mock_web_api_server_async, cleanup_mock_web_api_server_async
Expand All @@ -35,7 +36,10 @@ def setUp(self):
start_socket_mode_server(self, 3001)

def tearDown(self):
cleanup_mock_web_api_server_async(self)
try:
cleanup_mock_web_api_server_async(self)
finally:
stop_socket_mode_server(self)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were not always stopping the socket mode server I think this was leading to test hanging sometimes


@async_test
async def test_interactions(self):
Expand Down
Loading