7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
86 lines
2.9 KiB
Python
86 lines
2.9 KiB
Python
"""Tests for the daemon-thread excepthook.
|
|
|
|
Covers:
|
|
- _install_thread_excepthook logs uncaught exceptions from daemon threads.
|
|
- _perform_post_login_tasks wraps its body so an otherwise-uncaught exception
|
|
from inside the `with` context managers is logged instead of disappearing.
|
|
"""
|
|
|
|
import threading
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
|
def test_install_thread_excepthook_logs_uncaught_exception():
|
|
"""After installing the hook, an uncaught exception on a daemon thread
|
|
must be logged at ERROR level including the exception type and the
|
|
thread name. Without this, silent crashes in the queue processor
|
|
or APScheduler jobs are the mechanism by which the login path
|
|
gradually starves.
|
|
"""
|
|
from local_deep_research.web.app import _install_thread_excepthook
|
|
|
|
previous = threading.excepthook
|
|
_install_thread_excepthook()
|
|
try:
|
|
with patch("local_deep_research.web.app.logger") as mock_logger:
|
|
|
|
def raiser():
|
|
raise RuntimeError("boom from daemon")
|
|
|
|
t = threading.Thread(target=raiser, name="test-daemon", daemon=True)
|
|
t.start()
|
|
t.join(timeout=2.0)
|
|
|
|
assert not t.is_alive()
|
|
assert mock_logger.error.called, "excepthook did not log"
|
|
|
|
logged = mock_logger.error.call_args[0][0]
|
|
assert "test-daemon" in logged
|
|
assert "RuntimeError" in logged
|
|
assert "boom from daemon" in logged
|
|
finally:
|
|
threading.excepthook = previous
|
|
|
|
|
|
def test_perform_post_login_tasks_catches_outer_exceptions():
|
|
"""If the outer structure of _perform_post_login_tasks itself raises
|
|
(for example from inside a `with` context manager's __enter__) —
|
|
not inside a per-step try/except — the wrapper must log the
|
|
exception and not let the daemon thread die silently.
|
|
"""
|
|
from local_deep_research.web.auth import routes
|
|
|
|
with (
|
|
patch.object(
|
|
routes,
|
|
"_perform_post_login_tasks_body",
|
|
side_effect=RuntimeError("outer failure"),
|
|
),
|
|
patch.object(routes, "logger") as mock_logger,
|
|
):
|
|
# Must not raise.
|
|
routes._perform_post_login_tasks("alice", "pw")
|
|
|
|
assert mock_logger.exception.called
|
|
msg = mock_logger.exception.call_args[0][0]
|
|
assert "alice" in msg
|
|
assert "crashed" in msg.lower() or "post-login" in msg.lower()
|
|
|
|
|
|
def test_perform_post_login_tasks_body_runs_when_no_outer_error():
|
|
"""Positive path: when the body succeeds, the wrapper forwards to
|
|
it exactly once with the right args, and does not log any
|
|
crash.
|
|
"""
|
|
from local_deep_research.web.auth import routes
|
|
|
|
body = MagicMock()
|
|
with (
|
|
patch.object(routes, "_perform_post_login_tasks_body", body),
|
|
patch.object(routes, "logger") as mock_logger,
|
|
):
|
|
routes._perform_post_login_tasks("bob", "pw")
|
|
|
|
body.assert_called_once_with("bob", "pw")
|
|
mock_logger.exception.assert_not_called()
|