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

151 lines
5.5 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
"""Unit tests for EventActions serialization and its fallback helper."""
import datetime
import logging
from google.adk.events.event_actions import _make_json_serializable
from google.adk.events.event_actions import EventActions
from pydantic import BaseModel
class _Sample(BaseModel):
x: int = 5
label: str = 'hi'
class TestMakeJsonSerializable:
"""Tests for the `_make_json_serializable` fallback helper."""
def test_plain_values_are_unchanged(self):
value = {'a': 1, 'b': [1, 2], 'c': {'d': 'e'}, 'f': None, 'g': True}
assert _make_json_serializable(value) == value
def test_datetime_is_preserved_not_discarded(self):
dt = datetime.datetime(2024, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
assert _make_json_serializable(dt) == '2024-01-02T03:04:05Z'
def test_pydantic_model_is_serialized_to_dict(self):
assert _make_json_serializable(_Sample()) == {'x': 5, 'label': 'hi'}
def test_nested_rich_types_are_serialized(self):
dt = datetime.datetime(2024, 5, 6, tzinfo=datetime.timezone.utc)
result = _make_json_serializable({'when': dt, 'model': _Sample(), 'n': [1]})
assert result == {
'when': '2024-05-06T00:00:00Z',
'model': {'x': 5, 'label': 'hi'},
'n': [1],
}
def test_unserializable_value_is_replaced_with_repr(self):
result = _make_json_serializable(lambda: 1)
assert isinstance(result, str)
assert 'function' in result
def test_unserializable_value_nested(self):
result = _make_json_serializable({'cb': lambda: 1, 'ok': 2})
assert result['ok'] == 2
assert isinstance(result['cb'], str)
class TestStateDeltaSerialization:
"""Tests for the `state_delta` wrap serializer."""
def test_serializable_state_delta_round_trips(self):
actions = EventActions(state_delta={'a': 1, 'b': [1, 2], 'c': {'d': 'e'}})
dumped = actions.model_dump(mode='json')
assert dumped['state_delta'] == {'a': 1, 'b': [1, 2], 'c': {'d': 'e'}}
def test_non_serializable_state_delta_does_not_raise(self):
actions = EventActions(state_delta={'cb': lambda: 1, 'ok': 2})
dumped = actions.model_dump(mode='json')
assert dumped['state_delta']['ok'] == 2
assert isinstance(dumped['state_delta']['cb'], str)
def test_non_serializable_state_delta_logs_warning(self, caplog):
actions = EventActions(state_delta={'cb': lambda: 1})
with caplog.at_level(logging.WARNING):
actions.model_dump(mode='json')
assert any(
'Failed to serialize `state_delta`' in record.message
for record in caplog.records
)
def test_datetime_preserved_when_fallback_triggered(self):
# A callable forces the fallback path; the datetime must still serialize
# faithfully rather than being discarded.
dt = datetime.datetime(2024, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
actions = EventActions(state_delta={'when': dt, 'cb': lambda: 1})
dumped = actions.model_dump(mode='json')
assert dumped['state_delta']['when'] == '2024-01-02T03:04:05Z'
def test_exclude_is_respected_for_serializable_state(self):
actions = EventActions(
state_delta={'_adk_replay_config': {'dir': '/x'}, 'foo': 1}
)
dumped = actions.model_dump(
mode='json', exclude={'state_delta': {'_adk_replay_config': True}}
)
assert dumped['state_delta'] == {'foo': 1}
def test_exclude_is_respected_in_fallback_path(self):
# Even when sanitization is required (callable present), caller `exclude`
# directives must still be applied to the fallback output.
actions = EventActions(
state_delta={
'_adk_replay_config': {'dir': '/x'},
'cb': lambda: 1,
'ok': 2,
}
)
dumped = actions.model_dump(
mode='json', exclude={'state_delta': {'_adk_replay_config': True}}
)
assert '_adk_replay_config' not in dumped['state_delta']
assert dumped['state_delta']['ok'] == 2
assert isinstance(dumped['state_delta']['cb'], str)
class TestAgentStateSerialization:
"""Tests for the `agent_state` wrap serializer."""
def test_none_agent_state_serializes_to_none(self):
assert EventActions().model_dump(mode='json')['agent_state'] is None
def test_serializable_agent_state_round_trips(self):
actions = EventActions(agent_state={'a': 1, 'b': 'two'})
assert actions.model_dump(mode='json')['agent_state'] == {
'a': 1,
'b': 'two',
}
def test_non_serializable_agent_state_does_not_raise(self):
actions = EventActions(agent_state={'cb': lambda: 1, 'n': 3})
dumped = actions.model_dump(mode='json')
assert dumped['agent_state']['n'] == 3
assert isinstance(dumped['agent_state']['cb'], str)
def test_non_serializable_agent_state_logs_warning(self, caplog):
actions = EventActions(agent_state={'cb': lambda: 1})
with caplog.at_level(logging.WARNING):
actions.model_dump(mode='json')
assert any(
'Failed to serialize `agent_state`' in record.message
for record in caplog.records
)