Skip to content

Commit 346c498

Browse files
authored
Merge pull request #53 from UiPath/feature/integration_test
Integration tests
2 parents e6fc7fd + 12d56e6 commit 346c498

23 files changed

Lines changed: 6451 additions & 1 deletion
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Integration testing
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
integration-tests:
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: read
14+
pull-requests: write
15+
16+
strategy:
17+
matrix:
18+
include:
19+
- build-dir: quickstart-agent
20+
- build-dir: simple-hitl-agent
21+
22+
steps:
23+
- name: Checkout code
24+
uses: actions/checkout@v4
25+
26+
- name: Set up Docker Buildx
27+
uses: docker/setup-buildx-action@v3
28+
29+
- name: Build Docker image (${{ matrix.build-dir }})
30+
run: |
31+
docker build -f testcases/${{ matrix.build-dir }}/Dockerfile \
32+
-t ${{ matrix.build-dir }}:test \
33+
--build-arg CLIENT_ID="${{ secrets.ALPHA_TEST_CLIENT_ID }}" \
34+
--build-arg CLIENT_SECRET="${{ secrets.ALPHA_TEST_CLIENT_SECRET }}" \
35+
--build-arg BASE_URL="${{ secrets.ALPHA_BASE_URL }}" \
36+
.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ plugins = [
6767
"pydantic.mypy"
6868
]
6969
exclude = [
70-
"samples/.*"
70+
"samples/.*", "testcases/.*"
7171
]
7272

