Python: move all tests under tests and initial work on int tests (#206)

* move all tests under tests and initial work on int tests

* added updated tests setup and merge tests

* without failing step

* fixed upload

* updated file names for coverage

* reenable surface tests

* removed package matrix

* simplified variables

* correct path

* removed mistake

* fix mistake in path

* fix path

* windows specific env set

* updated merge tests

* slight update in marker

* added run integration tests settings

* updated setup, moved foundry int tests and updated merge test
This commit is contained in:
Eduard van Valkenburg
2025-07-22 17:26:00 +02:00
committed by GitHub
Unverified
parent f89c0be0ea
commit 5c992eb7ae
31 changed files with 978 additions and 639 deletions
+5 -4
View File
@@ -22,6 +22,7 @@ def override_env_param_dict(request: Any) -> dict[str, str]:
@fixture()
def azure_openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # type: ignore
"""Fixture to set environment variables for AzureOpenAISettings."""
if exclude_list is None:
exclude_list = []
@@ -29,6 +30,7 @@ def azure_openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dic
override_env_param_dict = {}
env_vars = {
"AZURE_OPENAI_ENDPOINT": "https://test-endpoint.com",
"AZURE_OPENAI_CHAT_DEPLOYMENT_NAME": "test_chat_deployment",
"AZURE_OPENAI_TEXT_DEPLOYMENT_NAME": "test_text_deployment",
"AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME": "test_embedding_deployment",
@@ -37,7 +39,6 @@ def azure_openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dic
"AZURE_OPENAI_TEXT_TO_AUDIO_DEPLOYMENT_NAME": "test_text_to_audio_deployment",
"AZURE_OPENAI_REALTIME_DEPLOYMENT_NAME": "test_realtime_deployment",
"AZURE_OPENAI_API_KEY": "test_api_key",
"AZURE_OPENAI_ENDPOINT": "https://test-endpoint.com",
"AZURE_OPENAI_API_VERSION": "2023-03-15-preview",
"AZURE_OPENAI_BASE_URL": "https://test_text_deployment.test-base-url.com",
"AZURE_OPENAI_TOKEN_ENDPOINT": "https://test-token-endpoint.com",
@@ -46,10 +47,10 @@ def azure_openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dic
env_vars.update(override_env_param_dict) # type: ignore
for key, value in env_vars.items():
if key not in exclude_list:
monkeypatch.setenv(key, value) # type: ignore
else:
if key in exclude_list:
monkeypatch.delenv(key, raising=False) # type: ignore
continue
monkeypatch.setenv(key, value) # type: ignore
return env_vars
@@ -1,121 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
from agent_framework import ChatClient, ChatMessage, ChatResponse, ChatResponseUpdate, TextContent, ai_function
from agent_framework_azure import AzureChatClient
@ai_function
def get_story_text() -> str:
"""Returns a story about Emily and David."""
return (
"Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change."
)
async def test_azure_openai_chat_client_response() -> None:
"""Test Azure OpenAI chat completion responses."""
azure_chat_client = AzureChatClient(deployment_name="gpt-4o")
assert isinstance(azure_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change.",
)
)
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = await azure_chat_client.get_response(messages=messages)
assert response is not None
assert isinstance(response, ChatResponse)
assert "scientists" in response.text
async def test_azure_openai_chat_client_response_tools() -> None:
"""Test AzureOpenAI chat completion responses."""
azure_chat_client = AzureChatClient(deployment_name="gpt-4o")
assert isinstance(azure_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = await azure_chat_client.get_response(
messages=messages,
tools=[get_story_text],
tool_choice="auto",
)
assert response is not None
assert isinstance(response, ChatResponse)
assert "scientists" in response.text
async def test_azure_openai_chat_client_streaming() -> None:
"""Test Azure OpenAI chat completion responses."""
azure_chat_client = AzureChatClient(deployment_name="gpt-4o")
assert isinstance(azure_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change.",
)
)
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = azure_chat_client.get_streaming_response(messages=messages)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert "scientists" in full_message
async def test_azure_openai_chat_client_streaming_tools() -> None:
"""Test AzureOpenAI chat completion responses."""
azure_chat_client = AzureChatClient(deployment_name="gpt-4o")
assert isinstance(azure_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = azure_chat_client.get_streaming_response(
messages=messages,
tools=[get_story_text],
tool_choice="auto",
)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert "scientists" in full_message
@@ -7,11 +7,15 @@ from unittest.mock import AsyncMock, MagicMock, patch
import openai
import pytest
from agent_framework import (
ChatClient,
ChatClientBase,
ChatMessage,
ChatResponse,
ChatResponseUpdate,
FunctionCallContent,
FunctionResultContent,
TextContent,
ai_function,
)
from agent_framework.exceptions import ServiceInitializationError, ServiceResponseException
from agent_framework.openai import (
@@ -32,6 +36,14 @@ from agent_framework_azure import AzureChatClient
# region Service Setup
skip_if_azure_integration_tests_disabled = pytest.mark.skipif(
os.getenv("RUN_INTEGRATION_TESTS", "false").lower() != "true"
or os.getenv("AZURE_OPENAI_ENDPOINT", "") in ("", "https://test-endpoint.com"),
reason="No real AZURE_OPENAI_ENDPOINT provided; skipping integration tests."
if os.getenv("RUN_INTEGRATION_TESTS", "false").lower() == "true"
else "Integration tests are disabled.",
)
def test_init(azure_openai_unit_test_env: dict[str, str]) -> None:
# Test successful initialization
@@ -618,3 +630,123 @@ async def test_cmc_streaming(
# To ensure consistency, we align the arguments here accordingly.
stream_options={"include_usage": True},
)
@ai_function
def get_story_text() -> str:
"""Returns a story about Emily and David."""
return (
"Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change."
)
@skip_if_azure_integration_tests_disabled
async def test_azure_openai_chat_client_response() -> None:
"""Test Azure OpenAI chat completion responses."""
azure_chat_client = AzureChatClient(deployment_name="gpt-4o")
assert isinstance(azure_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change.",
)
)
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = await azure_chat_client.get_response(messages=messages)
assert response is not None
assert isinstance(response, ChatResponse)
assert "scientists" in response.text
@skip_if_azure_integration_tests_disabled
async def test_azure_openai_chat_client_response_tools() -> None:
"""Test AzureOpenAI chat completion responses."""
azure_chat_client = AzureChatClient(deployment_name="gpt-4o")
assert isinstance(azure_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = await azure_chat_client.get_response(
messages=messages,
tools=[get_story_text],
tool_choice="auto",
)
assert response is not None
assert isinstance(response, ChatResponse)
assert "scientists" in response.text
@skip_if_azure_integration_tests_disabled
async def test_azure_openai_chat_client_streaming() -> None:
"""Test Azure OpenAI chat completion responses."""
azure_chat_client = AzureChatClient(deployment_name="gpt-4o")
assert isinstance(azure_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change.",
)
)
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = azure_chat_client.get_streaming_response(messages=messages)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert "scientists" in full_message
@skip_if_azure_integration_tests_disabled
async def test_azure_openai_chat_client_streaming_tools() -> None:
"""Test AzureOpenAI chat completion responses."""
azure_chat_client = AzureChatClient(deployment_name="gpt-4o")
assert isinstance(azure_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = azure_chat_client.get_streaming_response(
messages=messages,
tools=[get_story_text],
tool_choice="auto",
)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert "scientists" in full_message
+4 -3
View File
@@ -20,6 +20,7 @@ def override_env_param_dict(request: Any) -> dict[str, str]:
@fixture()
def foundry_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # type: ignore
"""Fixture to set environment variables for FoundrySettings."""
if exclude_list is None:
exclude_list = []
@@ -35,10 +36,10 @@ def foundry_unit_test_env(monkeypatch, exclude_list, override_env_param_dict):
env_vars.update(override_env_param_dict) # type: ignore
for key, value in env_vars.items():
if key not in exclude_list:
monkeypatch.setenv(key, value) # type: ignore
else:
if key in exclude_list:
monkeypatch.delenv(key, raising=False) # type: ignore
continue
monkeypatch.setenv(key, value) # type: ignore
return env_vars
@@ -1,112 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Annotated
from agent_framework import ChatClient, ChatMessage, ChatResponse, ChatResponseUpdate, TextContent
from pydantic import Field
from agent_framework_foundry import FoundryChatClient
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
return f"The weather in {location} is sunny with a high of 25°C."
async def test_foundry_chat_client_get_response() -> None:
"""Test Foundry Chat Client response."""
async with FoundryChatClient() as foundry_chat_client:
assert isinstance(foundry_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="The weather in Seattle is currently sunny with a high of 25°C. "
"It's a beautiful day for outdoor activities.",
)
)
messages.append(ChatMessage(role="user", text="What's the weather like today?"))
# Test that the client can be used to get a response
response = await foundry_chat_client.get_response(messages=messages)
assert response is not None
assert isinstance(response, ChatResponse)
assert any(word in response.text.lower() for word in ["sunny", "25"])
async def test_foundry_chat_client_get_response_tools() -> None:
"""Test Foundry Chat Client response with tools."""
async with FoundryChatClient() as foundry_chat_client:
assert isinstance(foundry_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="What's the weather like in Seattle?"))
# Test that the client can be used to get a response
response = await foundry_chat_client.get_response(
messages=messages,
tools=[get_weather],
tool_choice="auto",
)
assert response is not None
assert isinstance(response, ChatResponse)
assert any(word in response.text.lower() for word in ["sunny", "25"])
async def test_foundry_chat_client_streaming() -> None:
"""Test Foundry Chat Client streaming response."""
async with FoundryChatClient() as foundry_chat_client:
assert isinstance(foundry_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="The weather in Seattle is currently sunny with a high of 25°C. "
"It's a beautiful day for outdoor activities.",
)
)
messages.append(ChatMessage(role="user", text="What's the weather like today?"))
# Test that the client can be used to get a response
response = foundry_chat_client.get_streaming_response(messages=messages)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert any(word in full_message.lower() for word in ["sunny", "25"])
async def test_foundry_chat_client_streaming_tools() -> None:
"""Test Foundry Chat Client streaming response with tools."""
async with FoundryChatClient() as foundry_chat_client:
assert isinstance(foundry_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="What's the weather like in Seattle?"))
# Test that the client can be used to get a response
response = foundry_chat_client.get_streaming_response(
messages=messages,
tools=[get_weather],
tool_choice="auto",
)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert any(word in full_message.lower() for word in ["sunny", "25"])
@@ -1,13 +1,32 @@
# Copyright (c) Microsoft. All rights reserved.
import os
from typing import Annotated
from unittest.mock import MagicMock
import pytest
from agent_framework import ChatClient, ChatMessage, ChatOptions, ChatRole
from agent_framework import (
ChatClient,
ChatMessage,
ChatOptions,
ChatResponse,
ChatResponseUpdate,
ChatRole,
TextContent,
)
from agent_framework.exceptions import ServiceInitializationError
from pydantic import Field
from agent_framework_foundry import FoundryChatClient, FoundrySettings
skip_if_foundry_integration_tests_disabled = pytest.mark.skipif(
os.getenv("RUN_INTEGRATION_TESTS", "false").lower() != "true"
or os.getenv("FOUNDRY_PROJECT_ENDPOINT", "") in ("", "https://test-project.cognitiveservices.azure.com/"),
reason="No real FOUNDRY_PROJECT_ENDPOINT provided; skipping integration tests."
if os.getenv("RUN_INTEGRATION_TESTS", "false").lower() == "true"
else "Integration tests are disabled.",
)
def create_test_foundry_chat_client(
mock_ai_project_client: MagicMock,
@@ -18,7 +37,7 @@ def create_test_foundry_chat_client(
) -> FoundryChatClient:
"""Helper function to create FoundryChatClient instances for testing, bypassing Pydantic validation."""
if foundry_settings is None:
foundry_settings = FoundrySettings()
foundry_settings = FoundrySettings(env_file_path="test.env")
return FoundryChatClient.model_construct(
client=mock_ai_project_client,
@@ -140,8 +159,9 @@ async def test_foundry_chat_client_get_agent_id_or_create_create_new(
assert chat_client._should_delete_agent # type: ignore
@pytest.mark.parametrize("exclude_list", [["FOUNDRY_MODEL_DEPLOYMENT_NAME"]], indirect=True)
async def test_foundry_chat_client_get_agent_id_or_create_missing_model(
mock_ai_project_client: MagicMock,
mock_ai_project_client: MagicMock, foundry_unit_test_env: dict[str, str]
) -> None:
"""Test _get_agent_id_or_create when model_deployment_name is missing."""
chat_client = create_test_foundry_chat_client(mock_ai_project_client)
@@ -270,3 +290,111 @@ def test_foundry_chat_client_convert_function_results_to_tool_output_none(mock_a
assert run_id is None
assert tool_outputs is None
def get_weather(
location: Annotated[str, Field(description="The location to get the weather for.")],
) -> str:
"""Get the weather for a given location."""
return f"The weather in {location} is sunny with a high of 25°C."
@skip_if_foundry_integration_tests_disabled
async def test_foundry_chat_client_get_response() -> None:
"""Test Foundry Chat Client response."""
async with FoundryChatClient() as foundry_chat_client:
assert isinstance(foundry_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="The weather in Seattle is currently sunny with a high of 25°C. "
"It's a beautiful day for outdoor activities.",
)
)
messages.append(ChatMessage(role="user", text="What's the weather like today?"))
# Test that the client can be used to get a response
response = await foundry_chat_client.get_response(messages=messages)
assert response is not None
assert isinstance(response, ChatResponse)
assert any(word in response.text.lower() for word in ["sunny", "25"])
@skip_if_foundry_integration_tests_disabled
async def test_foundry_chat_client_get_response_tools() -> None:
"""Test Foundry Chat Client response with tools."""
async with FoundryChatClient() as foundry_chat_client:
assert isinstance(foundry_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="What's the weather like in Seattle?"))
# Test that the client can be used to get a response
response = await foundry_chat_client.get_response(
messages=messages,
tools=[get_weather],
tool_choice="auto",
)
assert response is not None
assert isinstance(response, ChatResponse)
assert any(word in response.text.lower() for word in ["sunny", "25"])
@skip_if_foundry_integration_tests_disabled
async def test_foundry_chat_client_streaming() -> None:
"""Test Foundry Chat Client streaming response."""
async with FoundryChatClient() as foundry_chat_client:
assert isinstance(foundry_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="The weather in Seattle is currently sunny with a high of 25°C. "
"It's a beautiful day for outdoor activities.",
)
)
messages.append(ChatMessage(role="user", text="What's the weather like today?"))
# Test that the client can be used to get a response
response = foundry_chat_client.get_streaming_response(messages=messages)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert any(word in full_message.lower() for word in ["sunny", "25"])
@skip_if_foundry_integration_tests_disabled
async def test_foundry_chat_client_streaming_tools() -> None:
"""Test Foundry Chat Client streaming response with tools."""
async with FoundryChatClient() as foundry_chat_client:
assert isinstance(foundry_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="What's the weather like in Seattle?"))
# Test that the client can be used to get a response
response = foundry_chat_client.get_streaming_response(
messages=messages,
tools=[get_weather],
tool_choice="auto",
)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert any(word in full_message.lower() for word in ["sunny", "25"])
+32 -47
View File
@@ -1,57 +1,42 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Any
from pydantic import BaseModel
from pytest import fixture
from agent_framework import ChatMessage
# region: Connector Settings fixtures
@fixture
def exclude_list(request: Any) -> list[str]:
"""Fixture that returns a list of environment variables to exclude."""
return request.param if hasattr(request, "param") else []
@fixture
def override_env_param_dict(request: Any) -> dict[str, str]:
"""Fixture that returns a dict of environment variables to override."""
return request.param if hasattr(request, "param") else {}
@fixture()
def openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # type: ignore
"""Fixture to set environment variables for OpenAISettings."""
if exclude_list is None:
exclude_list = []
if override_env_param_dict is None:
override_env_param_dict = {}
env_vars = {
"OPENAI_API_KEY": "test_api_key",
"OPENAI_ORG_ID": "test_org_id",
"OPENAI_RESPONSES_MODEL_ID": "test_responses_model_id",
"OPENAI_CHAT_MODEL_ID": "test_chat_model_id",
"OPENAI_TEXT_MODEL_ID": "test_text_model_id",
"OPENAI_EMBEDDING_MODEL_ID": "test_embedding_model_id",
"OPENAI_TEXT_TO_IMAGE_MODEL_ID": "test_text_to_image_model_id",
"OPENAI_AUDIO_TO_TEXT_MODEL_ID": "test_audio_to_text_model_id",
"OPENAI_TEXT_TO_AUDIO_MODEL_ID": "test_text_to_audio_model_id",
"OPENAI_REALTIME_MODEL_ID": "test_realtime_model_id",
}
env_vars.update(override_env_param_dict) # type: ignore
for key, value in env_vars.items():
if key not in exclude_list:
monkeypatch.setenv(key, value) # type: ignore
else:
monkeypatch.delenv(key, raising=False) # type: ignore
return env_vars
from agent_framework import AITool, ChatMessage, ai_function
@fixture(scope="function")
def chat_history() -> list[ChatMessage]:
return []
@fixture
def ai_tool() -> AITool:
"""Returns a generic AITool."""
class GenericTool(BaseModel):
name: str
description: str | None = None
additional_properties: dict[str, Any] | None = None
def parameters(self) -> dict[str, Any]:
"""Return the parameters of the tool as a JSON schema."""
return {
"name": {"type": "string"},
}
return GenericTool(name="generic_tool", description="A generic tool")
@fixture
def ai_function_tool() -> AITool:
"""Returns a executable AITool."""
@ai_function
def simple_function(x: int, y: int) -> int:
"""A simple function that adds two numbers."""
return x + y
return simple_function
@@ -1,120 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
from agent_framework import ChatClient, ChatMessage, ChatResponse, ChatResponseUpdate, TextContent, ai_function
from agent_framework.openai import OpenAIChatClient
@ai_function
def get_story_text() -> str:
"""Returns a story about Emily and David."""
return (
"Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change."
)
async def test_openai_chat_completion_response() -> None:
"""Test OpenAI chat completion responses."""
openai_chat_client = OpenAIChatClient(ai_model_id="gpt-4.1-mini")
assert isinstance(openai_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change.",
)
)
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = await openai_chat_client.get_response(messages=messages)
assert response is not None
assert isinstance(response, ChatResponse)
assert "scientists" in response.text
async def test_openai_chat_completion_response_tools() -> None:
"""Test OpenAI chat completion responses."""
openai_chat_client = OpenAIChatClient(ai_model_id="gpt-4.1-mini")
assert isinstance(openai_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = await openai_chat_client.get_response(
messages=messages,
tools=[get_story_text],
tool_choice="auto",
)
assert response is not None
assert isinstance(response, ChatResponse)
assert "scientists" in response.text
async def test_openai_chat_client_streaming() -> None:
"""Test Azure OpenAI chat completion responses."""
openai_chat_client = OpenAIChatClient(ai_model_id="gpt-4.1-mini")
assert isinstance(openai_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change.",
)
)
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = openai_chat_client.get_streaming_response(messages=messages)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert "scientists" in full_message
async def test_openai_chat_client_streaming_tools() -> None:
"""Test AzureOpenAI chat completion responses."""
openai_chat_client = OpenAIChatClient(ai_model_id="gpt-4.1-mini")
assert isinstance(openai_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = openai_chat_client.get_streaming_response(
messages=messages,
tools=[get_story_text],
tool_choice="auto",
)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert "scientists" in full_message
@@ -0,0 +1,51 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Any
from pytest import fixture
# region: Connector Settings fixtures
@fixture
def exclude_list(request: Any) -> list[str]:
"""Fixture that returns a list of environment variables to exclude."""
return request.param if hasattr(request, "param") else []
@fixture
def override_env_param_dict(request: Any) -> dict[str, str]:
"""Fixture that returns a dict of environment variables to override."""
return request.param if hasattr(request, "param") else {}
@fixture()
def openai_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # type: ignore
"""Fixture to set environment variables for OpenAISettings."""
if exclude_list is None:
exclude_list = []
if override_env_param_dict is None:
override_env_param_dict = {}
env_vars = {
"OPENAI_API_KEY": "test-dummy-key",
"OPENAI_ORG_ID": "test_org_id",
"OPENAI_RESPONSES_MODEL_ID": "test_responses_model_id",
"OPENAI_CHAT_MODEL_ID": "test_chat_model_id",
"OPENAI_TEXT_MODEL_ID": "test_text_model_id",
"OPENAI_EMBEDDING_MODEL_ID": "test_embedding_model_id",
"OPENAI_TEXT_TO_IMAGE_MODEL_ID": "test_text_to_image_model_id",
"OPENAI_AUDIO_TO_TEXT_MODEL_ID": "test_audio_to_text_model_id",
"OPENAI_TEXT_TO_AUDIO_MODEL_ID": "test_text_to_audio_model_id",
"OPENAI_REALTIME_MODEL_ID": "test_realtime_model_id",
}
env_vars.update(override_env_param_dict) # type: ignore
for key, value in env_vars.items():
if key in exclude_list:
monkeypatch.delenv(key, raising=False) # type: ignore
continue
monkeypatch.setenv(key, value) # type: ignore
return env_vars
@@ -0,0 +1,233 @@
# Copyright (c) Microsoft. All rights reserved.
import os
import pytest
from agent_framework import ChatClient, ChatMessage, ChatResponse, ChatResponseUpdate, TextContent, ai_function
from agent_framework.exceptions import ServiceInitializationError
from agent_framework.openai import OpenAIChatClient
skip_if_openai_integration_tests_disabled = pytest.mark.skipif(
os.getenv("RUN_INTEGRATION_TESTS", "false").lower() != "true"
or os.getenv("OPENAI_API_KEY", "") in ("", "test-dummy-key"),
reason="No real OPENAI_API_KEY provided; skipping integration tests."
if os.getenv("RUN_INTEGRATION_TESTS", "false").lower() == "true"
else "Integration tests are disabled.",
)
def test_init(openai_unit_test_env: dict[str, str]) -> None:
# Test successful initialization
open_ai_chat_completion = OpenAIChatClient()
assert open_ai_chat_completion.ai_model_id == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
assert isinstance(open_ai_chat_completion, ChatClient)
def test_init_validation_fail() -> None:
# Test successful initialization
with pytest.raises(ServiceInitializationError):
OpenAIChatClient(api_key="34523", ai_model_id={"test": "dict"}) # type: ignore
def test_init_ai_model_id_constructor(openai_unit_test_env: dict[str, str]) -> None:
# Test successful initialization
ai_model_id = "test_model_id"
open_ai_chat_completion = OpenAIChatClient(ai_model_id=ai_model_id)
assert open_ai_chat_completion.ai_model_id == ai_model_id
assert isinstance(open_ai_chat_completion, ChatClient)
def test_init_with_default_header(openai_unit_test_env: dict[str, str]) -> None:
default_headers = {"X-Unit-Test": "test-guid"}
# Test successful initialization
open_ai_chat_completion = OpenAIChatClient(
default_headers=default_headers,
)
assert open_ai_chat_completion.ai_model_id == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
assert isinstance(open_ai_chat_completion, ChatClient)
# Assert that the default header we added is present in the client's default headers
for key, value in default_headers.items():
assert key in open_ai_chat_completion.client.default_headers
assert open_ai_chat_completion.client.default_headers[key] == value
@pytest.mark.parametrize("exclude_list", [["OPENAI_CHAT_MODEL_ID"]], indirect=True)
def test_init_with_empty_model_id(openai_unit_test_env: dict[str, str]) -> None:
with pytest.raises(ServiceInitializationError):
OpenAIChatClient(
env_file_path="test.env",
)
@pytest.mark.parametrize("exclude_list", [["OPENAI_API_KEY"]], indirect=True)
def test_init_with_empty_api_key(openai_unit_test_env: dict[str, str]) -> None:
ai_model_id = "test_model_id"
with pytest.raises(ServiceInitializationError):
OpenAIChatClient(
ai_model_id=ai_model_id,
env_file_path="test.env",
)
def test_serialize(openai_unit_test_env: dict[str, str]) -> None:
default_headers = {"X-Unit-Test": "test-guid"}
settings = {
"ai_model_id": openai_unit_test_env["OPENAI_CHAT_MODEL_ID"],
"api_key": openai_unit_test_env["OPENAI_API_KEY"],
"default_headers": default_headers,
}
open_ai_chat_completion = OpenAIChatClient.from_dict(settings)
dumped_settings = open_ai_chat_completion.to_dict()
assert dumped_settings["ai_model_id"] == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
assert dumped_settings["api_key"] == openai_unit_test_env["OPENAI_API_KEY"]
# Assert that the default header we added is present in the dumped_settings default headers
for key, value in default_headers.items():
assert key in dumped_settings["default_headers"]
assert dumped_settings["default_headers"][key] == value
# Assert that the 'User-Agent' header is not present in the dumped_settings default headers
assert "User-Agent" not in dumped_settings["default_headers"]
def test_serialize_with_org_id(openai_unit_test_env: dict[str, str]) -> None:
settings = {
"ai_model_id": openai_unit_test_env["OPENAI_CHAT_MODEL_ID"],
"api_key": openai_unit_test_env["OPENAI_API_KEY"],
"org_id": openai_unit_test_env["OPENAI_ORG_ID"],
}
open_ai_chat_completion = OpenAIChatClient.from_dict(settings)
dumped_settings = open_ai_chat_completion.to_dict()
assert dumped_settings["ai_model_id"] == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
assert dumped_settings["api_key"] == openai_unit_test_env["OPENAI_API_KEY"]
assert dumped_settings["org_id"] == openai_unit_test_env["OPENAI_ORG_ID"]
# Assert that the 'User-Agent' header is not present in the dumped_settings default headers
assert "User-Agent" not in dumped_settings["default_headers"]
@ai_function
def get_story_text() -> str:
"""Returns a story about Emily and David."""
return (
"Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change."
)
@skip_if_openai_integration_tests_disabled
async def test_openai_chat_completion_response() -> None:
"""Test OpenAI chat completion responses."""
openai_chat_client = OpenAIChatClient(ai_model_id="gpt-4.1-mini")
assert isinstance(openai_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change.",
)
)
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = await openai_chat_client.get_response(messages=messages)
assert response is not None
assert isinstance(response, ChatResponse)
assert "scientists" in response.text
@skip_if_openai_integration_tests_disabled
async def test_openai_chat_completion_response_tools() -> None:
"""Test OpenAI chat completion responses."""
openai_chat_client = OpenAIChatClient(ai_model_id="gpt-4.1-mini")
assert isinstance(openai_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = await openai_chat_client.get_response(
messages=messages,
tools=[get_story_text],
tool_choice="auto",
)
assert response is not None
assert isinstance(response, ChatResponse)
assert "scientists" in response.text
@skip_if_openai_integration_tests_disabled
async def test_openai_chat_client_streaming() -> None:
"""Test Azure OpenAI chat completion responses."""
openai_chat_client = OpenAIChatClient(ai_model_id="gpt-4.1-mini")
assert isinstance(openai_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(
ChatMessage(
role="user",
text="Emily and David, two passionate scientists, met during a research expedition to Antarctica. "
"Bonded by their love for the natural world and shared curiosity, they uncovered a "
"groundbreaking phenomenon in glaciology that could potentially reshape our understanding "
"of climate change.",
)
)
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = openai_chat_client.get_streaming_response(messages=messages)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert "scientists" in full_message
@skip_if_openai_integration_tests_disabled
async def test_openai_chat_client_streaming_tools() -> None:
"""Test AzureOpenAI chat completion responses."""
openai_chat_client = OpenAIChatClient(ai_model_id="gpt-4.1-mini")
assert isinstance(openai_chat_client, ChatClient)
messages: list[ChatMessage] = []
messages.append(ChatMessage(role="user", text="who are Emily and David?"))
# Test that the client can be used to get a response
response = openai_chat_client.get_streaming_response(
messages=messages,
tools=[get_story_text],
tool_choice="auto",
)
full_message: str = ""
async for chunk in response:
assert chunk is not None
assert isinstance(chunk, ChatResponseUpdate)
for content in chunk.contents:
if isinstance(content, TextContent) and content.text:
full_message += content.text
assert "scientists" in full_message
@@ -1,38 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
from typing import Any
from pydantic import BaseModel
from pytest import fixture
from agent_framework import AITool, ai_function
@fixture
def ai_tool() -> AITool:
"""Returns a generic AITool."""
class GenericTool(BaseModel):
name: str
description: str | None = None
additional_properties: dict[str, Any] | None = None
def parameters(self) -> dict[str, Any]:
"""Return the parameters of the tool as a JSON schema."""
return {
"name": {"type": "string"},
}
return GenericTool(name="generic_tool", description="A generic tool")
@fixture
def ai_function_tool() -> AITool:
"""Returns a executable AITool."""
@ai_function
def simple_function(x: int, y: int) -> int:
"""A simple function that adds two numbers."""
return x + y
return simple_function
@@ -1,9 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
def test_azure():
try:
from agent_framework.azure import __version__
except ImportError:
__version__ = None
assert __version__ is not None
@@ -1,103 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
import pytest
from agent_framework import ChatClient
from agent_framework.exceptions import ServiceInitializationError
from agent_framework.openai import OpenAIChatClient
def test_init(openai_unit_test_env: dict[str, str]) -> None:
# Test successful initialization
open_ai_chat_completion = OpenAIChatClient()
assert open_ai_chat_completion.ai_model_id == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
assert isinstance(open_ai_chat_completion, ChatClient)
def test_init_validation_fail() -> None:
# Test successful initialization
with pytest.raises(ServiceInitializationError):
OpenAIChatClient(api_key="34523", ai_model_id={"test": "dict"}) # type: ignore
def test_init_ai_model_id_constructor(openai_unit_test_env: dict[str, str]) -> None:
# Test successful initialization
ai_model_id = "test_model_id"
open_ai_chat_completion = OpenAIChatClient(ai_model_id=ai_model_id)
assert open_ai_chat_completion.ai_model_id == ai_model_id
assert isinstance(open_ai_chat_completion, ChatClient)
def test_init_with_default_header(openai_unit_test_env: dict[str, str]) -> None:
default_headers = {"X-Unit-Test": "test-guid"}
# Test successful initialization
open_ai_chat_completion = OpenAIChatClient(
default_headers=default_headers,
)
assert open_ai_chat_completion.ai_model_id == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
assert isinstance(open_ai_chat_completion, ChatClient)
# Assert that the default header we added is present in the client's default headers
for key, value in default_headers.items():
assert key in open_ai_chat_completion.client.default_headers
assert open_ai_chat_completion.client.default_headers[key] == value
@pytest.mark.parametrize("exclude_list", [["OPENAI_CHAT_MODEL_ID"]], indirect=True)
def test_init_with_empty_model_id(openai_unit_test_env: dict[str, str]) -> None:
with pytest.raises(ServiceInitializationError):
OpenAIChatClient(
env_file_path="test.env",
)
@pytest.mark.parametrize("exclude_list", [["OPENAI_API_KEY"]], indirect=True)
def test_init_with_empty_api_key(openai_unit_test_env: dict[str, str]) -> None:
ai_model_id = "test_model_id"
with pytest.raises(ServiceInitializationError):
OpenAIChatClient(
ai_model_id=ai_model_id,
env_file_path="test.env",
)
def test_serialize(openai_unit_test_env: dict[str, str]) -> None:
default_headers = {"X-Unit-Test": "test-guid"}
settings = {
"ai_model_id": openai_unit_test_env["OPENAI_CHAT_MODEL_ID"],
"api_key": openai_unit_test_env["OPENAI_API_KEY"],
"default_headers": default_headers,
}
open_ai_chat_completion = OpenAIChatClient.from_dict(settings)
dumped_settings = open_ai_chat_completion.to_dict()
assert dumped_settings["ai_model_id"] == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
assert dumped_settings["api_key"] == openai_unit_test_env["OPENAI_API_KEY"]
# Assert that the default header we added is present in the dumped_settings default headers
for key, value in default_headers.items():
assert key in dumped_settings["default_headers"]
assert dumped_settings["default_headers"][key] == value
# Assert that the 'User-Agent' header is not present in the dumped_settings default headers
assert "User-Agent" not in dumped_settings["default_headers"]
def test_serialize_with_org_id(openai_unit_test_env: dict[str, str]) -> None:
settings = {
"ai_model_id": openai_unit_test_env["OPENAI_CHAT_MODEL_ID"],
"api_key": openai_unit_test_env["OPENAI_API_KEY"],
"org_id": openai_unit_test_env["OPENAI_ORG_ID"],
}
open_ai_chat_completion = OpenAIChatClient.from_dict(settings)
dumped_settings = open_ai_chat_completion.to_dict()
assert dumped_settings["ai_model_id"] == openai_unit_test_env["OPENAI_CHAT_MODEL_ID"]
assert dumped_settings["api_key"] == openai_unit_test_env["OPENAI_API_KEY"]
assert dumped_settings["org_id"] == openai_unit_test_env["OPENAI_ORG_ID"]
# Assert that the 'User-Agent' header is not present in the dumped_settings default headers
assert "User-Agent" not in dumped_settings["default_headers"]
@@ -1,8 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
from agent_framework import __version__
def test_version():
assert __version__ is not None