matlab-proxy 0.25.0__py3-none-any.whl → 0.26.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of matlab-proxy might be problematic. Click here for more details.
- matlab_proxy/app.py +66 -12
- matlab_proxy/constants.py +1 -0
- matlab_proxy/gui/index.html +1 -1
- matlab_proxy/gui/static/js/{index.qK3VCGVb.js → index.CZgGkMCD.js} +15 -15
- matlab_proxy/settings.py +22 -1
- matlab_proxy/util/cookie_jar.py +72 -0
- matlab_proxy/util/mwi/environment_variables.py +10 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/METADATA +4 -1
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/RECORD +24 -21
- matlab_proxy_manager/lib/api.py +156 -114
- matlab_proxy_manager/storage/server.py +5 -2
- matlab_proxy_manager/utils/constants.py +2 -1
- matlab_proxy_manager/utils/environment_variables.py +6 -1
- matlab_proxy_manager/utils/exceptions.py +45 -0
- matlab_proxy_manager/utils/helpers.py +2 -2
- matlab_proxy_manager/utils/logger.py +4 -1
- matlab_proxy_manager/web/app.py +71 -19
- tests/unit/test_app.py +116 -17
- tests/unit/test_settings.py +26 -6
- tests/unit/util/test_cookie_jar.py +252 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/LICENSE.md +0 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/WHEEL +0 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/entry_points.txt +0 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/top_level.txt +0 -0
matlab_proxy_manager/web/app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 The MathWorks, Inc.
|
|
1
|
+
# Copyright 2024-2025 The MathWorks, Inc.
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import os
|
|
@@ -14,6 +14,7 @@ from aiohttp import ClientSession, client_exceptions, web
|
|
|
14
14
|
import matlab_proxy.util.mwi.environment_variables as mwi_env
|
|
15
15
|
import matlab_proxy.util.system as mwi_sys
|
|
16
16
|
import matlab_proxy_manager.lib.api as mpm_lib
|
|
17
|
+
import matlab_proxy.constants as mp_constants
|
|
17
18
|
from matlab_proxy_manager.utils import constants, helpers, logger
|
|
18
19
|
from matlab_proxy_manager.utils import environment_variables as mpm_env
|
|
19
20
|
from matlab_proxy_manager.utils.auth import authenticate_access_decorator
|
|
@@ -44,6 +45,9 @@ def init_app() -> web.Application:
|
|
|
44
45
|
# Async event is utilized to signal app termination from this and other modules
|
|
45
46
|
app["shutdown_event"] = asyncio.Event()
|
|
46
47
|
|
|
48
|
+
# Tracks whether default matlab proxy is started or not
|
|
49
|
+
app["has_default_matlab_proxy_started"] = False
|
|
50
|
+
|
|
47
51
|
# Create and get the proxy manager data directory
|
|
48
52
|
try:
|
|
49
53
|
data_dir = helpers.create_and_get_proxy_manager_data_dir()
|
|
@@ -54,6 +58,10 @@ def init_app() -> web.Application:
|
|
|
54
58
|
# Setup idle timeout monitor for the app
|
|
55
59
|
monitor = OrphanedProcessMonitor(app)
|
|
56
60
|
|
|
61
|
+
# Load existing matlab proxy servers into app state for consistency
|
|
62
|
+
app["servers"] = helpers.pre_load_from_state_file(app.get("data_dir"))
|
|
63
|
+
log.debug("Loaded existing matlab proxy servers into app state: %s", app["servers"])
|
|
64
|
+
|
|
57
65
|
async def start_idle_monitor(app):
|
|
58
66
|
"""Start the idle timeout monitor."""
|
|
59
67
|
app["monitor_task"] = asyncio.create_task(monitor.start())
|
|
@@ -102,7 +110,7 @@ def init_app() -> web.Application:
|
|
|
102
110
|
return app
|
|
103
111
|
|
|
104
112
|
|
|
105
|
-
async def start_app(env_vars
|
|
113
|
+
async def start_app(env_vars):
|
|
106
114
|
"""
|
|
107
115
|
Initialize and start the web application.
|
|
108
116
|
|
|
@@ -118,9 +126,7 @@ async def start_app(env_vars: namedtuple):
|
|
|
118
126
|
app["port"] = env_vars.mpm_port
|
|
119
127
|
app["auth_token"] = env_vars.mpm_auth_token
|
|
120
128
|
app["parent_pid"] = env_vars.mpm_parent_pid
|
|
121
|
-
|
|
122
|
-
# Start default matlab proxy
|
|
123
|
-
await _start_default_proxy(app)
|
|
129
|
+
app["base_url_prefix"] = env_vars.base_url_prefix
|
|
124
130
|
|
|
125
131
|
web_logger = None if not mwi_env.is_web_logging_enabled() else log
|
|
126
132
|
|
|
@@ -175,6 +181,8 @@ def _register_signal_handler(loop, app):
|
|
|
175
181
|
def _catch_signals(app):
|
|
176
182
|
"""Handle termination signals for graceful shutdown."""
|
|
177
183
|
# Poll for parent process to clean up to avoid race conditions in cleanup of matlab proxies
|
|
184
|
+
# Ideally, we should minimize the work done when we catch exit signals, which would mean the
|
|
185
|
+
# polling for parent process should happen elsewhere
|
|
178
186
|
helpers.poll_for_server_deletion()
|
|
179
187
|
app.get("shutdown_event").set()
|
|
180
188
|
|
|
@@ -190,13 +198,13 @@ async def _start_default_proxy(app):
|
|
|
190
198
|
parent_id=app.get("parent_pid"),
|
|
191
199
|
is_shared_matlab=True,
|
|
192
200
|
mpm_auth_token=app.get("auth_token"),
|
|
201
|
+
base_url_prefix=app.get("base_url_prefix"),
|
|
193
202
|
)
|
|
194
|
-
|
|
195
|
-
log.error("Failed to start default matlab proxy using Jupyter")
|
|
196
|
-
return
|
|
203
|
+
errors = server_process.get("errors")
|
|
197
204
|
|
|
198
|
-
#
|
|
199
|
-
|
|
205
|
+
# Raising an exception if there was an error starting the default MATLAB proxy
|
|
206
|
+
if errors:
|
|
207
|
+
raise Exception(":".join(errors))
|
|
200
208
|
|
|
201
209
|
# Add the new/existing server to the app state
|
|
202
210
|
app["servers"][server_process.get("id")] = server_process
|
|
@@ -259,12 +267,21 @@ async def proxy(req):
|
|
|
259
267
|
f"Required header: ${constants.HEADER_MWI_MPM_CONTEXT} not found in the request"
|
|
260
268
|
)
|
|
261
269
|
|
|
270
|
+
# Raising exception from here is not cleanly handled by Jupyter server proxy.
|
|
271
|
+
# It only shows 599 with a generic stream closed error message.
|
|
272
|
+
# Hence returning 503 with custom error message as response.
|
|
273
|
+
try:
|
|
274
|
+
await _start_default_proxy_if_not_already_started(req)
|
|
275
|
+
except Exception as e:
|
|
276
|
+
log.error("Error starting default proxy: %s", e)
|
|
277
|
+
return _render_error_page(f"Error during startup: {e}")
|
|
278
|
+
|
|
262
279
|
client_key = f"{ctx}_{ident}"
|
|
263
280
|
default_key = f"{ctx}_default"
|
|
264
281
|
group_two_rel_url = match.group(2)
|
|
265
282
|
|
|
266
283
|
backend_server = _get_backend_server(req, client_key, default_key)
|
|
267
|
-
proxy_url = f
|
|
284
|
+
proxy_url = f"{backend_server.get('absolute_url')}/{group_two_rel_url}"
|
|
268
285
|
log.debug("Proxy URL: %s", proxy_url)
|
|
269
286
|
|
|
270
287
|
if (
|
|
@@ -326,7 +343,9 @@ async def _forward_websocket_request(
|
|
|
326
343
|
Returns:
|
|
327
344
|
web.WebSocketResponse: The response from the backend server
|
|
328
345
|
"""
|
|
329
|
-
ws_server = web.WebSocketResponse(
|
|
346
|
+
ws_server = web.WebSocketResponse(
|
|
347
|
+
max_msg_size=mp_constants.MAX_WEBSOCKET_MESSAGE_SIZE_IN_MB, compress=True
|
|
348
|
+
)
|
|
330
349
|
await ws_server.prepare(req)
|
|
331
350
|
|
|
332
351
|
async with aiohttp.ClientSession(
|
|
@@ -335,7 +354,11 @@ async def _forward_websocket_request(
|
|
|
335
354
|
connector=aiohttp.TCPConnector(ssl=False),
|
|
336
355
|
) as client_session:
|
|
337
356
|
try:
|
|
338
|
-
async with client_session.ws_connect(
|
|
357
|
+
async with client_session.ws_connect(
|
|
358
|
+
proxy_url,
|
|
359
|
+
max_msg_size=mp_constants.MAX_WEBSOCKET_MESSAGE_SIZE_IN_MB, # max websocket message size from MATLAB to browser
|
|
360
|
+
compress=12, # enable websocket messages compression
|
|
361
|
+
) as ws_client:
|
|
339
362
|
|
|
340
363
|
async def ws_forward(ws_src, ws_dest):
|
|
341
364
|
async for msg in ws_src:
|
|
@@ -373,6 +396,13 @@ async def _forward_websocket_request(
|
|
|
373
396
|
await ws_dest.close(
|
|
374
397
|
code=ws_dest.close_code, message=msg.extra
|
|
375
398
|
)
|
|
399
|
+
elif msg_type == aiohttp.WSMsgType.ERROR:
|
|
400
|
+
log.error(f"WebSocket error received: {msg}")
|
|
401
|
+
if "exceeds limit" in str(msg.data):
|
|
402
|
+
log.error(
|
|
403
|
+
f"Message too large: {msg.data}. Please refresh browser tab to reconnect."
|
|
404
|
+
)
|
|
405
|
+
break
|
|
376
406
|
else:
|
|
377
407
|
raise ValueError(f"Unexpected message type: {msg}")
|
|
378
408
|
|
|
@@ -421,6 +451,20 @@ async def _forward_http_request(
|
|
|
421
451
|
return web.Response(headers=headers, status=res.status, body=body)
|
|
422
452
|
|
|
423
453
|
|
|
454
|
+
async def _start_default_proxy_if_not_already_started(req):
|
|
455
|
+
app = req.app
|
|
456
|
+
req_path = req.rel_url
|
|
457
|
+
|
|
458
|
+
# Start default matlab-proxy only when it is not already started and
|
|
459
|
+
# if the request path contains the default MATLAB path (/matlab/default)
|
|
460
|
+
if not app.get(
|
|
461
|
+
"has_default_matlab_proxy_started", False
|
|
462
|
+
) and constants.MWI_DEFAULT_MATLAB_PATH in str(req_path):
|
|
463
|
+
log.debug("Starting default matlab-proxy for request path: %s", str(req_path))
|
|
464
|
+
await _start_default_proxy(app)
|
|
465
|
+
app["has_default_matlab_proxy_started"] = True
|
|
466
|
+
|
|
467
|
+
|
|
424
468
|
def _get_backend_server(req: web.Request, client_key: str, default_key: str) -> dict:
|
|
425
469
|
"""
|
|
426
470
|
Retrieves the backend server configuration for a given client key.
|
|
@@ -444,18 +488,22 @@ def _redirect_to_default(req_path) -> None:
|
|
|
444
488
|
Raises:
|
|
445
489
|
web.HTTPFound: Redirects the client to the new URL.
|
|
446
490
|
"""
|
|
447
|
-
new_redirect_url = f
|
|
491
|
+
new_redirect_url = f"{str(req_path).rstrip('/')}/default/"
|
|
448
492
|
log.info("Redirecting to %s", new_redirect_url)
|
|
449
493
|
raise web.HTTPFound(new_redirect_url)
|
|
450
494
|
|
|
451
495
|
|
|
452
496
|
def _render_error_page(error_msg: str) -> web.Response:
|
|
453
497
|
"""Returns 503 with error text"""
|
|
454
|
-
return web.HTTPServiceUnavailable(
|
|
498
|
+
return web.HTTPServiceUnavailable(
|
|
499
|
+
text=f'<p style="color: red;">{error_msg}</p>', content_type="text/html"
|
|
500
|
+
)
|
|
455
501
|
|
|
456
502
|
|
|
457
|
-
def _fetch_and_validate_required_env_vars()
|
|
458
|
-
EnvVars = namedtuple(
|
|
503
|
+
def _fetch_and_validate_required_env_vars():
|
|
504
|
+
EnvVars = namedtuple(
|
|
505
|
+
"EnvVars", ["mpm_port", "mpm_auth_token", "mpm_parent_pid", "base_url_prefix"]
|
|
506
|
+
)
|
|
459
507
|
|
|
460
508
|
port = os.getenv(mpm_env.get_env_name_mwi_mpm_port())
|
|
461
509
|
mpm_auth_token = os.getenv(mpm_env.get_env_name_mwi_mpm_auth_token())
|
|
@@ -466,9 +514,13 @@ def _fetch_and_validate_required_env_vars() -> namedtuple:
|
|
|
466
514
|
sys.exit(1)
|
|
467
515
|
|
|
468
516
|
try:
|
|
517
|
+
base_url_prefix = os.getenv(mpm_env.get_env_name_base_url_prefix(), "")
|
|
469
518
|
mwi_mpm_port: int = int(port)
|
|
470
519
|
return EnvVars(
|
|
471
|
-
mpm_port=mwi_mpm_port,
|
|
520
|
+
mpm_port=mwi_mpm_port,
|
|
521
|
+
mpm_auth_token=mpm_auth_token,
|
|
522
|
+
mpm_parent_pid=ctx,
|
|
523
|
+
base_url_prefix=base_url_prefix,
|
|
472
524
|
)
|
|
473
525
|
except ValueError as ve:
|
|
474
526
|
log.error("Error: Invalid type for port: %s", ve)
|
|
@@ -480,7 +532,7 @@ def main() -> None:
|
|
|
480
532
|
The main entry point of the application. Starts the app and run until the shutdown
|
|
481
533
|
signal to terminate the app is received.
|
|
482
534
|
"""
|
|
483
|
-
env_vars
|
|
535
|
+
env_vars = _fetch_and_validate_required_env_vars()
|
|
484
536
|
asyncio.run(start_app(env_vars))
|
|
485
537
|
|
|
486
538
|
|
tests/unit/test_app.py
CHANGED
|
@@ -7,7 +7,7 @@ import platform
|
|
|
7
7
|
import random
|
|
8
8
|
import time
|
|
9
9
|
from datetime import timedelta, timezone
|
|
10
|
-
from http import HTTPStatus
|
|
10
|
+
from http import HTTPStatus, cookies
|
|
11
11
|
|
|
12
12
|
import pytest
|
|
13
13
|
from aiohttp import WSMsgType
|
|
@@ -19,7 +19,9 @@ from matlab_proxy import app, util
|
|
|
19
19
|
from matlab_proxy.app import matlab_view
|
|
20
20
|
from matlab_proxy.util.mwi import environment_variables as mwi_env
|
|
21
21
|
from matlab_proxy.util.mwi.exceptions import EntitlementError, MatlabInstallError
|
|
22
|
-
from tests.unit.fixtures.fixture_auth import
|
|
22
|
+
from tests.unit.fixtures.fixture_auth import (
|
|
23
|
+
patch_authenticate_access_decorator, # noqa: F401
|
|
24
|
+
)
|
|
23
25
|
from tests.unit.mocks.mock_client import MockWebSocketClient
|
|
24
26
|
|
|
25
27
|
|
|
@@ -236,8 +238,8 @@ class FakeServer:
|
|
|
236
238
|
Setting up the server in the context of Pytest.
|
|
237
239
|
"""
|
|
238
240
|
|
|
239
|
-
def __init__(self,
|
|
240
|
-
self.loop =
|
|
241
|
+
def __init__(self, event_loop, aiohttp_client):
|
|
242
|
+
self.loop = event_loop
|
|
241
243
|
self.aiohttp_client = aiohttp_client
|
|
242
244
|
|
|
243
245
|
def __enter__(self):
|
|
@@ -256,7 +258,11 @@ def mock_request(mocker):
|
|
|
256
258
|
req = mocker.MagicMock()
|
|
257
259
|
req.app = {
|
|
258
260
|
"state": mocker.MagicMock(matlab_port=8000),
|
|
259
|
-
"settings": {
|
|
261
|
+
"settings": {
|
|
262
|
+
"matlab_protocol": "http",
|
|
263
|
+
"mwapikey": "test-key",
|
|
264
|
+
"cookie_jar": None,
|
|
265
|
+
},
|
|
260
266
|
}
|
|
261
267
|
req.headers = CIMultiDict()
|
|
262
268
|
req.cookies = {}
|
|
@@ -275,11 +281,7 @@ def mock_messages(mocker):
|
|
|
275
281
|
|
|
276
282
|
|
|
277
283
|
@pytest.fixture(name="test_server")
|
|
278
|
-
def test_server_fixture(
|
|
279
|
-
event_loop,
|
|
280
|
-
aiohttp_client,
|
|
281
|
-
monkeypatch,
|
|
282
|
-
):
|
|
284
|
+
def test_server_fixture(event_loop, aiohttp_client, monkeypatch, request):
|
|
283
285
|
"""A pytest fixture which yields a test server to be used by tests.
|
|
284
286
|
|
|
285
287
|
Args:
|
|
@@ -289,18 +291,29 @@ def test_server_fixture(
|
|
|
289
291
|
Yields:
|
|
290
292
|
aiohttp_client : A aiohttp_client server used by tests.
|
|
291
293
|
"""
|
|
292
|
-
#
|
|
293
|
-
|
|
294
|
+
# Default set of environment variables for testing convenience
|
|
295
|
+
default_env_vars_for_testing = [
|
|
296
|
+
(mwi_env.get_env_name_enable_mwi_auth_token(), "False")
|
|
297
|
+
]
|
|
298
|
+
custom_env_vars = getattr(request, "param", None)
|
|
299
|
+
|
|
300
|
+
if custom_env_vars:
|
|
301
|
+
default_env_vars_for_testing.extend(custom_env_vars)
|
|
302
|
+
|
|
303
|
+
for env_var_name, env_var_value in default_env_vars_for_testing:
|
|
304
|
+
monkeypatch.setenv(env_var_name, env_var_value)
|
|
305
|
+
|
|
294
306
|
try:
|
|
295
307
|
with FakeServer(event_loop, aiohttp_client) as test_server:
|
|
296
308
|
yield test_server
|
|
309
|
+
|
|
297
310
|
except ProcessLookupError:
|
|
298
311
|
pass
|
|
312
|
+
|
|
299
313
|
finally:
|
|
300
|
-
# Cleaning up the
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
)
|
|
314
|
+
# Cleaning up the environment variables set for testing
|
|
315
|
+
for env_var_name, _ in default_env_vars_for_testing:
|
|
316
|
+
monkeypatch.delenv(env_var_name, raising="False")
|
|
304
317
|
|
|
305
318
|
|
|
306
319
|
async def test_get_status_route(test_server):
|
|
@@ -689,7 +702,7 @@ async def test_matlab_view_websocket_success(
|
|
|
689
702
|
mock_request,
|
|
690
703
|
mock_websocket_messages,
|
|
691
704
|
headers,
|
|
692
|
-
patch_authenticate_access_decorator,
|
|
705
|
+
patch_authenticate_access_decorator, # noqa: F401
|
|
693
706
|
):
|
|
694
707
|
"""Test successful websocket connection and message forwarding"""
|
|
695
708
|
|
|
@@ -1198,3 +1211,89 @@ async def test_check_for_concurrency(test_server):
|
|
|
1198
1211
|
status_resp_json = json.loads(await status_resp.text())
|
|
1199
1212
|
assert "clientId" not in status_resp_json
|
|
1200
1213
|
assert "isActiveClient" not in status_resp_json
|
|
1214
|
+
|
|
1215
|
+
|
|
1216
|
+
# Pytest construct to set the environment variable `MWI_ENABLE_COOKIE_JAR` to `"True"`
|
|
1217
|
+
# before initializing the test_server.
|
|
1218
|
+
@pytest.mark.parametrize(
|
|
1219
|
+
"test_server",
|
|
1220
|
+
[
|
|
1221
|
+
[(mwi_env.Experimental.get_env_name_use_cookie_cache(), "True")],
|
|
1222
|
+
],
|
|
1223
|
+
indirect=True,
|
|
1224
|
+
)
|
|
1225
|
+
async def test_cookie_jar_http_request(proxy_payload, test_server):
|
|
1226
|
+
# Arrange
|
|
1227
|
+
actual_custom_cookie = cookies.Morsel()
|
|
1228
|
+
actual_custom_cookie.set("custom_cookie", "cookie_value", "cookie_value")
|
|
1229
|
+
actual_custom_cookie["domain"] = "example.com"
|
|
1230
|
+
actual_custom_cookie["path"] = "/"
|
|
1231
|
+
actual_custom_cookie["HttpOnly"] = True
|
|
1232
|
+
actual_custom_cookie["expires"] = (
|
|
1233
|
+
datetime.datetime.now() + timedelta(days=1)
|
|
1234
|
+
).strftime("%a, %d-%b-%Y %H:%M:%S GMT")
|
|
1235
|
+
|
|
1236
|
+
await wait_for_matlab_to_be_up(test_server, test_constants.ONE_SECOND_DELAY)
|
|
1237
|
+
|
|
1238
|
+
# Manually update cookie in cookie jar
|
|
1239
|
+
test_server.app["settings"]["cookie_jar"]._cookie_jar[
|
|
1240
|
+
"custom_cookie"
|
|
1241
|
+
] = actual_custom_cookie
|
|
1242
|
+
|
|
1243
|
+
# Act
|
|
1244
|
+
async with await test_server.get(
|
|
1245
|
+
"/http_get_request.html", data=json.dumps(proxy_payload)
|
|
1246
|
+
) as _:
|
|
1247
|
+
expected_custom_cookie = test_server.app["settings"]["cookie_jar"]._cookie_jar[
|
|
1248
|
+
"custom_cookie"
|
|
1249
|
+
]
|
|
1250
|
+
|
|
1251
|
+
# Assert
|
|
1252
|
+
assert actual_custom_cookie == expected_custom_cookie
|
|
1253
|
+
|
|
1254
|
+
|
|
1255
|
+
# Pytest construct to set the environment variable `MWI_ENABLE_COOKIE_JAR` to `"True"`
|
|
1256
|
+
# before initializing the test_server.
|
|
1257
|
+
@pytest.mark.parametrize(
|
|
1258
|
+
"test_server",
|
|
1259
|
+
[
|
|
1260
|
+
[(mwi_env.Experimental.get_env_name_use_cookie_cache(), "True")],
|
|
1261
|
+
],
|
|
1262
|
+
indirect=True,
|
|
1263
|
+
)
|
|
1264
|
+
async def test_cookie_jar_web_socket(proxy_payload, test_server):
|
|
1265
|
+
# Arrange
|
|
1266
|
+
|
|
1267
|
+
# Createa a custom cookie
|
|
1268
|
+
actual_custom_cookie = cookies.Morsel()
|
|
1269
|
+
actual_custom_cookie.set("custom_cookie", "cookie_value", "cookie_value")
|
|
1270
|
+
actual_custom_cookie["domain"] = "example.com"
|
|
1271
|
+
actual_custom_cookie["path"] = "/"
|
|
1272
|
+
actual_custom_cookie["expires"] = (
|
|
1273
|
+
datetime.datetime.now() + timedelta(days=1)
|
|
1274
|
+
).strftime("%a, %d-%b-%Y %H:%M:%S GMT")
|
|
1275
|
+
|
|
1276
|
+
# Update cookie in cookie jar
|
|
1277
|
+
test_server.app["settings"]["cookie_jar"]._cookie_jar[
|
|
1278
|
+
"custom_cookie"
|
|
1279
|
+
] = actual_custom_cookie
|
|
1280
|
+
|
|
1281
|
+
await wait_for_matlab_to_be_up(test_server, test_constants.ONE_SECOND_DELAY)
|
|
1282
|
+
|
|
1283
|
+
# Act
|
|
1284
|
+
async with test_server.get(
|
|
1285
|
+
"/http_ws_request.html/",
|
|
1286
|
+
headers={
|
|
1287
|
+
# Headers required to initiate a websocket connection
|
|
1288
|
+
# First 2 headers are required for the connection upgrade
|
|
1289
|
+
"Connection": "upgrade",
|
|
1290
|
+
"upgrade": "websocket",
|
|
1291
|
+
"Sec-WebSocket-Version": "13", # Required for initiating the websocket handshake with aiohttp server
|
|
1292
|
+
"Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", # Optional unique key for the websocket handshake
|
|
1293
|
+
},
|
|
1294
|
+
) as _:
|
|
1295
|
+
expected_custom_cookie = test_server.app["settings"]["cookie_jar"]._cookie_jar[
|
|
1296
|
+
"custom_cookie"
|
|
1297
|
+
]
|
|
1298
|
+
# Assert
|
|
1299
|
+
assert actual_custom_cookie == expected_custom_cookie
|
tests/unit/test_settings.py
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# Copyright 2020-2025 The MathWorks, Inc.
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
import time
|
|
5
4
|
import tempfile
|
|
6
|
-
import
|
|
5
|
+
import time
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
7
9
|
|
|
8
10
|
import matlab_proxy
|
|
9
11
|
import matlab_proxy.settings as settings
|
|
10
|
-
from matlab_proxy.constants import
|
|
11
|
-
from
|
|
12
|
-
import pytest
|
|
12
|
+
from matlab_proxy.constants import DEFAULT_PROCESS_START_TIMEOUT, VERSION_INFO_FILE_NAME
|
|
13
|
+
from matlab_proxy.util.cookie_jar import HttpOnlyCookieJar
|
|
13
14
|
from matlab_proxy.util.mwi import environment_variables as mwi_env
|
|
14
15
|
from matlab_proxy.util.mwi.exceptions import MatlabInstallError
|
|
15
16
|
|
|
@@ -122,7 +123,7 @@ def mock_shutil_which_fixture(mocker, fake_matlab_executable_path):
|
|
|
122
123
|
@pytest.fixture(name="non_existent_path")
|
|
123
124
|
def non_existent_path_fixture(tmp_path):
|
|
124
125
|
# Build path to a non existent folder
|
|
125
|
-
random_folder = tmp_path / f
|
|
126
|
+
random_folder = tmp_path / f"{str(time.time()).replace('.', '')}"
|
|
126
127
|
non_existent_path = Path(tmp_path) / random_folder
|
|
127
128
|
|
|
128
129
|
return non_existent_path
|
|
@@ -657,3 +658,22 @@ def test_get_matlab_settings_invalid_custom_matlab_root(mocker, monkeypatch, tmp
|
|
|
657
658
|
and mwi_env.get_env_name_custom_matlab_root()
|
|
658
659
|
in matlab_settings["error"].message
|
|
659
660
|
)
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
def test_get_cookie_jar(monkeypatch):
|
|
664
|
+
"""Test to check if Cookie Jar is returned as a part of server settings"""
|
|
665
|
+
monkeypatch.setenv(mwi_env.Experimental.get_env_name_use_cookie_cache(), "false")
|
|
666
|
+
assert (
|
|
667
|
+
settings.get_server_settings(matlab_proxy.get_default_config_name())[
|
|
668
|
+
"cookie_jar"
|
|
669
|
+
]
|
|
670
|
+
is None
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
monkeypatch.setenv(mwi_env.Experimental.get_env_name_use_cookie_cache(), "true")
|
|
674
|
+
assert isinstance(
|
|
675
|
+
settings.get_server_settings(matlab_proxy.get_default_config_name())[
|
|
676
|
+
"cookie_jar"
|
|
677
|
+
],
|
|
678
|
+
HttpOnlyCookieJar,
|
|
679
|
+
)
|