7373
follow_imports = "silent"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
UIPATH_URL=xxx
2+
UIPATH_TENANT_ID=xxx
3+
UIPATH_ORGANIZATION_ID=xxx
4+
UIPATH_ACCESS_TOKEN=xxx
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
FROM ghcr.io/astral-sh/uv:python3.12-bookworm
2+
3+
WORKDIR /app
4+
5+
COPY . .
6+
7+
WORKDIR /app/testcases/quickstart-agent
8+
9+
RUN uv sync
10+
11+
ARG CLIENT_ID
12+
ARG CLIENT_SECRET
13+
ARG BASE_URL
14+
15+
RUN if [ -z "$CLIENT_ID" ]; then echo "CLIENT_ID build arg is required" && exit 1; fi
16+
RUN if [ -z "$CLIENT_SECRET" ]; then echo "CLIENT_SECRET build arg is required" && exit 1; fi
17+
RUN if [ -z "$BASE_URL" ]; then echo "BASE_URL build arg is required" && exit 1; fi
18+
19+
# Set environment variables for runtime
20+
ENV CLIENT_ID=$CLIENT_ID
21+
ENV CLIENT_SECRET=$CLIENT_SECRET
22+
ENV BASE_URL=$BASE_URL
23+
ENV TAVILY_API_KEY=${TAVILY_API_KEY:-""}
24+
ENV UIPATH_TENANT_ID=${UIPATH_TENANT_ID:-""}
25+
ENV UIPATH_JOB_KEY=8c6a342e-036e-492c-a3d2-99e66f6554ce
26+
27+
# Authenticate with UiPath during build
28+
RUN uv run uipath auth --client-id="$CLIENT_ID" --client-secret="$CLIENT_SECRET" --base-url="$BASE_URL"
29+
30+
RUN uv run uipath pack
31+
32+
RUN AGENT_INPUT=$(cat input.json) && uv run uipath run agent "$AGENT_INPUT"
33+
34+
# Run the Python assert script to validate output
35+
RUN python src/assert.py
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
flowchart TD
2+
step__done["_done"]:::stepStyle
3+
step_critique_joke["critique_joke"]:::stepStyle
4+
step_generate_joke["generate_joke"]:::stepStyle
5+
event_JokeEvent([<p>JokeEvent</p>]):::defaultEventStyle
6+
event_CritiqueEvent([<p>CritiqueEvent</p>]):::stopEventStyle
7+
event_TopicEvent([<p>TopicEvent</p>]):::defaultEventStyle
8+
event_CritiqueEvent --> step__done
9+
step_critique_joke --> event_CritiqueEvent
10+
event_JokeEvent --> step_critique_joke
11+
step_generate_joke --> event_JokeEvent
12+
event_TopicEvent --> step_generate_joke
13+
classDef stepStyle fill:#f2f0ff,line-height:1.2
14+
classDef externalStyle fill:#f2f0ff,line-height:1.2
15+
classDef defaultEventStyle fill-opacity:0
16+
classDef stopEventStyle fill:#bfb6fc
17+
classDef inputRequiredStyle fill:#f2f0ff,line-height:1.2
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"topic": "cats"}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"dependencies": ["."],
3+
"workflows": {
4+
"agent": "./src/main.py:agent"
5+
},
6+
"env": ".env"
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[project]
2+
name = "llama-quickstart-agent"
3+
version = "0.0.6"
4+
description = "UiPath LlamaIndex Quickstart Agent"
5+
authors = [{ name = "John Doe", email = "john.doe@myemail.com" }]
6+
readme = { file = "README.md", content-type = "text/markdown" }
7+
requires-python = ">=3.10"
8+
dependencies = [
9+
"uipath-llamaindex",
10+
"llama-index-llms-openai>=0.2.2",
11+
"uipath>=2.0.82",
12+
]
13+
14+
[tool.uv.sources]
15+
uipath-llamaindex = { path = "../../", editable = true }
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import json
2+
import os
3+
import sys
4+
5+
print("Checking quickstart agent output...")
6+
7+
# Check NuGet package
8+
uipath_dir = ".uipath"
9+
if not os.path.exists(uipath_dir):
10+
print("NuGet package directory (.uipath) not found")
11+
sys.exit(1)
12+
13+
nupkg_files = [f for f in os.listdir(uipath_dir) if f.endswith(".nupkg")]
14+
if not nupkg_files:
15+
print("NuGet package file (.nupkg) not found in .uipath directory")
16+
sys.exit(1)
17+
18+
print(f"NuGet package found: {nupkg_files[0]}")
19+
20+
# Check agent output file
21+
output_file = "__uipath/output.json"
22+
if not os.path.isfile(output_file):
23+
print("Agent output file not found")
24+
sys.exit(1)
25+
26+
print("Agent output file found")
27+
28+
# Check status and required fields
29+
try:
30+
with open(output_file, "r", encoding="utf-8") as f:
31+
output_data = json.load(f)
32+
33+
# Check status
34+
status = output_data.get("status")
35+
if status != "successful":
36+
print(f"Agent execution failed with status: {status}")
37+
sys.exit(1)
38+
39+
print("Agent execution status: successful")
40+
41+
# Check required fields for quickstart agent
42+
if "output" not in output_data:
43+
print("Missing 'output' field in agent response")
44+
sys.exit(1)
45+
46+
output_content = output_data["output"]
47+
if "joke" not in output_content:
48+
print("Missing 'joke' field in output")
49+
sys.exit(1)
50+
51+
joke = output_content["joke"]
52+
if not joke or joke.strip() == "":
53+
print("Joke field is empty")
54+
sys.exit(1)
55+
56+
if "critique" not in output_content:
57+
print("Missing 'critique' field in output")
58+
sys.exit(1)
59+
60+
critique = output_content["critique"]
61+
if not critique or critique.strip() == "":
62+
print("Critique field is empty")
63+
sys.exit(1)
64+
65+
print(f"Joke: {joke}")
66+
print(f"Critique: {critique}")
67+
68+
print("Required fields validation passed")
69+
print("Quickstart agent working correctly.")
70+
71+
except Exception as e:
72+
print(f"Error checking output: {e}")
73+
sys.exit(1)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from llama_index.core.workflow import (
2+
Event,
3+
StartEvent,
4+
StopEvent,
5+
Workflow,
6+
step,
7+
)
8+
9+
from uipath_llamaindex.llms import UiPathOpenAI
10+
11+
12+
class TopicEvent(StartEvent):
13+
topic: str
14+
15+
16+
class JokeEvent(Event):
17+
joke: str
18+
19+
20+
class CritiqueEvent(StopEvent):
21+
joke: str
22+
critique: str
23+
24+
25+
class JokeFlow(Workflow):
26+
llm = UiPathOpenAI(model="gpt-4o-mini-2024-07-18")
27+
28+
@step
29+
async def generate_joke(self, ev: TopicEvent) -> JokeEvent:
30+
topic = ev.topic
31+
32+
prompt = f"Write your best joke about {topic}."
33+
response = await self.llm.acomplete(prompt)
34+
return JokeEvent(joke=str(response))
35+
36+
@step
37+
async def critique_joke(self, ev: JokeEvent) -> CritiqueEvent:
38+
joke = ev.joke
39+
40+
prompt = f"Give a thorough analysis and critique of the following joke: {joke}"
41+
response = await self.llm.acomplete(prompt)
42+
return CritiqueEvent(joke=joke, critique=str(response))
43+
44+
45+
agent = JokeFlow(timeout=60, verbose=False)

0 commit comments

Comments
 (0)