mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
1. users may want to list_artifacts in callbacks 2. save/load artifacts are already in callback_context PiperOrigin-RevId: 783399941
170 lines
6.1 KiB
Python
170 lines
6.1 KiB
Python
# Copyright 2025 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Tests for the CallbackContext class."""
|
|
|
|
from unittest.mock import AsyncMock
|
|
from unittest.mock import MagicMock
|
|
|
|
from google.adk.agents.callback_context import CallbackContext
|
|
from google.adk.tools.tool_context import ToolContext
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_invocation_context():
|
|
"""Create a mock invocation context for testing."""
|
|
mock_context = MagicMock()
|
|
mock_context.invocation_id = "test-invocation-id"
|
|
mock_context.agent.name = "test-agent-name"
|
|
mock_context.session.state = {"key1": "value1", "key2": "value2"}
|
|
mock_context.session.id = "test-session-id"
|
|
mock_context.app_name = "test-app"
|
|
mock_context.user_id = "test-user"
|
|
return mock_context
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_artifact_service():
|
|
"""Create a mock artifact service for testing."""
|
|
mock_service = AsyncMock()
|
|
mock_service.list_artifact_keys.return_value = [
|
|
"file1.txt",
|
|
"file2.txt",
|
|
"file3.txt",
|
|
]
|
|
return mock_service
|
|
|
|
|
|
@pytest.fixture
|
|
def callback_context_with_artifact_service(
|
|
mock_invocation_context, mock_artifact_service
|
|
):
|
|
"""Create a CallbackContext with a mock artifact service."""
|
|
mock_invocation_context.artifact_service = mock_artifact_service
|
|
return CallbackContext(mock_invocation_context)
|
|
|
|
|
|
@pytest.fixture
|
|
def callback_context_without_artifact_service(mock_invocation_context):
|
|
"""Create a CallbackContext without an artifact service."""
|
|
mock_invocation_context.artifact_service = None
|
|
return CallbackContext(mock_invocation_context)
|
|
|
|
|
|
class TestCallbackContextListArtifacts:
|
|
"""Test the list_artifacts method in CallbackContext."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_artifacts_returns_artifact_keys(
|
|
self, callback_context_with_artifact_service, mock_artifact_service
|
|
):
|
|
"""Test that list_artifacts returns the artifact keys from the service."""
|
|
result = await callback_context_with_artifact_service.list_artifacts()
|
|
|
|
assert result == ["file1.txt", "file2.txt", "file3.txt"]
|
|
mock_artifact_service.list_artifact_keys.assert_called_once_with(
|
|
app_name="test-app",
|
|
user_id="test-user",
|
|
session_id="test-session-id",
|
|
)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_artifacts_returns_empty_list(
|
|
self, callback_context_with_artifact_service, mock_artifact_service
|
|
):
|
|
"""Test that list_artifacts returns an empty list when no artifacts exist."""
|
|
mock_artifact_service.list_artifact_keys.return_value = []
|
|
|
|
result = await callback_context_with_artifact_service.list_artifacts()
|
|
|
|
assert result == []
|
|
mock_artifact_service.list_artifact_keys.assert_called_once_with(
|
|
app_name="test-app",
|
|
user_id="test-user",
|
|
session_id="test-session-id",
|
|
)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_artifacts_raises_value_error_when_service_is_none(
|
|
self, callback_context_without_artifact_service
|
|
):
|
|
"""Test that list_artifacts raises ValueError when artifact service is None."""
|
|
with pytest.raises(
|
|
ValueError, match="Artifact service is not initialized."
|
|
):
|
|
await callback_context_without_artifact_service.list_artifacts()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_artifacts_passes_through_service_exceptions(
|
|
self, callback_context_with_artifact_service, mock_artifact_service
|
|
):
|
|
"""Test that list_artifacts passes through exceptions from the artifact service."""
|
|
mock_artifact_service.list_artifact_keys.side_effect = Exception(
|
|
"Service error"
|
|
)
|
|
|
|
with pytest.raises(Exception, match="Service error"):
|
|
await callback_context_with_artifact_service.list_artifacts()
|
|
|
|
|
|
class TestToolContextListArtifacts:
|
|
"""Test that list_artifacts is available in ToolContext through inheritance."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_tool_context_inherits_list_artifacts(
|
|
self, mock_invocation_context, mock_artifact_service
|
|
):
|
|
"""Test that ToolContext inherits the list_artifacts method from CallbackContext."""
|
|
mock_invocation_context.artifact_service = mock_artifact_service
|
|
tool_context = ToolContext(mock_invocation_context)
|
|
|
|
result = await tool_context.list_artifacts()
|
|
|
|
assert result == ["file1.txt", "file2.txt", "file3.txt"]
|
|
mock_artifact_service.list_artifact_keys.assert_called_once_with(
|
|
app_name="test-app",
|
|
user_id="test-user",
|
|
session_id="test-session-id",
|
|
)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_tool_context_list_artifacts_raises_value_error_when_service_is_none(
|
|
self, mock_invocation_context
|
|
):
|
|
"""Test that ToolContext's list_artifacts raises ValueError when artifact service is None."""
|
|
mock_invocation_context.artifact_service = None
|
|
tool_context = ToolContext(mock_invocation_context)
|
|
|
|
with pytest.raises(
|
|
ValueError, match="Artifact service is not initialized."
|
|
):
|
|
await tool_context.list_artifacts()
|
|
|
|
def test_tool_context_has_list_artifacts_method(self):
|
|
"""Test that ToolContext has the list_artifacts method available."""
|
|
assert hasattr(ToolContext, "list_artifacts")
|
|
assert callable(getattr(ToolContext, "list_artifacts"))
|
|
|
|
def test_callback_context_has_list_artifacts_method(self):
|
|
"""Test that CallbackContext has the list_artifacts method available."""
|
|
assert hasattr(CallbackContext, "list_artifacts")
|
|
assert callable(getattr(CallbackContext, "list_artifacts"))
|
|
|
|
def test_tool_context_shares_same_list_artifacts_method_with_callback_context(
|
|
self,
|
|
):
|
|
"""Test that ToolContext and CallbackContext share the same list_artifacts method."""
|
|
assert ToolContext.list_artifacts is CallbackContext.list_artifacts
|