summaryrefslogtreecommitdiff
path: root/tests/test_logging.py
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-08-16 21:34:13 +0900
committertanaka takashi <isazaka@gmail.com>2026-08-16 21:34:13 +0900
commita9f083785a7e961a291e5366013fc89c0b801b01 (patch)
treecb456d3ee40b00b8b475429a6e29f05c93e0efad /tests/test_logging.py
parente45e2dbf160445891ec765ffb3e0e14f106cfb56 (diff)
refactor: streamline chat flow and improve diagnostics
Store server.log inside OLLAMA_WEB_DATA_DIR and manage the ollama-web file handler through the Starlette lifespan. Close and detach the handler on shutdown to prevent duplicate records and Windows file locks when applications are recreated. Stop converting DuckDuckGo provider failures into empty search results. Record a query-safe traceback, re-raise the original exception, and let ToolRegistry expose the exception type and message as a tool error without adding or spoofing Referer headers. Remove the unused non-streaming chat_with_tools implementation and its private helpers. Move capability, options, standard tool, MCP tool, and final tools=[] regression coverage onto the production streaming path. Add integration coverage for data/server.log placement, handler cleanup, repeated lifespans, and provider 403 diagnostics. Update the Unreleased changelog entry. Validated with 118 tests, Ruff, mypy, diff checks, real DuckDuckGo searches, successful result-page fetches, and observable 401/403 responses from sites that reject automated retrieval.
Diffstat (limited to 'tests/test_logging.py')
-rw-r--r--tests/test_logging.py88
1 files changed, 88 insertions, 0 deletions
diff --git a/tests/test_logging.py b/tests/test_logging.py
new file mode 100644
index 0000000..ef6fbd2
--- /dev/null
+++ b/tests/test_logging.py
@@ -0,0 +1,88 @@
+"""Tests for application file logging."""
+
+from __future__ import annotations
+
+import json
+import logging
+from pathlib import Path
+from unittest.mock import patch
+
+import pytest
+from starlette.testclient import TestClient
+
+from ollama_web.app import create_app
+from ollama_web.config import settings
+from ollama_web.tools.registry import default_registry
+
+
+def test_server_log_is_scoped_to_data_dir_and_app_lifespan(
+ tmp_path: Path,
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ data_dir = tmp_path / "data"
+ monkeypatch.setattr(settings, "data_dir", str(data_dir))
+ app_logger = logging.getLogger("ollama_web")
+ original_handlers = tuple(app_logger.handlers)
+ original_level = app_logger.level
+
+ app = create_app()
+ log_path = data_dir / "server.log"
+ assert not log_path.exists()
+
+ with TestClient(app):
+ assert len(app_logger.handlers) == len(original_handlers) + 1
+ logging.getLogger("ollama_web.test").info("lifespan log marker")
+
+ assert tuple(app_logger.handlers) == original_handlers
+ assert app_logger.level == original_level
+ assert log_path.read_text(encoding="utf-8").count("lifespan log marker") == 1
+
+ # Closing the lifespan must release the file on Windows as well.
+ log_path.unlink()
+ assert not log_path.exists()
+
+
+def test_repeated_app_lifespans_do_not_duplicate_log_handlers(
+ tmp_path: Path,
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ data_dir = tmp_path / "data"
+ monkeypatch.setattr(settings, "data_dir", str(data_dir))
+
+ with TestClient(create_app()):
+ logging.getLogger("ollama_web.test").info("first app marker")
+ with TestClient(create_app()):
+ logging.getLogger("ollama_web.test").info("second app marker")
+
+ content = (data_dir / "server.log").read_text(encoding="utf-8")
+ assert content.count("first app marker") == 1
+ assert content.count("second app marker") == 1
+
+
+def test_web_search_provider_error_is_written_to_server_log(
+ tmp_path: Path,
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ data_dir = tmp_path / "data"
+ monkeypatch.setattr(settings, "data_dir", str(data_dir))
+
+ class FailingDDGS:
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ return None
+
+ def text(self, query, max_results=5):
+ raise RuntimeError("403 Forbidden")
+
+ with patch("ollama_web.tools.search.DDGS", FailingDDGS), TestClient(create_app()):
+ result = json.loads(
+ default_registry().execute("web_search", {"query": "private search terms"})
+ )
+
+ assert result == {"error": "RuntimeError: 403 Forbidden"}
+ content = (data_dir / "server.log").read_text(encoding="utf-8")
+ assert "DuckDuckGo web search failed" in content
+ assert "RuntimeError: 403 Forbidden" in content
+ assert "private search terms" not in content