|
35 | 35 | from uipath.platform.context_grounding._context_grounding_service import ( |
36 | 36 | ContextGroundingService, |
37 | 37 | ) |
38 | | -from uipath.platform.errors import ContextGroundingIndexNotFoundError |
| 38 | +from uipath.platform.errors import ( |
| 39 | + ContextGroundingIndexNotFoundError, |
| 40 | + IngestionInProgressException, |
| 41 | +) |
39 | 42 | from uipath.platform.orchestrator._buckets_service import BucketsService |
40 | 43 | from uipath.platform.orchestrator._folder_service import FolderService |
41 | 44 |
|
@@ -3839,6 +3842,170 @@ async def test_unified_search_async( |
3839 | 3842 | assert response.semantic_results.metadata is not None |
3840 | 3843 | assert len(response.semantic_results.values) == 1 |
3841 | 3844 |
|
| 3845 | + def _mock_index_lookup( |
| 3846 | + self, |
| 3847 | + httpx_mock: HTTPXMock, |
| 3848 | + base_url: str, |
| 3849 | + org: str, |
| 3850 | + tenant: str, |
| 3851 | + ingestion_status: str, |
| 3852 | + ) -> None: |
| 3853 | + """Mock the folder + index lookup that precedes a unified search.""" |
| 3854 | + for _ in range(2): |
| 3855 | + httpx_mock.add_response( |
| 3856 | + url=f"{base_url}{org}{tenant}/orchestrator_/api/FoldersNavigation/GetFoldersForCurrentUser?searchText=test-folder-path&skip=0&take=20", |
| 3857 | + status_code=200, |
| 3858 | + json={ |
| 3859 | + "PageItems": [ |
| 3860 | + { |
| 3861 | + "Key": "test-folder-key", |
| 3862 | + "FullyQualifiedName": "test-folder-path", |
| 3863 | + } |
| 3864 | + ] |
| 3865 | + }, |
| 3866 | + ) |
| 3867 | + httpx_mock.add_response( |
| 3868 | + url=f"{base_url}{org}{tenant}/ecs_/v2/indexes?$filter=Name eq 'test-index'&$expand=dataSource", |
| 3869 | + status_code=200, |
| 3870 | + json={ |
| 3871 | + "value": [ |
| 3872 | + { |
| 3873 | + "id": "test-index-id", |
| 3874 | + "name": "test-index", |
| 3875 | + "lastIngestionStatus": ingestion_status, |
| 3876 | + } |
| 3877 | + ] |
| 3878 | + }, |
| 3879 | + ) |
| 3880 | + |
| 3881 | + @pytest.mark.anyio |
| 3882 | + @pytest.mark.httpx_mock(assert_all_responses_were_requested=False) |
| 3883 | + @pytest.mark.parametrize("ingestion_status", ["Queued", "InProgress"]) |
| 3884 | + async def test_unified_search_async_blocks_during_ingestion_by_default( |
| 3885 | + self, |
| 3886 | + httpx_mock: HTTPXMock, |
| 3887 | + service: ContextGroundingService, |
| 3888 | + base_url: str, |
| 3889 | + org: str, |
| 3890 | + tenant: str, |
| 3891 | + ingestion_status: str, |
| 3892 | + ) -> None: |
| 3893 | + self._mock_index_lookup(httpx_mock, base_url, org, tenant, ingestion_status) |
| 3894 | + |
| 3895 | + with pytest.raises(IngestionInProgressException): |
| 3896 | + await service.unified_search_async(name="test-index", query="test query") |
| 3897 | + |
| 3898 | + @pytest.mark.httpx_mock(assert_all_responses_were_requested=False) |
| 3899 | + @pytest.mark.parametrize("ingestion_status", ["Queued", "InProgress"]) |
| 3900 | + def test_unified_search_blocks_during_ingestion_by_default( |
| 3901 | + self, |
| 3902 | + httpx_mock: HTTPXMock, |
| 3903 | + service: ContextGroundingService, |
| 3904 | + base_url: str, |
| 3905 | + org: str, |
| 3906 | + tenant: str, |
| 3907 | + ingestion_status: str, |
| 3908 | + ) -> None: |
| 3909 | + self._mock_index_lookup(httpx_mock, base_url, org, tenant, ingestion_status) |
| 3910 | + |
| 3911 | + with pytest.raises(IngestionInProgressException): |
| 3912 | + service.unified_search(name="test-index", query="test query") |
| 3913 | + |
| 3914 | + @pytest.mark.parametrize("ingestion_status", ["Queued", "InProgress"]) |
| 3915 | + def test_unified_search_opt_in_searches_during_ingestion( |
| 3916 | + self, |
| 3917 | + httpx_mock: HTTPXMock, |
| 3918 | + service: ContextGroundingService, |
| 3919 | + base_url: str, |
| 3920 | + org: str, |
| 3921 | + tenant: str, |
| 3922 | + ingestion_status: str, |
| 3923 | + ) -> None: |
| 3924 | + self._mock_index_lookup(httpx_mock, base_url, org, tenant, ingestion_status) |
| 3925 | + httpx_mock.add_response( |
| 3926 | + url=f"{base_url}{org}{tenant}/ecs_/v1.2/search/test-index-id", |
| 3927 | + status_code=200, |
| 3928 | + json={ |
| 3929 | + "semanticResults": { |
| 3930 | + "metadata": { |
| 3931 | + "operation_id": "test-op", |
| 3932 | + "strategy": "test-strategy", |
| 3933 | + }, |
| 3934 | + "values": [ |
| 3935 | + { |
| 3936 | + "id": "result-1", |
| 3937 | + "source": "test-source", |
| 3938 | + "page_number": 1, |
| 3939 | + "content": "Partially ingested content", |
| 3940 | + "score": 0.95, |
| 3941 | + } |
| 3942 | + ], |
| 3943 | + }, |
| 3944 | + "explanation": "test explanation", |
| 3945 | + }, |
| 3946 | + ) |
| 3947 | + |
| 3948 | + response = service.unified_search( |
| 3949 | + name="test-index", |
| 3950 | + query="test query", |
| 3951 | + search_during_ingestion=True, |
| 3952 | + ) |
| 3953 | + |
| 3954 | + assert isinstance(response, UnifiedQueryResult) |
| 3955 | + assert response.semantic_results is not None |
| 3956 | + assert len(response.semantic_results.values) == 1 |
| 3957 | + assert ( |
| 3958 | + response.semantic_results.values[0].content == "Partially ingested content" |
| 3959 | + ) |
| 3960 | + |
| 3961 | + @pytest.mark.anyio |
| 3962 | + @pytest.mark.parametrize("ingestion_status", ["Queued", "InProgress"]) |
| 3963 | + async def test_unified_search_async_opt_in_searches_during_ingestion( |
| 3964 | + self, |
| 3965 | + httpx_mock: HTTPXMock, |
| 3966 | + service: ContextGroundingService, |
| 3967 | + base_url: str, |
| 3968 | + org: str, |
| 3969 | + tenant: str, |
| 3970 | + ingestion_status: str, |
| 3971 | + ) -> None: |
| 3972 | + self._mock_index_lookup(httpx_mock, base_url, org, tenant, ingestion_status) |
| 3973 | + httpx_mock.add_response( |
| 3974 | + url=f"{base_url}{org}{tenant}/ecs_/v1.2/search/test-index-id", |
| 3975 | + status_code=200, |
| 3976 | + json={ |
| 3977 | + "semanticResults": { |
| 3978 | + "metadata": { |
| 3979 | + "operation_id": "test-op", |
| 3980 | + "strategy": "test-strategy", |
| 3981 | + }, |
| 3982 | + "values": [ |
| 3983 | + { |
| 3984 | + "id": "result-1", |
| 3985 | + "source": "test-source", |
| 3986 | + "page_number": 1, |
| 3987 | + "content": "Partially ingested content", |
| 3988 | + "score": 0.95, |
| 3989 | + } |
| 3990 | + ], |
| 3991 | + }, |
| 3992 | + "explanation": "test explanation", |
| 3993 | + }, |
| 3994 | + ) |
| 3995 | + |
| 3996 | + response = await service.unified_search_async( |
| 3997 | + name="test-index", |
| 3998 | + query="test query", |
| 3999 | + search_during_ingestion=True, |
| 4000 | + ) |
| 4001 | + |
| 4002 | + assert isinstance(response, UnifiedQueryResult) |
| 4003 | + assert response.semantic_results is not None |
| 4004 | + assert len(response.semantic_results.values) == 1 |
| 4005 | + assert ( |
| 4006 | + response.semantic_results.values[0].content == "Partially ingested content" |
| 4007 | + ) |
| 4008 | + |
3842 | 4009 | def test_unified_search_with_scope( |
3843 | 4010 | self, |
3844 | 4011 | httpx_mock: HTTPXMock, |
|
0 commit comments