Skip to content

Commit f4579a1

Browse files
committed
fix: add unit tests
1 parent 911c8e2 commit f4579a1

10 files changed

Lines changed: 1107 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""CLI tests for uipath-openai-agents."""
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Fixtures for CLI tests."""
2+
3+
from pathlib import Path
4+
5+
import pytest
6+
7+
# Get the tests directory path relative to this conftest file
8+
TESTS_DIR = Path(__file__).parent.parent
9+
MOCKS_DIR = TESTS_DIR / "mocks"
10+
11+
12+
@pytest.fixture
13+
def simple_agent_basic() -> str:
14+
"""Load simple agent with basic configuration."""
15+
mock_file = MOCKS_DIR / "simple_agent_basic.py"
16+
with open(mock_file, "r") as file:
17+
data = file.read()
18+
return data
19+
20+
21+
@pytest.fixture
22+
def simple_agent_translation() -> str:
23+
"""Load simple agent with translation configuration."""
24+
mock_file = MOCKS_DIR / "simple_agent_translation.py"
25+
with open(mock_file, "r") as file:
26+
data = file.read()
27+
return data
28+
29+
30+
@pytest.fixture
31+
def openai_agents_config() -> str:
32+
"""Load openai_agents.json configuration."""
33+
mock_file = MOCKS_DIR / "openai_agents.json"
34+
with open(mock_file, "r") as file:
35+
data = file.read()
36+
return data
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
"""Tests for uipath init command with openai-agents."""
2+
3+
import json
4+
import os
5+
6+
from click.testing import CliRunner
7+
from uipath._cli.cli_init import init
8+
9+
10+
class TestInit:
11+
"""Test init command for OpenAI agents."""
12+
13+
def test_init_basic_config_generation(
14+
self,
15+
runner: CliRunner,
16+
temp_dir: str,
17+
simple_agent_basic: str,
18+
simple_agent_translation: str,
19+
openai_agents_config: str,
20+
) -> None:
21+
"""Test configuration file generation with basic agent."""
22+
with runner.isolated_filesystem(temp_dir=temp_dir):
23+
# Create agent scripts (config references both)
24+
with open("main.py", "w") as f:
25+
f.write(simple_agent_basic)
26+
27+
with open("translation.py", "w") as f:
28+
f.write(simple_agent_translation)
29+
30+
with open("openai_agents.json", "w") as f:
31+
f.write(openai_agents_config)
32+
33+
result = runner.invoke(init)
34+
assert result.exit_code == 0
35+
assert os.path.exists("entry-points.json")
36+
37+
with open("entry-points.json", "r") as f:
38+
config = json.load(f)
39+
40+
# Verify config structure
41+
assert "entryPoints" in config
42+
43+
# Verify entryPoints properties
44+
entry = config["entryPoints"][0]
45+
assert entry["filePath"] == "basic"
46+
assert entry["type"] == "agent"
47+
48+
# Verify input schema
49+
assert "input" in entry
50+
input_schema = entry["input"]
51+
assert input_schema["type"] == "object"
52+
assert "properties" in input_schema
53+
assert "required" in input_schema
54+
assert isinstance(input_schema["properties"], dict)
55+
assert isinstance(input_schema["required"], list)
56+
57+
# OpenAI agents use default message input
58+
assert "message" in input_schema["properties"]
59+
assert "message" in input_schema["required"]
60+
61+
# Verify output schema (default since no output_type specified)
62+
assert "output" in entry
63+
output_schema = entry["output"]
64+
assert "properties" in output_schema
65+
# Default output schema has "result" field
66+
assert "result" in output_schema["properties"]
67+
assert "required" in output_schema
68+
assert output_schema["type"] == "object"
69+
70+
def test_init_translation_agent_config_generation(
71+
self,
72+
runner: CliRunner,
73+
temp_dir: str,
74+
simple_agent_basic: str,
75+
simple_agent_translation: str,
76+
openai_agents_config: str,
77+
) -> None:
78+
"""Test configuration file generation with translation agent."""
79+
with runner.isolated_filesystem(temp_dir=temp_dir):
80+
# Create agent scripts
81+
with open("main.py", "w") as f:
82+
f.write(simple_agent_basic)
83+
84+
with open("translation.py", "w") as f:
85+
f.write(simple_agent_translation)
86+
87+
with open("openai_agents.json", "w") as f:
88+
f.write(openai_agents_config)
89+
90+
result = runner.invoke(init)
91+
assert result.exit_code == 0
92+
assert os.path.exists("entry-points.json")
93+
94+
with open("entry-points.json", "r") as f:
95+
config = json.load(f)
96+
97+
# Verify config structure
98+
assert "entryPoints" in config
99+
100+
# Find the translation entry point
101+
translation_entry = None
102+
for entry in config["entryPoints"]:
103+
if entry["filePath"] == "translation":
104+
translation_entry = entry
105+
break
106+
107+
assert translation_entry is not None
108+
assert translation_entry["type"] == "agent"
109+
110+
# Verify input schema - should use default messages
111+
assert "input" in translation_entry
112+
input_schema = translation_entry["input"]
113+
assert input_schema["type"] == "object"
114+
assert "properties" in input_schema
115+
assert "message" in input_schema["properties"]
116+
assert "message" in input_schema["required"]
117+
118+
# Verify output schema from agent's output_type
119+
assert "output" in translation_entry
120+
output_schema = translation_entry["output"]
121+
assert "properties" in output_schema
122+
123+
# Verify output properties from TranslationOutput
124+
out_props = output_schema["properties"]
125+
assert "original_text" in out_props
126+
assert out_props["original_text"]["type"] == "string"
127+
assert out_props["original_text"]["description"] == "The original text"
128+
129+
assert "translated_text" in out_props
130+
assert out_props["translated_text"]["type"] == "string"
131+
assert (
132+
out_props["translated_text"]["description"] == "The translated text"
133+
)
134+
135+
assert "target_language" in out_props
136+
assert out_props["target_language"]["type"] == "string"
137+
assert (
138+
out_props["target_language"]["description"] == "The target language"
139+
)
140+
141+
# Verify required fields in output
142+
assert "required" in output_schema
143+
assert "original_text" in output_schema["required"]
144+
assert "translated_text" in output_schema["required"]
145+
assert "target_language" in output_schema["required"]
146+
assert output_schema["type"] == "object"
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""Tests for uipath run command with openai-agents.
2+
3+
Note: These tests check CLI invocation and error handling.
4+
Full agent execution tests with OpenAI API calls should be marked as integration tests.
5+
"""
6+
7+
import os
8+
9+
from click.testing import CliRunner
10+
from uipath._cli.cli_run import run
11+
12+
13+
class TestRun:
14+
"""Test run command for OpenAI agents."""
15+
16+
def test_run_basic_agent_invocation(
17+
self,
18+
runner: CliRunner,
19+
temp_dir: str,
20+
simple_agent_basic: str,
21+
openai_agents_config: str,
22+
) -> None:
23+
"""Test basic agent invocation structure (without actual OpenAI API calls)."""
24+
input_file_name = "input.json"
25+
input_json_content = '{"message": "Hello, agent!"}'
26+
27+
with runner.isolated_filesystem(temp_dir=temp_dir):
28+
# create input file
29+
input_file_path = os.path.join(temp_dir, input_file_name)
30+
with open(input_file_path, "w") as f:
31+
f.write(input_json_content)
32+
33+
# Create agent script
34+
with open("main.py", "w") as f:
35+
f.write(simple_agent_basic)
36+
37+
with open("openai_agents.json", "w") as f:
38+
f.write(openai_agents_config)
39+
40+
# Note: This will fail without OpenAI API key, but we're testing CLI structure
41+
result = runner.invoke(run, ["basic", "--file", input_file_path])
42+
43+
# The command should invoke without crashing from CLI parsing
44+
# Actual execution may fail without API key, which is expected
45+
# We're testing the CLI invocation layer here
46+
assert result.exit_code in [0, 1] # 0 = success, 1 = runtime error
47+
48+
def test_run_with_invalid_agent_name(
49+
self,
50+
runner: CliRunner,
51+
temp_dir: str,
52+
simple_agent_basic: str,
53+
openai_agents_config: str,
54+
) -> None:
55+
"""Test run command with non-existent agent name."""
56+
input_file_name = "input.json"
57+
input_json_content = '{"message": "test"}'
58+
59+
with runner.isolated_filesystem(temp_dir=temp_dir):
60+
input_file_path = os.path.join(temp_dir, input_file_name)
61+
with open(input_file_path, "w") as f:
62+
f.write(input_json_content)
63+
64+
with open("main.py", "w") as f:
65+
f.write(simple_agent_basic)
66+
67+
with open("openai_agents.json", "w") as f:
68+
f.write(openai_agents_config)
69+
70+
# Try to run non-existent agent
71+
result = runner.invoke(
72+
run, ["nonexistent_agent", "--file", input_file_path]
73+
)
74+
75+
# Should fail with non-zero exit code
76+
assert result.exit_code != 0
77+
78+
def test_run_without_config_file(
79+
self,
80+
runner: CliRunner,
81+
temp_dir: str,
82+
simple_agent_basic: str,
83+
) -> None:
84+
"""Test run command without openai_agents.json file."""
85+
input_file_name = "input.json"
86+
input_json_content = '{"message": "test"}'
87+
88+
with runner.isolated_filesystem(temp_dir=temp_dir):
89+
input_file_path = os.path.join(temp_dir, input_file_name)
90+
with open(input_file_path, "w") as f:
91+
f.write(input_json_content)
92+
93+
with open("main.py", "w") as f:
94+
f.write(simple_agent_basic)
95+
96+
# No openai_agents.json file
97+
98+
result = runner.invoke(run, ["basic", "--file", input_file_path])
99+
100+
# Should fail without config file
101+
assert result.exit_code != 0
102+
103+
def test_run_with_malformed_input_json(
104+
self,
105+
runner: CliRunner,
106+
temp_dir: str,
107+
simple_agent_basic: str,
108+
openai_agents_config: str,
109+
) -> None:
110+
"""Test run command with malformed JSON input."""
111+
input_file_name = "input.json"
112+
input_json_content = '{"message": invalid json}' # Malformed
113+
114+
with runner.isolated_filesystem(temp_dir=temp_dir):
115+
input_file_path = os.path.join(temp_dir, input_file_name)
116+
with open(input_file_path, "w") as f:
117+
f.write(input_json_content)
118+
119+
with open("main.py", "w") as f:
120+
f.write(simple_agent_basic)
121+
122+
with open("openai_agents.json", "w") as f:
123+
f.write(openai_agents_config)
124+
125+
result = runner.invoke(run, ["basic", "--file", input_file_path])
126+
127+
# Should fail due to malformed JSON
128+
assert result.exit_code != 0
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Root conftest for uipath-openai-agents tests."""
2+
3+
import tempfile
4+
from typing import Generator
5+
6+
import pytest
7+
from click.testing import CliRunner
8+
9+
10+
@pytest.fixture
11+
def runner() -> CliRunner:
12+
"""Provide a Click CLI test runner."""
13+
return CliRunner()
14+
15+
16+
@pytest.fixture
17+
def temp_dir() -> Generator[str, None, None]:
18+
"""Provide a temporary directory for test files."""
19+
with tempfile.TemporaryDirectory() as tmp_dir:
20+
yield tmp_dir
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"agents": {
3+
"basic": "main.py:agent",
4+
"translation": "translation.py:agent"
5+
}
6+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""Simple OpenAI agent for testing - basic configuration."""
2+
3+
from agents import Agent
4+
5+
# Simple agent without output type (uses default behavior)
6+
agent = Agent(
7+
name="echo_agent",
8+
instructions="You are a helpful assistant. Respond to the user's message.",
9+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Simple OpenAI agent for testing - translation agent with custom output."""
2+
3+
from agents import Agent
4+
from pydantic import BaseModel, Field
5+
6+
7+
class TranslationOutput(BaseModel):
8+
"""Output model for translation."""
9+
10+
original_text: str = Field(description="The original text")
11+
translated_text: str = Field(description="The translated text")
12+
target_language: str = Field(description="The target language")
13+
14+
15+
# Agent with custom output type (direct Pydantic model)
16+
agent = Agent(
17+
name="translation_agent",
18+
instructions="You are a translation agent. Translate the given text to the target language specified in the message.",
19+
output_type=TranslationOutput,
20+
)

0 commit comments

Comments
 (0)