212 lines
7.4 KiB
Python
212 lines
7.4 KiB
Python
"""Synchronous end-to-end traces for the Google ADK integration.
|
|
|
|
Mirrors the AgentCore ``test_sync.py`` class layout: ``TestSimpleApp``,
|
|
``TestToolApp``, ``TestMultipleToolsApp``, ``TestDeepEvalFeatures``.
|
|
Each test produces a real trace via the ADK ``InMemoryRunner`` (which
|
|
runs the agent on Gemini under the hood) and asserts its shape against
|
|
a JSON schema in ``schemas/``.
|
|
|
|
Schema regeneration: ``GENERATE_SCHEMAS=true pytest tests/test_integrations/test_googleadk/test_sync.py``.
|
|
See ``schemas/README.md`` for the full workflow.
|
|
|
|
Skipped without ``GOOGLE_API_KEY`` — the underlying Gemini call would
|
|
fail authentication otherwise. Span-level configuration migrates to
|
|
per-call ``with next_*_span(...)`` blocks; ``init_*_googleadk(...)``
|
|
carries trace-level kwargs only.
|
|
"""
|
|
|
|
import os
|
|
|
|
import pytest
|
|
|
|
from deepeval.metrics import AnswerRelevancyMetric
|
|
from deepeval.tracing import next_agent_span, next_llm_span, next_tool_span
|
|
|
|
from tests.test_integrations.test_googleadk.apps.googleadk_simple_app import (
|
|
init_simple_googleadk,
|
|
invoke_simple_agent,
|
|
)
|
|
from tests.test_integrations.test_googleadk.apps.googleadk_tool_app import (
|
|
init_tool_googleadk,
|
|
invoke_tool_agent,
|
|
)
|
|
from tests.test_integrations.test_googleadk.apps.googleadk_multiple_tools_app import (
|
|
init_multiple_tools_googleadk,
|
|
invoke_multiple_tools_agent,
|
|
)
|
|
from tests.test_integrations.test_googleadk.apps.googleadk_eval_app import (
|
|
init_evals_googleadk,
|
|
invoke_evals_agent,
|
|
)
|
|
from tests.test_integrations.test_googleadk.conftest import trace_test
|
|
|
|
|
|
pytestmark = pytest.mark.skipif(
|
|
not os.getenv("GOOGLE_API_KEY"),
|
|
reason="GOOGLE_API_KEY is required to run Google ADK tests against Gemini.",
|
|
)
|
|
|
|
|
|
class TestSimpleApp:
|
|
|
|
@trace_test("googleadk_simple_schema.json")
|
|
def test_simple_greeting(self):
|
|
invoke_func = init_simple_googleadk(
|
|
name="googleadk-simple-test",
|
|
tags=["googleadk", "simple"],
|
|
metadata={"test_type": "simple"},
|
|
thread_id="simple-123",
|
|
user_id="test-user",
|
|
)
|
|
|
|
result = invoke_simple_agent(
|
|
"Say hello in exactly three words.",
|
|
invoke_func=invoke_func,
|
|
)
|
|
|
|
assert result is not None
|
|
assert len(result) > 0
|
|
|
|
|
|
class TestToolApp:
|
|
|
|
@trace_test("googleadk_tool_schema.json")
|
|
def test_tool_calculation(self):
|
|
invoke_func = init_tool_googleadk(
|
|
name="googleadk-tool-test",
|
|
tags=["googleadk", "tool"],
|
|
metadata={"test_type": "tool"},
|
|
thread_id="tool-123",
|
|
user_id="test-user",
|
|
)
|
|
|
|
result = invoke_tool_agent(
|
|
"What is 7 multiplied by 8?",
|
|
invoke_func=invoke_func,
|
|
)
|
|
|
|
assert result is not None
|
|
assert "56" in result
|
|
|
|
@trace_test("googleadk_tool_metric_collection_schema.json")
|
|
def test_tool_metric_collection(self):
|
|
"""Tool-level metric_collection now flows through
|
|
``with next_tool_span(metric_collection=...)`` at the call
|
|
site instead of a top-level ``tool_metric_collection_map``
|
|
kwarg on ``instrument_google_adk``.
|
|
|
|
``next_tool_span`` is one-shot — it hits the FIRST tool span
|
|
emitted inside the ``with`` block, which matches the
|
|
single-tool-call test below."""
|
|
invoke_func = init_tool_googleadk(
|
|
name="googleadk-tool-metric-test",
|
|
tags=["googleadk", "tool", "metric-collection"],
|
|
metadata={"test_type": "tool_metric_collection"},
|
|
thread_id="tool-metric-123",
|
|
user_id="test-user",
|
|
)
|
|
|
|
with next_tool_span(metric_collection="calculator-metrics"):
|
|
result = invoke_tool_agent(
|
|
"What is 15 plus 25?",
|
|
invoke_func=invoke_func,
|
|
)
|
|
|
|
assert result is not None
|
|
assert "40" in result
|
|
|
|
|
|
class TestMultipleToolsApp:
|
|
|
|
@trace_test("googleadk_multiple_tools_weather_schema.json")
|
|
def test_multiple_tools_weather_only(self):
|
|
invoke_func = init_multiple_tools_googleadk(
|
|
name="googleadk-multiple-tools-weather",
|
|
tags=["googleadk", "multiple-tools", "weather"],
|
|
metadata={"test_type": "multiple_tools_weather"},
|
|
thread_id="multiple-tools-weather-123",
|
|
user_id="test-user",
|
|
)
|
|
|
|
result = invoke_multiple_tools_agent(
|
|
"Use the get_weather tool exactly once to get the weather in Tokyo.",
|
|
invoke_func=invoke_func,
|
|
)
|
|
|
|
assert result is not None
|
|
assert "72" in result or "sunny" in result.lower()
|
|
|
|
@trace_test("googleadk_multiple_tools_time_schema.json")
|
|
def test_multiple_tools_time_only(self):
|
|
invoke_func = init_multiple_tools_googleadk(
|
|
name="googleadk-multiple-tools-time",
|
|
tags=["googleadk", "multiple-tools", "time"],
|
|
metadata={"test_type": "multiple_tools_time"},
|
|
thread_id="multiple-tools-time-123",
|
|
user_id="test-user",
|
|
)
|
|
|
|
result = invoke_multiple_tools_agent(
|
|
"Use the get_time tool exactly once to get the current time in London.",
|
|
invoke_func=invoke_func,
|
|
)
|
|
|
|
assert result is not None
|
|
assert "7:00" in result or "GMT" in result
|
|
|
|
@trace_test("googleadk_parallel_tools_schema.json")
|
|
def test_parallel_tool_calls(self):
|
|
invoke_func = init_multiple_tools_googleadk(
|
|
name="googleadk-parallel-tools",
|
|
tags=["googleadk", "parallel-tools"],
|
|
metadata={"test_type": "parallel_tools"},
|
|
thread_id="parallel-tools-123",
|
|
user_id="test-user",
|
|
)
|
|
|
|
result = invoke_multiple_tools_agent(
|
|
"Use both the get_weather tool AND the get_time tool for Paris. "
|
|
"Call both tools exactly once each.",
|
|
invoke_func=invoke_func,
|
|
)
|
|
|
|
assert result is not None
|
|
assert "62" in result or "cloudy" in result.lower()
|
|
assert "8:00" in result or "CET" in result
|
|
|
|
|
|
class TestDeepEvalFeatures:
|
|
"""Span-level configuration migrates to per-call ``with next_*_span(...)``.
|
|
|
|
Previously ``init_evals_googleadk`` accepted
|
|
``agent_metric_collection`` / ``llm_metric_collection`` /
|
|
``tool_metric_collection_map`` / ``agent_metrics`` and stamped them
|
|
onto every span at instrument time. Now the test wraps the agent
|
|
invocation in stacked ``with`` blocks that stage values for the
|
|
next agent / LLM / tool span emitted inside the wrapper. The
|
|
``special_tool`` itself uses ``update_current_span(...)`` from
|
|
inside its body for its own metric collection — handled in
|
|
``apps/googleadk_eval_app.py``."""
|
|
|
|
@trace_test("googleadk_features_sync.json")
|
|
def test_full_features_sync(self):
|
|
invoke_func = init_evals_googleadk(
|
|
name="googleadk-full-features-sync",
|
|
tags=["googleadk", "features", "sync"],
|
|
metadata={"env": "testing", "priority": "high"},
|
|
thread_id="thread-sync-features-001",
|
|
user_id="user-sync-001",
|
|
metric_collection="trace_metrics_override_v1",
|
|
)
|
|
|
|
with next_agent_span(
|
|
metric_collection="agent_metrics_v1",
|
|
metrics=[AnswerRelevancyMetric()],
|
|
), next_llm_span(metric_collection="llm_metrics_v1"):
|
|
result = invoke_evals_agent(
|
|
"Use the special_tool to process 'Sync Data'",
|
|
invoke_func=invoke_func,
|
|
)
|
|
|
|
assert result is not None
|