-
Notifications
You must be signed in to change notification settings - Fork 835
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: improve the mock server experience (#1602)
- Loading branch information
1 parent
a5b9db6
commit fe598cd
Showing
64 changed files
with
663 additions
and
1,784 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import asyncio | ||
from http.server import SimpleHTTPRequestHandler | ||
from queue import Queue | ||
import threading | ||
import time | ||
from typing import Type | ||
from unittest import TestCase | ||
|
||
from tests.mock_web_api_server.received_requests import ReceivedRequests | ||
from tests.mock_web_api_server.mock_server_thread import MockServerThread | ||
|
||
|
||
def setup_mock_web_api_server(test: TestCase, handler: Type[SimpleHTTPRequestHandler], port: int = 8888): | ||
test.server_started = threading.Event() | ||
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() | ||
|
||
|
||
def cleanup_mock_web_api_server(test: TestCase): | ||
test.thread.stop() | ||
test.thread = None | ||
|
||
|
||
def assert_received_request_count(test: TestCase, path: str, min_count: int, timeout: float = 1): | ||
start_time = time.time() | ||
error = None | ||
while time.time() - start_time < timeout: | ||
try: | ||
received_count = test.received_requests.get(path, 0) | ||
assert ( | ||
received_count == min_count | ||
), f"Expected {min_count} '{path}' {'requests' if min_count > 1 else 'request'}, but got {received_count}!" | ||
return | ||
except Exception as e: | ||
error = e | ||
# waiting for some requests to be received | ||
time.sleep(0.05) | ||
|
||
if error is not None: | ||
raise error | ||
|
||
|
||
def assert_auth_test_count(test: TestCase, expected_count: int): | ||
assert_received_request_count(test, "/auth.test", expected_count, 0.5) | ||
|
||
|
||
######### | ||
# async # | ||
######### | ||
|
||
|
||
def setup_mock_web_api_server_async(test: TestCase, handler: Type[SimpleHTTPRequestHandler], port: int = 8888): | ||
test.server_started = threading.Event() | ||
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() | ||
|
||
|
||
def cleanup_mock_web_api_server_async(test: TestCase): | ||
test.thread.stop_unsafe() | ||
test.thread = None | ||
|
||
|
||
async def assert_received_request_count_async(test: TestCase, path: str, min_count: int, timeout: float = 1): | ||
start_time = time.time() | ||
error = None | ||
while time.time() - start_time < timeout: | ||
try: | ||
received_count = await test.received_requests.get_async(path, 0) | ||
assert ( | ||
received_count == min_count | ||
), f"Expected {min_count} '{path}' {'requests' if min_count > 1 else 'request'}, but got {received_count}!" | ||
return | ||
except Exception as e: | ||
error = e | ||
# waiting for mock_received_requests updates | ||
await asyncio.sleep(0.05) | ||
|
||
if error is not None: | ||
raise error | ||
|
||
|
||
async def assert_auth_test_count_async(test: TestCase, expected_count: int): | ||
await assert_received_request_count_async(test, "/auth.test", expected_count, 0.5) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
from asyncio import Queue | ||
import asyncio | ||
from http.server import HTTPServer, SimpleHTTPRequestHandler | ||
import threading | ||
from typing import Type, Union | ||
from unittest import TestCase | ||
|
||
|
||
class MockServerThread(threading.Thread): | ||
def __init__( | ||
self, queue: Union[Queue, asyncio.Queue], test: TestCase, handler: Type[SimpleHTTPRequestHandler], port: int = 8888 | ||
): | ||
threading.Thread.__init__(self) | ||
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.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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import asyncio | ||
from queue import Queue | ||
from typing import Optional, Union | ||
|
||
|
||
class ReceivedRequests: | ||
def __init__(self, queue: Union[Queue, asyncio.Queue]): | ||
self.queue = queue | ||
self.received_requests: dict = {} | ||
|
||
def get(self, key: str, default: Optional[int] = None) -> Optional[int]: | ||
while not self.queue.empty(): | ||
path = self.queue.get() | ||
self.received_requests[path] = self.received_requests.get(path, 0) + 1 | ||
return self.received_requests.get(key, default) | ||
|
||
async def get_async(self, key: str, default: Optional[int] = None) -> Optional[int]: | ||
while not self.queue.empty(): | ||
path = await self.queue.get() | ||
self.received_requests[path] = self.received_requests.get(path, 0) + 1 | ||
return self.received_requests.get(key, default) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.