mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
8091d052d8
Updates third-party dev dependencies across the Python workspace and validates that all runtime dependency bounds still hold at both ends. Dev dependency bumps (root, lab, declarative, durabletask): - uv 0.11.6 -> 0.11.17, ruff 0.15.8 -> 0.15.15, pytest-asyncio 1.3.0 -> 1.4.0, mcp 1.27.0 -> 1.27.2, azure-monitor-opentelemetry 1.8.7 -> 1.8.8, poethepoet 0.42.1 -> 0.46.0, prek 0.3.9 -> 0.4.3, types-python-dateutil and types-PyYaml stub bumps. - Transitive Dependabot items swept via lock: idna 3.11 -> 3.17, pip 26.0.1 -> 26.1.2. Deliberately excluded: - opentelemetry-sdk stays 1.40.0: azure-monitor-opentelemetry (incl. 1.8.8) hard-pins opentelemetry-sdk==1.40. - mypy stays 1.20.0 and pyright stays 1.1.408: the 2.1.0 / 1.1.409 bumps introduce new diagnostics that fail type checking and need dedicated PRs. - rich kept as a range: agentlightning (lab[lightning]) forces rich==13.9.4. Code/formatting changes driven by the ruff upgrade: - devui lifespan now uses try/finally so shutdown cleanup always runs (ruff RUF075). - Removed unused TYPE_CHECKING imports in core and foundry flagged by ruff 0.15.15. - Reapplied ruff 0.15.15 formatting to the files it changed. Validation: validate-dependency-bounds-test "*" passes (31/31 lower + 31/31 upper); typing 62/62; lint 31/31; devui tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
99 lines
4.1 KiB
Python
99 lines
4.1 KiB
Python
# Copyright (c) Microsoft. All rights reserved.
|
|
|
|
"""Unit tests for _resolve_toolbox_endpoint() in the foundry-hosted-agents response samples.
|
|
|
|
Covers both 04_foundry_toolbox/main.py and 06_files/main.py which share the same
|
|
implementation of _resolve_toolbox_endpoint().
|
|
"""
|
|
|
|
import importlib
|
|
import importlib.util
|
|
import sys
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stub out packages unavailable in the unit-test environment so that importing
|
|
# the sample modules does not fail.
|
|
# ---------------------------------------------------------------------------
|
|
_MISSING_MODULES = (
|
|
"agent_framework_foundry_hosting",
|
|
"azure.ai.agentserver",
|
|
"azure.ai.agentserver.responses",
|
|
)
|
|
for _mod_name in _MISSING_MODULES:
|
|
sys.modules.setdefault(_mod_name, MagicMock())
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Load the two sample modules by file path to avoid needing them on sys.path.
|
|
# ---------------------------------------------------------------------------
|
|
_RESPONSES_DIR = (
|
|
Path(__file__).parent.parent.parent.parent / "samples" / "04-hosting" / "foundry-hosted-agents" / "responses"
|
|
)
|
|
|
|
|
|
def _load_sample(subdir: str, module_alias: str):
|
|
spec = importlib.util.spec_from_file_location(module_alias, _RESPONSES_DIR / subdir / "main.py")
|
|
mod = importlib.util.module_from_spec(spec) # type: ignore[arg-type]
|
|
spec.loader.exec_module(mod) # type: ignore[union-attr]
|
|
return mod
|
|
|
|
|
|
_toolbox_mod = _load_sample("04_foundry_toolbox", "foundry_toolbox_main")
|
|
_files_mod = _load_sample("06_files", "files_main")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Parameterise over both modules so the same test cases run for each.
|
|
# ---------------------------------------------------------------------------
|
|
@pytest.fixture(params=["04_foundry_toolbox", "06_files"])
|
|
def resolve_endpoint(request):
|
|
"""Return _resolve_toolbox_endpoint from the requested sample module."""
|
|
mod = _toolbox_mod if request.param == "04_foundry_toolbox" else _files_mod
|
|
return mod._resolve_toolbox_endpoint
|
|
|
|
|
|
class TestResolveToolboxEndpoint:
|
|
def test_explicit_endpoint_returned_as_is(self, resolve_endpoint, monkeypatch: pytest.MonkeyPatch):
|
|
monkeypatch.setenv("FOUNDRY_TOOLBOX_ENDPOINT", "https://example.com/mcp")
|
|
monkeypatch.delenv("FOUNDRY_PROJECT_ENDPOINT", raising=False)
|
|
monkeypatch.delenv("TOOLBOX_NAME", raising=False)
|
|
|
|
assert resolve_endpoint() == "https://example.com/mcp"
|
|
|
|
def test_empty_string_raises_value_error(self, resolve_endpoint, monkeypatch: pytest.MonkeyPatch):
|
|
monkeypatch.setenv("FOUNDRY_TOOLBOX_ENDPOINT", "")
|
|
|
|
with pytest.raises(ValueError, match="FOUNDRY_TOOLBOX_ENDPOINT is set but empty"):
|
|
resolve_endpoint()
|
|
|
|
def test_fallback_constructs_url_from_project_vars(self, resolve_endpoint, monkeypatch: pytest.MonkeyPatch):
|
|
monkeypatch.delenv("FOUNDRY_TOOLBOX_ENDPOINT", raising=False)
|
|
monkeypatch.setenv("FOUNDRY_PROJECT_ENDPOINT", "https://project.azure.com/")
|
|
monkeypatch.setenv("TOOLBOX_NAME", "my-toolbox")
|
|
|
|
result = resolve_endpoint()
|
|
|
|
assert result == "https://project.azure.com/toolsets/my-toolbox/mcp?api-version=v1"
|
|
|
|
def test_fallback_strips_trailing_slash_from_project_endpoint(
|
|
self, resolve_endpoint, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
monkeypatch.delenv("FOUNDRY_TOOLBOX_ENDPOINT", raising=False)
|
|
monkeypatch.setenv("FOUNDRY_PROJECT_ENDPOINT", "https://project.azure.com///")
|
|
monkeypatch.setenv("TOOLBOX_NAME", "my-toolbox")
|
|
|
|
result = resolve_endpoint()
|
|
|
|
assert result == "https://project.azure.com/toolsets/my-toolbox/mcp?api-version=v1"
|
|
|
|
def test_neither_variable_group_set_raises_key_error(self, resolve_endpoint, monkeypatch: pytest.MonkeyPatch):
|
|
monkeypatch.delenv("FOUNDRY_TOOLBOX_ENDPOINT", raising=False)
|
|
monkeypatch.delenv("FOUNDRY_PROJECT_ENDPOINT", raising=False)
|
|
monkeypatch.delenv("TOOLBOX_NAME", raising=False)
|
|
|
|
with pytest.raises(KeyError):
|
|
resolve_endpoint()
|