matlab-proxy 0.13.1__py3-none-any.whl → 0.15.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 -5
- matlab_proxy/constants.py +1 -0
- matlab_proxy/gui/asset-manifest.json +3 -3
- matlab_proxy/gui/index.html +1 -1
- matlab_proxy/gui/static/js/{main.0fcee5e5.js → main.14aa7840.js} +3 -3
- matlab_proxy/gui/static/js/main.14aa7840.js.map +1 -0
- matlab_proxy/util/mw.py +4 -4
- matlab_proxy/util/mwi/download.py +145 -0
- matlab_proxy/util/mwi/embedded_connector/helpers.py +1 -1
- matlab_proxy/util/mwi/embedded_connector/request.py +3 -3
- {matlab_proxy-0.13.1.dist-info → matlab_proxy-0.15.0.dist-info}/METADATA +2 -1
- {matlab_proxy-0.13.1.dist-info → matlab_proxy-0.15.0.dist-info}/RECORD +29 -16
- {matlab_proxy-0.13.1.dist-info → matlab_proxy-0.15.0.dist-info}/WHEEL +1 -1
- {matlab_proxy-0.13.1.dist-info → matlab_proxy-0.15.0.dist-info}/top_level.txt +1 -0
- tests/integration/__init__.py +1 -0
- tests/integration/integration_tests_with_license/__init__.py +1 -0
- tests/integration/integration_tests_with_license/conftest.py +47 -0
- tests/integration/integration_tests_with_license/test_http_end_points.py +223 -0
- tests/integration/integration_tests_without_license/__init__.py +1 -0
- tests/integration/integration_tests_without_license/conftest.py +115 -0
- tests/integration/integration_tests_without_license/test_matlab_is_down_if_unlicensed.py +46 -0
- tests/integration/utils/__init__.py +1 -0
- tests/integration/utils/integration_tests_utils.py +352 -0
- tests/integration/utils/licensing.py +152 -0
- tests/utils/__init__.py +1 -0
- tests/utils/logging_util.py +81 -0
- matlab_proxy/gui/static/js/main.0fcee5e5.js.map +0 -1
- /matlab_proxy/gui/static/js/{main.0fcee5e5.js.LICENSE.txt → main.14aa7840.js.LICENSE.txt} +0 -0
- {matlab_proxy-0.13.1.dist-info → matlab_proxy-0.15.0.dist-info}/LICENSE.md +0 -0
- {matlab_proxy-0.13.1.dist-info → matlab_proxy-0.15.0.dist-info}/entry_points.txt +0 -0
matlab_proxy/util/mw.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2020-2024 The MathWorks, Inc.
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import os
|
|
@@ -46,7 +46,7 @@ async def fetch_entitlements(mhlm_api_endpoint, access_token, matlab_release):
|
|
|
46
46
|
list: Representing a list of Dicts containing the id, label and license_number.
|
|
47
47
|
"""
|
|
48
48
|
# Get entitlements for token
|
|
49
|
-
async with aiohttp.ClientSession() as client_session:
|
|
49
|
+
async with aiohttp.ClientSession(trust_env=True) as client_session:
|
|
50
50
|
async with client_session.post(
|
|
51
51
|
mhlm_api_endpoint,
|
|
52
52
|
headers={"content-type": "application/x-www-form-urlencoded"},
|
|
@@ -99,7 +99,7 @@ async def fetch_expand_token(mwa_api_endpoint, identity_token, source_id):
|
|
|
99
99
|
Returns:
|
|
100
100
|
Dict: Containing User and License expiration details.
|
|
101
101
|
"""
|
|
102
|
-
async with aiohttp.ClientSession() as client_session:
|
|
102
|
+
async with aiohttp.ClientSession(trust_env=True) as client_session:
|
|
103
103
|
async with client_session.post(
|
|
104
104
|
f"{mwa_api_endpoint}/tokens",
|
|
105
105
|
headers={
|
|
@@ -146,7 +146,7 @@ async def fetch_access_token(mwa_api_endpoint, identity_token, source_id):
|
|
|
146
146
|
Returns:
|
|
147
147
|
Dict : Containing the Access token.
|
|
148
148
|
"""
|
|
149
|
-
async with aiohttp.ClientSession() as client_session:
|
|
149
|
+
async with aiohttp.ClientSession(trust_env=True) as client_session:
|
|
150
150
|
async with client_session.post(
|
|
151
151
|
f"{mwa_api_endpoint}/tokens/access",
|
|
152
152
|
headers={
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Copyright 2024 The MathWorks, Inc.
|
|
2
|
+
|
|
3
|
+
# This file contains functions required to enable downloads from the file browser
|
|
4
|
+
from matlab_proxy.util.mwi import logger as mwi_logger
|
|
5
|
+
from matlab_proxy.util import mwi, system
|
|
6
|
+
|
|
7
|
+
logger = mwi_logger.get()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _is_null_base_url(base_url):
|
|
11
|
+
return base_url == "/" or base_url == ""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def is_download_request(req):
|
|
15
|
+
"""
|
|
16
|
+
Determine if the incoming request is for a download action.
|
|
17
|
+
|
|
18
|
+
This function checks if the request's relative URL path starts with
|
|
19
|
+
'/download/' or with '{base_url}/download/', depending on the base URL
|
|
20
|
+
specified in the application settings.
|
|
21
|
+
|
|
22
|
+
Parameters:
|
|
23
|
+
req (HTTPRequest): HTTPRequest Object
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
- bool: True if the request is for a download, False otherwise.
|
|
27
|
+
```
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
base_url = req.app["settings"]["base_url"]
|
|
31
|
+
if _is_null_base_url(base_url):
|
|
32
|
+
return req.rel_url.path.startswith("/download")
|
|
33
|
+
else:
|
|
34
|
+
return req.rel_url.path.startswith(f"{base_url}/download")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async def get_download_url(req):
|
|
38
|
+
"""
|
|
39
|
+
Asynchronously generates a download URL for a file.
|
|
40
|
+
|
|
41
|
+
This function takes a request object, extracts the full path to the file, and
|
|
42
|
+
uses the MATLAB Web Interface (MWI) to generate a download URL for that file.
|
|
43
|
+
It logs the full path and the response from the MWI. If successful, it returns
|
|
44
|
+
the download URL; otherwise, it returns None.
|
|
45
|
+
|
|
46
|
+
Parameters:
|
|
47
|
+
The request object containing necessary information to process the download.
|
|
48
|
+
Returns:
|
|
49
|
+
The download URL string if successful, None otherwise.
|
|
50
|
+
Raises:
|
|
51
|
+
Logs an error message and returns None if an error occurs.
|
|
52
|
+
"""
|
|
53
|
+
full_path_to_file = _get_download_payload_path(req)
|
|
54
|
+
logger.debug(f"full_path_to_file: {full_path_to_file}")
|
|
55
|
+
|
|
56
|
+
args = [full_path_to_file, 1.0]
|
|
57
|
+
data = mwi.embedded_connector.helpers.get_data_to_feval_mcode(
|
|
58
|
+
"matlab.ui.internal.URLUtils.getURLToUserFile", *args, nargout=1
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
state = req.app["state"]
|
|
63
|
+
headers = state._get_token_auth_headers()
|
|
64
|
+
url = mwi.embedded_connector.helpers.get_mvm_endpoint(
|
|
65
|
+
state.settings["mwi_server_url"]
|
|
66
|
+
)
|
|
67
|
+
resp_json = await mwi.embedded_connector.send_request(
|
|
68
|
+
url=url,
|
|
69
|
+
method="POST",
|
|
70
|
+
data=data,
|
|
71
|
+
headers=headers,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
logger.debug(f"EC Response URL: {resp_json}")
|
|
75
|
+
|
|
76
|
+
resp = resp_json["messages"]["FEvalResponse"][0]
|
|
77
|
+
|
|
78
|
+
if not resp["isError"]:
|
|
79
|
+
# No error detected, proceed to fetch the results
|
|
80
|
+
download_url = resp["results"][0]
|
|
81
|
+
logger.debug(f"download_url: {download_url}")
|
|
82
|
+
base_url = req.app["settings"]["base_url"]
|
|
83
|
+
return (
|
|
84
|
+
download_url
|
|
85
|
+
if _is_null_base_url(base_url)
|
|
86
|
+
else f"{base_url}{download_url}"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
except KeyError as key_err:
|
|
90
|
+
logger.error(f"Invalid Key Usage Detected! Check key: {key_err}")
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
except Exception as err:
|
|
94
|
+
logger.error(
|
|
95
|
+
f"Failed to create download url from the Embedded Connector due to err: {err}"
|
|
96
|
+
)
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
# In case of any failures.
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _get_download_payload_path(req):
|
|
104
|
+
"""
|
|
105
|
+
Constructs the file system path to the payload for a download request.
|
|
106
|
+
|
|
107
|
+
This function analyzes the incoming request to determine the intended file path
|
|
108
|
+
for download. It takes into account the base URL from the application settings,
|
|
109
|
+
the nature of the request (whether it's a download request), and the operating
|
|
110
|
+
system to format the path correctly. The function supports different path
|
|
111
|
+
formatting for Windows and Unix-like systems due to their differences in file
|
|
112
|
+
system path syntax.
|
|
113
|
+
|
|
114
|
+
Note:
|
|
115
|
+
This function is intended to be used internally and starts with an underscore
|
|
116
|
+
to indicate it is a private member of the module.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
req: An object representing the incoming request, which includes the relative
|
|
120
|
+
URL from which the file path can be deduced.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
A string representing the file system path to the requested download payload,
|
|
124
|
+
or None if the request is not a download request.
|
|
125
|
+
"""
|
|
126
|
+
base_url = req.app["settings"]["base_url"]
|
|
127
|
+
if is_download_request(req):
|
|
128
|
+
from pathlib import Path
|
|
129
|
+
|
|
130
|
+
compare_str = (
|
|
131
|
+
"/download" if _is_null_base_url(base_url) else f"{base_url}/download"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
if system.is_windows():
|
|
135
|
+
# On Windows, the URL is of the form : /downloadC:\some\path\to\file.txt
|
|
136
|
+
return str(
|
|
137
|
+
Path((req.rel_url.path).replace("/download", "/download/")).relative_to(
|
|
138
|
+
f"{compare_str}"
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
else:
|
|
142
|
+
# On Posix, the URL is of the form : /download/some/path/to/file.txt
|
|
143
|
+
return "/" + str(Path((req.rel_url.path)).relative_to(f"{compare_str}"))
|
|
144
|
+
|
|
145
|
+
return None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2020-
|
|
1
|
+
# Copyright 2020-2024 The MathWorks, Inc.
|
|
2
2
|
|
|
3
3
|
"""
|
|
4
4
|
This file contains the methods to communicate with the embedded connector.
|
|
@@ -42,7 +42,7 @@ async def send_request(url: str, data: dict, method: str, headers: dict = None)
|
|
|
42
42
|
data = json.dumps(data)
|
|
43
43
|
|
|
44
44
|
try:
|
|
45
|
-
async with aiohttp.ClientSession() as session:
|
|
45
|
+
async with aiohttp.ClientSession(trust_env=True) as session:
|
|
46
46
|
logger.debug(
|
|
47
47
|
f"sending request: method={method}, url={url}, data={data}, headers={headers}, "
|
|
48
48
|
)
|
|
@@ -106,7 +106,7 @@ async def get_state(mwi_server_url, headers=None):
|
|
|
106
106
|
return "up"
|
|
107
107
|
except Exception as err:
|
|
108
108
|
logger.debug(
|
|
109
|
-
f"{err}:
|
|
109
|
+
f"{err}: Embedded connector is currently not responding to ping requests."
|
|
110
110
|
)
|
|
111
111
|
pass
|
|
112
112
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: matlab-proxy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: Python® package enables you to launch MATLAB® and access it from a web browser.
|
|
5
5
|
Home-page: https://github.com/mathworks/matlab-proxy/
|
|
6
6
|
Author: The MathWorks, Inc.
|
|
@@ -26,6 +26,7 @@ Requires-Dist: black ; extra == 'dev'
|
|
|
26
26
|
Requires-Dist: pytest ; extra == 'dev'
|
|
27
27
|
Requires-Dist: pytest-env ; extra == 'dev'
|
|
28
28
|
Requires-Dist: pytest-cov ; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-timeout ; extra == 'dev'
|
|
29
30
|
Requires-Dist: pytest-mock ; extra == 'dev'
|
|
30
31
|
Requires-Dist: pytest-aiohttp ; extra == 'dev'
|
|
31
32
|
Requires-Dist: psutil ; extra == 'dev'
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
matlab_proxy/__init__.py,sha256=6cwi8buKCMtw9OeWaOYUHEoqwl5MyJ_s6GxgNuqPuNg,1673
|
|
2
|
-
matlab_proxy/app.py,sha256=
|
|
2
|
+
matlab_proxy/app.py,sha256=ABCfuYtHE6zoVm3fUkNdaFMUvbKx8n53JOM5WeklWjo,33584
|
|
3
3
|
matlab_proxy/app_state.py,sha256=HV4_igTkUVf-CQWPKc7s3z4Ea_MkSBbV7k3I-AG-m28,55374
|
|
4
|
-
matlab_proxy/constants.py,sha256=
|
|
4
|
+
matlab_proxy/constants.py,sha256=k9vESSF1HSrr2-tCgIEomJ47Q7UR4wbrMCWzZnLLoPc,924
|
|
5
5
|
matlab_proxy/default_configuration.py,sha256=DxQaHzAivzstiPl_nDfxs8SOyP9oaK9v3RP4LtroJl4,843
|
|
6
6
|
matlab_proxy/devel.py,sha256=nR6XPVBUEdQ-RZGtYvX1YHTp8gj9cuw5Hp8ahasMBc8,14310
|
|
7
7
|
matlab_proxy/settings.py,sha256=YjchyZAzvLfl-CiwxAPtSaTTo7aRgD6inS4-jZmsuNY,24687
|
|
8
8
|
matlab_proxy/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
matlab_proxy/gui/asset-manifest.json,sha256=
|
|
9
|
+
matlab_proxy/gui/asset-manifest.json,sha256=0eynKD0QHNdOgsiH3IuXXNkRQph4sd_QV4S89qocW2k,3516
|
|
10
10
|
matlab_proxy/gui/favicon.ico,sha256=7w7Ki1uQP2Rgwc64dOV4-NrTu97I3WsZw8OvRSoY1A0,130876
|
|
11
|
-
matlab_proxy/gui/index.html,sha256=
|
|
11
|
+
matlab_proxy/gui/index.html,sha256=IxsvWXcW8bVcVPdnnMQoolow1BFirTUyCo-O9uYGYTQ,637
|
|
12
12
|
matlab_proxy/gui/manifest.json,sha256=NwDbrALM5auYyj2bbEf4aGwAUDqNl1FzMFQpPiG2Ty4,286
|
|
13
13
|
matlab_proxy/gui/robots.txt,sha256=kNJLw79pisHhc3OVAimMzKcq3x9WT6sF9IS4xI0crdI,67
|
|
14
14
|
matlab_proxy/gui/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -16,9 +16,9 @@ matlab_proxy/gui/static/css/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
|
|
|
16
16
|
matlab_proxy/gui/static/css/main.47712126.css,sha256=OT5ccyC0a6fVg956C-8b6uDVbZZVgcpXbHjdO6v4ZBI,274313
|
|
17
17
|
matlab_proxy/gui/static/css/main.47712126.css.map,sha256=RdfmXfQvzvvh4XZuDWShm8CD8pA2Gb2K6MtMzrgJyKM,350495
|
|
18
18
|
matlab_proxy/gui/static/js/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
matlab_proxy/gui/static/js/main.
|
|
20
|
-
matlab_proxy/gui/static/js/main.
|
|
21
|
-
matlab_proxy/gui/static/js/main.
|
|
19
|
+
matlab_proxy/gui/static/js/main.14aa7840.js,sha256=Eu6ZKinNe4gYoD1KV-CsYDJHg0DNKVq4-Qxy2sT2A-U,294128
|
|
20
|
+
matlab_proxy/gui/static/js/main.14aa7840.js.LICENSE.txt,sha256=3cj3DrwM51esz1ogL9VVU1ZyXyXJ6u-Ec2CI9CCcI_A,1689
|
|
21
|
+
matlab_proxy/gui/static/js/main.14aa7840.js.map,sha256=JbKOBbRaQIVoticAYynd6nEc1msGas1RXxnzvA1eWDs,935545
|
|
22
22
|
matlab_proxy/gui/static/media/MATLAB-env-blur.4fc94edbc82d3184e5cb.png,sha256=QpmQTLDvBu2-b7ev83Rvpt0Q72R6wdQGkuJMPPpjv7M,220290
|
|
23
23
|
matlab_proxy/gui/static/media/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
matlab_proxy/gui/static/media/arrow.0c2968b90bd9a64c8c3f.svg,sha256=XtmvDWzGZnwCZm08TKBnqt5hc1wphJnNupG0Fx_faAY,327
|
|
@@ -56,22 +56,35 @@ matlab_proxy/matlab/startup.m,sha256=YRtI8P2flDJSDcPxJ2008B2l1T9JpqiUbzhQxA0frbc
|
|
|
56
56
|
matlab_proxy/util/__init__.py,sha256=bRfvYEbxsaiYhtWq5imTZM7PRrSEJ7GTlVBptvunaYQ,7902
|
|
57
57
|
matlab_proxy/util/event_loop.py,sha256=Zqd282jlvPHHyc4kg8IjIzlzh9zLM_SAc5xjqUOrm04,1144
|
|
58
58
|
matlab_proxy/util/list_servers.py,sha256=M93coVZjyQCdIvCCxsNOU_XDWNjBSysOJ5tWXaTjP8Y,1369
|
|
59
|
-
matlab_proxy/util/mw.py,sha256=
|
|
59
|
+
matlab_proxy/util/mw.py,sha256=dLGSdfcTZiwKR1MMZA-39o-8na13IEPZOGBqcaHmKVI,11086
|
|
60
60
|
matlab_proxy/util/system.py,sha256=XoT3Rv5MwPkdfhk2oMvUwxxlzZmADMlxzi9IRQyGgbA,1692
|
|
61
61
|
matlab_proxy/util/windows.py,sha256=R9-VA7f0snVanSR7IgbHz3kvSnthZuUYe2UhBd5QWMQ,3440
|
|
62
62
|
matlab_proxy/util/mwi/__init__.py,sha256=zI-X1lafr8H3j17PyA0oSZ0q5nINfK-WDA7VmJKmSAQ,158
|
|
63
63
|
matlab_proxy/util/mwi/custom_http_headers.py,sha256=kfDjSnEXEVzoF2pZuEn76LKayeD2WKoQEDu2Y9EMOAo,7154
|
|
64
|
+
matlab_proxy/util/mwi/download.py,sha256=-GJj3yOsL4vF_9baqRXkgBI-vu_OwjZMQVkJXFS8GMc,4965
|
|
64
65
|
matlab_proxy/util/mwi/environment_variables.py,sha256=bIz0QFWo0pgyvSeJ_kAobUCS17V05CSmFWm3zYIOIsA,7139
|
|
65
66
|
matlab_proxy/util/mwi/exceptions.py,sha256=93HrHbOq24KI4Md2el23XN01wIqVShEK29Pbt2V0Jr8,4628
|
|
66
67
|
matlab_proxy/util/mwi/logger.py,sha256=e7wTPclrtJ-aX5mPk_pUJMX7-1QD_snGBW1P2ks-ETE,3311
|
|
67
68
|
matlab_proxy/util/mwi/token_auth.py,sha256=25uQE2cul6MZNTj1HQqukiBS014dj7URZfMOFPKcS3Y,9606
|
|
68
69
|
matlab_proxy/util/mwi/validators.py,sha256=BMMOD-0tdjGIALm1MmG4yXVRoD2ZUXkrJXLWP_D5FGo,11712
|
|
69
70
|
matlab_proxy/util/mwi/embedded_connector/__init__.py,sha256=SVSckEJ4zQQ2KkNPT_un8ndMAImcMOTrai7ShAbmFY4,114
|
|
70
|
-
matlab_proxy/util/mwi/embedded_connector/helpers.py,sha256=
|
|
71
|
-
matlab_proxy/util/mwi/embedded_connector/request.py,sha256
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
matlab_proxy/util/mwi/embedded_connector/helpers.py,sha256=p6TedefbvhlZT64IMwFjrb0panWCXf-T3XPoztDbxM0,3391
|
|
72
|
+
matlab_proxy/util/mwi/embedded_connector/request.py,sha256=-6DL9K8JWjX5u5XVOEGaqBUIwQ-oCVW30-VP3qk_rzw,3730
|
|
73
|
+
tests/integration/__init__.py,sha256=ttzJ8xKWGxOJZz56qOiWOn6sp5LGomkZMn_w4KJLRMU,42
|
|
74
|
+
tests/integration/integration_tests_with_license/__init__.py,sha256=vVYZCur-QhmIGCxUmn-WZjIywtDQidaLDmlmrRHRlgY,37
|
|
75
|
+
tests/integration/integration_tests_with_license/conftest.py,sha256=sCaIXB8d4vf05C7JWSVA7g5gnPjbpRq3dftuBpWyp1s,1599
|
|
76
|
+
tests/integration/integration_tests_with_license/test_http_end_points.py,sha256=fDA2VyauxM8x0Gw9ArZLI4YFOVduX6Wg-UiHdr5tmHk,7411
|
|
77
|
+
tests/integration/integration_tests_without_license/__init__.py,sha256=vVYZCur-QhmIGCxUmn-WZjIywtDQidaLDmlmrRHRlgY,37
|
|
78
|
+
tests/integration/integration_tests_without_license/conftest.py,sha256=z5r_hALWo7Lh0kyN-h1N2oCj1jIug3-0RXQm92XTtPI,3426
|
|
79
|
+
tests/integration/integration_tests_without_license/test_matlab_is_down_if_unlicensed.py,sha256=Nd87UkEjZk6eh_3y8VybKrB0uQUErw90w_Jnu02OHXY,1536
|
|
80
|
+
tests/integration/utils/__init__.py,sha256=ttzJ8xKWGxOJZz56qOiWOn6sp5LGomkZMn_w4KJLRMU,42
|
|
81
|
+
tests/integration/utils/integration_tests_utils.py,sha256=IbJ9CedFHiz3k85FBY-8GwotTnjPF3jF4AHdKio7jqk,10321
|
|
82
|
+
tests/integration/utils/licensing.py,sha256=rEBjvMXO8R3mL6KnePu2lojmOsjD4GXl9frf9N0Wacs,4842
|
|
83
|
+
tests/utils/__init__.py,sha256=ttzJ8xKWGxOJZz56qOiWOn6sp5LGomkZMn_w4KJLRMU,42
|
|
84
|
+
tests/utils/logging_util.py,sha256=VBy_NRvwau3C_CVTBjK5RMROrQimnJYHO2U0aKSZiRw,2234
|
|
85
|
+
matlab_proxy-0.15.0.dist-info/LICENSE.md,sha256=oF0h3UdSF-rlUiMGYwi086ZHqelzz7yOOk9HFDv9ELo,2344
|
|
86
|
+
matlab_proxy-0.15.0.dist-info/METADATA,sha256=TFAiv_gJ5Mt79rX7mf8RPrIMkU6uvYRGaRA4_zTWDHw,10108
|
|
87
|
+
matlab_proxy-0.15.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
88
|
+
matlab_proxy-0.15.0.dist-info/entry_points.txt,sha256=DbBLYgnRt8UGiOpd0zHigRTyyMdZYhMdvCvSYP7wPN0,244
|
|
89
|
+
matlab_proxy-0.15.0.dist-info/top_level.txt,sha256=9uVTjsUCAS4TwsxueTBxrBg3PdBiTSsYowAkHPv9VY0,19
|
|
90
|
+
matlab_proxy-0.15.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Copyright 2023-2024 The MathWorks, Inc.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Copyright 2023 The MathWorks, Inc.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Copyright 2023-2024 The MathWorks, Inc.
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from tests.integration.utils import integration_tests_utils as utils
|
|
5
|
+
import pytest
|
|
6
|
+
from matlab_proxy.util.mwi import environment_variables as mwi_env
|
|
7
|
+
from tests.utils.logging_util import create_integ_test_logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
_logger = create_integ_test_logger(
|
|
11
|
+
__name__, log_file_path=os.getenv("MWI_INTEG_TESTS_LOG_FILE_PATH")
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture(scope="module", name="module_monkeypatch")
|
|
16
|
+
def monkeypatch_module_scope_fixture():
|
|
17
|
+
"""
|
|
18
|
+
To ensure that modifications made with the monkeypatch fixture
|
|
19
|
+
persist across all tests in the module, this fixture
|
|
20
|
+
has been created in 'module' scope. This is done because a 'module'
|
|
21
|
+
scope object is needed with matlab-proxy 'module' scope fixture.
|
|
22
|
+
This allows us to patch certain aspects, like environment variables,
|
|
23
|
+
for all tests within the module.
|
|
24
|
+
|
|
25
|
+
Yields:
|
|
26
|
+
class object: Object of class MonkeyPatch
|
|
27
|
+
"""
|
|
28
|
+
with pytest.MonkeyPatch.context() as mp:
|
|
29
|
+
yield mp
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.fixture(autouse=True, scope="module")
|
|
33
|
+
def matlab_proxy_fixture(module_monkeypatch, request):
|
|
34
|
+
"""
|
|
35
|
+
Pytest fixture for managing a standalone matlab-proxy process
|
|
36
|
+
for testing purposes. This fixture sets up a matlab-proxy process in
|
|
37
|
+
the module scope, and tears it down after all the tests are executed.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
utils.perform_basic_checks()
|
|
41
|
+
|
|
42
|
+
module_monkeypatch.setenv(mwi_env.get_env_name_testing(), "false")
|
|
43
|
+
module_monkeypatch.setenv(mwi_env.get_env_name_development(), "false")
|
|
44
|
+
_logger.info("Started MATLAB Proxy process")
|
|
45
|
+
|
|
46
|
+
# Run the matlab proxy tests
|
|
47
|
+
yield
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Copyright 2023-2024 The MathWorks, Inc.
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
import matlab_proxy.settings as settings
|
|
7
|
+
from tests.integration.utils import integration_tests_utils as utils
|
|
8
|
+
import pytest
|
|
9
|
+
from matlab_proxy.util import system
|
|
10
|
+
import requests
|
|
11
|
+
import re
|
|
12
|
+
from requests.adapters import HTTPAdapter, Retry
|
|
13
|
+
from urllib.parse import urlparse, parse_qs
|
|
14
|
+
from tests.utils.logging_util import create_integ_test_logger
|
|
15
|
+
from logging import DEBUG
|
|
16
|
+
|
|
17
|
+
_logger = create_integ_test_logger(__name__)
|
|
18
|
+
|
|
19
|
+
# Timeout for polling the matlab-proxy http endpoints
|
|
20
|
+
# matlab proxy in Mac machines takes more time to be 'up'
|
|
21
|
+
|
|
22
|
+
MAX_TIMEOUT = settings.get_process_startup_timeout()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RealMATLABServer:
|
|
26
|
+
"""
|
|
27
|
+
Context Manager class which returns matlab proxy web server serving real MATLAB
|
|
28
|
+
for testing.
|
|
29
|
+
|
|
30
|
+
Setting up the server in the context of Pytest.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, event_loop):
|
|
34
|
+
self.event_loop = event_loop
|
|
35
|
+
|
|
36
|
+
def __enter__(self):
|
|
37
|
+
# Store the matlab proxy logs in os.pipe for testing
|
|
38
|
+
# os.pipe2 is only supported in Linux systems
|
|
39
|
+
_logger.info("Setting up MATLAB Server for integration test")
|
|
40
|
+
|
|
41
|
+
_logger.debug("Entering RealMATLABServer enter section.")
|
|
42
|
+
self.dpipe = os.pipe2(os.O_NONBLOCK) if system.is_linux() else os.pipe()
|
|
43
|
+
self.mwi_app_port = utils.get_random_free_port()
|
|
44
|
+
self.matlab_config_file_path = str(utils.get_matlab_config_file())
|
|
45
|
+
|
|
46
|
+
self.temp_dir_path = os.path.dirname(
|
|
47
|
+
os.path.dirname(self.matlab_config_file_path)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
self.temp_dir_name = "temp_dir"
|
|
51
|
+
self.mwi_base_url = "/matlab-test"
|
|
52
|
+
|
|
53
|
+
# Environment variables to launch matlab proxy
|
|
54
|
+
input_env = {
|
|
55
|
+
"MWI_APP_PORT": self.mwi_app_port,
|
|
56
|
+
"MWI_BASE_URL": self.mwi_base_url,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
self.proc = self.event_loop.run_until_complete(
|
|
60
|
+
utils.start_matlab_proxy_app(out=self.dpipe[1], input_env=input_env)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
utils.wait_server_info_ready(self.mwi_app_port)
|
|
64
|
+
parsed_url = urlparse(utils.get_connection_string(self.mwi_app_port))
|
|
65
|
+
|
|
66
|
+
self.headers = {
|
|
67
|
+
"mwi_auth_token": (
|
|
68
|
+
parse_qs(parsed_url.query)["mwi_auth_token"][0]
|
|
69
|
+
if "mwi_auth_token" in parse_qs(parsed_url.query)
|
|
70
|
+
else ""
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
self.connection_scheme = parsed_url.scheme
|
|
74
|
+
self.url = parsed_url.scheme + "://" + parsed_url.netloc + parsed_url.path
|
|
75
|
+
return self
|
|
76
|
+
|
|
77
|
+
async def _terminate_process(self, timeout=0):
|
|
78
|
+
"""
|
|
79
|
+
Asynchronous helper method to terminate the process with a timeout.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
timeout: Maximum number of seconds to wait
|
|
83
|
+
for the process to terminate
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
import asyncio
|
|
87
|
+
|
|
88
|
+
process = self.proc
|
|
89
|
+
try:
|
|
90
|
+
process.terminate()
|
|
91
|
+
await asyncio.wait_for(process.wait(), timeout=timeout)
|
|
92
|
+
except asyncio.TimeoutError:
|
|
93
|
+
_logger.warning(
|
|
94
|
+
"Termination of the MATLAB Server process timed out. Attempting to kill."
|
|
95
|
+
)
|
|
96
|
+
process.kill()
|
|
97
|
+
await process.wait()
|
|
98
|
+
_logger.debug("Killed the MATLAB process after timeout.")
|
|
99
|
+
|
|
100
|
+
def __exit__(self, exc_type, exc_value, exc_traceback):
|
|
101
|
+
_logger.info("Tearing down the MATLAB Server.")
|
|
102
|
+
self.event_loop.run_until_complete(self._terminate_process(timeout=10))
|
|
103
|
+
_logger.debug("Terminated the MATLAB process.")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _send_http_get_request(uri, connection_scheme, headers, http_endpoint=""):
|
|
107
|
+
"""Send HTTP request to matlab-proxy server.
|
|
108
|
+
Returns HTTP response JSON"""
|
|
109
|
+
|
|
110
|
+
request_uri = uri + http_endpoint
|
|
111
|
+
|
|
112
|
+
json_response = None
|
|
113
|
+
with requests.Session() as s:
|
|
114
|
+
retries = Retry(total=10, backoff_factor=0.1)
|
|
115
|
+
s.mount(f"{connection_scheme}://", HTTPAdapter(max_retries=retries))
|
|
116
|
+
response = s.get(request_uri, headers=headers, verify=False)
|
|
117
|
+
json_response = json.loads(response.text)
|
|
118
|
+
|
|
119
|
+
return json_response
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _check_matlab_status(matlab_proxy_app_fixture, status):
|
|
123
|
+
uri = matlab_proxy_app_fixture.url
|
|
124
|
+
connection_scheme = matlab_proxy_app_fixture.connection_scheme
|
|
125
|
+
headers = matlab_proxy_app_fixture.headers
|
|
126
|
+
|
|
127
|
+
matlab_status = None
|
|
128
|
+
|
|
129
|
+
start_time = time.time()
|
|
130
|
+
while matlab_status != status and (time.time() - start_time < MAX_TIMEOUT):
|
|
131
|
+
time.sleep(1)
|
|
132
|
+
res = _send_http_get_request(
|
|
133
|
+
uri, connection_scheme, headers, http_endpoint="/get_status"
|
|
134
|
+
)
|
|
135
|
+
matlab_status = res["matlab"]["status"]
|
|
136
|
+
|
|
137
|
+
return matlab_status
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@pytest.fixture
|
|
141
|
+
def matlab_proxy_app_fixture(
|
|
142
|
+
loop,
|
|
143
|
+
):
|
|
144
|
+
"""A pytest fixture which yields a real matlab server to be used by tests.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
loop (Event event_loop): The built-in event event_loop provided by pytest.
|
|
148
|
+
|
|
149
|
+
Yields:
|
|
150
|
+
real_matlab_server : A real matlab web server used by tests.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
with RealMATLABServer(loop) as matlab_proxy_app:
|
|
155
|
+
yield matlab_proxy_app
|
|
156
|
+
except ProcessLookupError as e:
|
|
157
|
+
_logger.debug("ProcessLookupError found in matlab proxy app fixture")
|
|
158
|
+
_logger.debug(e)
|
|
159
|
+
pass
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_matlab_is_up(matlab_proxy_app_fixture):
|
|
163
|
+
"""Test that the status switches from 'starting' to 'up' within a timeout.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
matlab_proxy_app_fixture: A pytest fixture which yields a real matlab server to be used by tests.
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
status = _check_matlab_status(matlab_proxy_app_fixture, "up")
|
|
170
|
+
assert status == "up"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_stop_matlab(matlab_proxy_app_fixture):
|
|
174
|
+
"""Test to check that matlab is in 'down' state when
|
|
175
|
+
we send the delete request to 'stop_matlab' endpoint
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
matlab_proxy_app_fixture: A pytest fixture which yields a real matlab server to be used by tests.
|
|
179
|
+
"""
|
|
180
|
+
status = _check_matlab_status(matlab_proxy_app_fixture, "up")
|
|
181
|
+
assert status == "up"
|
|
182
|
+
|
|
183
|
+
http_endpoint_to_test = "/stop_matlab"
|
|
184
|
+
stop_url = matlab_proxy_app_fixture.url + http_endpoint_to_test
|
|
185
|
+
|
|
186
|
+
with requests.Session() as s:
|
|
187
|
+
retries = Retry(total=10, backoff_factor=0.1)
|
|
188
|
+
s.mount(
|
|
189
|
+
f"{matlab_proxy_app_fixture.connection_scheme}://",
|
|
190
|
+
HTTPAdapter(max_retries=retries),
|
|
191
|
+
)
|
|
192
|
+
s.delete(stop_url, headers=matlab_proxy_app_fixture.headers, verify=False)
|
|
193
|
+
|
|
194
|
+
status = _check_matlab_status(matlab_proxy_app_fixture, "down")
|
|
195
|
+
assert status == "down"
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# FIXME: If output has logging or extra debug info, 600 bytes might not be enough.
|
|
199
|
+
async def test_print_message(matlab_proxy_app_fixture):
|
|
200
|
+
"""Test if the right logs are printed
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
matlab_proxy_app_fixture: A pytest fixture which yields a real matlab server to be used by tests.
|
|
204
|
+
|
|
205
|
+
"""
|
|
206
|
+
# Checks if matlab proxy is in "up" state or not
|
|
207
|
+
status = _check_matlab_status(matlab_proxy_app_fixture, "up")
|
|
208
|
+
assert status == "up"
|
|
209
|
+
|
|
210
|
+
uri_regex = f"{matlab_proxy_app_fixture.connection_scheme}://[a-zA-Z0-9\-_.]+:{matlab_proxy_app_fixture.mwi_app_port}{matlab_proxy_app_fixture.mwi_base_url}"
|
|
211
|
+
|
|
212
|
+
read_descriptor, write_descriptor = matlab_proxy_app_fixture.dpipe
|
|
213
|
+
number_of_bytes = 600
|
|
214
|
+
|
|
215
|
+
if read_descriptor:
|
|
216
|
+
line = os.read(read_descriptor, number_of_bytes).decode("utf-8")
|
|
217
|
+
process_logs = line.strip()
|
|
218
|
+
|
|
219
|
+
assert bool(re.search(uri_regex, process_logs)) == True
|
|
220
|
+
|
|
221
|
+
# Close the read and write descriptors.
|
|
222
|
+
os.close(read_descriptor)
|
|
223
|
+
os.close(write_descriptor)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Copyright 2023 The MathWorks, Inc.
|