chore: import upstream snapshot with attribution
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

This commit is contained in:
wehub-resource-sync
2026-07-13 13:08:55 +08:00
commit 7a0da7932b
2985 changed files with 1049377 additions and 0 deletions
+339
View File
@@ -0,0 +1,339 @@
"""
Coverage tests for log_utils module.
Targets branches not exercised by test_log_utils.py and
test_log_utils_extended.py:
- InterceptHandler.emit: depth-walking loop stops at non-logging frame
- _get_research_id: None when no app context and no record extra
- _get_research_id: reads from record["extra"]["research_id"]
- _process_log_queue: stop-event exits the loop; None entry is skipped
- database_sink: username extraction from record["extra"]["username"]
- flush_log_queue: handles exception inside loop gracefully
- config_logger: debug=True path warns about unsafe logging
- config_logger: file logging disabled by default (no 4th add call)
"""
_logging = __import__("logging") # test needs stdlib LogRecord
from datetime import datetime # noqa: E402
from unittest.mock import Mock, patch # noqa: E402
MODULE = "local_deep_research.utilities.log_utils"
# ---------------------------------------------------------------------------
# InterceptHandler
# ---------------------------------------------------------------------------
class TestInterceptHandlerDepthWalking:
"""The depth-walking loop in emit should traverse past logging frames."""
def test_emit_with_valid_level(self):
from local_deep_research.utilities.log_utils import InterceptHandler
handler = InterceptHandler()
record = _logging.LogRecord(
name="test",
level=_logging.WARNING,
pathname="test.py",
lineno=10,
msg="warn",
args=(),
exc_info=None,
)
with patch(f"{MODULE}.logger") as mock_logger:
mock_level = Mock()
mock_level.name = "WARNING"
mock_logger.level.return_value = mock_level
mock_opt = Mock()
mock_logger.opt.return_value = mock_opt
handler.emit(record)
mock_opt.log.assert_called_once()
# level argument should be the resolved name
args = mock_opt.log.call_args[0]
assert args[0] == "WARNING"
def test_emit_with_unknown_level_uses_levelno(self):
from local_deep_research.utilities.log_utils import InterceptHandler
handler = InterceptHandler()
record = _logging.LogRecord(
name="test",
level=37,
pathname="test.py",
lineno=1,
msg="custom",
args=(),
exc_info=None,
)
record.levelname = "CUSTOM_LEVEL"
with patch(f"{MODULE}.logger") as mock_logger:
mock_logger.level.side_effect = ValueError("unknown")
mock_opt = Mock()
mock_logger.opt.return_value = mock_opt
handler.emit(record)
# levelno (37) used when name lookup fails
args = mock_opt.log.call_args[0]
assert args[0] == 37
# ---------------------------------------------------------------------------
# _get_research_id
# ---------------------------------------------------------------------------
class TestGetResearchId:
def test_returns_none_when_no_context_and_no_extra(self):
from local_deep_research.utilities.log_utils import _get_research_id
with patch(f"{MODULE}.has_app_context", return_value=False):
result = _get_research_id(record={"extra": {}})
assert result is None
def test_returns_id_from_record_extra(self):
from local_deep_research.utilities.log_utils import _get_research_id
record = {"extra": {"research_id": "record-123"}}
result = _get_research_id(record=record)
assert result == "record-123"
def test_returns_id_from_flask_g_when_no_extra(self):
from local_deep_research.utilities.log_utils import _get_research_id
mock_g = Mock()
mock_g.get.return_value = "flask-456"
with patch(f"{MODULE}.has_app_context", return_value=True):
with patch(f"{MODULE}.g", mock_g):
result = _get_research_id(record={"extra": {}})
assert result == "flask-456"
def test_returns_none_with_no_record(self):
from local_deep_research.utilities.log_utils import _get_research_id
with patch(f"{MODULE}.has_app_context", return_value=False):
result = _get_research_id(record=None)
assert result is None
# ---------------------------------------------------------------------------
# database_sink username extraction
# ---------------------------------------------------------------------------
class TestDatabaseSinkUsernameExtraction:
def _make_message(self, extra=None):
msg = Mock()
msg.record = {
"time": datetime.now(),
"message": "test",
"name": "mod",
"function": "fn",
"line": 1,
"level": Mock(name="INFO"),
"extra": extra or {},
}
return msg
def test_username_from_extra_is_queued(self):
from local_deep_research.utilities.log_utils import database_sink
import local_deep_research.utilities.log_utils as mod
msg = self._make_message(extra={"username": "alice"})
with patch.object(mod, "has_app_context", return_value=False):
with patch.object(mod, "_log_queue") as mock_q:
database_sink(msg)
queued = mock_q.put_nowait.call_args[0][0]
assert queued["username"] == "alice"
def test_no_username_queues_none(self):
"""When research_id is set but username isn't, queue entry has
username=None — the daemon's get_user_db_session will then look it
up via session/thread-context fallbacks."""
from local_deep_research.utilities.log_utils import database_sink
import local_deep_research.utilities.log_utils as mod
msg = self._make_message(extra={"research_id": "rid-1"})
with patch.object(mod, "has_app_context", return_value=False):
with patch.object(mod, "_log_queue") as mock_q:
database_sink(msg)
queued = mock_q.put_nowait.call_args[0][0]
assert queued["username"] is None
def test_no_research_context_does_not_queue(self):
"""ResearchLog is research-scoped — logs with neither research_id
nor username should be skipped, not queued."""
from local_deep_research.utilities.log_utils import database_sink
import local_deep_research.utilities.log_utils as mod
msg = self._make_message(extra={})
with patch.object(mod, "has_app_context", return_value=False):
with patch.object(mod, "_log_queue") as mock_q:
database_sink(msg)
mock_q.put_nowait.assert_not_called()
# ---------------------------------------------------------------------------
# flush_log_queue exception inside loop
# ---------------------------------------------------------------------------
class TestFlushLogQueueExceptionHandling:
def test_exception_in_write_does_not_abort_flush(self):
"""If _write_log_to_database raises, flush should continue."""
from local_deep_research.utilities.log_utils import flush_log_queue
import local_deep_research.utilities.log_utils as mod
entry = {
"timestamp": datetime.now(),
"message": "m",
"module": "m",
"function": "f",
"line_no": 1,
"level": "INFO",
"research_id": None,
"username": None,
}
with patch.object(mod, "_log_queue") as mock_q:
mock_q.empty.side_effect = [False, True]
mock_q.get_nowait.return_value = entry
with patch.object(
mod, "_write_log_to_database", side_effect=Exception("db fail")
):
# Should not raise
flush_log_queue()
# ---------------------------------------------------------------------------
# config_logger debug path and no-file-logging path
# ---------------------------------------------------------------------------
class TestConfigLoggerDebugAndFileLogging:
def test_debug_true_adds_warning(self):
from local_deep_research.utilities.log_utils import config_logger
with patch(f"{MODULE}.logger") as mock_logger:
config_logger("app", debug=True)
mock_logger.warning.assert_called()
warning_msg = mock_logger.warning.call_args[0][0]
assert "DEBUG" in warning_msg or "debug" in warning_msg.lower()
def test_file_logging_disabled_by_default(self):
"""With LDR_ENABLE_FILE_LOGGING unset, no file sink is added."""
from local_deep_research.utilities.log_utils import config_logger
import os
env = {
k: v
for k, v in os.environ.items()
if k != "LDR_ENABLE_FILE_LOGGING"
}
with patch.dict("os.environ", env, clear=True):
with patch(f"{MODULE}.logger") as mock_logger:
config_logger("app")
# Only 3 sinks: stderr, database_sink, frontend_progress_sink
assert mock_logger.add.call_count == 3
def test_stderr_level_info_when_not_debug(self):
from local_deep_research.utilities.log_utils import config_logger
with patch(f"{MODULE}.logger") as mock_logger:
config_logger("app", debug=False)
# First add call is stderr
first_add = mock_logger.add.call_args_list[0]
assert first_add[1].get("level") == "INFO"
def test_stderr_level_debug_when_debug_true(self):
from local_deep_research.utilities.log_utils import config_logger
with patch(f"{MODULE}.logger") as mock_logger:
config_logger("app", debug=True)
first_add = mock_logger.add.call_args_list[0]
assert first_add[1].get("level") == "DEBUG"
# ---------------------------------------------------------------------------
# Sink-level diagnose policy (#4182): even when the operator opts into
# LDR_LOGURU_DIAGNOSE, the persisted DB sink and the browser-facing
# frontend sink must NEVER render frame locals (which can hold the
# SQLCipher master password). Only the local stderr sink may.
# ---------------------------------------------------------------------------
class TestDiagnoseSinkPolicy:
def test_diagnose_never_enabled_on_db_or_frontend_sink(self):
from local_deep_research.utilities.log_utils import (
config_logger,
database_sink,
frontend_progress_sink,
)
import os
env = {
k: v
for k, v in os.environ.items()
if k != "LDR_ENABLE_FILE_LOGGING"
}
# Opt into diagnose the way an operator debugging locally would.
env["LDR_LOGURU_DIAGNOSE"] = "true"
with patch.dict("os.environ", env, clear=True):
with patch(f"{MODULE}.logger") as mock_logger:
config_logger("app", debug=True)
# Map each add() call to its sink (first positional arg).
by_sink = {
call.args[0]: call.kwargs.get("diagnose")
for call in mock_logger.add.call_args_list
}
# stderr opted in -> diagnose may be True; the persisted and
# shipped sinks must be hard False regardless.
assert by_sink[database_sink] is False
assert by_sink[frontend_progress_sink] is False
def test_stderr_gets_diagnose_when_opted_in(self):
import sys
from local_deep_research.utilities.log_utils import config_logger
import os
env = {
k: v
for k, v in os.environ.items()
if k != "LDR_ENABLE_FILE_LOGGING"
}
env["LDR_LOGURU_DIAGNOSE"] = "true"
with patch.dict("os.environ", env, clear=True):
with patch(f"{MODULE}.logger") as mock_logger:
config_logger("app", debug=True)
stderr_calls = [
c
for c in mock_logger.add.call_args_list
if c.args and c.args[0] is sys.stderr
]
assert stderr_calls, "stderr sink was not configured"
assert stderr_calls[0].kwargs.get("diagnose") is True