mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-11 18:07:31 +00:00
3a90ac2784
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
179 lines
6.1 KiB
Python
179 lines
6.1 KiB
Python
"""Tests for graphify.querylog."""
|
|
import json
|
|
import os
|
|
import pytest
|
|
from pathlib import Path
|
|
|
|
from graphify.querylog import log_query, nodes_from_result
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# nodes_from_result
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_nodes_from_result_parses_header():
|
|
result = "Traversal: BFS depth=2 | Start: ['foo'] | 7 nodes found\n\nNODE foo"
|
|
assert nodes_from_result(result) == 7
|
|
|
|
|
|
def test_nodes_from_result_singular():
|
|
assert nodes_from_result("1 node found") == 1
|
|
|
|
|
|
def test_nodes_from_result_missing():
|
|
assert nodes_from_result("no match here") is None
|
|
|
|
|
|
def test_nodes_from_result_empty():
|
|
assert nodes_from_result("") is None
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# log_query — basic write
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_log_query_writes_jsonl(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_DISABLE", raising=False)
|
|
|
|
log_query(kind="query", question="what is X", corpus="/some/graph.json",
|
|
result="3 nodes found\nNODE a", duration_ms=12.5, mode="bfs", depth=2)
|
|
|
|
lines = log_file.read_text().splitlines()
|
|
assert len(lines) == 1
|
|
rec = json.loads(lines[0])
|
|
assert rec["kind"] == "query"
|
|
assert rec["question"] == "what is X"
|
|
assert rec["corpus"] == "/some/graph.json"
|
|
assert rec["nodes_returned"] == 3
|
|
assert rec["result_chars"] > 0
|
|
assert rec["duration_ms"] == pytest.approx(12.5, abs=0.01)
|
|
assert rec["mode"] == "bfs"
|
|
assert "ts" in rec
|
|
|
|
|
|
def test_log_query_appends(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_DISABLE", raising=False)
|
|
|
|
log_query(kind="query", question="q1", corpus="/g.json")
|
|
log_query(kind="query", question="q2", corpus="/g.json")
|
|
|
|
lines = log_file.read_text().splitlines()
|
|
assert len(lines) == 2
|
|
assert json.loads(lines[0])["question"] == "q1"
|
|
assert json.loads(lines[1])["question"] == "q2"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# opt-out / opt-in
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_disable_env(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG_DISABLE", "1")
|
|
|
|
log_query(kind="query", question="q", corpus="/g.json")
|
|
|
|
assert not log_file.exists()
|
|
|
|
|
|
def test_disable_env_true(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG_DISABLE", "true")
|
|
|
|
log_query(kind="query", question="q", corpus="/g.json")
|
|
|
|
assert not log_file.exists()
|
|
|
|
|
|
def test_responses_not_logged_by_default(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_DISABLE", raising=False)
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_RESPONSES", raising=False)
|
|
|
|
log_query(kind="query", question="q", corpus="/g.json", result="NODE foo")
|
|
|
|
rec = json.loads(log_file.read_text())
|
|
assert "response" not in rec
|
|
|
|
|
|
def test_responses_optin(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG_RESPONSES", "1")
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_DISABLE", raising=False)
|
|
|
|
log_query(kind="query", question="q", corpus="/g.json", result="NODE foo bar")
|
|
|
|
rec = json.loads(log_file.read_text())
|
|
assert rec["response"] == "NODE foo bar"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# robustness — never raises
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_log_never_raises(tmp_path, monkeypatch):
|
|
# Point at a directory — open() for append will fail
|
|
bad_path = tmp_path / "is_a_dir"
|
|
bad_path.mkdir()
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(bad_path))
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_DISABLE", raising=False)
|
|
|
|
# Must not raise
|
|
log_query(kind="query", question="q", corpus="/g.json")
|
|
|
|
|
|
def test_log_creates_parent_dirs(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "deep" / "nested" / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_DISABLE", raising=False)
|
|
|
|
log_query(kind="query", question="q", corpus="/g.json")
|
|
|
|
assert log_file.exists()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# field coverage
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_nodes_returned_inferred_from_result(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_DISABLE", raising=False)
|
|
|
|
log_query(kind="query", question="q", corpus="/g.json",
|
|
result="5 nodes found\nNODE a\nNODE b")
|
|
|
|
rec = json.loads(log_file.read_text())
|
|
assert rec["nodes_returned"] == 5
|
|
|
|
|
|
def test_explicit_nodes_returned_takes_precedence(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_DISABLE", raising=False)
|
|
|
|
log_query(kind="path", question="A -> B", corpus="/g.json", nodes_returned=3)
|
|
|
|
rec = json.loads(log_file.read_text())
|
|
assert rec["nodes_returned"] == 3
|
|
|
|
|
|
def test_kind_mcp_query(tmp_path, monkeypatch):
|
|
log_file = tmp_path / "q.log"
|
|
monkeypatch.setenv("GRAPHIFY_QUERY_LOG", str(log_file))
|
|
monkeypatch.delenv("GRAPHIFY_QUERY_LOG_DISABLE", raising=False)
|
|
|
|
log_query(kind="mcp_query", question="q", corpus="/g.json")
|
|
|
|
rec = json.loads(log_file.read_text())
|
|
assert rec["kind"] == "mcp_query"
|