intuned-runtime 1.3.1__py3-none-any.whl → 1.3.2__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.
- intuned_cli/__init__.py +15 -24
- intuned_cli/commands/__init__.py +6 -1
- intuned_cli/commands/attempt_api_command.py +8 -0
- intuned_cli/commands/attempt_authsession_check_command.py +8 -0
- intuned_cli/commands/attempt_authsession_command.py +4 -4
- intuned_cli/commands/attempt_authsession_create_command.py +9 -1
- intuned_cli/commands/attempt_command.py +4 -4
- intuned_cli/commands/authsession_command.py +12 -0
- intuned_cli/commands/authsession_record_command.py +54 -0
- intuned_cli/commands/command.py +6 -4
- intuned_cli/commands/deploy_command.py +2 -0
- intuned_cli/commands/init_command.py +2 -0
- intuned_cli/commands/run_api_command.py +9 -1
- intuned_cli/commands/run_authsession_command.py +4 -4
- intuned_cli/commands/run_authsession_create_command.py +34 -4
- intuned_cli/commands/run_authsession_update_command.py +33 -4
- intuned_cli/commands/run_authsession_validate_command.py +32 -3
- intuned_cli/commands/run_command.py +4 -4
- intuned_cli/commands/save_command.py +2 -0
- intuned_cli/controller/__test__/test_api.py +159 -18
- intuned_cli/controller/__test__/test_authsession.py +497 -6
- intuned_cli/controller/api.py +40 -39
- intuned_cli/controller/authsession.py +213 -110
- intuned_cli/controller/deploy.py +3 -3
- intuned_cli/controller/save.py +47 -48
- intuned_cli/types.py +14 -0
- intuned_cli/utils/__test__/test_browser.py +132 -0
- intuned_cli/utils/__test__/test_traces.py +27 -0
- intuned_cli/utils/api_helpers.py +54 -5
- intuned_cli/utils/auth_session_helpers.py +42 -7
- intuned_cli/utils/backend.py +4 -1
- intuned_cli/utils/browser.py +63 -0
- intuned_cli/utils/error.py +14 -0
- intuned_cli/utils/exclusions.py +1 -0
- intuned_cli/utils/help.py +9 -0
- intuned_cli/utils/traces.py +31 -0
- intuned_cli/utils/wrapper.py +58 -0
- intuned_internal_cli/__init__.py +7 -0
- {intuned_runtime-1.3.1.dist-info → intuned_runtime-1.3.2.dist-info}/METADATA +4 -2
- {intuned_runtime-1.3.1.dist-info → intuned_runtime-1.3.2.dist-info}/RECORD +45 -37
- runtime/browser/launch_chromium.py +4 -0
- runtime/types/settings_types.py +13 -4
- {intuned_runtime-1.3.1.dist-info → intuned_runtime-1.3.2.dist-info}/WHEEL +0 -0
- {intuned_runtime-1.3.1.dist-info → intuned_runtime-1.3.2.dist-info}/entry_points.txt +0 -0
- {intuned_runtime-1.3.1.dist-info → intuned_runtime-1.3.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,21 @@
|
|
1
|
+
import asyncio
|
1
2
|
from dataclasses import dataclass
|
2
3
|
from typing import Any
|
4
|
+
from typing import Awaitable
|
5
|
+
from typing import Callable
|
6
|
+
from typing import cast
|
3
7
|
from typing import Generator
|
4
8
|
from unittest.mock import AsyncMock
|
9
|
+
from unittest.mock import MagicMock
|
5
10
|
from unittest.mock import Mock
|
6
11
|
from unittest.mock import patch
|
7
12
|
|
8
13
|
import pytest
|
9
14
|
|
15
|
+
from intuned_cli.controller.api import get_cli_run_options
|
10
16
|
from intuned_cli.controller.authsession import execute_attempt_check_auth_session_cli
|
11
17
|
from intuned_cli.controller.authsession import execute_attempt_create_auth_session_cli
|
18
|
+
from intuned_cli.controller.authsession import execute_record_auth_session_cli
|
12
19
|
from intuned_cli.controller.authsession import execute_run_create_auth_session_cli
|
13
20
|
from intuned_cli.controller.authsession import execute_run_update_auth_session_cli
|
14
21
|
from intuned_cli.controller.authsession import execute_run_validate_auth_session_cli
|
@@ -20,8 +27,7 @@ from intuned_cli.utils.error import CLIError
|
|
20
27
|
from runtime.errors.run_api_errors import AutomationError
|
21
28
|
from runtime.types.run_types import ProxyConfig
|
22
29
|
from runtime.types.run_types import StorageState
|
23
|
-
|
24
|
-
from .test_api import AsyncContextManagerMock
|
30
|
+
from runtime.types.run_types import TracingDisabled
|
25
31
|
|
26
32
|
|
27
33
|
def get_mock_console():
|
@@ -88,6 +94,8 @@ def shared_mocks() -> Generator[SharedMocks, Any, None]:
|
|
88
94
|
class AttemptApiMocks:
|
89
95
|
extendable_timeout: AsyncMock
|
90
96
|
run_api: AsyncMock
|
97
|
+
cli_trace: AsyncMock
|
98
|
+
get_cli_run_options: AsyncMock
|
91
99
|
|
92
100
|
|
93
101
|
@pytest.fixture
|
@@ -95,13 +103,19 @@ def attempt_api_mocks() -> Generator[AttemptApiMocks, Any, None]:
|
|
95
103
|
"""Mock dependencies for attempt_api tests."""
|
96
104
|
_mock_timeout_patch = patch("intuned_cli.controller.authsession.extendable_timeout")
|
97
105
|
_mock_run_api_patch = patch("intuned_cli.controller.authsession.run_api", new_callable=AsyncMock)
|
106
|
+
_mock_cli_trace_patch = patch("intuned_cli.controller.authsession.cli_trace")
|
107
|
+
_mock_get_cli_run_options_patch = patch(
|
108
|
+
"intuned_cli.controller.authsession.get_cli_run_options", new_callable=AsyncMock
|
109
|
+
)
|
98
110
|
|
99
111
|
with (
|
100
112
|
_mock_timeout_patch as mock_timeout,
|
101
113
|
_mock_run_api_patch as mock_run_api,
|
114
|
+
_mock_cli_trace_patch as mock_cli_trace,
|
115
|
+
_mock_get_cli_run_options_patch as mock_get_cli_run_options,
|
102
116
|
):
|
103
117
|
# Setup default return values
|
104
|
-
mock_timeout.return_value =
|
118
|
+
mock_timeout.return_value = MagicMock()
|
105
119
|
|
106
120
|
# Mock run_api to return success by default
|
107
121
|
mock_result = Mock()
|
@@ -109,9 +123,21 @@ def attempt_api_mocks() -> Generator[AttemptApiMocks, Any, None]:
|
|
109
123
|
mock_result.payload_to_append = []
|
110
124
|
mock_run_api.return_value = mock_result
|
111
125
|
|
126
|
+
mock_cli_trace_return_value = MagicMock()
|
127
|
+
mock_cli_trace_return_value.__enter__.return_value = TracingDisabled()
|
128
|
+
mock_cli_trace.return_value = mock_cli_trace_return_value
|
129
|
+
|
130
|
+
async def get_cli_run_options_side_effect(*args: Any, **kwargs: Any):
|
131
|
+
kwargs["keep_browser_open"] = False
|
132
|
+
return await get_cli_run_options(*args, **kwargs)
|
133
|
+
|
134
|
+
mock_get_cli_run_options.side_effect = get_cli_run_options_side_effect
|
135
|
+
|
112
136
|
yield AttemptApiMocks(
|
113
137
|
extendable_timeout=mock_timeout,
|
114
138
|
run_api=mock_run_api,
|
139
|
+
cli_trace=mock_cli_trace,
|
140
|
+
get_cli_run_options=mock_get_cli_run_options,
|
115
141
|
)
|
116
142
|
|
117
143
|
|
@@ -184,6 +210,70 @@ def execute_cli_mocks() -> Generator[ExecuteCLIMocks, Any, None]:
|
|
184
210
|
)
|
185
211
|
|
186
212
|
|
213
|
+
@dataclass
|
214
|
+
class RecordAuthSessionMocks:
|
215
|
+
launch_chromium: AsyncMock
|
216
|
+
page: Mock
|
217
|
+
browser_context: Mock
|
218
|
+
# asyncio_sleep: AsyncMock
|
219
|
+
resolve_sleep: Callable[[], Awaitable[None]]
|
220
|
+
|
221
|
+
|
222
|
+
@pytest.fixture
|
223
|
+
def record_auth_session_mocks() -> Generator[RecordAuthSessionMocks, Any, None]:
|
224
|
+
"""Mock dependencies for execute_record_auth_session_cli tests."""
|
225
|
+
from asyncio import sleep as original_sleep
|
226
|
+
|
227
|
+
_mock_launch_chromium = patch("runtime.browser.launch_chromium")
|
228
|
+
_mock_asyncio_sleep = patch("asyncio.sleep", new_callable=AsyncMock)
|
229
|
+
_mock_asyncio_timeout = patch("asyncio.timeout")
|
230
|
+
_mock_get_storage_state = patch("intuned_cli.controller.authsession.get_storage_state", new_callable=AsyncMock)
|
231
|
+
|
232
|
+
with (
|
233
|
+
_mock_launch_chromium as mock_launch_chromium,
|
234
|
+
_mock_asyncio_sleep as _mock_asyncio_sleep,
|
235
|
+
_mock_asyncio_timeout as _mock_asyncio_timeout,
|
236
|
+
_mock_get_storage_state as _mock_get_storage_state,
|
237
|
+
):
|
238
|
+
mock_launch_chromium_return_value = Mock()
|
239
|
+
mock_page = Mock()
|
240
|
+
mock_page.url = ""
|
241
|
+
mock_page.wait_for_load_state = AsyncMock(return_value=None)
|
242
|
+
mock_page.goto = AsyncMock(return_value=None)
|
243
|
+
|
244
|
+
mock_browser_context = Mock()
|
245
|
+
mock_browser_context.pages = [mock_page]
|
246
|
+
|
247
|
+
mock_launch_chromium_return_value.__aenter__ = AsyncMock(return_value=(mock_browser_context, mock_page))
|
248
|
+
mock_launch_chromium_return_value.__aexit__ = AsyncMock(return_value=None)
|
249
|
+
mock_launch_chromium.return_value = mock_launch_chromium_return_value
|
250
|
+
|
251
|
+
mock_asyncio_timeout_return_value = MagicMock()
|
252
|
+
mock_asyncio_timeout_return_value.__aenter__.return_value = MagicMock()
|
253
|
+
_mock_asyncio_timeout.__aenter__.return_value = mock_asyncio_timeout_return_value
|
254
|
+
|
255
|
+
sleep_future: asyncio.Future[Any] = cast(asyncio.Future[Any], None)
|
256
|
+
|
257
|
+
async def asyncio_sleep_side_effect(_):
|
258
|
+
nonlocal sleep_future
|
259
|
+
await original_sleep(0)
|
260
|
+
sleep_future = asyncio.Future()
|
261
|
+
|
262
|
+
_mock_asyncio_sleep.side_effect = asyncio_sleep_side_effect
|
263
|
+
|
264
|
+
async def resolve_sleep_future():
|
265
|
+
await original_sleep(0)
|
266
|
+
if sleep_future:
|
267
|
+
sleep_future.set_result(None)
|
268
|
+
|
269
|
+
yield RecordAuthSessionMocks(
|
270
|
+
launch_chromium=mock_launch_chromium,
|
271
|
+
page=mock_page,
|
272
|
+
browser_context=mock_browser_context,
|
273
|
+
resolve_sleep=resolve_sleep_future,
|
274
|
+
)
|
275
|
+
|
276
|
+
|
187
277
|
class TestRunCheck:
|
188
278
|
"""Test suite for Auth Session controller functions."""
|
189
279
|
|
@@ -194,10 +284,71 @@ class TestRunCheck:
|
|
194
284
|
auth=_get_empty_auth_session(),
|
195
285
|
headless=False,
|
196
286
|
timeout=6000,
|
287
|
+
trace_id=None,
|
288
|
+
keep_browser_open=False,
|
197
289
|
)
|
198
290
|
|
199
291
|
attempt_api_mocks.extendable_timeout.assert_called_once_with(6000)
|
200
292
|
|
293
|
+
@pytest.mark.asyncio
|
294
|
+
async def test_uses_trace_context_manager(self, attempt_api_mocks: AttemptApiMocks):
|
295
|
+
"""Test that attempt_api uses the trace context manager."""
|
296
|
+
# Import inside test to avoid circular import issues
|
297
|
+
|
298
|
+
await run_check(
|
299
|
+
auth=_get_empty_auth_session(),
|
300
|
+
headless=False,
|
301
|
+
timeout=6000,
|
302
|
+
trace_id=None,
|
303
|
+
keep_browser_open=False,
|
304
|
+
)
|
305
|
+
|
306
|
+
attempt_api_mocks.cli_trace.assert_called_once_with(None)
|
307
|
+
|
308
|
+
attempt_api_mocks.cli_trace.reset_mock()
|
309
|
+
await run_check(
|
310
|
+
auth=_get_empty_auth_session(),
|
311
|
+
headless=False,
|
312
|
+
timeout=6000,
|
313
|
+
trace_id="trace-id",
|
314
|
+
keep_browser_open=False,
|
315
|
+
)
|
316
|
+
|
317
|
+
attempt_api_mocks.cli_trace.assert_called_once_with("trace-id")
|
318
|
+
|
319
|
+
@pytest.mark.asyncio
|
320
|
+
async def test_uses_get_cli_run_options(self, attempt_api_mocks: AttemptApiMocks):
|
321
|
+
"""Test that attempt_api calls get_cli_run_options with the correct parameters."""
|
322
|
+
# Import inside test to avoid circular import issues
|
323
|
+
|
324
|
+
await run_check(
|
325
|
+
auth=_get_empty_auth_session(),
|
326
|
+
headless=False,
|
327
|
+
timeout=6000,
|
328
|
+
trace_id=None,
|
329
|
+
keep_browser_open=False,
|
330
|
+
)
|
331
|
+
|
332
|
+
attempt_api_mocks.get_cli_run_options.assert_called_once_with(
|
333
|
+
headless=False,
|
334
|
+
proxy=None,
|
335
|
+
keep_browser_open=False,
|
336
|
+
)
|
337
|
+
|
338
|
+
attempt_api_mocks.get_cli_run_options.reset_mock()
|
339
|
+
await run_check(
|
340
|
+
auth=_get_empty_auth_session(),
|
341
|
+
headless=True,
|
342
|
+
proxy="proxy",
|
343
|
+
timeout=6000,
|
344
|
+
trace_id=None,
|
345
|
+
keep_browser_open=True,
|
346
|
+
)
|
347
|
+
call_args = attempt_api_mocks.get_cli_run_options.call_args[1]
|
348
|
+
assert call_args["headless"] is True
|
349
|
+
assert call_args["proxy"] is not None
|
350
|
+
assert call_args["keep_browser_open"] is True
|
351
|
+
|
201
352
|
@pytest.mark.asyncio
|
202
353
|
async def test_calls_run_api_with_correct_parameters_and_parses_proxy(self, attempt_api_mocks: AttemptApiMocks):
|
203
354
|
"""Test that run_check calls run_api with correct parameters and parses proxy."""
|
@@ -216,6 +367,8 @@ class TestRunCheck:
|
|
216
367
|
headless=False,
|
217
368
|
timeout=999999999,
|
218
369
|
proxy="proxy",
|
370
|
+
trace_id=None,
|
371
|
+
keep_browser_open=False,
|
219
372
|
)
|
220
373
|
|
221
374
|
mock_parse_proxy.assert_called_once_with("proxy")
|
@@ -237,6 +390,8 @@ class TestRunCheck:
|
|
237
390
|
auth=StorageState(cookies=[], origins=[], session_storage=[]),
|
238
391
|
headless=False,
|
239
392
|
timeout=999999999,
|
393
|
+
trace_id=None,
|
394
|
+
keep_browser_open=False,
|
240
395
|
)
|
241
396
|
|
242
397
|
assert result_true is True
|
@@ -247,6 +402,8 @@ class TestRunCheck:
|
|
247
402
|
auth=_get_empty_auth_session(),
|
248
403
|
headless=False,
|
249
404
|
timeout=999999999,
|
405
|
+
trace_id=None,
|
406
|
+
keep_browser_open=False,
|
250
407
|
)
|
251
408
|
|
252
409
|
assert result_false is False
|
@@ -262,6 +419,8 @@ class TestRunCheck:
|
|
262
419
|
auth=StorageState(cookies=[], origins=[], session_storage=[]),
|
263
420
|
headless=False,
|
264
421
|
timeout=999999999,
|
422
|
+
trace_id=None,
|
423
|
+
keep_browser_open=False,
|
265
424
|
)
|
266
425
|
|
267
426
|
# Test with AutomationError - should return False, not throw
|
@@ -272,10 +431,43 @@ class TestRunCheck:
|
|
272
431
|
auth=StorageState(cookies=[], origins=[], session_storage=[]),
|
273
432
|
headless=False,
|
274
433
|
timeout=999999999,
|
434
|
+
trace_id=None,
|
435
|
+
keep_browser_open=False,
|
275
436
|
)
|
276
437
|
|
277
438
|
|
278
439
|
class TestRunCheckWithRetries:
|
440
|
+
@pytest.mark.asyncio
|
441
|
+
async def test_calls_check_with_trace_id_correctly(self, with_retries_mocks: WithRetriesMocks):
|
442
|
+
"""Test that run_check_with_retries calls run_check with the correct trace_id."""
|
443
|
+
|
444
|
+
await run_check_with_retries(
|
445
|
+
auth=_get_empty_auth_session(),
|
446
|
+
retries=10,
|
447
|
+
headless=False,
|
448
|
+
timeout=999999999,
|
449
|
+
trace=False,
|
450
|
+
keep_browser_open=False,
|
451
|
+
)
|
452
|
+
|
453
|
+
with_retries_mocks.run_check.assert_called()
|
454
|
+
call_args = with_retries_mocks.run_check.call_args
|
455
|
+
assert call_args[1]["trace_id"] is None
|
456
|
+
|
457
|
+
with_retries_mocks.run_check.reset_mock()
|
458
|
+
|
459
|
+
await run_check_with_retries(
|
460
|
+
auth=_get_empty_auth_session(),
|
461
|
+
retries=10,
|
462
|
+
headless=False,
|
463
|
+
timeout=999999999,
|
464
|
+
trace=True,
|
465
|
+
keep_browser_open=False,
|
466
|
+
)
|
467
|
+
with_retries_mocks.run_check.assert_called()
|
468
|
+
call_args = with_retries_mocks.run_check.call_args
|
469
|
+
assert isinstance(call_args[1]["trace_id"], str)
|
470
|
+
|
279
471
|
@pytest.mark.asyncio
|
280
472
|
async def test_retries_the_check_if_it_fails(self, with_retries_mocks: WithRetriesMocks):
|
281
473
|
"""Test that run_check_with_retries retries the check if it fails."""
|
@@ -286,6 +478,8 @@ class TestRunCheckWithRetries:
|
|
286
478
|
retries=10,
|
287
479
|
headless=False,
|
288
480
|
timeout=999999999,
|
481
|
+
trace=False,
|
482
|
+
keep_browser_open=False,
|
289
483
|
)
|
290
484
|
|
291
485
|
assert result is True
|
@@ -301,6 +495,8 @@ class TestRunCheckWithRetries:
|
|
301
495
|
retries=10,
|
302
496
|
headless=False,
|
303
497
|
timeout=999999999,
|
498
|
+
trace=False,
|
499
|
+
keep_browser_open=False,
|
304
500
|
)
|
305
501
|
|
306
502
|
assert result is False
|
@@ -318,6 +514,8 @@ class TestRunCheckWithRetries:
|
|
318
514
|
retries=10,
|
319
515
|
headless=False,
|
320
516
|
timeout=999999999,
|
517
|
+
trace=False,
|
518
|
+
keep_browser_open=False,
|
321
519
|
)
|
322
520
|
|
323
521
|
assert result is True
|
@@ -335,6 +533,8 @@ class TestRunCheckWithRetries:
|
|
335
533
|
retries=10,
|
336
534
|
headless=False,
|
337
535
|
timeout=999999999,
|
536
|
+
trace=False,
|
537
|
+
keep_browser_open=False,
|
338
538
|
)
|
339
539
|
|
340
540
|
with_retries_mocks.run_check.assert_called_once()
|
@@ -350,10 +550,71 @@ class TestRunCreate:
|
|
350
550
|
auth_session_input={},
|
351
551
|
headless=False,
|
352
552
|
timeout=6000,
|
553
|
+
trace_id=None,
|
554
|
+
keep_browser_open=False,
|
353
555
|
)
|
354
556
|
|
355
557
|
attempt_api_mocks.extendable_timeout.assert_called_once_with(6000)
|
356
558
|
|
559
|
+
@pytest.mark.asyncio
|
560
|
+
async def test_uses_trace_context_manager(self, attempt_api_mocks: AttemptApiMocks):
|
561
|
+
"""Test that run_create uses the trace context manager."""
|
562
|
+
attempt_api_mocks.run_api.return_value = _create_success_result("session")
|
563
|
+
|
564
|
+
await run_create(
|
565
|
+
auth_session_input={},
|
566
|
+
headless=False,
|
567
|
+
timeout=6000,
|
568
|
+
trace_id=None,
|
569
|
+
keep_browser_open=False,
|
570
|
+
)
|
571
|
+
|
572
|
+
attempt_api_mocks.cli_trace.assert_called_once_with(None)
|
573
|
+
|
574
|
+
attempt_api_mocks.cli_trace.reset_mock()
|
575
|
+
await run_create(
|
576
|
+
auth_session_input={},
|
577
|
+
headless=False,
|
578
|
+
timeout=6000,
|
579
|
+
trace_id="trace-id",
|
580
|
+
keep_browser_open=False,
|
581
|
+
)
|
582
|
+
|
583
|
+
attempt_api_mocks.cli_trace.assert_called_once_with("trace-id")
|
584
|
+
|
585
|
+
@pytest.mark.asyncio
|
586
|
+
async def test_uses_get_cli_run_options(self, attempt_api_mocks: AttemptApiMocks):
|
587
|
+
"""Test that run_create calls get_cli_run_options with the correct parameters."""
|
588
|
+
attempt_api_mocks.run_api.return_value = _create_success_result("session")
|
589
|
+
|
590
|
+
await run_create(
|
591
|
+
auth_session_input={},
|
592
|
+
headless=False,
|
593
|
+
timeout=6000,
|
594
|
+
trace_id=None,
|
595
|
+
keep_browser_open=False,
|
596
|
+
)
|
597
|
+
|
598
|
+
attempt_api_mocks.get_cli_run_options.assert_called_once_with(
|
599
|
+
headless=False,
|
600
|
+
proxy=None,
|
601
|
+
keep_browser_open=False,
|
602
|
+
)
|
603
|
+
|
604
|
+
attempt_api_mocks.get_cli_run_options.reset_mock()
|
605
|
+
await run_create(
|
606
|
+
auth_session_input={},
|
607
|
+
headless=True,
|
608
|
+
proxy="proxy",
|
609
|
+
timeout=6000,
|
610
|
+
trace_id=None,
|
611
|
+
keep_browser_open=True,
|
612
|
+
)
|
613
|
+
call_args = attempt_api_mocks.get_cli_run_options.call_args[1]
|
614
|
+
assert call_args["headless"] is True
|
615
|
+
assert call_args["proxy"] is not None
|
616
|
+
assert call_args["keep_browser_open"] is True
|
617
|
+
|
357
618
|
@pytest.mark.asyncio
|
358
619
|
async def test_calls_run_api_with_correct_parameters_and_parses_proxy(self, attempt_api_mocks: AttemptApiMocks):
|
359
620
|
"""Test that run_create calls run_api with correct parameters and parses proxy."""
|
@@ -372,6 +633,8 @@ class TestRunCreate:
|
|
372
633
|
headless=False,
|
373
634
|
timeout=999999999,
|
374
635
|
proxy="proxy",
|
636
|
+
trace_id=None,
|
637
|
+
keep_browser_open=False,
|
375
638
|
)
|
376
639
|
|
377
640
|
mock_parse_proxy.assert_called_once_with("proxy")
|
@@ -394,6 +657,8 @@ class TestRunCreate:
|
|
394
657
|
auth_session_input={},
|
395
658
|
headless=False,
|
396
659
|
timeout=999999999,
|
660
|
+
trace_id=None,
|
661
|
+
keep_browser_open=False,
|
397
662
|
)
|
398
663
|
|
399
664
|
assert storage_state == "session"
|
@@ -409,10 +674,45 @@ class TestRunCreate:
|
|
409
674
|
auth_session_input={},
|
410
675
|
headless=False,
|
411
676
|
timeout=999999999,
|
677
|
+
trace_id=None,
|
678
|
+
keep_browser_open=False,
|
412
679
|
)
|
413
680
|
|
414
681
|
|
415
682
|
class TestRunCreateWithRetries:
|
683
|
+
@pytest.mark.asyncio
|
684
|
+
async def test_calls_create_with_trace_id_correctly(self, with_retries_mocks: WithRetriesMocks):
|
685
|
+
"""Test that run_create_with_retries calls run_create with the correct trace_id."""
|
686
|
+
|
687
|
+
await run_create_with_retries(
|
688
|
+
auth_session_id="testId",
|
689
|
+
auth_session_input={},
|
690
|
+
retries=10,
|
691
|
+
headless=False,
|
692
|
+
timeout=999999999,
|
693
|
+
trace=False,
|
694
|
+
keep_browser_open=False,
|
695
|
+
)
|
696
|
+
|
697
|
+
with_retries_mocks.run_create.assert_called()
|
698
|
+
call_args = with_retries_mocks.run_create.call_args
|
699
|
+
assert call_args[1]["trace_id"] is None
|
700
|
+
|
701
|
+
with_retries_mocks.run_create.reset_mock()
|
702
|
+
|
703
|
+
await run_create_with_retries(
|
704
|
+
auth_session_id="testId",
|
705
|
+
auth_session_input={},
|
706
|
+
retries=10,
|
707
|
+
headless=False,
|
708
|
+
timeout=999999999,
|
709
|
+
trace=True,
|
710
|
+
keep_browser_open=False,
|
711
|
+
)
|
712
|
+
with_retries_mocks.run_create.assert_called()
|
713
|
+
call_args = with_retries_mocks.run_create.call_args
|
714
|
+
assert isinstance(call_args[1]["trace_id"], str)
|
715
|
+
|
416
716
|
@pytest.mark.asyncio
|
417
717
|
async def test_saves_the_auth_session_instance(self, with_retries_mocks: WithRetriesMocks):
|
418
718
|
"""Test that run_create_with_retries saves the auth session instance."""
|
@@ -427,6 +727,8 @@ class TestRunCreateWithRetries:
|
|
427
727
|
retries=1,
|
428
728
|
headless=False,
|
429
729
|
timeout=30,
|
730
|
+
trace=False,
|
731
|
+
keep_browser_open=False,
|
430
732
|
)
|
431
733
|
|
432
734
|
assert with_retries_mocks.run_create.call_count == 1
|
@@ -449,6 +751,8 @@ class TestRunCreateWithRetries:
|
|
449
751
|
retries=10,
|
450
752
|
headless=False,
|
451
753
|
timeout=30,
|
754
|
+
trace=False,
|
755
|
+
keep_browser_open=False,
|
452
756
|
)
|
453
757
|
|
454
758
|
assert with_retries_mocks.run_create.call_count == 2
|
@@ -465,6 +769,8 @@ class TestRunCreateWithRetries:
|
|
465
769
|
retries=3,
|
466
770
|
headless=False,
|
467
771
|
timeout=30,
|
772
|
+
trace=False,
|
773
|
+
keep_browser_open=False,
|
468
774
|
)
|
469
775
|
|
470
776
|
assert with_retries_mocks.run_create.call_count == 3
|
@@ -482,6 +788,8 @@ class TestRunCreateWithRetries:
|
|
482
788
|
retries=10,
|
483
789
|
headless=False,
|
484
790
|
timeout=30,
|
791
|
+
trace=False,
|
792
|
+
keep_browser_open=False,
|
485
793
|
)
|
486
794
|
|
487
795
|
with_retries_mocks.run_create.assert_called_once()
|
@@ -498,6 +806,8 @@ class TestExecuteAuthSessionValidateCLI:
|
|
498
806
|
create_retries=1,
|
499
807
|
headless=False,
|
500
808
|
timeout=30,
|
809
|
+
trace=False,
|
810
|
+
keep_browser_open=False,
|
501
811
|
)
|
502
812
|
|
503
813
|
shared_mocks.assert_api_file_exists.assert_called_once_with("auth-sessions", "check")
|
@@ -516,6 +826,8 @@ class TestExecuteAuthSessionValidateCLI:
|
|
516
826
|
create_retries=1,
|
517
827
|
headless=False,
|
518
828
|
timeout=30,
|
829
|
+
trace=False,
|
830
|
+
keep_browser_open=False,
|
519
831
|
)
|
520
832
|
|
521
833
|
assert execute_cli_mocks.run_check_with_retries.call_count == 1
|
@@ -535,6 +847,8 @@ class TestExecuteAuthSessionValidateCLI:
|
|
535
847
|
create_retries=1,
|
536
848
|
headless=False,
|
537
849
|
timeout=30,
|
850
|
+
trace=False,
|
851
|
+
keep_browser_open=False,
|
538
852
|
)
|
539
853
|
|
540
854
|
@pytest.mark.asyncio
|
@@ -554,6 +868,8 @@ class TestExecuteAuthSessionValidateCLI:
|
|
554
868
|
create_retries=1,
|
555
869
|
headless=False,
|
556
870
|
timeout=30,
|
871
|
+
trace=False,
|
872
|
+
keep_browser_open=False,
|
557
873
|
)
|
558
874
|
|
559
875
|
# Should call assert for both check and create APIs
|
@@ -578,6 +894,8 @@ class TestExecuteAuthSessionValidateCLI:
|
|
578
894
|
create_retries=1,
|
579
895
|
headless=False,
|
580
896
|
timeout=30,
|
897
|
+
trace=False,
|
898
|
+
keep_browser_open=False,
|
581
899
|
)
|
582
900
|
|
583
901
|
@pytest.mark.asyncio
|
@@ -598,6 +916,8 @@ class TestExecuteAuthSessionValidateCLI:
|
|
598
916
|
create_retries=1,
|
599
917
|
headless=False,
|
600
918
|
timeout=30,
|
919
|
+
trace=False,
|
920
|
+
keep_browser_open=False,
|
601
921
|
)
|
602
922
|
|
603
923
|
@pytest.mark.asyncio
|
@@ -618,6 +938,8 @@ class TestExecuteAuthSessionValidateCLI:
|
|
618
938
|
create_retries=1,
|
619
939
|
headless=False,
|
620
940
|
timeout=30,
|
941
|
+
trace=False,
|
942
|
+
keep_browser_open=False,
|
621
943
|
)
|
622
944
|
|
623
945
|
@pytest.mark.asyncio
|
@@ -636,6 +958,8 @@ class TestExecuteAuthSessionValidateCLI:
|
|
636
958
|
create_retries=1,
|
637
959
|
headless=False,
|
638
960
|
timeout=30,
|
961
|
+
trace=False,
|
962
|
+
keep_browser_open=False,
|
639
963
|
)
|
640
964
|
|
641
965
|
assert result == auth
|
@@ -655,6 +979,8 @@ class TestExecuteAuthSessionCreateCLI:
|
|
655
979
|
create_retries=1,
|
656
980
|
headless=False,
|
657
981
|
timeout=30,
|
982
|
+
trace=False,
|
983
|
+
keep_browser_open=False,
|
658
984
|
)
|
659
985
|
|
660
986
|
# Should assert both create and check API files exist
|
@@ -674,6 +1000,8 @@ class TestExecuteAuthSessionCreateCLI:
|
|
674
1000
|
create_retries=1,
|
675
1001
|
headless=False,
|
676
1002
|
timeout=30,
|
1003
|
+
trace=False,
|
1004
|
+
keep_browser_open=False,
|
677
1005
|
)
|
678
1006
|
|
679
1007
|
@pytest.mark.asyncio
|
@@ -692,6 +1020,8 @@ class TestExecuteAuthSessionCreateCLI:
|
|
692
1020
|
create_retries=1,
|
693
1021
|
headless=False,
|
694
1022
|
timeout=30,
|
1023
|
+
trace=False,
|
1024
|
+
keep_browser_open=False,
|
695
1025
|
)
|
696
1026
|
|
697
1027
|
@pytest.mark.asyncio
|
@@ -709,6 +1039,8 @@ class TestExecuteAuthSessionCreateCLI:
|
|
709
1039
|
create_retries=1,
|
710
1040
|
headless=False,
|
711
1041
|
timeout=30,
|
1042
|
+
trace=False,
|
1043
|
+
keep_browser_open=False,
|
712
1044
|
)
|
713
1045
|
|
714
1046
|
# run_create_with_retries is tested to save in its own tests, so just verify it was called here
|
@@ -731,6 +1063,8 @@ class TestExecuteAuthSessionCreateCLI:
|
|
731
1063
|
create_retries=1,
|
732
1064
|
headless=False,
|
733
1065
|
timeout=30,
|
1066
|
+
trace=False,
|
1067
|
+
keep_browser_open=False,
|
734
1068
|
)
|
735
1069
|
|
736
1070
|
# Verify that store was called with the provided id
|
@@ -754,6 +1088,8 @@ class TestExecuteAuthSessionUpdateCLI:
|
|
754
1088
|
create_retries=1,
|
755
1089
|
headless=False,
|
756
1090
|
timeout=30,
|
1091
|
+
trace=False,
|
1092
|
+
keep_browser_open=False,
|
757
1093
|
)
|
758
1094
|
|
759
1095
|
@pytest.mark.asyncio
|
@@ -770,6 +1106,8 @@ class TestExecuteAuthSessionUpdateCLI:
|
|
770
1106
|
create_retries=1,
|
771
1107
|
headless=False,
|
772
1108
|
timeout=30,
|
1109
|
+
trace=False,
|
1110
|
+
keep_browser_open=False,
|
773
1111
|
)
|
774
1112
|
|
775
1113
|
# Should use the provided input data
|
@@ -780,9 +1118,10 @@ class TestExecuteAuthSessionUpdateCLI:
|
|
780
1118
|
create_retries=1,
|
781
1119
|
headless=False,
|
782
1120
|
timeout=30,
|
783
|
-
proxy=None,
|
784
1121
|
metadata=mock_metadata,
|
785
1122
|
log=False,
|
1123
|
+
trace=False,
|
1124
|
+
keep_browser_open=False,
|
786
1125
|
)
|
787
1126
|
|
788
1127
|
@pytest.mark.asyncio
|
@@ -798,6 +1137,8 @@ class TestExecuteAuthSessionUpdateCLI:
|
|
798
1137
|
create_retries=1,
|
799
1138
|
headless=False,
|
800
1139
|
timeout=30,
|
1140
|
+
trace=False,
|
1141
|
+
keep_browser_open=False,
|
801
1142
|
)
|
802
1143
|
|
803
1144
|
# Should use the provided input data
|
@@ -814,6 +1155,8 @@ class TestExecuteAttemptAuthSessionCLI:
|
|
814
1155
|
id="testId",
|
815
1156
|
headless=False,
|
816
1157
|
timeout=30,
|
1158
|
+
trace=False,
|
1159
|
+
keep_browser_open=False,
|
817
1160
|
)
|
818
1161
|
|
819
1162
|
shared_mocks.assert_api_file_exists.assert_called_once_with("auth-sessions", "check")
|
@@ -827,6 +1170,8 @@ class TestExecuteAttemptAuthSessionCLI:
|
|
827
1170
|
id="testId",
|
828
1171
|
headless=False,
|
829
1172
|
timeout=30,
|
1173
|
+
trace=False,
|
1174
|
+
keep_browser_open=False,
|
830
1175
|
)
|
831
1176
|
|
832
1177
|
@pytest.mark.asyncio
|
@@ -839,6 +1184,8 @@ class TestExecuteAttemptAuthSessionCLI:
|
|
839
1184
|
id="testId",
|
840
1185
|
headless=False,
|
841
1186
|
timeout=30,
|
1187
|
+
trace=False,
|
1188
|
+
keep_browser_open=False,
|
842
1189
|
)
|
843
1190
|
|
844
1191
|
|
@@ -851,6 +1198,8 @@ class TestExecuteAttemptCreateAuthSessionCLI:
|
|
851
1198
|
input_data={},
|
852
1199
|
headless=False,
|
853
1200
|
timeout=30,
|
1201
|
+
trace=False,
|
1202
|
+
keep_browser_open=False,
|
854
1203
|
)
|
855
1204
|
|
856
1205
|
shared_mocks.assert_api_file_exists.assert_called_once_with("auth-sessions", "create")
|
@@ -868,6 +1217,8 @@ class TestExecuteAttemptCreateAuthSessionCLI:
|
|
868
1217
|
input_data={},
|
869
1218
|
headless=False,
|
870
1219
|
timeout=30,
|
1220
|
+
trace=False,
|
1221
|
+
keep_browser_open=False,
|
871
1222
|
)
|
872
1223
|
|
873
1224
|
@pytest.mark.asyncio
|
@@ -879,15 +1230,17 @@ class TestExecuteAttemptCreateAuthSessionCLI:
|
|
879
1230
|
input_data={},
|
880
1231
|
headless=False,
|
881
1232
|
timeout=30,
|
1233
|
+
trace=False,
|
1234
|
+
keep_browser_open=False,
|
882
1235
|
)
|
883
1236
|
|
884
1237
|
execute_cli_mocks.run_create_with_retries.assert_called_once()
|
885
1238
|
call_args = execute_cli_mocks.run_create_with_retries.call_args.kwargs
|
886
1239
|
assert call_args["auth_session_input"] == {}
|
887
|
-
assert call_args["retries"]
|
1240
|
+
assert call_args["retries"] is None
|
888
1241
|
assert call_args["headless"] is False
|
889
1242
|
assert call_args["timeout"] == 30
|
890
|
-
assert call_args
|
1243
|
+
assert call_args.get("proxy") is None
|
891
1244
|
|
892
1245
|
@pytest.mark.asyncio
|
893
1246
|
async def test_uses_auth_session_id_to_save_if_provided(self, execute_cli_mocks: ExecuteCLIMocks):
|
@@ -899,9 +1252,147 @@ class TestExecuteAttemptCreateAuthSessionCLI:
|
|
899
1252
|
input_data={},
|
900
1253
|
headless=False,
|
901
1254
|
timeout=30,
|
1255
|
+
trace=False,
|
1256
|
+
keep_browser_open=False,
|
902
1257
|
)
|
903
1258
|
|
904
1259
|
# Verify that store was called with the provided id
|
905
1260
|
execute_cli_mocks.run_create_with_retries.assert_called_once()
|
906
1261
|
call_args = execute_cli_mocks.run_create_with_retries.call_args.kwargs
|
907
1262
|
assert call_args["auth_session_id"] == "customId"
|
1263
|
+
|
1264
|
+
|
1265
|
+
class TestExecuteRecordAuthSessionCLI:
|
1266
|
+
@pytest.mark.asyncio
|
1267
|
+
async def test_launches_browser_with_app_mode(
|
1268
|
+
self,
|
1269
|
+
record_auth_session_mocks: RecordAuthSessionMocks,
|
1270
|
+
with_retries_mocks: WithRetriesMocks,
|
1271
|
+
execute_cli_mocks: ExecuteCLIMocks,
|
1272
|
+
):
|
1273
|
+
"""Test that execute_record_auth_session_cli launches browser with app mode."""
|
1274
|
+
record_auth_session_mocks.page.url = "url"
|
1275
|
+
await execute_record_auth_session_cli(
|
1276
|
+
start_url="url",
|
1277
|
+
finish_url="url",
|
1278
|
+
headless=False,
|
1279
|
+
timeout=30,
|
1280
|
+
trace=False,
|
1281
|
+
keep_browser_open=False,
|
1282
|
+
)
|
1283
|
+
|
1284
|
+
record_auth_session_mocks.launch_chromium.assert_called_once()
|
1285
|
+
call_args = record_auth_session_mocks.launch_chromium.call_args.kwargs
|
1286
|
+
assert call_args["app_mode_initial_url"] == "url"
|
1287
|
+
assert call_args["headless"] is False
|
1288
|
+
|
1289
|
+
@pytest.mark.asyncio
|
1290
|
+
async def test_navigates_to_start_url_if_pages_does_not_load_with_it(
|
1291
|
+
self,
|
1292
|
+
record_auth_session_mocks: RecordAuthSessionMocks,
|
1293
|
+
with_retries_mocks: WithRetriesMocks,
|
1294
|
+
execute_cli_mocks: ExecuteCLIMocks,
|
1295
|
+
):
|
1296
|
+
record_auth_session_mocks.page.url = "finish_url"
|
1297
|
+
|
1298
|
+
"""Test that execute_record_auth_session_cli navigates to start_url if page does not load with it."""
|
1299
|
+
await execute_record_auth_session_cli(
|
1300
|
+
start_url="start_url",
|
1301
|
+
finish_url="finish_url",
|
1302
|
+
headless=False,
|
1303
|
+
timeout=30,
|
1304
|
+
trace=False,
|
1305
|
+
keep_browser_open=False,
|
1306
|
+
)
|
1307
|
+
|
1308
|
+
record_auth_session_mocks.page.goto.assert_called_once_with("start_url")
|
1309
|
+
|
1310
|
+
@pytest.mark.asyncio
|
1311
|
+
async def test_waits_for_finish_url(
|
1312
|
+
self,
|
1313
|
+
record_auth_session_mocks: RecordAuthSessionMocks,
|
1314
|
+
with_retries_mocks: WithRetriesMocks,
|
1315
|
+
execute_cli_mocks: ExecuteCLIMocks,
|
1316
|
+
):
|
1317
|
+
"""Test that execute_record_auth_session_cli waits for finish_url."""
|
1318
|
+
import asyncio
|
1319
|
+
|
1320
|
+
record_auth_session_mocks.page.url = "start_url"
|
1321
|
+
|
1322
|
+
record_task = asyncio.create_task(
|
1323
|
+
execute_record_auth_session_cli(
|
1324
|
+
start_url="start_url",
|
1325
|
+
finish_url="finish_url",
|
1326
|
+
headless=False,
|
1327
|
+
timeout=30,
|
1328
|
+
trace=False,
|
1329
|
+
keep_browser_open=False,
|
1330
|
+
)
|
1331
|
+
)
|
1332
|
+
|
1333
|
+
# simulate time passing without URL changing
|
1334
|
+
await record_auth_session_mocks.resolve_sleep()
|
1335
|
+
await record_auth_session_mocks.resolve_sleep()
|
1336
|
+
await record_auth_session_mocks.resolve_sleep()
|
1337
|
+
assert record_task.done() is False
|
1338
|
+
|
1339
|
+
record_auth_session_mocks.page.url = "finish_url"
|
1340
|
+
|
1341
|
+
await record_auth_session_mocks.resolve_sleep()
|
1342
|
+
|
1343
|
+
await record_task
|
1344
|
+
|
1345
|
+
@pytest.mark.asyncio
|
1346
|
+
async def test_throws_if_timeout(
|
1347
|
+
self,
|
1348
|
+
record_auth_session_mocks: RecordAuthSessionMocks,
|
1349
|
+
with_retries_mocks: WithRetriesMocks,
|
1350
|
+
execute_cli_mocks: ExecuteCLIMocks,
|
1351
|
+
):
|
1352
|
+
"""Test that execute_record_auth_session_cli throws if timeout."""
|
1353
|
+
import asyncio as mocked_asyncio
|
1354
|
+
|
1355
|
+
record_task = asyncio.create_task(
|
1356
|
+
execute_record_auth_session_cli(
|
1357
|
+
start_url="start_url",
|
1358
|
+
finish_url="finish_url",
|
1359
|
+
headless=False,
|
1360
|
+
timeout=30,
|
1361
|
+
trace=False,
|
1362
|
+
keep_browser_open=False,
|
1363
|
+
)
|
1364
|
+
)
|
1365
|
+
|
1366
|
+
# simulate time passing without URL changing
|
1367
|
+
await record_auth_session_mocks.resolve_sleep()
|
1368
|
+
await record_auth_session_mocks.resolve_sleep()
|
1369
|
+
await record_auth_session_mocks.resolve_sleep()
|
1370
|
+
assert record_task.done() is False
|
1371
|
+
|
1372
|
+
cast(AsyncMock, mocked_asyncio.sleep).side_effect = asyncio.TimeoutError()
|
1373
|
+
|
1374
|
+
await record_auth_session_mocks.resolve_sleep()
|
1375
|
+
|
1376
|
+
with pytest.raises(CLIError, match="Timeout"):
|
1377
|
+
await record_task
|
1378
|
+
|
1379
|
+
@pytest.mark.asyncio
|
1380
|
+
async def test_stores_auth_session_and_validates_if_successful(
|
1381
|
+
self,
|
1382
|
+
record_auth_session_mocks: RecordAuthSessionMocks,
|
1383
|
+
with_retries_mocks: WithRetriesMocks,
|
1384
|
+
execute_cli_mocks: ExecuteCLIMocks,
|
1385
|
+
):
|
1386
|
+
"""Test that execute_record_auth_session_cli stores auth session and validates it if successful."""
|
1387
|
+
record_auth_session_mocks.page.url = "url"
|
1388
|
+
await execute_record_auth_session_cli(
|
1389
|
+
start_url="url",
|
1390
|
+
finish_url="url",
|
1391
|
+
headless=False,
|
1392
|
+
timeout=30,
|
1393
|
+
trace=False,
|
1394
|
+
keep_browser_open=False,
|
1395
|
+
)
|
1396
|
+
|
1397
|
+
with_retries_mocks.store_auth_session_instance.assert_called_once()
|
1398
|
+
execute_cli_mocks.run_check_with_retries.assert_called_once()
|