Skip to content

Commit 89c52ea

Browse files
add tests
1 parent 0e7732c commit 89c52ea

File tree

5 files changed

+219
-7
lines changed

5 files changed

+219
-7
lines changed

src/uipath/platform/common/interrupt_models.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
from pydantic import BaseModel, ConfigDict, Field, model_validator
66

7+
from uipath.platform.context_grounding.context_grounding_index import (
8+
ContextGroundingIndex,
9+
)
10+
711
from ..action_center import Task
812
from ..context_grounding import (
913
BatchTransformCreationResponse,
@@ -85,16 +89,16 @@ class WaitDeepRag(BaseModel):
8589

8690

8791
class CreateEphemeralIndex(BaseModel):
88-
"""Model representing a Jit Index task creation."""
92+
"""Model representing a Ephemeral Index task creation."""
8993

9094
usage: str
9195
attachments: list[str]
9296

9397

9498
class WaitEphemeralIndex(BaseModel):
95-
"""Model representing a wait Jit Index task."""
99+
"""Model representing a wait Ephemeral Index task."""
96100

97-
id: str
101+
index: ContextGroundingIndex
98102

99103

100104
class CreateBatchTransform(BaseModel):

src/uipath/platform/context_grounding/context_grounding_index.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ class ContextGroundingIndex(BaseModel):
4444
extra="allow",
4545
)
4646

47-
@field_serializer("last_ingested", "last_queried", when_used="json")
47+
@field_serializer("last_ingested", "last_queried")
4848
def serialize_datetime(self, value):
49-
"""Serialize datetime fields to ISO 8601 format for JSON output."""
49+
"""Serialize datetime fields to ISO 8601 format."""
5050
if isinstance(value, datetime):
5151
return value.isoformat() if value else None
5252
return value

src/uipath/platform/resume_triggers/_protocol.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,14 +526,14 @@ async def _handle_ephemeral_index_job_trigger(
526526
) -> None:
527527
"""Handle ephemeral index"""
528528
if isinstance(value, WaitEphemeralIndex):
529-
resume_trigger.item_key = value.ephemeral_index.id
529+
resume_trigger.item_key = value.index.id
530530
elif isinstance(value, CreateEphemeralIndex):
531531
ephemeral_index = uipath.context_grounding.create_ephemeral_index(
532532
usage=value.usage,
533533
attachments=value.attachments,
534534
)
535535
if not ephemeral_index:
536-
raise Exception("Failed to start ephemeral index")
536+
raise Exception("Failed to create ephemeral index")
537537
resume_trigger.item_key = ephemeral_index.id
538538

