* feat: add optional nanobot features * test: update azure install hint expectation * fix: validate optional feature extras maintainer edit: verify requested dependency extras before treating optional features as installed, propagate restart state from feature enablement, and align docs with the new plugins enable command. * fix: bound optional feature installs maintainer edit: make optional feature installs time out as a normal install failure instead of leaving the WebUI or CLI action waiting indefinitely. * feat: slim optional channel dependencies * fix: log optional install commands * fix(webui): gate remote feature installs * docs: clarify webhook plugin example * fix(webui): harden optional feature installs * fix: install optional deps without package fallback * fix(cli): refine plugin feature controls * fix(webui): count enabled nanobot features * fix(webui): allow slow feature install routes * fix(webui): allow disabling websocket channel * fix(plugins): simplify optional feature controls * fix(webui): polish apps catalog states * fix(webui): confirm nanobot support installs * fix(webui): polish nanobot install dialog * fix(webui): suppress empty websocket handshakes * fix(webui): clarify apps plugin summary * fix(webui): localize workspace access copy * fix(plugins): polish optional feature controls (#4691) --------- Co-authored-by: Xubin Ren <52506698+Re-bin@users.noreply.github.com>
42 lines
1.4 KiB
Python
42 lines
1.4 KiB
Python
"""Tests for WebUI websocket logging helpers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from nanobot.webui.websocket_logging import (
|
|
OPENING_HANDSHAKE_FAILED_MESSAGE,
|
|
WebSocketHandshakeNoiseFilter,
|
|
)
|
|
|
|
|
|
def _log_record(message: str, exc: BaseException) -> logging.LogRecord:
|
|
return logging.LogRecord(
|
|
name="websockets.server",
|
|
level=logging.ERROR,
|
|
pathname=__file__,
|
|
lineno=1,
|
|
msg=message,
|
|
args=(),
|
|
exc_info=(type(exc), exc, exc.__traceback__),
|
|
)
|
|
|
|
|
|
def test_websocket_handshake_noise_filter_suppresses_disconnects() -> None:
|
|
filter_ = WebSocketHandshakeNoiseFilter()
|
|
wrapped = RuntimeError("wrapped")
|
|
wrapped.__cause__ = BrokenPipeError(32, "Broken pipe")
|
|
empty_handshake = RuntimeError("wrapped")
|
|
empty_handshake.__cause__ = EOFError("connection closed while reading HTTP request line")
|
|
|
|
assert not filter_.filter(_log_record(OPENING_HANDSHAKE_FAILED_MESSAGE, BrokenPipeError()))
|
|
assert not filter_.filter(_log_record(OPENING_HANDSHAKE_FAILED_MESSAGE, wrapped))
|
|
assert not filter_.filter(_log_record(OPENING_HANDSHAKE_FAILED_MESSAGE, empty_handshake))
|
|
|
|
|
|
def test_websocket_handshake_noise_filter_keeps_real_errors() -> None:
|
|
filter_ = WebSocketHandshakeNoiseFilter()
|
|
|
|
assert filter_.filter(_log_record(OPENING_HANDSHAKE_FAILED_MESSAGE, RuntimeError("boom")))
|
|
assert filter_.filter(_log_record("connection handler failed", BrokenPipeError()))
|