Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions .roost/runreport.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
{
"run_id": "b8f7d58a",
"started_at": "2026-04-29T07:50:06.814694Z",
"ended_at": "2026-04-29T07:53:19.583557Z",
"status": "ok",
"config": {
"repo": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777448936/source/adk-python",
"out": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777448936/source/adk-python",
"workers": 5,
"scenarios_from": "planner",
"provider": "env:AI_TYPE",
"model": "gemini/gemini-3-flash-preview",
"jedi": true
},
"summary": {
"targets_total": 1,
"targets_passed": 1,
"targets_failed": 0,
"targets_partial": 0,
"targets_skipped": 0,
"scenarios_total": 7,
"scenarios_passed": 7,
"scenarios_failed": 0,
"coverage_weighted": null,
"llm_cost_usd": 0.2364,
"llm_input_tokens": 763149,
"llm_output_tokens": 22003,
"llm_cache_read_input_tokens": 469210,
"llm_cache_creation_input_tokens": 0,
"llm_api_calls": 29,
"elapsed_ms": 0
},
"targets": [
{
"target_symbol_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event",
"symbol_kind": "function",
"source_file": "src/google/adk/a2a/converters/event_converter.py",
"source_range": [
201,
265
],
"test_file": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777448936/source/adk-python/adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py",
"test_file_hash": "sha256:734a053d4f8d2dc335614b1dc2a6db421963016af14f889f8c6caf7decc02c12",
"test_status": "passed",
"iterations": 29,
"pivots": 0,
"scenarios": [
{
"scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#0",
"scenario_name": "none_task_raises_value_error",
"passed": true,
"duration_ms": null,
"failure_reason": null,
"stderr_excerpt": null
},
{
"scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#1",
"scenario_name": "extract_from_artifacts",
"passed": true,
"duration_ms": null,
"failure_reason": null,
"stderr_excerpt": null
},
{
"scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#2",
"scenario_name": "extract_from_status",
"passed": true,
"duration_ms": null,
"failure_reason": null,
"stderr_excerpt": null
},
{
"scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#3",
"scenario_name": "extract_from_history",
"passed": true,
"duration_ms": null,
"failure_reason": null,
"stderr_excerpt": null
},
{
"scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#4",
"scenario_name": "minimal_event_with_context",
"passed": true,
"duration_ms": null,
"failure_reason": null,
"stderr_excerpt": null
},
{
"scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#5",
"scenario_name": "minimal_event_defaults",
"passed": true,
"duration_ms": null,
"failure_reason": null,
"stderr_excerpt": null
},
{
"scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#6",
"scenario_name": "conversion_failure_wraps_exception",
"passed": true,
"duration_ms": null,
"failure_reason": null,
"stderr_excerpt": null
}
],
"coverage_pct": null,
"writer_cost_usd": 0.23643899999999998,
"writer_input_tokens": 763149,
"writer_output_tokens": 22003,
"writer_cache_read_input_tokens": 469210,
"writer_cache_creation_input_tokens": 0,
"diagnostics": []
}
],
"files_written": [
{
"path": "adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py",
"hash": "sha256:734a053d4f8d2dc335614b1dc2a6db421963016af14f889f8c6caf7decc02c12",
"status": "created"
}
],
"pr_ready": {
"branch_suggestion": "roost/python-tests-20260429-0753",
"commit_message": "roost-pytest: add 1 test file(s)",
"pr_title": "Auto-generated Python unit tests (1 file(s))",
"pr_body_markdown": "## Summary\n- 1 targets with fully green tests\n\n## Generated test files\n- `adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py`",
"changed_files": [
"adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py"
]
},
"diagnostics": []
}
Empty file added __init__.py
Empty file.
Empty file added adk/__init__.py
Empty file.
Empty file added adk/a2a/__init__.py
Empty file.
Empty file added adk/a2a/converters/__init__.py
Empty file.
Empty file.
148 changes: 148 additions & 0 deletions adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# ROOST_METHOD_HASH=convert_a2a_task_to_event_40cb3ce258
# ROOST_METHOD_SIG_HASH=convert_a2a_task_to_event_124ed678ea

"""Tests for `src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event`.

Auto-generated by roost-pytest. Re-generate when the source
changes; see the run report for generation details.
"""
# Source: src/google/adk/a2a/converters/event_converter.py:201-265
# Scenarios:
# - [error_path] none_task_raises_value_error: Verify that passing None as the task raises a ValueError.
# - [happy_path] extract_from_artifacts: Verify that message content is correctly extracted from the last artifact and passed to the message converter.
# - [happy_path] extract_from_status: Verify that message content is extracted from the task status if artifacts are missing.
# - [happy_path] extract_from_history: Verify that message content is extracted from the task history if artifacts and status are missing.
# - [happy_path] minimal_event_with_context: Verify that a minimal Event is created with context information when no message content is found in the task.
# - [edge_case] minimal_event_defaults: Verify that a minimal Event is created with default values and a generated UUID when no context or author is provided.
# - [error_path] conversion_failure_wraps_exception: Verify that failures in the underlying message conversion are wrapped in a RuntimeError.

import pytest
import uuid
from unittest import mock
from google.adk.a2a.converters.event_converter import convert_a2a_task_to_event
from google.adk.agents.invocation_context import InvocationContext
from google.adk.events.event import Event
from a2a.types import Message, Role

