Skip to content

Commit 5389c6b

Browse files
author
Joel Collins
committed
Added fake websocket client
1 parent 87c27ec commit 5389c6b

File tree

1 file changed

+87
-22
lines changed

1 file changed

+87
-22
lines changed

tests/conftest.py

Lines changed: 87 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,39 @@
77
from labthings.server.labthing import LabThing
88
from labthings.server.view import View
99

10+
from werkzeug.test import EnvironBuilder
1011
from flask.testing import FlaskClient
1112

1213

14+
class FakeWebsocket:
15+
def __init__(self, message: str, recieve_once=True):
16+
self.message = message
17+
self.responses = []
18+
self.closed = False
19+
self.recieve_once = recieve_once
20+
21+
# I mean screw whoever is responsible for this having to be a thing...
22+
self.receive = self.recieve
23+
24+
def recieve(self):
25+
# Get message
26+
message_to_send = self.message
27+
# If only sending a message to the server once
28+
if self.recieve_once:
29+
# Clear our message
30+
self.message = None
31+
return message_to_send
32+
33+
@property
34+
def response(self):
35+
return self.responses[-1]
36+
37+
def send(self, response):
38+
self.responses.append(response)
39+
self.closed = True
40+
return response
41+
42+
1343
class JsonClient(FlaskClient):
1444
def open(self, *args, **kwargs):
1545
kwargs.setdefault(
@@ -20,6 +50,57 @@ def open(self, *args, **kwargs):
2050
return super().open(*args, **kwargs)
2151

2252

53+
class SocketClient(FlaskClient):
54+
def __init__(self, app, response_wrapper, *args, **kwargs):
55+
super().__init__(app, response_wrapper, *args, **kwargs)
56+
self.app = app
57+
self.response_wrapper = response_wrapper
58+
self.socket = FakeWebsocket(message=None)
59+
self.environ_base = {
60+
"HTTP_UPGRADE": "websocket",
61+
"wsgi.websocket": self.socket,
62+
}
63+
64+
def connect(self, *args, message=None, **kwargs):
65+
kwargs.setdefault("environ_overrides", {})[
66+
"flask._preserve_context"
67+
] = self.preserve_context
68+
kwargs.setdefault("environ_base", self.environ_base)
69+
builder = EnvironBuilder(*args, **kwargs)
70+
71+
try:
72+
environ = builder.get_environ()
73+
finally:
74+
builder.close()
75+
76+
self.socket.message = message
77+
78+
with self.app.app_context():
79+
run_wsgi_app(self.app, environ)
80+
81+
# Once the connection has been closed, return responses
82+
return self.socket.responses
83+
84+
85+
def run_wsgi_app(app, environ, buffered=False):
86+
response = []
87+
buffer = []
88+
89+
def start_response(status, headers, exc_info=None):
90+
if exc_info:
91+
try:
92+
raise exc_info[1].with_traceback(exc_info[2])
93+
finally:
94+
exc_info = None
95+
response[:] = [status, headers]
96+
return buffer.append
97+
98+
# Return value from the wsgi_app call
99+
# In the case of our SocketMiddleware, will return []
100+
app_rv = app(environ, start_response)
101+
return app_rv
102+
103+
23104
@pytest.fixture
24105
def empty_view_cls():
25106
class EmptyViewClass(View):
@@ -146,6 +227,12 @@ def client(app):
146227
return app.test_client()
147228

148229

230+
@pytest.fixture
231+
def ws_client(app):
232+
app.test_client_class = SocketClient
233+
return app.test_client()
234+
235+
149236
@pytest.fixture
150237
def thing_client(thing):
151238
thing.app.test_client_class = JsonClient
@@ -167,28 +254,6 @@ def extensions_path(app):
167254
return os.path.join(os.path.dirname(__file__), "extensions")
168255

169256

170-
class FakeWebsocket:
171-
def __init__(self, message: str, recieve_once=True):
172-
self.message = message
173-
self.response = None
174-
self.closed = False
175-
self.recieve_once = recieve_once
176-
177-
def receive(self):
178-
# Get message
179-
message_to_send = self.message
180-
# If only sending a message to the server once
181-
if self.recieve_once:
182-
# Clear our message
183-
self.message = None
184-
return message_to_send
185-
186-
def send(self, response):
187-
self.response = response
188-
self.closed = True
189-
return response
190-
191-
192257
@pytest.fixture
193258
def fake_websocket():
194259
"""

0 commit comments

Comments
 (0)