Spaces:
Runtime error
Runtime error
| """Integration tests for the RAG application.""" | |
| from unittest.mock import MagicMock, Mock, patch | |
| import pytest | |
| from models import create_embeddings, create_llm | |
| from qa_chain import create_qa_chain | |
| from utils import format_chat_history, format_context_with_highlight, messages_to_tuples | |
| from vectorstore import load_or_create_vectorstore | |
| def test_integration_rag_flow(mock_embeddings_class, mock_chroma_class): | |
| """Test full RAG flow from embeddings to QA chain.""" | |
| # Setup mocks | |
| mock_embeddings = MagicMock() | |
| mock_embeddings_class.return_value = mock_embeddings | |
| mock_vectorstore = MagicMock() | |
| mock_vectorstore.get.return_value = { | |
| "documents": ["Test document content"], | |
| "metadatas": [{"source": "pdf/test.pdf", "page": 1}], | |
| } | |
| mock_vectorstore.as_retriever.return_value = MagicMock() | |
| mock_chroma_class.return_value = mock_vectorstore | |
| # Test full flow | |
| embeddings = create_embeddings() | |
| vectorstore = load_or_create_vectorstore(embeddings) | |
| qa_chain = create_qa_chain(vectorstore) | |
| assert embeddings is not None | |
| assert vectorstore is not None | |
| assert qa_chain is not None | |
| def test_integration_llm_creation(mock_chat_openai): | |
| """Test LLM creation integration.""" | |
| mock_llm = MagicMock() | |
| mock_chat_openai.return_value = mock_llm | |
| llm = create_llm(streaming=True) | |
| assert llm is not None | |
| mock_chat_openai.assert_called_once() | |
| def test_integration_chat_history_conversion(): | |
| """Test integration of chat history conversion and formatting.""" | |
| messages = [ | |
| {"role": "user", "content": "Question 1"}, | |
| {"role": "assistant", "content": "Answer 1"}, | |
| {"role": "user", "content": "Question 2"}, | |
| ] | |
| # Convert to tuples | |
| tuples = messages_to_tuples(messages) | |
| assert len(tuples) == 1 | |
| assert tuples[0][0] == "Question 1" | |
| # Format history | |
| formatted = format_chat_history(tuples) | |
| assert "Question 1" in formatted | |
| assert "Answer 1" in formatted | |
| def test_integration_context_formatting(): | |
| """Test integration of context formatting with all features.""" | |
| from langchain_core.documents import Document | |
| docs = [ | |
| Document( | |
| page_content="This is test content about machine learning.", | |
| metadata={"source": "pdf/test1.pdf", "page": 1}, | |
| ), | |
| Document( | |
| page_content="Another document about neural networks.", | |
| metadata={"source": "pdf/test2.pdf", "page": 2}, | |
| ), | |
| ] | |
| docs_with_scores = [(docs[0], 0.9), (docs[1], 0.8)] | |
| hybrid_scores = [ | |
| (docs[0], 0.9, 0.85, 0.95), | |
| (docs[1], 0.8, 0.75, 0.85), | |
| ] | |
| result = format_context_with_highlight( | |
| docs, | |
| docs_with_scores=docs_with_scores, | |
| rewritten_query="machine learning neural networks", | |
| hybrid_scores=hybrid_scores, | |
| ) | |
| assert "Sources:" in result | |
| assert "test1.pdf" in result | |
| assert "test2.pdf" in result | |
| assert "π Rewritten:" in result | |
| assert "machine learning neural networks" in result | |
| assert "β" in result # Top chunk highlighted | |
| assert "f:" in result # Fused score | |
| assert "s:" in result # Semantic score | |
| assert "k:" in result # Keyword score | |
| def test_integration_qa_chain_streaming(mock_format_history, mock_create_llm, mock_vectorstore): | |
| """Test integration of QA chain streaming.""" | |
| from qa_chain import create_qa_chain | |
| mock_format_history.return_value = "Previous: Test" | |
| # Create proper mock chunks with content as property | |
| from unittest.mock import PropertyMock | |
| mock_chunk1 = MagicMock() | |
| mock_chunk1.content = "This is " | |
| mock_chunk2 = MagicMock() | |
| mock_chunk2.content = "a test " | |
| mock_chunk3 = MagicMock() | |
| mock_chunk3.content = "response." | |
| mock_llm = MagicMock() | |
| mock_llm.stream.return_value = [mock_chunk1, mock_chunk2, mock_chunk3] | |
| mock_create_llm.return_value = mock_llm | |
| mock_retriever = MagicMock() | |
| mock_doc = Mock(page_content="Retrieved context", metadata={"source": "test.pdf", "page": 1}) | |
| mock_retriever.invoke.return_value = [mock_doc] | |
| mock_vectorstore.as_retriever.return_value = mock_retriever | |
| qa_chain = create_qa_chain(mock_vectorstore) | |
| # Mock the chain operator - this is what gets called in stream() | |
| mock_chain = MagicMock() | |
| mock_chain.stream.return_value = [mock_chunk1, mock_chunk2, mock_chunk3] | |
| qa_chain._prompt.__or__ = MagicMock(return_value=mock_chain) | |
| inputs = { | |
| "question": "What is this?", | |
| "chat_history": [("Previous question", "Previous answer")], | |
| } | |
| results = list(qa_chain.stream(inputs)) | |
| assert len(results) > 0 | |
| assert all("chunk" in r for r in results) | |
| # Check that chunks are accumulated - they should be strings | |
| final_chunk = results[-1]["chunk"] | |
| # The chunks get accumulated, so we should see all three | |
| assert isinstance(final_chunk, str) or hasattr(final_chunk, '__str__') | |
| chunk_str = str(final_chunk) if not isinstance(final_chunk, str) else final_chunk | |
| assert len(chunk_str) > 0 | |
| assert len(results[-1]["source_documents"]) > 0 | |
| def test_integration_hybrid_retrieval(mock_bm25, mock_vectorstore): | |
| """Test integration of hybrid retrieval.""" | |
| from retrievers import HybridRetriever | |
| from langchain_core.documents import Document | |
| mock_vectorstore.get.return_value = { | |
| "documents": ["Document about AI", "Document about ML"], | |
| "metadatas": [ | |
| {"source": "pdf/ai.pdf", "page": 1}, | |
| {"source": "pdf/ml.pdf", "page": 2}, | |
| ], | |
| } | |
| doc1 = Document( | |
| page_content="Document about AI", | |
| metadata={"source": "pdf/ai.pdf", "page": 1}, | |
| ) | |
| doc2 = Document( | |
| page_content="Document about ML", | |
| metadata={"source": "pdf/ml.pdf", "page": 2}, | |
| ) | |
| mock_vectorstore.similarity_search_with_score.return_value = [ | |
| (doc1, 0.1), | |
| (doc2, 0.2), | |
| ] | |
| mock_bm25_instance = MagicMock() | |
| mock_bm25_instance.get_scores.return_value = [0.8, 0.6] | |
| mock_bm25.return_value = mock_bm25_instance | |
| retriever = HybridRetriever(mock_vectorstore) | |
| results = retriever.hybrid_search("AI machine learning", k=2, alpha=0.7) | |
| assert len(results) == 2 | |
| assert all("doc" in r for r in results) | |
| assert all("fused_score" in r for r in results) | |
| assert all("semantic_score" in r for r in results) | |
| assert all("keyword_score" in r for r in results) | |
| # Check that scores are fused correctly | |
| for result in results: | |
| assert 0 <= result["fused_score"] <= 1 | |
| assert 0 <= result["semantic_score"] <= 1 | |
| assert 0 <= result["keyword_score"] <= 1 | |
| def test_integration_end_to_end_rag_query(): | |
| """Test end-to-end RAG query processing.""" | |
| from qa_chain import QAChainWrapper | |
| from langchain_core.prompts import ChatPromptTemplate | |
| from langchain_core.documents import Document | |
| # Setup mocks | |
| mock_vectorstore = MagicMock() | |
| mock_vectorstore.get.return_value = { | |
| "documents": ["RAG is Retrieval-Augmented Generation"], | |
| "metadatas": [{"source": "pdf/rag.pdf", "page": 1}], | |
| } | |
| mock_retriever = MagicMock() | |
| mock_retriever.invoke.return_value = [ | |
| Document( | |
| page_content="RAG is Retrieval-Augmented Generation", | |
| metadata={"source": "pdf/rag.pdf", "page": 1}, | |
| ) | |
| ] | |
| mock_vectorstore.as_retriever.return_value = mock_retriever | |
| prompt = ChatPromptTemplate.from_template("Answer: {context}") | |
| with patch("qa_chain.create_llm") as mock_create_llm: | |
| mock_llm = MagicMock() | |
| mock_llm.stream.return_value = [ | |
| MagicMock(content="RAG stands for "), | |
| MagicMock(content="Retrieval-Augmented Generation."), | |
| ] | |
| mock_create_llm.return_value = mock_llm | |
| qa_chain = QAChainWrapper(mock_vectorstore, prompt) | |
| inputs = { | |
| "question": "What is RAG?", | |
| "chat_history": [], | |
| } | |
| results = list(qa_chain.stream(inputs)) | |
| assert len(results) > 0 | |
| final_result = results[-1] | |
| assert "chunk" in final_result | |
| assert "source_documents" in final_result | |
| assert len(final_result["source_documents"]) > 0 | |