@pytest.mark.generated
@pytest.mark.error_path
def test_none_task_raises_value_error():
"""Verify that passing None as the task raises a ValueError."""
with pytest.raises(ValueError, match="A2A task cannot be None"):
convert_a2a_task_to_event(None)

@pytest.mark.generated
@pytest.mark.happy_path
@mock.patch("google.adk.a2a.converters.event_converter.convert_a2a_message_to_event")
@mock.patch("google.adk.a2a.converters.event_converter.Message")
@mock.patch("google.adk.a2a.converters.event_converter.Role")
def test_extract_from_artifacts(mock_role, mock_message_cls, mock_convert_msg):
"""Verify that message content is correctly extracted from the last artifact and passed to the message converter."""
mock_role.agent = "agent_role"
a2a_task = mock.Mock()
artifact = mock.Mock()
artifact.parts = ["part1"]
a2a_task.artifacts = [artifact]

ctx = mock.Mock(spec=InvocationContext)
custom_pc = mock.Mock()

mock_message_instance = mock.Mock()
mock_message_cls.return_value = mock_message_instance

convert_a2a_task_to_event(a2a_task, author="test-author", invocation_context=ctx, part_converter=custom_pc)

mock_message_cls.assert_called_once_with(
message_id="", role="agent_role", parts=["part1"]
)
mock_convert_msg.assert_called_once_with(
mock_message_instance, "test-author", ctx, part_converter=custom_pc
)

@pytest.mark.generated
@pytest.mark.happy_path
@mock.patch("google.adk.a2a.converters.event_converter.convert_a2a_message_to_event")
def test_extract_from_status(mock_convert_msg):
"""Verify that message content is extracted from the task status if artifacts are missing."""
a2a_task = mock.Mock()
a2a_task.artifacts = []
a2a_task.status.message.parts = ["part2"]

convert_a2a_task_to_event(a2a_task)

mock_convert_msg.assert_called_once_with(
a2a_task.status.message, None, None, part_converter=mock.ANY
)

@pytest.mark.generated
@pytest.mark.happy_path
@mock.patch("google.adk.a2a.converters.event_converter.convert_a2a_message_to_event")
def test_extract_from_history(mock_convert_msg):
"""Verify that message content is extracted from the task history if artifacts and status are missing."""
a2a_task = mock.Mock()
a2a_task.artifacts = []
a2a_task.status = None
msg1 = mock.Mock()
msg2 = mock.Mock()
a2a_task.history = [msg1, msg2]

convert_a2a_task_to_event(a2a_task)

mock_convert_msg.assert_called_once_with(
msg2, None, None, part_converter=mock.ANY
)

@pytest.mark.generated
@pytest.mark.happy_path
def test_minimal_event_with_context():
"""Verify that a minimal Event is created with context information when no message content is found in the task."""
a2a_task = mock.Mock()
a2a_task.artifacts = []
a2a_task.status = None
a2a_task.history = []

ctx = mock.Mock(spec=InvocationContext)
ctx.invocation_id = "id-123"
ctx.branch = "branch-abc"

event = convert_a2a_task_to_event(a2a_task, invocation_context=ctx, author="custom-author")

assert isinstance(event, Event)
assert event.invocation_id == "id-123"
assert event.author == "custom-author"
assert event.branch == "branch-abc"

@pytest.mark.generated
@pytest.mark.edge_case
@mock.patch("google.adk.a2a.converters.event_converter.uuid.uuid4")
def test_minimal_event_defaults(mock_uuid):
"""Verify that a minimal Event is created with default values and a generated UUID when no context or author is provided."""
a2a_task = mock.Mock()
a2a_task.artifacts = []
a2a_task.status = None
a2a_task.history = []

fixed_uuid = uuid.UUID("12345678-1234-5678-1234-567812345678")
mock_uuid.return_value = fixed_uuid

event = convert_a2a_task_to_event(a2a_task)

assert isinstance(event, Event)
assert event.invocation_id == str(fixed_uuid)
assert event.author == "a2a agent"
assert event.branch is None

@pytest.mark.generated
@pytest.mark.error_path
@mock.patch("google.adk.a2a.converters.event_converter.convert_a2a_message_to_event")
def test_conversion_failure_wraps_exception(mock_convert_msg):
"""Verify that failures in the underlying message conversion are wrapped in a RuntimeError."""
a2a_task = mock.Mock()
a2a_task.artifacts = []
a2a_task.status = None
a2a_task.history = [mock.Mock()]

mock_convert_msg.side_effect = ValueError("inner error")

with pytest.raises(RuntimeError, match="Failed to convert task message: inner error"):
convert_a2a_task_to_event(a2a_task)
27 changes: 27 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""roost-pytest test-suite configuration.

This file is auto-generated. It registers the custom markers used by
generated tests so pytest doesn't warn ``PytestUnknownMarkWarning``.
Add your own fixtures/hooks below the marker block as you would in
any pytest project.
"""

from __future__ import annotations

import pytest


_GENERATED_MARKERS = {
'generated': 'test was auto-generated by roost-pytest',
'happy_path': 'exercises the primary success path',
'edge_case': 'exercises an edge / boundary condition',
'error_path': 'exercises an exception or failure path',
'security': 'exercises a security-sensitive behaviour',
'property': 'property / invariant test (often parametrised)',
'regression': 'guards against a previously fixed bug',
}


def pytest_configure(config: pytest.Config) -> None:
for name, description in _GENERATED_MARKERS.items():
config.addinivalue_line("markers", f"{name}: {description}")
Loading