539539
async def _handle_batch_rag_job_trigger(

tests/cli/test_hitl.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,21 @@
2525
WaitJob,
2626
WaitTask,
2727
)
28+
from uipath.platform.common.interrupt_models import (
29+
CreateEphemeralIndex,
30+
WaitEphemeralIndex,
31+
)
2832
from uipath.platform.context_grounding import (
2933
BatchTransformCreationResponse,
3034
BatchTransformOutputColumn,
3135
Citation,
3236
CitationMode,
3337
DeepRagCreationResponse,
3438
DeepRagStatus,
39+
IndexStatus,
40+
)
41+
from uipath.platform.context_grounding.context_grounding_index import (
42+
ContextGroundingIndex,
3543
)
3644
from uipath.platform.orchestrator import (
3745
Job,
@@ -517,6 +525,95 @@ async def test_read_batch_rag_trigger_pending(
517525
reader = UiPathResumeTriggerReader()
518526
await reader.read_trigger(resume_trigger)
519527

528+
@pytest.mark.anyio
529+
async def test_read_ephemeral_index_trigger_successful(
530+
self,
531+
setup_test_env: None,
532+
) -> None:
533+
"""Test reading a successful ephemeral index trigger."""
534+
index_id = "test-ephemeral-index-id"
535+
index_data = {
536+
"id": index_id,
537+
"name": "test-index",
538+
"lastIngestionStatus": IndexStatus.SUCCESSFUL.value,
539+
}
540+
541+
mock_retrieve_by_id = AsyncMock(return_value=index_data)
542+
543+
with patch(
544+
"uipath.platform.context_grounding._context_grounding_service.ContextGroundingService.retrieve_by_id",
545+
new=mock_retrieve_by_id,
546+
):
547+
resume_trigger = UiPathResumeTrigger(
548+
trigger_type=UiPathResumeTriggerType.EPHEMERAL_INDEX,
549+
item_key=index_id,
550+
)
551+
reader = UiPathResumeTriggerReader()
552+
result = await reader.read_trigger(resume_trigger)
553+
554+
assert isinstance(result, ContextGroundingIndex)
555+
assert result.id == index_id
556+
mock_retrieve_by_id.assert_called_once_with(index_id)
557+
558+
@pytest.mark.anyio
559+
async def test_read_ephemeral_index_trigger_pending(
560+
self,
561+
setup_test_env: None,
562+
) -> None:
563+
"""Test reading a pending ephemeral index trigger raises pending error."""
564+
from uipath.core.errors import UiPathPendingTriggerError
565+
566+
index_id = "test-ephemeral-index-id"
567+
index_data = {
568+
"id": index_id,
569+
"name": "test-index",
570+
"lastIngestionStatus": IndexStatus.IN_PROGRESS.value,
571+
}
572+
573+
mock_retrieve_by_id = AsyncMock(return_value=index_data)
574+
575+
with patch(
576+
"uipath.platform.context_grounding._context_grounding_service.ContextGroundingService.retrieve_by_id",
577+
new=mock_retrieve_by_id,
578+
):
579+
resume_trigger = UiPathResumeTrigger(
580+
trigger_type=UiPathResumeTriggerType.EPHEMERAL_INDEX,
581+
item_key=index_id,
582+
)
583+
584+
with pytest.raises(UiPathPendingTriggerError):
585+
reader = UiPathResumeTriggerReader()
586+
await reader.read_trigger(resume_trigger)
587+
588+
@pytest.mark.anyio
589+
async def test_read_ephemeral_index_trigger_failed(
590+
self,
591+
setup_test_env: None,
592+
) -> None:
593+
"""Test reading a failed ephemeral index trigger raises faulted error."""
594+
index_id = "test-ephemeral-index-id"
595+
index_data = {
596+
"id": index_id,
597+
"name": "test-index",
598+
"lastIngestionStatus": IndexStatus.FAILED.value,
599+
}
600+
601+
mock_retrieve_by_id = AsyncMock(return_value=index_data)
602+
603+
with patch(
604+
"uipath.platform.context_grounding._context_grounding_service.ContextGroundingService.retrieve_by_id",
605+
new=mock_retrieve_by_id,
606+
):
607+
resume_trigger = UiPathResumeTrigger(
608+
trigger_type=UiPathResumeTriggerType.EPHEMERAL_INDEX,
609+
item_key=index_id,
610+
)
611+
612+
with pytest.raises(UiPathFaultedTriggerError) as exc_info:
613+
reader = UiPathResumeTriggerReader()
614+
await reader.read_trigger(resume_trigger)
615+
assert exc_info.value.args[0] == ErrorCategory.USER
616+
520617

521618
class TestHitlProcessor:
522619
"""Tests for the HitlProcessor class."""
@@ -778,6 +875,62 @@ async def test_create_resume_trigger_wait_batch_transform(
778875
assert resume_trigger.trigger_type == UiPathResumeTriggerType.BATCH_RAG
779876
assert resume_trigger.item_key == batch_transform_id
780877

878+
@pytest.mark.anyio
879+
async def test_create_resume_trigger_create_ephemeral_index(
880+
self,
881+
setup_test_env: None,
882+
) -> None:
883+
"""Test creating a resume trigger for CreateEphemeralIndex."""
884+
index_id = "test-ephemeral-index-id"
885+
attachments = ["attachment-uuid-1", "attachment-uuid-2"]
886+
create_ephemeral_index = CreateEphemeralIndex(
887+
usage="DeepRAG",
888+
attachments=attachments,
889+
)
890+
891+
mock_index = ContextGroundingIndex(
892+
id=index_id,
893+
name="ephemeral-index",
894+
last_ingestion_status=IndexStatus.QUEUED.value,
895+
)
896+
mock_create_ephemeral_index = AsyncMock(return_value=mock_index)
897+
898+
with patch(
899+
"uipath.platform.context_grounding._context_grounding_service.ContextGroundingService.create_ephemeral_index",
900+
new=mock_create_ephemeral_index,
901+
):
902+
processor = UiPathResumeTriggerCreator()
903+
resume_trigger = await processor.create_trigger(create_ephemeral_index)
904+
905+
assert resume_trigger is not None
906+
assert resume_trigger.trigger_type == UiPathResumeTriggerType.EPHEMERAL_INDEX
907+
assert resume_trigger.item_key == index_id
908+
mock_create_ephemeral_index.assert_called_once_with(
909+
usage=create_ephemeral_index.usage,
910+
attachments=create_ephemeral_index.attachments,
911+
)
912+
913+
@pytest.mark.anyio
914+
async def test_create_resume_trigger_wait_ephemeral_index(
915+
self,
916+
setup_test_env: None,
917+
) -> None:
918+
"""Test creating a resume trigger for WaitEphemeralIndex."""
919+
index_id = "test-ephemeral-index-id"
920+
ephemeral_index = ContextGroundingIndex(
921+
id=index_id,
922+
name="ephemeral-index",
923+
last_ingestion_status=IndexStatus.IN_PROGRESS.value,
924+
)
925+
wait_ephemeral_index = WaitEphemeralIndex(index=ephemeral_index)
926+
927+
processor = UiPathResumeTriggerCreator()
928+
resume_trigger = await processor.create_trigger(wait_ephemeral_index)
929+
930+
assert resume_trigger is not None
931+
assert resume_trigger.trigger_type == UiPathResumeTriggerType.EPHEMERAL_INDEX
932+
assert resume_trigger.item_key == index_id
933+
781934

782935
class TestDocumentExtractionModels:
783936
"""Tests for document extraction models."""

tests/sdk/services/test_context_grounding_service.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,6 +1760,61 @@ def test_download_batch_transform_result_creates_nested_directories(
17601760
assert destination.read_bytes() == b"col1,col2\nval1,val2"
17611761
assert destination.parent.exists()
17621762

1763+
def test_create_ephemeral_index(
1764+
self,
1765+
httpx_mock: HTTPXMock,
1766+
service: ContextGroundingService,
1767+
base_url: str,
1768+
org: str,
1769+
tenant: str,
1770+
version: str,
1771+
) -> None:
1772+
import uuid
1773+
1774+
httpx_mock.add_response(
1775+
url=f"{base_url}{org}{tenant}/ecs_/v2/indexes/createephemeral",
1776+
status_code=200,
1777+
json={
1778+
"id": "ephemeral-index-id",
1779+
"name": "ephemeral-index",
1780+
"lastIngestionStatus": "Queued",
1781+
},
1782+
)
1783+
1784+
attachment_ids = [uuid.uuid4(), uuid.uuid4()]
1785+
index = service.create_ephemeral_index(
1786+
usage="DeepRAG",
1787+
attachments=attachment_ids,
1788+
)
1789+
1790+
assert isinstance(index, ContextGroundingIndex)
1791+
assert index.id == "ephemeral-index-id"
1792+
assert index.name == "ephemeral-index"
1793+
assert index.last_ingestion_status == "Queued"
1794+
1795+
sent_requests = httpx_mock.get_requests()
1796+
if sent_requests is None:
1797+
raise Exception("No request was sent")
1798+
1799+
assert sent_requests[0].method == "POST"
1800+
assert (
1801+
sent_requests[0].url
1802+
== f"{base_url}{org}{tenant}/ecs_/v2/indexes/createephemeral"
1803+
)
1804+
1805+
request_data = json.loads(sent_requests[0].content)
1806+
assert request_data["usage"] == "DeepRAG"
1807+
assert "dataSource" in request_data
1808+
assert request_data["dataSource"]["attachments"] == [
1809+
str(att) for att in attachment_ids
1810+
]
1811+
1812+
assert HEADER_USER_AGENT in sent_requests[0].headers
1813+
assert (
1814+
sent_requests[0].headers[HEADER_USER_AGENT]
1815+
== f"UiPath.Python.Sdk/UiPath.Python.Sdk.Activities.ContextGroundingService.create_ephemeral_index/{version}"
1816+
)
1817+
17631818
@pytest.mark.anyio
17641819
async def test_download_batch_transform_result_async_creates_nested_directories(
17651820
self,

0 commit comments

Comments
 (0)