Skip to content

Commit c28b0da

Browse files
authored
✨E2E: increase timeout for video streaming and improve a bit logs about websockets (#6384)
1 parent 1327f2e commit c28b0da

File tree

6 files changed

+81
-49
lines changed

6 files changed

+81
-49
lines changed

packages/pytest-simcore/src/pytest_simcore/helpers/logging_tools.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,14 @@ def log_context(
133133
else:
134134
ctx_msg = msg
135135

136-
started_time = datetime.datetime.now(tz=datetime.timezone.utc)
136+
started_time = datetime.datetime.now(tz=datetime.UTC)
137137
try:
138138
DynamicIndentFormatter.cls_increase_indent()
139139

140140
logger.log(level, ctx_msg.starting, *args, **kwargs)
141141
with _increased_logger_indent(logger):
142142
yield SimpleNamespace(logger=logger, messages=ctx_msg)
143-
elapsed_time = datetime.datetime.now(tz=datetime.timezone.utc) - started_time
143+
elapsed_time = datetime.datetime.now(tz=datetime.UTC) - started_time
144144
done_message = (
145145
f"{ctx_msg.done} ({_timedelta_as_minute_second_ms(elapsed_time)})"
146146
)
@@ -152,7 +152,7 @@ def log_context(
152152
)
153153

154154
except:
155-
elapsed_time = datetime.datetime.now(tz=datetime.timezone.utc) - started_time
155+
elapsed_time = datetime.datetime.now(tz=datetime.UTC) - started_time
156156
error_message = (
157157
f"{ctx_msg.raised} ({_timedelta_as_minute_second_ms(elapsed_time)})"
158158
)

packages/pytest-simcore/src/pytest_simcore/helpers/playwright.py

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import logging
44
import re
55
from collections import defaultdict
6-
from contextlib import ExitStack
6+
from collections.abc import Generator, Iterator
77
from dataclasses import dataclass, field
88
from enum import Enum, unique
9-
from typing import Any, Final, Generator
9+
from typing import Any, Final
1010

1111
from playwright.sync_api import FrameLocator, Page, Request, WebSocket
1212
from pytest_simcore.helpers.logging_tools import log_context
@@ -263,28 +263,37 @@ def wait_for_pipeline_state(
263263
return current_state
264264

265265

266-
def on_web_socket_default_handler(ws) -> None:
267-
"""Usage
268-
269-
from pytest_simcore.playwright_utils import on_web_socket_default_handler
270-
271-
page.on("websocket", on_web_socket_default_handler)
272-
273-
"""
274-
stack = ExitStack()
275-
ctx = stack.enter_context(
276-
log_context(
277-
logging.INFO,
278-
(
279-
f"WebSocket opened: {ws.url}",
280-
"WebSocket closed",
281-
),
282-
)
283-
)
266+
@contextlib.contextmanager
267+
def web_socket_default_log_handler(web_socket: WebSocket) -> Iterator[None]:
284268

285-
ws.on("framesent", lambda payload: ctx.logger.info("⬇️ %s", payload))
286-
ws.on("framereceived", lambda payload: ctx.logger.info("⬆️ %s", payload))
287-
ws.on("close", lambda payload: stack.close()) # noqa: ARG005
269+
try:
270+
with log_context(
271+
logging.DEBUG,
272+
msg="handle websocket message (set to --log-cli-level=DEBUG level if you wanna see all of them)",
273+
) as ctx:
274+
275+
def on_framesent(payload: str | bytes) -> None:
276+
ctx.logger.debug("⬇️ Frame sent: %s", payload)
277+
278+
def on_framereceived(payload: str | bytes) -> None:
279+
ctx.logger.debug("⬆️ Frame received: %s", payload)
280+
281+
def on_close(payload: WebSocket) -> None:
282+
ctx.logger.warning("⚠️ Websocket closed: %s", payload)
283+
284+
def on_socketerror(error_msg: str) -> None:
285+
ctx.logger.error("❌ Websocket error: %s", error_msg)
286+
287+
web_socket.on("framesent", on_framesent)
288+
web_socket.on("framereceived", on_framereceived)
289+
web_socket.on("close", on_close)
290+
web_socket.on("socketerror", on_socketerror)
291+
yield
292+
finally:
293+
web_socket.remove_listener("framesent", on_framesent)
294+
web_socket.remove_listener("framereceived", on_framereceived)
295+
web_socket.remove_listener("close", on_close)
296+
web_socket.remove_listener("socketerror", on_socketerror)
288297

289298

290299
def _node_started_predicate(request: Request) -> bool:

packages/pytest-simcore/src/pytest_simcore/helpers/playwright_sim4life.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import arrow
88
from playwright.sync_api import FrameLocator, Page, WebSocket, expect
9+
from pydantic import TypeAdapter # pylint: disable=no-name-in-module
10+
from pydantic import ByteSize
911

1012
from .logging_tools import log_context
1113
from .playwright import (
@@ -17,7 +19,7 @@
1719
wait_for_service_running,
1820
)
1921

20-
_S4L_STREAMING_ESTABLISHMENT_MAX_TIME: Final[int] = 15 * SECOND
22+
_S4L_STREAMING_ESTABLISHMENT_MAX_TIME: Final[int] = 30 * SECOND
2123
_S4L_SOCKETIO_REGEX: Final[re.Pattern] = re.compile(
2224
r"^(?P<protocol>[^:]+)://(?P<node_id>[^\.]+)\.services\.(?P<hostname>[^\/]+)\/socket\.io\/.+$"
2325
)
@@ -63,7 +65,7 @@ def __call__(self, message: str) -> bool:
6365
self._initial_bit_rate_time = arrow.utcnow().datetime
6466
self.logger.info(
6567
"%s",
66-
f"{self._initial_bit_rate=} at {self._initial_bit_rate_time.isoformat()}",
68+
f"{TypeAdapter(ByteSize).validate_python(self._initial_bit_rate).human_readable()}/s at {self._initial_bit_rate_time.isoformat()}",
6769
)
6870
return False
6971

@@ -78,7 +80,7 @@ def __call__(self, message: str) -> bool:
7880
bitrate_test = bool(self._initial_bit_rate != current_bitrate)
7981
self.logger.info(
8082
"%s",
81-
f"{current_bitrate=} after {elapsed_time=}: {'good!' if bitrate_test else 'failed! bitrate did not change! TIP: talk with MaG about underwater cables!'}",
83+
f"{TypeAdapter(ByteSize).validate_python(current_bitrate).human_readable()}/s after {elapsed_time=}: {'good!' if bitrate_test else 'failed! bitrate did not change! TIP: talk with MaG about underwater cables!'}",
8284
)
8385
return bitrate_test
8486

tests/e2e-playwright/tests/conftest.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,16 @@
2525
from pytest import Item
2626
from pytest_simcore.helpers.logging_tools import log_context
2727
from pytest_simcore.helpers.playwright import (
28-
SECOND,
2928
MINUTE,
29+
SECOND,
3030
AutoRegisteredUser,
3131
RunningState,
3232
ServiceType,
3333
SocketIOEvent,
3434
SocketIOProjectClosedWaiter,
3535
SocketIOProjectStateUpdatedWaiter,
3636
decode_socketio_42_message,
37+
web_socket_default_log_handler,
3738
)
3839

3940
_PROJECT_CLOSING_TIMEOUT: Final[int] = 10 * MINUTE
@@ -171,9 +172,11 @@ def pytest_runtest_makereport(item: Item, call):
171172
diagnostics["duration"] = str(end_time - start_time)
172173

173174
# Print the diagnostics report
174-
print(f"\nDiagnostics repoort for {test_name} ---")
175-
print(json.dumps(diagnostics, indent=2))
176-
print("---")
175+
with log_context(
176+
logging.WARNING,
177+
f"ℹ️ Diagnostics report for {test_name} ---", # noqa: RUF001
178+
) as ctx:
179+
ctx.logger.warning(json.dumps(diagnostics, indent=2))
177180

178181

179182
@pytest.hookimpl(tryfirst=True)
@@ -369,7 +372,8 @@ def log_in_and_out(
369372
if quickStartWindowCloseBtnLocator.is_visible():
370373
quickStartWindowCloseBtnLocator.click()
371374

372-
yield ws
375+
with web_socket_default_log_handler(ws):
376+
yield ws
373377

374378
with log_context(
375379
logging.INFO,
@@ -410,12 +414,17 @@ def _(
410414
f"Open project in {product_url=} as {product_billable=}",
411415
) as ctx:
412416
waiter = SocketIOProjectStateUpdatedWaiter(expected_states=expected_states)
413-
timeout = _OPENING_TUTORIAL_MAX_WAIT_TIME if template_id is not None else _OPENING_NEW_EMPTY_PROJECT_MAX_WAIT_TIME
417+
timeout = (
418+
_OPENING_TUTORIAL_MAX_WAIT_TIME
419+
if template_id is not None
420+
else _OPENING_NEW_EMPTY_PROJECT_MAX_WAIT_TIME
421+
)
414422
with (
415-
log_in_and_out.expect_event("framereceived", waiter, timeout=timeout + 10 * SECOND),
423+
log_in_and_out.expect_event(
424+
"framereceived", waiter, timeout=timeout + 10 * SECOND
425+
),
416426
page.expect_response(
417-
re.compile(r"/projects/[^:]+:open"),
418-
timeout=timeout + 5 * SECOND
427+
re.compile(r"/projects/[^:]+:open"), timeout=timeout + 5 * SECOND
419428
) as response_info,
420429
):
421430
# Project detail view pop-ups shows
@@ -436,8 +445,11 @@ def _(
436445
# From the long running tasks response's urls, only their path is relevant
437446
def url_to_path(url):
438447
return urllib.parse.urlparse(url).path
448+
439449
def wait_for_done(response):
440-
if url_to_path(response.url) == url_to_path(lrt_data["status_href"]):
450+
if url_to_path(response.url) == url_to_path(
451+
lrt_data["status_href"]
452+
):
441453
resp_data = response.json()
442454
resp_data = resp_data["data"]
443455
assert "task_progress" in resp_data
@@ -448,10 +460,13 @@ def wait_for_done(response):
448460
task_progress["message"],
449461
)
450462
return False
451-
if url_to_path(response.url) == url_to_path(lrt_data["result_href"]):
463+
if url_to_path(response.url) == url_to_path(
464+
lrt_data["result_href"]
465+
):
452466
copying_logger.logger.info("project created")
453467
return response.status == 201
454468
return False
469+
455470
with page.expect_response(wait_for_done, timeout=timeout):
456471
# if the above calls go to fast, this test could fail
457472
# not expected in the sim4life context though

tests/e2e-playwright/tests/sim4life/test_sim4life.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
from typing import Any
1212

1313
from playwright.sync_api import Page, WebSocket
14-
from pytest_simcore.helpers.playwright import ServiceType
14+
from pytest_simcore.helpers.playwright import (
15+
ServiceType,
16+
web_socket_default_log_handler,
17+
)
1518
from pytest_simcore.helpers.playwright_sim4life import (
1619
check_video_streaming,
1720
interact_with_s4l,
@@ -49,8 +52,9 @@ def test_sim4life(
4952
page, node_ids[0], log_in_and_out, autoscaled=autoscaled, copy_workspace=False
5053
)
5154
s4l_websocket = resp["websocket"]
52-
s4l_iframe = resp["iframe"]
53-
interact_with_s4l(page, s4l_iframe)
55+
with web_socket_default_log_handler(s4l_websocket):
56+
s4l_iframe = resp["iframe"]
57+
interact_with_s4l(page, s4l_iframe)
5458

55-
if check_videostreaming:
56-
check_video_streaming(page, s4l_iframe, s4l_websocket)
59+
if check_videostreaming:
60+
check_video_streaming(page, s4l_iframe, s4l_websocket)

tests/e2e-playwright/tests/sim4life/test_template.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from typing import Any
1212

1313
from playwright.sync_api import Page, WebSocket
14+
from pytest_simcore.helpers.playwright import web_socket_default_log_handler
1415
from pytest_simcore.helpers.playwright_sim4life import (
1516
check_video_streaming,
1617
interact_with_s4l,
@@ -39,8 +40,9 @@ def test_template(
3940
page, node_ids[0], log_in_and_out, autoscaled=autoscaled, copy_workspace=True
4041
)
4142
s4l_websocket = resp["websocket"]
42-
s4l_iframe = resp["iframe"]
43-
interact_with_s4l(page, s4l_iframe)
43+
with web_socket_default_log_handler(s4l_websocket):
44+
s4l_iframe = resp["iframe"]
45+
interact_with_s4l(page, s4l_iframe)
4446

45-
if check_videostreaming:
46-
check_video_streaming(page, s4l_iframe, s4l_websocket)
47+
if check_videostreaming:
48+
check_video_streaming(page, s4l_iframe, s4l_websocket)

0 commit comments

Comments
 (0)