test: 补充知识处理、检索与 Agent 回归用例
覆盖切块、向量检索、工具调用和历史预算;模型相关用例使用桩。
This commit is contained in:
1 parent
2dd062787d
commit
d9fe727c3f
123 files changed
+29005
No files matched your search
@@ -0,0 +1,238 @@
|
||||
"""
|
||||
Copyright 2024-2026 ReplyPier
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch, PropertyMock
|
||||
from agno.document import Document
|
||||
|
||||
from app.knowledge.enhanced_pdf_kb import EnhancedPDFKnowledgeBase
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_vector_db():
|
||||
"""Create a mock vector database"""
|
||||
db = MagicMock()
|
||||
db.exists.return_value = True
|
||||
db.embedder = MagicMock()
|
||||
return db
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_reader():
|
||||
"""Create a mock PDF reader"""
|
||||
reader = MagicMock()
|
||||
return reader
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_document():
|
||||
"""Create a mock document"""
|
||||
doc = MagicMock(spec=Document)
|
||||
doc.id = "test_doc_1"
|
||||
doc.embedding = None
|
||||
return doc
|
||||
|
||||
|
||||
class TestEnhancedPDFKnowledgeBase:
|
||||
"""Tests for EnhancedPDFKnowledgeBase class"""
|
||||
|
||||
def test_load_no_vector_db(self):
|
||||
"""Test load when no vector db is provided"""
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = None
|
||||
|
||||
# Should return early without error
|
||||
kb.load()
|
||||
|
||||
def test_load_no_reader(self, mock_vector_db):
|
||||
"""Test load when no reader is provided"""
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = None
|
||||
|
||||
# Should return early without error
|
||||
kb.load()
|
||||
|
||||
def test_load_recreate_db(self, mock_vector_db, mock_reader):
|
||||
"""Test load with recreate=True"""
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = []
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
kb.load(recreate=True)
|
||||
|
||||
mock_vector_db.drop.assert_called_once()
|
||||
mock_vector_db.create.assert_called_once()
|
||||
|
||||
def test_load_create_if_not_exists(self, mock_vector_db, mock_reader):
|
||||
"""Test load creates db if it doesn't exist"""
|
||||
mock_vector_db.exists.return_value = False
|
||||
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = []
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
kb.load(recreate=False)
|
||||
|
||||
mock_vector_db.create.assert_called_once()
|
||||
|
||||
def test_load_with_documents(self, mock_vector_db, mock_reader, mock_document):
|
||||
"""Test load with documents"""
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = [[mock_document]]
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
kb.load(upsert=True)
|
||||
|
||||
# Document should be embedded
|
||||
mock_document.embed.assert_called_once_with(embedder=mock_vector_db.embedder)
|
||||
# Documents should be upserted
|
||||
mock_vector_db.upsert.assert_called_once()
|
||||
|
||||
def test_load_with_filters(self, mock_vector_db, mock_reader, mock_document):
|
||||
"""Test load with metadata filters"""
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = [[mock_document]]
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
filters = {"organization_id": "test_org", "agent_id": "test_agent"}
|
||||
kb.load(upsert=True, filters=filters)
|
||||
|
||||
mock_vector_db.upsert.assert_called_once_with(
|
||||
documents=[mock_document],
|
||||
filters=filters
|
||||
)
|
||||
|
||||
def test_load_document_already_embedded(self, mock_vector_db, mock_reader):
|
||||
"""Test load when document is already embedded"""
|
||||
doc = MagicMock(spec=Document)
|
||||
doc.id = "test_doc_1"
|
||||
doc.embedding = [0.1, 0.2, 0.3] # Already has embedding
|
||||
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = [[doc]]
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
kb.load(upsert=True)
|
||||
|
||||
# embed should not be called since doc already has embedding
|
||||
doc.embed.assert_not_called()
|
||||
|
||||
def test_load_embedding_error(self, mock_vector_db, mock_reader, mock_document):
|
||||
"""Test load when embedding fails"""
|
||||
mock_document.embed.side_effect = Exception("Embedding error")
|
||||
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = [[mock_document]]
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
# Should not raise, but log error
|
||||
kb.load(upsert=True)
|
||||
|
||||
def test_load_upsert_error(self, mock_vector_db, mock_reader, mock_document):
|
||||
"""Test load when upsert fails"""
|
||||
mock_vector_db.upsert.side_effect = Exception("Upsert error")
|
||||
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = [[mock_document]]
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
# Should not raise, but log error
|
||||
kb.load(upsert=True)
|
||||
|
||||
def test_load_skip_upsert(self, mock_vector_db, mock_reader, mock_document):
|
||||
"""Test load with upsert=False"""
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = [[mock_document]]
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
kb.load(upsert=False)
|
||||
|
||||
# upsert should not be called
|
||||
mock_vector_db.upsert.assert_not_called()
|
||||
|
||||
def test_load_multiple_document_lists(self, mock_vector_db, mock_reader):
|
||||
"""Test load with multiple document lists"""
|
||||
doc1 = MagicMock(spec=Document)
|
||||
doc1.id = "doc1"
|
||||
doc1.embedding = None
|
||||
|
||||
doc2 = MagicMock(spec=Document)
|
||||
doc2.id = "doc2"
|
||||
doc2.embedding = None
|
||||
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = [[doc1], [doc2]]
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_vector_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
kb.load(upsert=True)
|
||||
|
||||
# Both documents should be embedded
|
||||
doc1.embed.assert_called_once()
|
||||
doc2.embed.assert_called_once()
|
||||
|
||||
# upsert should be called twice (once per document list)
|
||||
assert mock_vector_db.upsert.call_count == 2
|
||||
|
||||
def test_load_no_embedder(self, mock_reader):
|
||||
"""Test load when vector_db has no embedder"""
|
||||
mock_db = MagicMock()
|
||||
mock_db.exists.return_value = True
|
||||
# No embedder attribute
|
||||
del mock_db.embedder
|
||||
|
||||
doc = MagicMock(spec=Document)
|
||||
doc.id = "doc1"
|
||||
doc.embedding = None
|
||||
|
||||
with patch.object(EnhancedPDFKnowledgeBase, 'document_lists', new_callable=PropertyMock) as mock_doc_lists:
|
||||
mock_doc_lists.return_value = [[doc]]
|
||||
|
||||
kb = EnhancedPDFKnowledgeBase(path="/test/path")
|
||||
kb.vector_db = mock_db
|
||||
kb.reader = mock_reader
|
||||
|
||||
kb.load(upsert=True)
|
||||
|
||||
# embed should not be called since no embedder
|
||||
doc.embed.assert_not_called()
|
||||
Reference in new issue
Block a user