Files
liqiang b119135836
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
2026-08-20 13:12:50 +00:00

169 lines
4.9 KiB
Python

"""Regression test: GraphRAGIndexer.search must return empty list for non-positive top_k."""
import importlib
import sys
import types
from contextlib import contextmanager
from dataclasses import dataclass
import numpy as np
import pytest
class STStub:
def __init__(self, *args, **kwargs):
self.encode_calls = 0
def encode(self, texts, **kwargs):
self.encode_calls += 1
return np.array([[0.1, 0.2, 0.3]])
@dataclass
class GraphRAGConfig:
llm_api_key: str = "test"
base_url: str = "test"
llm_model: str = "test"
_MISSING = object()
_STUBBED_MODULES = (
"openai",
"sentence_transformers",
"pandas",
"sklearn",
"sklearn.metrics",
"sklearn.metrics.pairwise",
"loguru",
"tqdm",
"config",
"networkx",
)
class GraphStub:
def __init__(self):
self._neighbors = {}
def add_node(self, node):
self._neighbors.setdefault(node, set())
def __contains__(self, node):
return node in self._neighbors
def neighbors(self, node):
return iter(self._neighbors[node])
@contextmanager
def _isolated_graphrag_module():
modules = {name: types.ModuleType(name) for name in _STUBBED_MODULES}
modules["openai"].OpenAI = object
modules["sentence_transformers"].SentenceTransformer = STStub
modules["sklearn"].__path__ = []
modules["sklearn"].metrics = modules["sklearn.metrics"]
modules["sklearn.metrics"].__path__ = []
modules["sklearn.metrics"].pairwise = modules["sklearn.metrics.pairwise"]
modules["sklearn.metrics.pairwise"].cosine_similarity = (
lambda a, b: np.array([[0.95]])
)
modules["loguru"].logger = types.SimpleNamespace(
info=lambda *a, **k: None,
warning=lambda *a, **k: None,
error=lambda *a, **k: None,
)
modules["tqdm"].tqdm = lambda x, **k: x
modules["config"].GraphRAGConfig = GraphRAGConfig
modules["networkx"].Graph = GraphStub
previous_module = sys.modules.pop("graphrag_indexer", _MISSING)
try:
with pytest.MonkeyPatch.context() as monkeypatch:
for name, module in modules.items():
monkeypatch.setitem(sys.modules, name, module)
yield importlib.import_module("graphrag_indexer")
finally:
sys.modules.pop("graphrag_indexer", None)
if previous_module is not _MISSING:
sys.modules["graphrag_indexer"] = previous_module
@pytest.fixture
def graphrag_module():
with _isolated_graphrag_module() as module:
yield module
def _make_indexer(graphrag_module):
indexer = graphrag_module.GraphRAGIndexer.__new__(
graphrag_module.GraphRAGIndexer
)
indexer.config = graphrag_module.GraphRAGConfig()
indexer.embedding_model = graphrag_module.SentenceTransformer()
indexer.entities = {
"e1": graphrag_module.Entity(
"e1",
"intel x86",
"instruction",
"intel x86 instruction",
np.array([0.1, 0.2, 0.3]),
{},
),
"e2": graphrag_module.Entity(
"e2",
"registers",
"register",
"intel registers",
np.array([0.1, 0.2, 0.3]),
{},
),
"e3": graphrag_module.Entity(
"e3",
"cpu flags",
"feature",
"cpu status flags",
np.array([0.1, 0.2, 0.3]),
{},
),
}
indexer.communities = {}
indexer.graph = graphrag_module.nx.Graph()
for entity_id in indexer.entities:
indexer.graph.add_node(entity_id)
return indexer
def test_search_nonpositive_top_k_returns_empty(graphrag_module):
"""Non-positive result limits return before query encoding."""
indexer = _make_indexer(graphrag_module)
assert indexer.search("intel", top_k=0) == []
assert indexer.search("intel", top_k=-1) == []
assert indexer.search("intel", top_k=-5) == []
assert indexer.embedding_model.encode_calls == 0
def test_search_positive_top_k_returns_results(graphrag_module):
"""Positive result limits still run retrieval and cap the results."""
indexer = _make_indexer(graphrag_module)
results = indexer.search("intel", top_k=2)
assert len(results) == 2
assert results[0]["id"] in ("e1", "e2", "e3")
assert results[1]["id"] in ("e1", "e2", "e3")
def test_dependency_stubs_are_restored():
"""Scoped dependency replacements leave neighboring collection unchanged."""
tracked_modules = (*_STUBBED_MODULES, "graphrag_indexer")
before = {
name: sys.modules.get(name, _MISSING)
for name in tracked_modules
}
with _isolated_graphrag_module() as module:
assert sys.modules["graphrag_indexer"] is module
for name in _STUBBED_MODULES:
assert sys.modules[name] is not before[name]
for name, previous_module in before.items():
assert sys.modules.get(name, _MISSING) is previous_module