Skip to content

Commit

Permalink
Merge pull request #29 from harveymmaunders/python-websocket-testing
Browse files Browse the repository at this point in the history
Python websocket testing
  • Loading branch information
harveymmaunders authored Jan 23, 2025
2 parents 7568ecc + 09af940 commit a8e6ae6
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 14 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ jobs:
run: python -m pip install --upgrade pip
- name: Install dependencies
run: pip install -r requirements.txt
- name: Install dev dependencies
run: pip install -r dev-requirements.txt
- name: Run pytest
run: pytest tests/
- name: Run black check (linting)
Expand Down
3 changes: 3 additions & 0 deletions client-samples/python/rest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ python -m venv venv
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r dev-requirements.txt
python client-application.py
```
Expand All @@ -61,6 +62,8 @@ python -m venv venv

python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r dev-requirements.txt

python client-application.py
```

Expand Down
4 changes: 4 additions & 0 deletions client-samples/python/rest/dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
black==23.11.0
requests-mock==1.12.1
pytest==8.3.4
parameterized==0.9.0
9 changes: 1 addition & 8 deletions client-samples/python/rest/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1 @@
black==24.10.0
chardet==5.2.0
msal==1.31.1
parameterized==0.9.0
pytest==8.3.4
rel==0.4.9.19
requests-mock==1.12.1
six==1.17.0
msal==1.25.0
2 changes: 2 additions & 0 deletions client-samples/python/websockets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ python -m venv venv
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r dev-requirements.txt
python client.py
```
Expand All @@ -69,6 +70,7 @@ python -m venv venv

python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r dev-requirements.txt
python client.py
```

Expand Down
5 changes: 4 additions & 1 deletion client-samples/python/websockets/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ def __init__(
self.verify_http = verify_http
self.retry_bad_handshake_status = retry_bad_handshake_status

def connect(self):
def connect(self, retry=True):
# instantiate new app to ensure old connection is properly cleaned up
self.ws = websocket.WebSocketApp(
self.url,
Expand Down Expand Up @@ -257,6 +257,9 @@ def get_headers():
proxy_type=proxy_type,
sslopt=ssl_options,
)
if not retry:
self.ws.close()
break
if teardown:
self.ws.close()
print(
Expand Down
3 changes: 3 additions & 0 deletions client-samples/python/websockets/dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
black==23.11.0
pytest==8.3.4
websockets==14.2
4 changes: 1 addition & 3 deletions client-samples/python/websockets/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
black==24.3.0
msal==1.25.0
pytest==8.3.4
websocket-client==1.6.4
websocket-client==1.6.4
4 changes: 2 additions & 2 deletions client-samples/python/websockets/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ def test_config(self):
Test that the correct config is loaded.
"""
config = load_config("./tests/test-config.json")
assert config == MOCK_CONFIG, "Config loaded correctly"
assert config == MOCK_CONFIG, "Incorrect config values"

def test_proxies(self):
"""
Test that the correct proxies are loaded.
"""
proxies = get_proxies(MOCK_CONFIG)
assert proxies == TEST_PROXY_CONFIG, "Proxies loaded correctly"
assert proxies == TEST_PROXY_CONFIG, "Incorrect proxy values"

def test_null_proxy_config(self):
"""
Expand Down
97 changes: 97 additions & 0 deletions client-samples/python/websockets/tests/test_websocket_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import os
import sys
import asyncio
import threading
from time import sleep
import unittest
from unittest.mock import MagicMock, patch

from websockets.asyncio.server import serve


sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from test_consts import MOCK_CONFIG
from client import create_connection

LOCAL_MOCK_CONFIG = MOCK_CONFIG.copy()
LOCAL_MOCK_CONFIG["proxy_host"] = None
LOCAL_MOCK_CONFIG["proxy_port"] = None

MOCK_TOKEN = "mock_token"

API_HOST = "localhost"
API_PORT = 8765
API_URL = f"ws://{API_HOST}:{API_PORT}"


async def on_connect(websocket):
await websocket.send("Connected")
await asyncio.sleep(2)
await websocket.close()


async def run_server():
async with serve(on_connect, API_HOST, API_PORT) as server:
await server.serve_forever()


def start_echo_server():
asyncio.run(run_server())


class TestApiCall(unittest.TestCase):
def setUp(self):
"""
setUp function runs before each unit test.
Sets up patches
"""
self.acquire_token_patch = patch(
"client.acquire_token", return_value=MOCK_TOKEN
)
self.get_client_app_patch = patch("client.get_client_app", return_value=None)
self.get_requests_ca_bundle_patch = patch(
"client.get_requests_ca_bundle", return_value=None
)
self.acquire_token_patch.start()
self.get_client_app_patch.start()
self.get_requests_ca_bundle_patch.start()

def tearDown(self):
"""
tearDown function runs after each unit test.
"""
self.acquire_token_patch.stop()
self.get_client_app_patch.stop()
self.get_requests_ca_bundle_patch.stop()

def connect(self):
self.websocket_handler.connect(retry=False)

def test_websocket_handler_connects_and_receives_messgae(self):
"""
Connect to a websockets echo server, and test websocket handler can connect and recieve messages.
"""
# As the thread is set as a daemon, the code will exit, once main thread is done.
server_thread = threading.Thread(target=start_echo_server, daemon=True)
server_thread.start()
sleep(1)

self.websocket_handler = create_connection(LOCAL_MOCK_CONFIG, API_URL)
self.websocket_handler.on_open = MagicMock()
self.websocket_handler.on_message = MagicMock()

thread = threading.Thread(target=self.connect)
thread.start()
thread.join(timeout=5)

# If thread is still alive after 5 seconds, fail the test
if thread.is_alive():
self.fail("websocket_handler.connect() took longer than 5 seconds to run")

self.websocket_handler.on_open.assert_called_once()
self.websocket_handler.on_message.assert_called_once()


if __name__ == "__main__":
unittest.main()

0 comments on commit a8e6ae6

Please sign in to comment.