| import pytest |
| import json |
| from unittest.mock import MagicMock, AsyncMock, patch |
| import torch |
| from langchain_core.messages import AIMessage |
| from src.pipelines.graph_runner_pipeline import GraphRunnerPipeline |
| from src.models.agent_models import Orchastrator_Output |
|
|
| @pytest.mark.asyncio |
| async def test_graph_runner_pipeline_casual_chat(): |
| """Test that GraphRunnerPipeline correctly routes to casual chat and returns response.""" |
| |
| mock_structured_output = AsyncMock() |
| mock_structured_output.ainvoke.return_value = Orchastrator_Output( |
| redirect_to="chat_node", |
| querie="" |
| ) |
| |
| mock_chat_output = AsyncMock() |
| mock_chat_output.ainvoke.return_value = AIMessage(content="Hello! How can I help you today?") |
| |
| mock_llm = MagicMock() |
| mock_llm.with_structured_output.return_value = mock_structured_output |
| mock_llm.bind_tools.return_value = mock_chat_output |
| |
| |
| with patch("src.nodes.agents_nodes.llm", mock_llm): |
| pipeline = GraphRunnerPipeline() |
| |
| chunks = [] |
| async for chunk in pipeline.initiate(thread_id="test_thread_1", query="Hello"): |
| chunks.append(chunk) |
| |
| assert len(chunks) > 0 |
| first_chunk_str = chunks[0].replace("data: ", "").strip() |
| first_chunk = json.loads(first_chunk_str) |
| |
| |
| assert "orchestrator" in first_chunk or "chat" in first_chunk |
| mock_llm.with_structured_output.assert_called_once_with(Orchastrator_Output) |
| mock_structured_output.ainvoke.assert_called_once() |
| mock_llm.bind_tools.assert_called_once() |
| mock_chat_output.ainvoke.assert_called_once() |
|
|
|
|
| @pytest.mark.skip( |
| reason=( |
| "Written against the deprecated retreiver_node which used " |
| "vectorizer.get_similar_data() + MyModel.predict_emb(). " |
| "The active node is now retriever_node_v2 which calls " |
| "vectorizer.invoke() directly. Update this test for the new node." |
| ) |
| ) |
| @pytest.mark.asyncio |
| async def test_graph_runner_pipeline_retrieval(): |
|
|
| """Test that GraphRunnerPipeline correctly routes to retriever, queries vector db, and returns recommendations.""" |
| |
| mock_structured_output = AsyncMock() |
| mock_structured_output.ainvoke.return_value = Orchastrator_Output( |
| redirect_to="retreiver_node", |
| querie="blue jeans" |
| ) |
| |
| |
| mock_chat_output = AsyncMock() |
| mock_chat_output.ainvoke.return_value = AIMessage(content="I found these Sleek Blue Jeans for you.") |
| |
| mock_llm = MagicMock() |
| mock_llm.with_structured_output.return_value = mock_structured_output |
| mock_llm.bind_tools.return_value = mock_chat_output |
| |
| |
| mock_mymodel_inst = MagicMock() |
| mock_mymodel_inst.predict_emb.return_value = torch.zeros((1, 512)) |
| mock_mymodel_inst.load_model = MagicMock() |
| |
| |
| mock_vectorizer_inst = MagicMock() |
| mock_match_1 = MagicMock() |
| mock_match_1.id = "101" |
| mock_match_1.score = 0.95 |
| mock_match_1.metadata = {"name": "Sleek Blue Jeans", "price": 1200.0} |
| mock_vectorizer_inst.get_similar_data = AsyncMock(return_value={ |
| "matches": [mock_match_1] |
| }) |
| |
| |
| with patch("src.nodes.agents_nodes.llm", mock_llm), \ |
| patch("src.nodes.agents_nodes.my_model", return_value=mock_mymodel_inst), \ |
| patch("src.nodes.agents_nodes.vectorizer", return_value=mock_vectorizer_inst), \ |
| patch("src.nodes.agents_nodes._get_image_feat", return_value=torch.zeros((1, 2048))), \ |
| patch("src.nodes.agents_nodes._get_text_feat", return_value=torch.zeros((1, 768))): |
| |
| pipeline = GraphRunnerPipeline() |
| |
| chunks = [] |
| async for chunk in pipeline.initiate(thread_id="test_thread_2", query="Show me blue jeans"): |
| chunks.append(chunk) |
| |
| assert len(chunks) > 0 |
| |
| |
| mock_vectorizer_inst.get_similar_data.assert_called_once() |
| mock_mymodel_inst.predict_emb.assert_called_once() |
| mock_chat_output.ainvoke.assert_called_once() |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_graph_runner_pipeline_retrieval_v2(): |
| """Test that GraphRunnerPipeline correctly routes to retriever_node_v2, |
| calls vectorizer.invoke(), and returns product recommendations.""" |
|
|
| |
| mock_structured_output = AsyncMock() |
| mock_structured_output.ainvoke.return_value = Orchastrator_Output( |
| redirect_to="retreiver_node", |
| querie="blue jeans" |
| ) |
|
|
| |
| mock_chat_output = AsyncMock() |
| mock_chat_output.ainvoke.return_value = AIMessage( |
| content="I found these Sleek Blue Jeans for you." |
| ) |
|
|
| mock_llm = MagicMock() |
| mock_llm.with_structured_output.return_value = mock_structured_output |
| mock_llm.bind_tools.return_value = mock_chat_output |
|
|
| |
| mock_vectorizer_inst = MagicMock() |
| mock_vectorizer_inst.invoke = AsyncMock(return_value=[ |
| { |
| "id": "101", |
| "score": 0.95, |
| "metadata": {"name": "Sleek Blue Jeans", "price": 1200.0} |
| } |
| ]) |
|
|
| with patch("src.nodes.agents_nodes.llm", mock_llm), \ |
| patch("src.nodes.agents_nodes.vectorizer", return_value=mock_vectorizer_inst), \ |
| patch("src.nodes.agents_nodes._get_text_feat", return_value=torch.zeros((1, 768))), \ |
| patch("src.nodes.agents_nodes._get_image_feat", return_value=torch.zeros((1, 2048))): |
|
|
| pipeline = GraphRunnerPipeline() |
|
|
| chunks = [] |
| async for chunk in pipeline.initiate(thread_id="test_thread_v2", query="Show me blue jeans"): |
| chunks.append(chunk) |
|
|
| assert len(chunks) > 0 |
|
|
| |
| mock_vectorizer_inst.invoke.assert_called_once() |
|
|
| |
| mock_chat_output.ainvoke.assert_called_once() |
|
|
|
|