Files
wehub-resource-sync ec2b666284
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:25:13 +08:00

211 lines
7.1 KiB
Python

# Copyright 2026 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.
from __future__ import annotations
from unittest.mock import Mock
from a2a.types import TaskArtifactUpdateEvent
from a2a.types import TaskStatusUpdateEvent
from google.adk.a2a import _compat
from google.adk.a2a.converters.from_adk_event import convert_event_to_a2a_events
from google.adk.events import event_actions
from google.adk.events.event import Event
from google.genai import types as genai_types
import pytest
class TestFromAdk:
"""Test suite for from_adk functions."""
def setup_method(self):
"""Set up test fixtures."""
self.mock_event = Mock(spec=Event)
self.mock_event.id = "test-event-id"
self.mock_event.invocation_id = "test-invocation-id"
self.mock_event.author = "test-author"
self.mock_event.branch = None
self.mock_event.content = None
self.mock_event.error_code = None
self.mock_event.error_message = None
self.mock_event.grounding_metadata = None
self.mock_event.citation_metadata = None
self.mock_event.custom_metadata = None
self.mock_event.usage_metadata = None
self.mock_event.actions = None
self.mock_event.partial = True
self.mock_event.long_running_tool_ids = None
def test_convert_event_to_a2a_events_artifact_update(self):
"""Test conversion of event to TaskArtifactUpdateEvent."""
# Setup event with content
self.mock_event.content = genai_types.Content(
parts=[genai_types.Part(text="hello")], role="model"
)
self.mock_event.author = "agent-1"
agents_artifacts = {}
# Mock part converter to return a standard text part
mock_a2a_part = _compat.make_text_part("hello")
mock_convert_part = Mock(return_value=[mock_a2a_part])
result = convert_event_to_a2a_events(
self.mock_event,
agents_artifacts,
task_id="task-123",
context_id="context-456",
part_converter=mock_convert_part,
)
assert len(result) == 1
assert isinstance(result[0], TaskArtifactUpdateEvent)
assert result[0].task_id == "task-123"
assert result[0].context_id == "context-456"
assert result[0].artifact.parts == [mock_a2a_part]
assert "agent-1" in agents_artifacts # Artifact ID should be stored
def test_convert_event_to_a2a_events_error(self):
"""Test conversion of event with error to TaskStatusUpdateEvent."""
self.mock_event.error_code = "ERR001"
self.mock_event.error_message = "Something went wrong"
agents_artifacts = {}
result = convert_event_to_a2a_events(
self.mock_event,
agents_artifacts,
task_id="task-123",
context_id="context-456",
)
# Should not return any artifact events
assert len(result) == 0
def test_convert_event_to_a2a_events_none_event(self):
"""Test convert_event_to_a2a_events with None event."""
with pytest.raises(ValueError, match="Event cannot be None"):
convert_event_to_a2a_events(None, {})
def test_convert_event_to_a2a_events_none_artifacts(self):
"""Test convert_event_to_a2a_events with None agents_artifacts."""
with pytest.raises(ValueError, match="Agents artifacts cannot be None"):
convert_event_to_a2a_events(self.mock_event, None)
def test_convert_event_to_a2a_events_with_actions(self):
"""Test conversion of event with actions to TaskStatusUpdateEvent."""
self.mock_event.actions = event_actions.EventActions()
self.mock_event.actions.artifact_delta["image"] = 0
agents_artifacts = {}
result = convert_event_to_a2a_events(
self.mock_event,
agents_artifacts,
task_id="task-123",
context_id="context-456",
)
assert len(result) == 1
assert isinstance(result[0], TaskStatusUpdateEvent)
assert result[0].task_id == "task-123"
assert result[0].context_id == "context-456"
metadata = result[0].status.message.metadata
assert "adk_actions" in metadata
assert metadata["adk_actions"]["artifactDelta"] == {"image": 0}
class TestSerializeValue:
"""Tests for _serialize_value preserving JSON-native types."""
def setup_method(self) -> None:
from google.adk.a2a.converters.from_adk_event import _serialize_value
self.serialize = _serialize_value
def test_dict_preserved(self) -> None:
value = {"key": "val", "nested": {"a": 1}}
result = self.serialize(value)
assert result == value
assert isinstance(result, dict)
def test_list_preserved(self) -> None:
value = [1, "two", {"three": 3}]
result = self.serialize(value)
assert result == value
assert isinstance(result, list)
def test_int_preserved(self) -> None:
result = self.serialize(42)
assert result == 42
assert isinstance(result, int)
def test_float_preserved(self) -> None:
result = self.serialize(3.14)
assert result == 3.14
assert isinstance(result, float)
def test_bool_preserved(self) -> None:
assert self.serialize(True) is True
assert self.serialize(False) is False
def test_string_preserved(self) -> None:
assert self.serialize("hello") == "hello"
def test_none_returns_none(self) -> None:
assert self.serialize(None) is None
def test_non_json_type_stringified(self) -> None:
"""Non-JSON-native types should still be converted to str."""
from datetime import datetime
dt = datetime(2025, 1, 1)
result = self.serialize(dt)
assert isinstance(result, str)
def test_nested_non_json_value_in_dict_stringified(self) -> None:
"""A non-JSON-native value nested in a dict is stringified."""
from datetime import datetime
dt = datetime(2025, 1, 1)
value = {"when": dt, "count": 1, "label": "x"}
result = self.serialize(value)
assert result == {"when": str(dt), "count": 1, "label": "x"}
assert isinstance(result["when"], str)
assert isinstance(result["count"], int)
assert isinstance(result["label"], str)
def test_nested_non_json_value_in_list_stringified(self) -> None:
"""A non-JSON-native value nested in a list is stringified."""
from datetime import datetime
dt = datetime(2025, 1, 1)
value = [dt, 1, "x"]
result = self.serialize(value)
assert result == [str(dt), 1, "x"]
assert isinstance(result[0], str)
assert isinstance(result[1], int)
assert isinstance(result[2], str)
def test_non_string_dict_key_stringified(self) -> None:
"""Non-string dict keys are stringified so the result is JSON-encodable."""
from datetime import datetime
dt = datetime(2025, 1, 1)
value = {dt: "when", 1: "one", "label": "x"}
result = self.serialize(value)
assert result == {str(dt): "when", "1": "one", "label": "x"}
assert all(isinstance(k, str) for k in result)