|
44 | 44 | Content: ABC |
45 | 45 | Metadata: {'docs_url': 'https://example.com/doc2', 'title': 'Doc2', 'document_id': 'doc-2', \ |
46 | 46 | 'source': None} |
| 47 | +""", |
| 48 | + """Result 2b |
| 49 | +Content: ABC |
| 50 | + Metadata: {'docs_url': 'https://example.com/doc2b', 'title': 'Doc2b', 'document_id': 'doc-2b', \ |
| 51 | +'source': None} |
47 | 52 | """, |
48 | 53 | """END of knowledge_search tool results. |
49 | 54 | """, |
@@ -101,10 +106,6 @@ def setup_configuration_fixture(): |
101 | 106 | async def test_query_endpoint_handler_configuration_not_loaded(mocker): |
102 | 107 | """Test the query endpoint handler if configuration is not loaded.""" |
103 | 108 | # simulate state when no configuration is loaded |
104 | | - mocker.patch( |
105 | | - "app.endpoints.query.configuration", |
106 | | - return_value=mocker.Mock(), |
107 | | - ) |
108 | 109 | mocker.patch("app.endpoints.query.configuration", None) |
109 | 110 |
|
110 | 111 | query = "What is OpenStack?" |
@@ -272,12 +273,11 @@ async def test_query_endpoint_handler_with_referenced_documents(mocker): |
272 | 273 | def test_select_model_and_provider_id_from_request(mocker): |
273 | 274 | """Test the select_model_and_provider_id function.""" |
274 | 275 | mocker.patch( |
275 | | - "metrics.utils.configuration.inference.default_provider", |
| 276 | + "app.endpoints.query.configuration.inference.default_provider", |
276 | 277 | "default_provider", |
277 | 278 | ) |
278 | 279 | mocker.patch( |
279 | | - "metrics.utils.configuration.inference.default_model", |
280 | | - "default_model", |
| 280 | + "app.endpoints.query.configuration.inference.default_model", "default_model" |
281 | 281 | ) |
282 | 282 |
|
283 | 283 | model_list = [ |
@@ -312,12 +312,11 @@ def test_select_model_and_provider_id_from_request(mocker): |
312 | 312 | def test_select_model_and_provider_id_from_configuration(mocker): |
313 | 313 | """Test the select_model_and_provider_id function.""" |
314 | 314 | mocker.patch( |
315 | | - "metrics.utils.configuration.inference.default_provider", |
| 315 | + "app.endpoints.query.configuration.inference.default_provider", |
316 | 316 | "default_provider", |
317 | 317 | ) |
318 | 318 | mocker.patch( |
319 | | - "metrics.utils.configuration.inference.default_model", |
320 | | - "default_model", |
| 319 | + "app.endpoints.query.configuration.inference.default_model", "default_model" |
321 | 320 | ) |
322 | 321 |
|
323 | 322 | model_list = [ |
@@ -557,11 +556,13 @@ async def test_retrieve_response_with_knowledge_search_extracts_referenced_docum |
557 | 556 | assert conversation_id == "fake_conversation_id" |
558 | 557 |
|
559 | 558 | # Assert referenced documents were extracted correctly |
560 | | - assert len(referenced_documents) == 2 |
| 559 | + assert len(referenced_documents) == 3 |
561 | 560 | assert referenced_documents[0]["doc_url"] == "https://example.com/doc1" |
562 | 561 | assert referenced_documents[0]["doc_title"] == "Doc1" |
563 | 562 | assert referenced_documents[1]["doc_url"] == "https://example.com/doc2" |
564 | 563 | assert referenced_documents[1]["doc_title"] == "Doc2" |
| 564 | + assert referenced_documents[2]["doc_url"] == "https://example.com/doc2b" |
| 565 | + assert referenced_documents[2]["doc_title"] == "Doc2b" |
565 | 566 |
|
566 | 567 | # Doc3 should not be included because it has "Title" instead of "title" |
567 | 568 | doc_titles = [doc["doc_title"] for doc in referenced_documents] |
@@ -1722,3 +1723,153 @@ def test_process_knowledge_search_content_with_no_text_attribute(mocker): |
1722 | 1723 |
|
1723 | 1724 | # Verify metadata_map remains empty since text attribute is missing |
1724 | 1725 | assert len(metadata_map) == 0 |
| 1726 | + |
| 1727 | + |
| 1728 | +@pytest.mark.asyncio |
| 1729 | +async def test_retrieve_response_with_none_content(prepare_agent_mocks, mocker): |
| 1730 | + """Test retrieve_response handles None content gracefully.""" |
| 1731 | + mock_client, mock_agent = prepare_agent_mocks |
| 1732 | + |
| 1733 | + # Mock response with None content |
| 1734 | + mock_response = mocker.Mock() |
| 1735 | + mock_response.output_message.content = None |
| 1736 | + mock_response.steps = [] |
| 1737 | + mock_agent.create_turn.return_value = mock_response |
| 1738 | + |
| 1739 | + mock_client.shields.list.return_value = [] |
| 1740 | + mock_client.vector_dbs.list.return_value = [] |
| 1741 | + |
| 1742 | + # Mock configuration with empty MCP servers |
| 1743 | + mock_config = mocker.Mock() |
| 1744 | + mock_config.mcp_servers = [] |
| 1745 | + mocker.patch("app.endpoints.query.configuration", mock_config) |
| 1746 | + mocker.patch( |
| 1747 | + "app.endpoints.query.get_agent", |
| 1748 | + return_value=(mock_agent, "fake_conversation_id", "fake_session_id"), |
| 1749 | + ) |
| 1750 | + |
| 1751 | + query_request = QueryRequest(query="What is OpenStack?") |
| 1752 | + model_id = "fake_model_id" |
| 1753 | + access_token = "test_token" |
| 1754 | + |
| 1755 | + response, conversation_id, _ = await retrieve_response( |
| 1756 | + mock_client, model_id, query_request, access_token |
| 1757 | + ) |
| 1758 | + |
| 1759 | + # Should return empty string instead of "None" |
| 1760 | + assert response == "" |
| 1761 | + assert conversation_id == "fake_conversation_id" |
| 1762 | + |
| 1763 | + |
| 1764 | +@pytest.mark.asyncio |
| 1765 | +async def test_retrieve_response_with_missing_output_message( |
| 1766 | + prepare_agent_mocks, mocker |
| 1767 | +): |
| 1768 | + """Test retrieve_response handles missing output_message gracefully.""" |
| 1769 | + mock_client, mock_agent = prepare_agent_mocks |
| 1770 | + |
| 1771 | + # Mock response without output_message attribute |
| 1772 | + mock_response = mocker.Mock(spec=["steps"]) # Only has steps attribute |
| 1773 | + mock_response.steps = [] |
| 1774 | + mock_agent.create_turn.return_value = mock_response |
| 1775 | + |
| 1776 | + mock_client.shields.list.return_value = [] |
| 1777 | + mock_client.vector_dbs.list.return_value = [] |
| 1778 | + |
| 1779 | + # Mock configuration with empty MCP servers |
| 1780 | + mock_config = mocker.Mock() |
| 1781 | + mock_config.mcp_servers = [] |
| 1782 | + mocker.patch("app.endpoints.query.configuration", mock_config) |
| 1783 | + mocker.patch( |
| 1784 | + "app.endpoints.query.get_agent", |
| 1785 | + return_value=(mock_agent, "fake_conversation_id", "fake_session_id"), |
| 1786 | + ) |
| 1787 | + |
| 1788 | + query_request = QueryRequest(query="What is OpenStack?") |
| 1789 | + model_id = "fake_model_id" |
| 1790 | + access_token = "test_token" |
| 1791 | + |
| 1792 | + response, conversation_id, _ = await retrieve_response( |
| 1793 | + mock_client, model_id, query_request, access_token |
| 1794 | + ) |
| 1795 | + |
| 1796 | + # Should return empty string when output_message is missing |
| 1797 | + assert response == "" |
| 1798 | + assert conversation_id == "fake_conversation_id" |
| 1799 | + |
| 1800 | + |
| 1801 | +@pytest.mark.asyncio |
| 1802 | +async def test_retrieve_response_with_missing_content_attribute( |
| 1803 | + prepare_agent_mocks, mocker |
| 1804 | +): |
| 1805 | + """Test retrieve_response handles missing content attribute gracefully.""" |
| 1806 | + mock_client, mock_agent = prepare_agent_mocks |
| 1807 | + |
| 1808 | + # Mock response with output_message but no content attribute |
| 1809 | + mock_response = mocker.Mock() |
| 1810 | + mock_response.output_message = mocker.Mock(spec=[]) # No content attribute |
| 1811 | + mock_response.steps = [] |
| 1812 | + mock_agent.create_turn.return_value = mock_response |
| 1813 | + |
| 1814 | + mock_client.shields.list.return_value = [] |
| 1815 | + mock_client.vector_dbs.list.return_value = [] |
| 1816 | + |
| 1817 | + # Mock configuration with empty MCP servers |
| 1818 | + mock_config = mocker.Mock() |
| 1819 | + mock_config.mcp_servers = [] |
| 1820 | + mocker.patch("app.endpoints.query.configuration", mock_config) |
| 1821 | + mocker.patch( |
| 1822 | + "app.endpoints.query.get_agent", |
| 1823 | + return_value=(mock_agent, "fake_conversation_id", "fake_session_id"), |
| 1824 | + ) |
| 1825 | + |
| 1826 | + query_request = QueryRequest(query="What is OpenStack?") |
| 1827 | + model_id = "fake_model_id" |
| 1828 | + access_token = "test_token" |
| 1829 | + |
| 1830 | + response, conversation_id, _ = await retrieve_response( |
| 1831 | + mock_client, model_id, query_request, access_token |
| 1832 | + ) |
| 1833 | + |
| 1834 | + # Should return empty string when content attribute is missing |
| 1835 | + assert response == "" |
| 1836 | + assert conversation_id == "fake_conversation_id" |
| 1837 | + |
| 1838 | + |
| 1839 | +@pytest.mark.asyncio |
| 1840 | +async def test_retrieve_response_with_structured_content_object( |
| 1841 | + prepare_agent_mocks, mocker |
| 1842 | +): |
| 1843 | + """Test retrieve_response handles structured content objects properly.""" |
| 1844 | + mock_client, mock_agent = prepare_agent_mocks |
| 1845 | + |
| 1846 | + # Mock response with a structured content object |
| 1847 | + structured_content = {"type": "text", "value": "This is structured content"} |
| 1848 | + mock_response = mocker.Mock() |
| 1849 | + mock_response.output_message.content = structured_content |
| 1850 | + mock_response.steps = [] |
| 1851 | + mock_agent.create_turn.return_value = mock_response |
| 1852 | + |
| 1853 | + mock_client.shields.list.return_value = [] |
| 1854 | + mock_client.vector_dbs.list.return_value = [] |
| 1855 | + |
| 1856 | + # Mock configuration with empty MCP servers |
| 1857 | + mock_config = mocker.Mock() |
| 1858 | + mock_config.mcp_servers = [] |
| 1859 | + mocker.patch("app.endpoints.query.configuration", mock_config) |
| 1860 | + mocker.patch( |
| 1861 | + "app.endpoints.query.get_agent", |
| 1862 | + return_value=(mock_agent, "fake_conversation_id", "fake_session_id"), |
| 1863 | + ) |
| 1864 | + |
| 1865 | + query_request = QueryRequest(query="What is OpenStack?") |
| 1866 | + model_id = "fake_model_id" |
| 1867 | + access_token = "test_token" |
| 1868 | + |
| 1869 | + response, conversation_id, _ = await retrieve_response( |
| 1870 | + mock_client, model_id, query_request, access_token |
| 1871 | + ) |
| 1872 | + |
| 1873 | + # Should convert the structured object to string representation |
| 1874 | + assert response == str(structured_content) |
| 1875 | + assert conversation_id == "fake_conversation_id" |
0 commit comments