mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 10:15:27 -04:00
fix: search analytics crashes recording when the JSON file predates a counter (#1224)
* refactor: single _default_analytics() instead of duplicated default dicts * fix: merge analytics defaults so an old/partial file doesn't KeyError on record * test: analytics load merges defaults; record survives a partial file
This commit is contained in:
+23
-18
@@ -45,24 +45,8 @@ class RateLimitError(SearchEngineError):
|
|||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Analytics helpers
|
# Analytics helpers
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
def _load_analytics() -> Dict[str, Any]:
|
def _default_analytics() -> Dict[str, Any]:
|
||||||
"""Load analytics data from the JSON file, creating defaults if missing."""
|
"""A fresh analytics document with every counter present."""
|
||||||
if not ANALYTICS_FILE.exists():
|
|
||||||
default = {
|
|
||||||
"total_queries": 0,
|
|
||||||
"successful_queries": 0,
|
|
||||||
"failed_queries": 0,
|
|
||||||
"cache_hits": 0,
|
|
||||||
"cache_misses": 0,
|
|
||||||
"query_patterns": {},
|
|
||||||
}
|
|
||||||
_save_analytics(default)
|
|
||||||
return default
|
|
||||||
try:
|
|
||||||
with open(ANALYTICS_FILE, "r", encoding="utf-8") as f:
|
|
||||||
return json.load(f)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Failed to load analytics file: {e}")
|
|
||||||
return {
|
return {
|
||||||
"total_queries": 0,
|
"total_queries": 0,
|
||||||
"successful_queries": 0,
|
"successful_queries": 0,
|
||||||
@@ -73,6 +57,27 @@ def _load_analytics() -> Dict[str, Any]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _load_analytics() -> Dict[str, Any]:
|
||||||
|
"""Load analytics data from the JSON file, creating defaults if missing."""
|
||||||
|
if not ANALYTICS_FILE.exists():
|
||||||
|
default = _default_analytics()
|
||||||
|
_save_analytics(default)
|
||||||
|
return default
|
||||||
|
try:
|
||||||
|
with open(ANALYTICS_FILE, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
# Merge over defaults so a file written by an older schema (or a
|
||||||
|
# partial write) still has every counter — _record_query indexes
|
||||||
|
# these keys directly and would otherwise raise KeyError.
|
||||||
|
merged = _default_analytics()
|
||||||
|
if isinstance(data, dict):
|
||||||
|
merged.update(data)
|
||||||
|
return merged
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to load analytics file: {e}")
|
||||||
|
return _default_analytics()
|
||||||
|
|
||||||
|
|
||||||
def _save_analytics(data: Dict[str, Any]) -> None:
|
def _save_analytics(data: Dict[str, Any]) -> None:
|
||||||
"""Persist analytics data to the JSON file."""
|
"""Persist analytics data to the JSON file."""
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
"""Tests for analytics default-merge on load (src/search/analytics.py)."""
|
||||||
|
import json
|
||||||
|
|
||||||
|
import src.search.analytics as analytics
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_merges_defaults_for_partial_file(tmp_path, monkeypatch):
|
||||||
|
# A file written by an older schema is missing most counters.
|
||||||
|
f = tmp_path / "search_analytics.json"
|
||||||
|
f.write_text(json.dumps({"total_queries": 5}), encoding="utf-8")
|
||||||
|
monkeypatch.setattr(analytics, "ANALYTICS_FILE", f)
|
||||||
|
|
||||||
|
data = analytics._load_analytics()
|
||||||
|
|
||||||
|
# Existing value preserved, every missing counter filled with its default.
|
||||||
|
assert data["total_queries"] == 5
|
||||||
|
assert data["query_patterns"] == {}
|
||||||
|
for key in ("successful_queries", "failed_queries", "cache_hits", "cache_misses"):
|
||||||
|
assert data[key] == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_record_query_survives_partial_file(tmp_path, monkeypatch):
|
||||||
|
f = tmp_path / "search_analytics.json"
|
||||||
|
f.write_text(json.dumps({"total_queries": 1}), encoding="utf-8")
|
||||||
|
monkeypatch.setattr(analytics, "ANALYTICS_FILE", f)
|
||||||
|
|
||||||
|
# Before the fix this raised KeyError on the missing counters.
|
||||||
|
analytics._record_query("hello world", success=True, cache_hit=False)
|
||||||
|
|
||||||
|
data = analytics._load_analytics()
|
||||||
|
assert data["total_queries"] == 2
|
||||||
|
assert data["successful_queries"] == 1
|
||||||
|
assert data["query_patterns"]["hello world"]["count"] == 1
|
||||||
Reference in New Issue
Block a user