matlab-proxy 0.15.0__py3-none-any.whl → 0.16.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 +13 -7
- matlab_proxy/app_state.py +9 -6
- 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.14aa7840.js → main.522d83ba.js} +3 -3
- matlab_proxy/gui/static/js/main.522d83ba.js.map +1 -0
- matlab_proxy/settings.py +7 -4
- matlab_proxy/util/__init__.py +8 -1
- matlab_proxy/util/mwi/token_auth.py +19 -5
- {matlab_proxy-0.15.0.dist-info → matlab_proxy-0.16.0.dist-info}/METADATA +1 -1
- {matlab_proxy-0.15.0.dist-info → matlab_proxy-0.16.0.dist-info}/RECORD +40 -20
- tests/integration/integration_tests_with_license/test_http_end_points.py +4 -4
- tests/integration/integration_tests_without_license/conftest.py +4 -3
- tests/integration/integration_tests_without_license/test_matlab_is_down_if_unlicensed.py +3 -0
- tests/unit/__init__.py +1 -0
- tests/unit/conftest.py +67 -0
- tests/unit/test_app.py +1113 -0
- tests/unit/test_app_state.py +586 -0
- tests/unit/test_constants.py +6 -0
- tests/unit/test_ddux.py +22 -0
- tests/unit/test_devel.py +246 -0
- tests/unit/test_non_dev_mode.py +169 -0
- tests/unit/test_settings.py +460 -0
- tests/unit/util/__init__.py +3 -0
- tests/unit/util/mwi/__init__.py +1 -0
- tests/unit/util/mwi/embedded_connector/__init__.py +1 -0
- tests/unit/util/mwi/embedded_connector/test_helpers.py +29 -0
- tests/unit/util/mwi/embedded_connector/test_request.py +64 -0
- tests/unit/util/mwi/test_custom_http_headers.py +281 -0
- tests/unit/util/mwi/test_logger.py +49 -0
- tests/unit/util/mwi/test_token_auth.py +303 -0
- tests/unit/util/mwi/test_validators.py +331 -0
- tests/unit/util/test_mw.py +550 -0
- tests/unit/util/test_util.py +135 -0
- matlab_proxy/gui/static/js/main.14aa7840.js.map +0 -1
- /matlab_proxy/gui/static/js/{main.14aa7840.js.LICENSE.txt → main.522d83ba.js.LICENSE.txt} +0 -0
- {matlab_proxy-0.15.0.dist-info → matlab_proxy-0.16.0.dist-info}/LICENSE.md +0 -0
- {matlab_proxy-0.15.0.dist-info → matlab_proxy-0.16.0.dist-info}/WHEEL +0 -0
- {matlab_proxy-0.15.0.dist-info → matlab_proxy-0.16.0.dist-info}/entry_points.txt +0 -0
- {matlab_proxy-0.15.0.dist-info → matlab_proxy-0.16.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# Copyright 2020-2023 The MathWorks, Inc.
|
|
2
|
+
|
|
3
|
+
"""Tests for functions in matlab_proxy/util/mwi_validators.py
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import random
|
|
8
|
+
import socket
|
|
9
|
+
import tempfile
|
|
10
|
+
from matlab_proxy.util.mwi.validators import validate_matlab_root_path
|
|
11
|
+
from matlab_proxy import constants
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import matlab_proxy
|
|
15
|
+
import pytest
|
|
16
|
+
from matlab_proxy.util import system
|
|
17
|
+
from matlab_proxy.util.mwi import environment_variables as mwi_env
|
|
18
|
+
from matlab_proxy.util.mwi import validators
|
|
19
|
+
from matlab_proxy.util.mwi.exceptions import (
|
|
20
|
+
NetworkLicensingError,
|
|
21
|
+
FatalError,
|
|
22
|
+
MatlabInstallError,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.mark.parametrize(
|
|
27
|
+
"MLM_LICENSE_FILE",
|
|
28
|
+
[
|
|
29
|
+
("/path/to/a/non-existent/file"),
|
|
30
|
+
("1234"),
|
|
31
|
+
("hostname"),
|
|
32
|
+
("1234hostname"),
|
|
33
|
+
],
|
|
34
|
+
ids=[
|
|
35
|
+
"Invalid path to a license file",
|
|
36
|
+
"NLM string with just port number",
|
|
37
|
+
"NLM string with just hostname",
|
|
38
|
+
"NLM string with just port number and hostname",
|
|
39
|
+
],
|
|
40
|
+
)
|
|
41
|
+
def test_validate_mlm_license_file_invalid_value(MLM_LICENSE_FILE, monkeypatch):
|
|
42
|
+
"""Check if validator raises expected exception"""
|
|
43
|
+
|
|
44
|
+
env_name = mwi_env.get_env_name_network_license_manager()
|
|
45
|
+
|
|
46
|
+
monkeypatch.setenv(env_name, MLM_LICENSE_FILE)
|
|
47
|
+
nlm_conn_str = os.getenv(env_name)
|
|
48
|
+
|
|
49
|
+
with pytest.raises(NetworkLicensingError) as e_info:
|
|
50
|
+
validators.validate_mlm_license_file(nlm_conn_str)
|
|
51
|
+
assert MLM_LICENSE_FILE in str(e_info.value)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@pytest.fixture(name="temporary_license_file")
|
|
55
|
+
def temporary_license_file_fixture(tmp_path):
|
|
56
|
+
"""Pytest fixture which returns a valid path to temporary license file."""
|
|
57
|
+
import time
|
|
58
|
+
|
|
59
|
+
temp_license_file_path = tmp_path / f'{str(time.time()).replace(".", "")}.lic'
|
|
60
|
+
temp_license_file_path.touch()
|
|
61
|
+
|
|
62
|
+
return temp_license_file_path
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_validate_mlm_license_file_valid_license_file_path(
|
|
66
|
+
temporary_license_file, monkeypatch
|
|
67
|
+
):
|
|
68
|
+
"""Check if a valid license path has been supplied to MLM_LICENSE_FILE env var"""
|
|
69
|
+
env_name = mwi_env.get_env_name_network_license_manager()
|
|
70
|
+
monkeypatch.setenv(env_name, str(temporary_license_file))
|
|
71
|
+
|
|
72
|
+
validated_file_path = validators.validate_mlm_license_file(os.getenv(env_name))
|
|
73
|
+
assert str(temporary_license_file) == validated_file_path
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@pytest.mark.parametrize(
|
|
77
|
+
"MLM_LICENSE_FILE",
|
|
78
|
+
[
|
|
79
|
+
(["1234@1.2_any-alphanumeric"]),
|
|
80
|
+
(["1234@1.2_any-alphanumeric", "1234@1.2_any-alphanumeric"]),
|
|
81
|
+
(
|
|
82
|
+
[
|
|
83
|
+
"1234@1.2_any-alphanumeric",
|
|
84
|
+
"1234@1.2_any-alphanumeric",
|
|
85
|
+
"1234@1.2_any-alphanumeric",
|
|
86
|
+
]
|
|
87
|
+
),
|
|
88
|
+
[
|
|
89
|
+
"1234@1.2_any-alphanumeric,1234@1.2_any-alphanumeric,1234@1.2_any-alphanumeric"
|
|
90
|
+
],
|
|
91
|
+
(
|
|
92
|
+
[
|
|
93
|
+
"1234@1.2_any-alphanumeric",
|
|
94
|
+
"1234@1.2_any-alphanumeric,1234@1.2_any-alphanumeric,1234@1.2_any-alphanumeric",
|
|
95
|
+
]
|
|
96
|
+
),
|
|
97
|
+
(
|
|
98
|
+
[
|
|
99
|
+
"1234@1.2_any-alphanumeric,1234@1.2_any-alphanumeric,1234@1.2_any-alphanumeric",
|
|
100
|
+
"1234@1.2_any-alphanumeric",
|
|
101
|
+
]
|
|
102
|
+
),
|
|
103
|
+
(
|
|
104
|
+
[
|
|
105
|
+
"1234@1.2_any-alphanumeric",
|
|
106
|
+
"1234@1.2_any-alphanumeric,1234@1.2_any-alphanumeric,1234@1.2_any-alphanumeric",
|
|
107
|
+
"1234@1.2_any-alphanumeric",
|
|
108
|
+
]
|
|
109
|
+
),
|
|
110
|
+
],
|
|
111
|
+
ids=[
|
|
112
|
+
"1 NLM server",
|
|
113
|
+
"2 NLM servers",
|
|
114
|
+
"3 NLM servers",
|
|
115
|
+
"Just a server triad",
|
|
116
|
+
"1 NLM server prefixed to a server triad",
|
|
117
|
+
"1 NLM server suffixed to a server triad",
|
|
118
|
+
"1 NLM server prefixed and another suffixed to a server triad",
|
|
119
|
+
],
|
|
120
|
+
)
|
|
121
|
+
def test_validate_mlm_license_file_for_valid_nlm_string(MLM_LICENSE_FILE, monkeypatch):
|
|
122
|
+
"""Check if port@hostname passes validation"""
|
|
123
|
+
|
|
124
|
+
seperator = system.get_mlm_license_file_seperator()
|
|
125
|
+
MLM_LICENSE_FILE = seperator.join(MLM_LICENSE_FILE)
|
|
126
|
+
env_name = mwi_env.get_env_name_network_license_manager()
|
|
127
|
+
monkeypatch.setenv(env_name, MLM_LICENSE_FILE)
|
|
128
|
+
conn_str = validators.validate_mlm_license_file(os.getenv(env_name))
|
|
129
|
+
assert conn_str == MLM_LICENSE_FILE
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_validate_mlm_license_file_None():
|
|
133
|
+
"""Test to check if validate_mlm_license_file() returns None when nlm_conn_str is None."""
|
|
134
|
+
assert validators.validate_mlm_license_file(None) is None
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_get_with_environment_variables(monkeypatch):
|
|
138
|
+
"""Check if path to license file passes validation"""
|
|
139
|
+
env_name = mwi_env.get_env_name_network_license_manager()
|
|
140
|
+
fd, path = tempfile.mkstemp()
|
|
141
|
+
monkeypatch.setenv(env_name, path)
|
|
142
|
+
try:
|
|
143
|
+
conn_str = validators.validate_mlm_license_file(os.getenv(env_name))
|
|
144
|
+
assert conn_str == str(path)
|
|
145
|
+
finally:
|
|
146
|
+
os.close(fd)
|
|
147
|
+
os.remove(path)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_validate_app_port_is_free_false():
|
|
151
|
+
"""Test to validate if supplied app port is free"""
|
|
152
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
153
|
+
s.bind(("", 0))
|
|
154
|
+
port = s.getsockname()[1]
|
|
155
|
+
with pytest.raises(FatalError) as e:
|
|
156
|
+
validators.validate_app_port_is_free(port)
|
|
157
|
+
s.close()
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def test_validate_app_port_is_free_true():
|
|
161
|
+
"""Test to validate if supplied app port is free"""
|
|
162
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
163
|
+
s.bind(("", 0))
|
|
164
|
+
port = s.getsockname()[1]
|
|
165
|
+
s.close()
|
|
166
|
+
assert validators.validate_app_port_is_free(port) == port
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_validate_app_port_None():
|
|
170
|
+
"""Tests if validated app port is None when MWI_APP_PORT env variable is not set.
|
|
171
|
+
If validated app port is None implies a random free port will be used at launch.
|
|
172
|
+
"""
|
|
173
|
+
assert validators.validate_app_port_is_free(None) is None
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def test_validate_env_config_true():
|
|
177
|
+
"""Validate the default config which is used in this package."""
|
|
178
|
+
config = validators.validate_env_config(matlab_proxy.get_default_config_name())
|
|
179
|
+
assert isinstance(config, dict)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def test_validate_env_config_false():
|
|
183
|
+
"""Passing a non existent config should raise FatalError exception"""
|
|
184
|
+
|
|
185
|
+
with pytest.raises(FatalError) as e:
|
|
186
|
+
config = validators.validate_env_config(str(random.randint(10, 100)))
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_get_configs():
|
|
190
|
+
"""Test to check if atleast 1 env config is discovered.
|
|
191
|
+
When this package is installed, we will have a default config.
|
|
192
|
+
"""
|
|
193
|
+
configs = validators.__get_configs()
|
|
194
|
+
|
|
195
|
+
assert len(configs.keys()) >= 1
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@pytest.mark.parametrize(
|
|
199
|
+
"mwi_base_url, validated_base_url",
|
|
200
|
+
[
|
|
201
|
+
("", ""),
|
|
202
|
+
("/bla", "/bla"),
|
|
203
|
+
("/bla/", "/bla"),
|
|
204
|
+
],
|
|
205
|
+
ids=[
|
|
206
|
+
"Launch integration at root",
|
|
207
|
+
"Launch at custom path",
|
|
208
|
+
"Launch at custom with suffix: /",
|
|
209
|
+
],
|
|
210
|
+
)
|
|
211
|
+
def test_validate_base_url(mwi_base_url, validated_base_url):
|
|
212
|
+
"""Tests multiple base_urls which will beparsed and validated successfully.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
base_url (str): base_url
|
|
216
|
+
validated_base_url (str): validated base_url
|
|
217
|
+
"""
|
|
218
|
+
assert validators.validate_base_url(mwi_base_url) == validated_base_url
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def test_validate_base_url_no_prefix_error():
|
|
222
|
+
"""Test to check base_url will throw error when a prefix / is not present in it.[summary]"""
|
|
223
|
+
with pytest.raises(FatalError) as e:
|
|
224
|
+
validators.validate_base_url("matlab/")
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def test_validate_mwi_ssl_key_and_cert_file(monkeypatch):
|
|
228
|
+
"""Check if port@hostname passes validation"""
|
|
229
|
+
ssl_cert_file_env_name = mwi_env.get_env_name_ssl_cert_file()
|
|
230
|
+
ssl_key_file_env_name = mwi_env.get_env_name_ssl_key_file()
|
|
231
|
+
fd, path = tempfile.mkstemp()
|
|
232
|
+
|
|
233
|
+
monkeypatch.setenv(ssl_cert_file_env_name, path)
|
|
234
|
+
monkeypatch.setenv(ssl_key_file_env_name, path)
|
|
235
|
+
try:
|
|
236
|
+
# Verify that if KEY and CERT are provided
|
|
237
|
+
key_file, cert_file = validators.validate_ssl_key_and_cert_file(
|
|
238
|
+
os.getenv(ssl_key_file_env_name), os.getenv(ssl_cert_file_env_name)
|
|
239
|
+
)
|
|
240
|
+
assert key_file == str(path)
|
|
241
|
+
assert cert_file == str(path)
|
|
242
|
+
|
|
243
|
+
# Verify that KEY can be None
|
|
244
|
+
key_file, cert_file = validators.validate_ssl_key_and_cert_file(
|
|
245
|
+
None, os.getenv(ssl_cert_file_env_name)
|
|
246
|
+
)
|
|
247
|
+
assert key_file == None
|
|
248
|
+
assert cert_file == str(path)
|
|
249
|
+
|
|
250
|
+
# Verify that if KEY is provided, CERT must also be provided
|
|
251
|
+
with pytest.raises(FatalError) as e:
|
|
252
|
+
validators.validate_ssl_key_and_cert_file(
|
|
253
|
+
os.getenv(ssl_key_file_env_name), None
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# Verify that KEY is valid file location
|
|
257
|
+
with pytest.raises(FatalError) as e:
|
|
258
|
+
validators.validate_ssl_key_and_cert_file(
|
|
259
|
+
"/file/does/not/exist", os.getenv(ssl_cert_file_env_name)
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# Verify that KEY is valid file location
|
|
263
|
+
with pytest.raises(FatalError) as e:
|
|
264
|
+
validators.validate_ssl_key_and_cert_file(
|
|
265
|
+
os.getenv(ssl_key_file_env_name), "/file/does/not/exist"
|
|
266
|
+
)
|
|
267
|
+
finally:
|
|
268
|
+
# Need to close the file descriptor in Windows
|
|
269
|
+
# Or else PermissionError is raised.
|
|
270
|
+
os.close(fd)
|
|
271
|
+
os.remove(path)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def test_validate_matlab_root_path(tmp_path):
|
|
275
|
+
"""Checks if matlab root is validated without raising exceptions"""
|
|
276
|
+
|
|
277
|
+
# Arrange
|
|
278
|
+
matlab_root = Path(tmp_path) / "MATLAB"
|
|
279
|
+
os.mkdir(matlab_root)
|
|
280
|
+
version_info_file = Path(matlab_root) / constants.VERSION_INFO_FILE_NAME
|
|
281
|
+
version_info_file.touch()
|
|
282
|
+
|
|
283
|
+
# Act
|
|
284
|
+
actual_matlab_root = validate_matlab_root_path(
|
|
285
|
+
matlab_root, is_custom_matlab_root=False
|
|
286
|
+
)
|
|
287
|
+
actual_matlab_root_custom = validate_matlab_root_path(
|
|
288
|
+
matlab_root, is_custom_matlab_root=True
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# Assert
|
|
292
|
+
assert actual_matlab_root == matlab_root
|
|
293
|
+
assert actual_matlab_root_custom == matlab_root
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def test_validate_matlab_root_path_invalid_root_path(tmp_path):
|
|
297
|
+
"""Checks if validate_matlab_root_path raises MatlabInstallError when non-existent path is supplied"""
|
|
298
|
+
# Arrange
|
|
299
|
+
matlab_root = Path(tmp_path) / "MATLAB"
|
|
300
|
+
|
|
301
|
+
# Act
|
|
302
|
+
with pytest.raises(MatlabInstallError):
|
|
303
|
+
actual_matlab_root = validate_matlab_root_path(
|
|
304
|
+
matlab_root, is_custom_matlab_root=False
|
|
305
|
+
)
|
|
306
|
+
actual_matlab_root_custom = validate_matlab_root_path(
|
|
307
|
+
matlab_root, is_custom_matlab_root=True
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
# Assert
|
|
311
|
+
assert actual_matlab_root is None
|
|
312
|
+
assert actual_matlab_root_custom is None
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def test_validate_matlab_root_path_non_existent_versioninfo_file(tmp_path):
|
|
316
|
+
"""Checks if validate_matlab_root_path does not raise any exceptions even if VersionInfo.xml file does not exist"""
|
|
317
|
+
# Arrange
|
|
318
|
+
matlab_root = Path(tmp_path) / "MATLAB"
|
|
319
|
+
os.mkdir(matlab_root)
|
|
320
|
+
|
|
321
|
+
# Act
|
|
322
|
+
actual_matlab_root = validate_matlab_root_path(
|
|
323
|
+
matlab_root, is_custom_matlab_root=False
|
|
324
|
+
)
|
|
325
|
+
actual_matlab_root_custom = validate_matlab_root_path(
|
|
326
|
+
matlab_root, is_custom_matlab_root=True
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
# Assert
|
|
330
|
+
assert actual_matlab_root is None
|
|
331
|
+
assert actual_matlab_root_custom is None
|