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,586 @@
|
|
|
1
|
+
# Copyright 2023-2024 The MathWorks, Inc.
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from matlab_proxy import settings
|
|
12
|
+
from matlab_proxy.app_state import AppState
|
|
13
|
+
from matlab_proxy.constants import MWI_AUTH_TOKEN_NAME_FOR_HTTP
|
|
14
|
+
from matlab_proxy.util.mwi.exceptions import LicensingError, MatlabError
|
|
15
|
+
from tests.unit.util import MockResponse
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture
|
|
19
|
+
def sample_settings_fixture(tmp_path):
|
|
20
|
+
"""A pytest fixture which returns a dict containing sample settings for the AppState class.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
tmp_path : Builtin pytest fixture
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
dict: A dictionary of sample settings
|
|
27
|
+
"""
|
|
28
|
+
tmp_file = tmp_path / "parent_1" / "parent_2" / "tmp_file.json"
|
|
29
|
+
return {
|
|
30
|
+
"error": None,
|
|
31
|
+
"warnings": [],
|
|
32
|
+
"matlab_config_file": tmp_file,
|
|
33
|
+
"is_xvfb_available": True,
|
|
34
|
+
"mwi_server_url": "dummy",
|
|
35
|
+
"mwi_logs_root_dir": Path(settings.get_mwi_config_folder(dev=True)),
|
|
36
|
+
"app_port": 12345,
|
|
37
|
+
"mwapikey": "asdf",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def app_state_fixture(sample_settings_fixture):
|
|
43
|
+
"""A pytest fixture which returns an instance of AppState class with no errors.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
sample_settings_fixture (dict): A dictionary of sample settings to be used by
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
AppState: An object of the AppState class
|
|
50
|
+
"""
|
|
51
|
+
app_state = AppState(settings=sample_settings_fixture)
|
|
52
|
+
app_state.processes = {"matlab": None, "xvfb": None}
|
|
53
|
+
app_state.licensing = {"type": "existing_license"}
|
|
54
|
+
return app_state
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.fixture
|
|
58
|
+
def sample_token_headers_fixture():
|
|
59
|
+
return {MWI_AUTH_TOKEN_NAME_FOR_HTTP: "asdf"}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.fixture
|
|
63
|
+
def app_state_with_token_auth_fixture(
|
|
64
|
+
app_state_fixture, sample_token_headers_fixture, tmp_path
|
|
65
|
+
):
|
|
66
|
+
"""Pytest fixture which returns AppState instance with token authentication enabled.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
app_state_fixture (AppState): Pytest fixture
|
|
70
|
+
tmp_path (str): Built-in pytest fixture
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
(AppState, dict): Instance of the AppState class with token authentication enabled and token headers
|
|
74
|
+
"""
|
|
75
|
+
tmp_matlab_ready_file = Path(tmp_path) / "tmp_file.txt"
|
|
76
|
+
tmp_matlab_ready_file.touch()
|
|
77
|
+
((mwi_auth_token_name, mwi_auth_token_hash),) = sample_token_headers_fixture.items()
|
|
78
|
+
app_state_fixture.matlab_session_files["matlab_ready_file"] = tmp_matlab_ready_file
|
|
79
|
+
app_state_fixture.settings["mwi_is_token_auth_enabled"] = True
|
|
80
|
+
app_state_fixture.settings["mwi_auth_token_name_for_env"] = mwi_auth_token_name
|
|
81
|
+
app_state_fixture.settings["mwi_auth_token_name_for_http"] = (
|
|
82
|
+
MWI_AUTH_TOKEN_NAME_FOR_HTTP
|
|
83
|
+
)
|
|
84
|
+
app_state_fixture.settings["mwi_auth_token_hash"] = mwi_auth_token_hash
|
|
85
|
+
app_state_fixture.settings["mwi_server_url"] = "http://localhost:8888"
|
|
86
|
+
|
|
87
|
+
return app_state_fixture
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@pytest.fixture
|
|
91
|
+
def mocker_os_patching_fixture(mocker, platform):
|
|
92
|
+
"""A pytest fixture which patches the is_* functions in system.py module
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
mocker : Built in pytest fixture
|
|
96
|
+
platform (str): A string representing "windows", "linux" or "mac"
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
mocker: Built in pytest fixture with patched calls to system.py module.
|
|
100
|
+
"""
|
|
101
|
+
mocker.patch("matlab_proxy.app_state.system.is_linux", return_value=False)
|
|
102
|
+
mocker.patch("matlab_proxy.app_state.system.is_windows", return_value=False)
|
|
103
|
+
mocker.patch("matlab_proxy.app_state.system.is_mac", return_value=False)
|
|
104
|
+
mocker.patch("matlab_proxy.app_state.system.is_posix", return_value=False)
|
|
105
|
+
|
|
106
|
+
if platform == "linux":
|
|
107
|
+
mocker.patch("matlab_proxy.app_state.system.is_linux", return_value=True)
|
|
108
|
+
mocker.patch("matlab_proxy.app_state.system.is_posix", return_value=True)
|
|
109
|
+
|
|
110
|
+
elif platform == "windows":
|
|
111
|
+
mocker.patch("matlab_proxy.app_state.system.is_windows", return_value=True)
|
|
112
|
+
mocker.patch("matlab_proxy.app_state.system.is_posix", return_value=False)
|
|
113
|
+
|
|
114
|
+
else:
|
|
115
|
+
mocker.patch("matlab_proxy.app_state.system.is_mac", return_value=True)
|
|
116
|
+
mocker.patch("matlab_proxy.app_state.system.is_posix", return_value=True)
|
|
117
|
+
|
|
118
|
+
return mocker
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclass(frozen=True)
|
|
122
|
+
class Mock_xvfb:
|
|
123
|
+
"""An immutable dataclass representing a mocked Xvfb process"""
|
|
124
|
+
|
|
125
|
+
returncode: Optional[int]
|
|
126
|
+
pid: Optional[int]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@dataclass(frozen=True)
|
|
130
|
+
class Mock_matlab:
|
|
131
|
+
"""An immutable dataclass representing a mocked MATLAB process"""
|
|
132
|
+
|
|
133
|
+
returncode: Optional[int]
|
|
134
|
+
pid: Optional[int]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@pytest.mark.parametrize(
|
|
138
|
+
"licensing, expected",
|
|
139
|
+
[
|
|
140
|
+
(None, False),
|
|
141
|
+
({"type": "nlm", "conn_str": "123@host"}, True),
|
|
142
|
+
({"type": "nlm"}, False),
|
|
143
|
+
({"type": "mhlm", "identity_token": "random_token"}, False),
|
|
144
|
+
(
|
|
145
|
+
{
|
|
146
|
+
"type": "mhlm",
|
|
147
|
+
"identity_token": "random_token",
|
|
148
|
+
"source_id": "dummy_id",
|
|
149
|
+
"expiry": "Jan 1, 1970",
|
|
150
|
+
"entitlement_id": "123456",
|
|
151
|
+
},
|
|
152
|
+
True,
|
|
153
|
+
),
|
|
154
|
+
({"type": "existing_license"}, True),
|
|
155
|
+
({"type": "invalid_type"}, False),
|
|
156
|
+
],
|
|
157
|
+
ids=[
|
|
158
|
+
"None licensing",
|
|
159
|
+
"happy path-nlm",
|
|
160
|
+
"incomplete nlm data",
|
|
161
|
+
"incomplete mhlm data",
|
|
162
|
+
"happy path-mhlm",
|
|
163
|
+
"happy path-existing license",
|
|
164
|
+
"invalid license",
|
|
165
|
+
],
|
|
166
|
+
)
|
|
167
|
+
def test_is_licensed(app_state_fixture, licensing, expected):
|
|
168
|
+
"""Test to check is_licensed()
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
app_state_fixture (AppState): Object of AppState class with defaults set
|
|
172
|
+
licensing (dict): Represents licensing information
|
|
173
|
+
expected (bool): Expected return value.
|
|
174
|
+
"""
|
|
175
|
+
# Arrange
|
|
176
|
+
# Nothing to arrange
|
|
177
|
+
|
|
178
|
+
# Act
|
|
179
|
+
app_state_fixture.licensing = licensing
|
|
180
|
+
|
|
181
|
+
# Assert
|
|
182
|
+
assert app_state_fixture.is_licensed() == expected
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@pytest.mark.parametrize(
|
|
186
|
+
"err, expected_err",
|
|
187
|
+
[
|
|
188
|
+
(MatlabError(message="dummy error"), MatlabError(message="dummy")),
|
|
189
|
+
(LicensingError(message="license issue"), None),
|
|
190
|
+
],
|
|
191
|
+
ids=["Any error except licensing error", "licensing error"],
|
|
192
|
+
)
|
|
193
|
+
def test_unset_licensing(err, app_state_fixture, expected_err):
|
|
194
|
+
"""Test to check unset_liecnsing removes licensing from the AppState object
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
err (Exception): Custom exceptions defined in exceptions.py
|
|
198
|
+
licensing (bool): Whether licensing info is removed
|
|
199
|
+
expected_err (Exception): Expected exception
|
|
200
|
+
"""
|
|
201
|
+
# Arrange
|
|
202
|
+
app_state_fixture.error = err
|
|
203
|
+
|
|
204
|
+
# Act
|
|
205
|
+
app_state_fixture.unset_licensing()
|
|
206
|
+
|
|
207
|
+
# Assert
|
|
208
|
+
assert app_state_fixture.licensing == None
|
|
209
|
+
assert type(app_state_fixture.error) is type(expected_err)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
# config file is deleted when licensing info is not set i.e. set to None
|
|
213
|
+
def test_persist_licensing_when_licensing_info_is_not_set(app_state_fixture):
|
|
214
|
+
"""Test to check if data is not persisted to a file if licensing info is not present
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
tmp_path (Path): Built in pytest fixture
|
|
218
|
+
"""
|
|
219
|
+
# Arrange
|
|
220
|
+
# Nothing to arrange
|
|
221
|
+
app_state_fixture.licensing = None
|
|
222
|
+
|
|
223
|
+
# Act
|
|
224
|
+
app_state_fixture.persist_config_data()
|
|
225
|
+
|
|
226
|
+
# Assert
|
|
227
|
+
assert os.path.exists(app_state_fixture.settings["matlab_config_file"]) is False
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@pytest.mark.parametrize(
|
|
231
|
+
"licensing_data",
|
|
232
|
+
[
|
|
233
|
+
({"type": "nlm", "conn_str": "123@host"}),
|
|
234
|
+
(
|
|
235
|
+
{
|
|
236
|
+
"type": "mhlm",
|
|
237
|
+
"identity_token": "random_token",
|
|
238
|
+
"source_id": "dummy_id",
|
|
239
|
+
"expiry": "Jan 1, 1970",
|
|
240
|
+
"entitlement_id": "123456",
|
|
241
|
+
}
|
|
242
|
+
),
|
|
243
|
+
({"type": "existing_license"}),
|
|
244
|
+
],
|
|
245
|
+
ids=["nlm type", "mhlm type", "existing license type"],
|
|
246
|
+
)
|
|
247
|
+
def test_persist_config_data(licensing_data: dict, tmp_path):
|
|
248
|
+
"""Test to check if persist_licensing() writes data to the file system
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
data (dict): Represents matlab-proxy licensing data
|
|
252
|
+
tmp_path : Built-in pytest fixture.
|
|
253
|
+
"""
|
|
254
|
+
# Arrange
|
|
255
|
+
tmp_file = tmp_path / "parent_1" / "parent_2" / "tmp_file.json"
|
|
256
|
+
settings = {
|
|
257
|
+
"matlab_config_file": tmp_file,
|
|
258
|
+
"error": None,
|
|
259
|
+
"matlab_version": None,
|
|
260
|
+
"warnings": [],
|
|
261
|
+
}
|
|
262
|
+
app_state = AppState(settings=settings)
|
|
263
|
+
app_state.licensing = licensing_data
|
|
264
|
+
|
|
265
|
+
cached_data = {"licensing": licensing_data, "matlab": {"version": None}}
|
|
266
|
+
|
|
267
|
+
# Act
|
|
268
|
+
app_state.persist_config_data()
|
|
269
|
+
with open(tmp_file, "r") as file:
|
|
270
|
+
got = file.read()
|
|
271
|
+
|
|
272
|
+
# Assert
|
|
273
|
+
assert json.loads(got) == cached_data
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
validate_required_processes_test_data = [
|
|
277
|
+
(None, None, "linux", False), # xvfb is None == True
|
|
278
|
+
(None, Mock_xvfb(None, 1), "linux", False), # matlab is None == True
|
|
279
|
+
(
|
|
280
|
+
Mock_matlab(None, 1),
|
|
281
|
+
Mock_xvfb(None, 1),
|
|
282
|
+
"linux",
|
|
283
|
+
True,
|
|
284
|
+
), # All branches are skipped and nothing returned
|
|
285
|
+
(
|
|
286
|
+
Mock_matlab(None, 1),
|
|
287
|
+
Mock_xvfb(123, 2),
|
|
288
|
+
"linux",
|
|
289
|
+
False,
|
|
290
|
+
), # xvfb.returncode is not None == True
|
|
291
|
+
(
|
|
292
|
+
Mock_matlab(123, 1),
|
|
293
|
+
Mock_xvfb(None, 2),
|
|
294
|
+
"linux",
|
|
295
|
+
False,
|
|
296
|
+
), # matlab.returncode is not None == True
|
|
297
|
+
(
|
|
298
|
+
Mock_matlab(None, 1),
|
|
299
|
+
None,
|
|
300
|
+
"linux",
|
|
301
|
+
True,
|
|
302
|
+
), # Xvfb not found on path
|
|
303
|
+
]
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
@pytest.mark.parametrize(
|
|
307
|
+
"matlab, xvfb, platform, expected",
|
|
308
|
+
validate_required_processes_test_data,
|
|
309
|
+
ids=[
|
|
310
|
+
"processes_not_running",
|
|
311
|
+
"matlab_not_running",
|
|
312
|
+
"All_required_processes_running",
|
|
313
|
+
"All_processes_running_with_xvfb_returning_non_zero_code",
|
|
314
|
+
"All_processes_running_with_matlab_returning_non_zero_code",
|
|
315
|
+
"xvfb_is_optional_matlab_starts_without_it",
|
|
316
|
+
],
|
|
317
|
+
)
|
|
318
|
+
def test_are_required_processes_ready(
|
|
319
|
+
app_state_fixture, mocker_os_patching_fixture, matlab, xvfb, expected
|
|
320
|
+
):
|
|
321
|
+
"""Test to check if required processes are ready
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
app_state_fixture (AppState): Object of AppState class with defaults set
|
|
325
|
+
mocker_os_patching_fixture (mocker): Custom pytest fixture for mocking
|
|
326
|
+
matlab (Mock_matlab): Represents a mocked MATLAB process
|
|
327
|
+
xvfb (Mock_xvfb): Represents a mocked Xvfb process
|
|
328
|
+
expected (bool): Expected return value based on process return code
|
|
329
|
+
"""
|
|
330
|
+
# Arrange
|
|
331
|
+
app_state_fixture.processes = {"matlab": matlab, "xvfb": xvfb}
|
|
332
|
+
if not xvfb:
|
|
333
|
+
app_state_fixture.settings["is_xvfb_available"] = False
|
|
334
|
+
|
|
335
|
+
# Act
|
|
336
|
+
actual = app_state_fixture._are_required_processes_ready()
|
|
337
|
+
|
|
338
|
+
# Assert
|
|
339
|
+
assert actual == expected
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
get_matlab_status_based_on_connector_status_test_data = [
|
|
343
|
+
("up", True, "up"),
|
|
344
|
+
("down", True, "starting"),
|
|
345
|
+
("up", False, "starting"),
|
|
346
|
+
]
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
@pytest.mark.parametrize(
|
|
350
|
+
"connector_status, ready_file_present, matlab_status",
|
|
351
|
+
get_matlab_status_based_on_connector_status_test_data,
|
|
352
|
+
ids=["connector_up", "connector_down", "connector_up_ready_file_not_present"],
|
|
353
|
+
)
|
|
354
|
+
async def test_get_matlab_status_based_on_connector_status(
|
|
355
|
+
mocker, app_state_fixture, connector_status, ready_file_present, matlab_status
|
|
356
|
+
):
|
|
357
|
+
"""Test to check matlab status based on connector status
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
mocker : Built in pytest fixture.
|
|
361
|
+
connector_status (str): Status of Embedded Connector.
|
|
362
|
+
ready_file_present (bool): Represents if the ready file has been created or not.
|
|
363
|
+
matlab_status (str): Represents the status of MATLAB process.
|
|
364
|
+
"""
|
|
365
|
+
# Arrange
|
|
366
|
+
mocker.patch(
|
|
367
|
+
"matlab_proxy.app_state.mwi.embedded_connector.request.get_state",
|
|
368
|
+
return_value=connector_status,
|
|
369
|
+
)
|
|
370
|
+
mocker.patch.object(Path, "exists", return_value=ready_file_present)
|
|
371
|
+
app_state_fixture.settings["mwi_is_token_auth_enabled"] = False
|
|
372
|
+
app_state_fixture.matlab_session_files["matlab_ready_file"] = Path("dummy")
|
|
373
|
+
|
|
374
|
+
# Act
|
|
375
|
+
actual_matlab_status = await app_state_fixture._get_matlab_connector_status()
|
|
376
|
+
|
|
377
|
+
# Assert
|
|
378
|
+
assert actual_matlab_status == matlab_status
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
@pytest.mark.parametrize(
|
|
382
|
+
"valid_processes, connector_status, expected",
|
|
383
|
+
[
|
|
384
|
+
(True, "up", "up"),
|
|
385
|
+
(False, "up", "down"),
|
|
386
|
+
(True, "down", "down"),
|
|
387
|
+
],
|
|
388
|
+
ids=[
|
|
389
|
+
"valid_processes_connector_up",
|
|
390
|
+
"invalid_processes_connector_up",
|
|
391
|
+
"valid_processes_connector_down",
|
|
392
|
+
],
|
|
393
|
+
)
|
|
394
|
+
async def test_get_matlab_state(
|
|
395
|
+
app_state_fixture, mocker, valid_processes, connector_status, expected
|
|
396
|
+
):
|
|
397
|
+
"""Test to check get_matlab_state returns the correct MATLAB state based on the connector status
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
app_state_fixture (AppState): Object of AppState class with defaults set
|
|
401
|
+
mocker : Built in pytest fixture
|
|
402
|
+
valid_processes (bool): Represents if the processes are valid or not
|
|
403
|
+
connector_status (str): Status of Embedded Connector.
|
|
404
|
+
expected (str): Expected status of MATLAB process.
|
|
405
|
+
"""
|
|
406
|
+
# Arrange
|
|
407
|
+
mocker.patch.object(
|
|
408
|
+
AppState,
|
|
409
|
+
"_are_required_processes_ready",
|
|
410
|
+
return_value=valid_processes,
|
|
411
|
+
)
|
|
412
|
+
mocker.patch.object(
|
|
413
|
+
AppState,
|
|
414
|
+
"_get_matlab_connector_status",
|
|
415
|
+
return_value=connector_status,
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
# Act
|
|
419
|
+
actual_state = await app_state_fixture.get_matlab_state()
|
|
420
|
+
|
|
421
|
+
# Assert
|
|
422
|
+
assert actual_state == expected
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
@pytest.mark.parametrize("platform", [("linux"), ("windows"), ("mac")])
|
|
426
|
+
async def test_track_embedded_connector(mocker_os_patching_fixture, app_state_fixture):
|
|
427
|
+
"""Test to check track_embedded_connector task
|
|
428
|
+
|
|
429
|
+
Args:
|
|
430
|
+
mocker_os_patching_fixture (mocker): Custom pytest fixture for mocking
|
|
431
|
+
app_state_fixture (AppState): Object of AppState class with defaults set
|
|
432
|
+
"""
|
|
433
|
+
|
|
434
|
+
# Arrange
|
|
435
|
+
# patching embedded_connector_start_time to EPOCH+1 seconds and state to be "down"
|
|
436
|
+
mocker_os_patching_fixture.patch.object(
|
|
437
|
+
app_state_fixture, "embedded_connector_start_time", new=float(1.0)
|
|
438
|
+
)
|
|
439
|
+
mocker_os_patching_fixture.patch.object(
|
|
440
|
+
app_state_fixture, "embedded_connector_state", return_value="down"
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
# verify that stop_matlab() is called once
|
|
444
|
+
spy = mocker_os_patching_fixture.spy(app_state_fixture, "stop_matlab")
|
|
445
|
+
|
|
446
|
+
# Act
|
|
447
|
+
await app_state_fixture._AppState__track_embedded_connector_state()
|
|
448
|
+
|
|
449
|
+
# Assert
|
|
450
|
+
spy.assert_called_once()
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
@pytest.mark.parametrize(
|
|
454
|
+
"env_var_name, filter_prefix, is_filtered",
|
|
455
|
+
[("MWI_AUTH_TOKEN", "MWI_", None), ("MWIFOO_AUTH_TOKEN", "MWI_", "foo")],
|
|
456
|
+
ids=["env_var_is_filtered", "env_var_is_not_filtered"],
|
|
457
|
+
)
|
|
458
|
+
def test_env_variables_filtration_for_xvfb_process(
|
|
459
|
+
monkeypatch, env_var_name, filter_prefix, is_filtered
|
|
460
|
+
):
|
|
461
|
+
"""Test to check if __filter_env_variables filters environment variables with a certain prefix correctly.
|
|
462
|
+
|
|
463
|
+
Args:
|
|
464
|
+
monkeypatch (Object): Built-in pytest fixture for monkeypatching
|
|
465
|
+
env_var_name (str): Name of the environment variable
|
|
466
|
+
filter_prefix (str): Prefix to check for filtering
|
|
467
|
+
is_filtered (bool): To check if the env variable with specified prefix is filtered.
|
|
468
|
+
"""
|
|
469
|
+
# Arrange
|
|
470
|
+
env_var = env_var_name
|
|
471
|
+
monkeypatch.setenv(env_var, "foo")
|
|
472
|
+
|
|
473
|
+
# Act
|
|
474
|
+
filtered_env_vars: dict = AppState._AppState__filter_env_variables(
|
|
475
|
+
os.environ, filter_prefix
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
# Assert
|
|
479
|
+
assert filtered_env_vars.get(env_var) == is_filtered
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
@pytest.mark.parametrize(
|
|
483
|
+
"platform, expected_output",
|
|
484
|
+
[("linux", "stdout"), ("windows", "file"), ("mac", "stdout")],
|
|
485
|
+
)
|
|
486
|
+
async def test_setup_env_for_matlab(
|
|
487
|
+
mocker_os_patching_fixture, platform, expected_output, app_state_fixture, tmp_path
|
|
488
|
+
):
|
|
489
|
+
"""Test to check MW_DIAGNOSTIC_DEST is set appropriately for posix and non-posix systems
|
|
490
|
+
|
|
491
|
+
Args:
|
|
492
|
+
mocker_os_patching_fixture (mocker): Custom pytest fixture for mocking
|
|
493
|
+
platform (str): string describing a platform
|
|
494
|
+
app_state_fixture (AppState): Object of AppState class with defaults set
|
|
495
|
+
tmp_path (Path): Built-in pytest fixture for temporary paths
|
|
496
|
+
"""
|
|
497
|
+
|
|
498
|
+
# Arrange
|
|
499
|
+
app_state_fixture.licensing = {"type": "existing_license"}
|
|
500
|
+
app_state_fixture.settings = {"mwapikey": None, "matlab_display": ":1"}
|
|
501
|
+
app_state_fixture.mwi_logs_dir = tmp_path
|
|
502
|
+
mocker_os_patching_fixture.patch(
|
|
503
|
+
"matlab_proxy.app_state.logger.isEnabledFor", return_value=True
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
# Act
|
|
507
|
+
matlab_env = await app_state_fixture._AppState__setup_env_for_matlab()
|
|
508
|
+
|
|
509
|
+
# Assert
|
|
510
|
+
assert expected_output in matlab_env["MW_DIAGNOSTIC_DEST"]
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
@pytest.mark.parametrize(
|
|
514
|
+
"function_to_call ,mock_response",
|
|
515
|
+
[
|
|
516
|
+
("_get_matlab_connector_status", MockResponse(ok=True)),
|
|
517
|
+
(
|
|
518
|
+
"_AppState__send_stop_request_to_matlab",
|
|
519
|
+
MockResponse(
|
|
520
|
+
ok=True, payload={"messages": {"EvalResponse": [{"isError": None}]}}
|
|
521
|
+
),
|
|
522
|
+
),
|
|
523
|
+
],
|
|
524
|
+
ids=["request matlab connector status", "send request to stop matlab"],
|
|
525
|
+
)
|
|
526
|
+
async def test_requests_sent_by_matlab_proxy_have_headers(
|
|
527
|
+
app_state_with_token_auth_fixture,
|
|
528
|
+
function_to_call,
|
|
529
|
+
mock_response,
|
|
530
|
+
mocker,
|
|
531
|
+
sample_token_headers_fixture,
|
|
532
|
+
):
|
|
533
|
+
"""Test to check if token headers are included in requests sent by matlab-proxy when authentication is enabled
|
|
534
|
+
|
|
535
|
+
Args:
|
|
536
|
+
app_state_fixture_with_token_auth (AppState): Instance of AppState class with token authentication enabled
|
|
537
|
+
mocker : Built-in pytest fixture
|
|
538
|
+
"""
|
|
539
|
+
# Arrange
|
|
540
|
+
mocked_request = mocker.patch(
|
|
541
|
+
"aiohttp.ClientSession.request", return_value=mock_response
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
# Act
|
|
545
|
+
# Call the function passed as a string
|
|
546
|
+
method = getattr(app_state_with_token_auth_fixture, function_to_call)
|
|
547
|
+
_ = await method()
|
|
548
|
+
|
|
549
|
+
# Assert
|
|
550
|
+
connector_status_request_headers = list(mocked_request.call_args_list)[0].kwargs[
|
|
551
|
+
"headers"
|
|
552
|
+
]
|
|
553
|
+
assert sample_token_headers_fixture == connector_status_request_headers
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
async def test_start_matlab_without_xvfb(app_state_fixture, mocker):
|
|
557
|
+
"""Test to check if Matlab process starts without throwing errors when Xvfb is not present
|
|
558
|
+
|
|
559
|
+
Args:
|
|
560
|
+
app_state_fixture (AppState): Object of AppState class with defaults set
|
|
561
|
+
mocker : Built-in pytest fixture
|
|
562
|
+
"""
|
|
563
|
+
# Arrange
|
|
564
|
+
app_state_fixture.settings["is_xvfb_available"] = False
|
|
565
|
+
mock_matlab = Mock_matlab(None, 1)
|
|
566
|
+
|
|
567
|
+
# Starting asyncio tasks related to matlab is not required here as only Xvfb check is required.
|
|
568
|
+
mocker.patch.object(
|
|
569
|
+
AppState, "_AppState__start_matlab_process", return_value=mock_matlab
|
|
570
|
+
)
|
|
571
|
+
mocker.patch.object(
|
|
572
|
+
AppState, "_AppState__matlab_stderr_reader_posix", return_value=None
|
|
573
|
+
)
|
|
574
|
+
mocker.patch.object(
|
|
575
|
+
AppState, "_AppState__track_embedded_connector_state", return_value=None
|
|
576
|
+
)
|
|
577
|
+
mocker.patch.object(AppState, "_AppState__update_matlab_port", return_value=None)
|
|
578
|
+
|
|
579
|
+
# Act
|
|
580
|
+
await app_state_fixture.start_matlab()
|
|
581
|
+
|
|
582
|
+
# Assert
|
|
583
|
+
# Check if Xvfb has not started
|
|
584
|
+
assert app_state_fixture.processes["xvfb"] is None
|
|
585
|
+
# Check if Matlab started
|
|
586
|
+
assert app_state_fixture.processes["matlab"] is mock_matlab
|
tests/unit/test_ddux.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Copyright 2020-2022 The MathWorks, Inc.
|
|
2
|
+
|
|
3
|
+
import matlab_proxy
|
|
4
|
+
from matlab_proxy import util
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_get_mwi_ddux_value():
|
|
8
|
+
"""Tests ddux value for matlab-proxy with different extension names"""
|
|
9
|
+
expected_result = matlab_proxy.__get_matlab_proxy_base_ddux_value()
|
|
10
|
+
actual_result = matlab_proxy.get_mwi_ddux_value(
|
|
11
|
+
matlab_proxy.get_default_config_name()
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
assert expected_result == actual_result
|
|
15
|
+
|
|
16
|
+
expected_result = f"MATLAB_PROXY:HELLO_WORLD:V1"
|
|
17
|
+
actual_result = matlab_proxy.get_mwi_ddux_value("hello world")
|
|
18
|
+
|
|
19
|
+
assert expected_result == actual_result
|
|
20
|
+
|
|
21
|
+
actual_result = matlab_proxy.get_mwi_ddux_value(" \n \t hello-world \n")
|
|
22
|
+
assert expected_result == actual_result
|