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
123 changes: 123 additions & 0 deletions .roost/runreport.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
{
"run_id": "bdea8de7",
"started_at": "2026-04-29T07:13:24.994217Z",
"ended_at": "2026-04-29T07:16:05.672162Z",
"status": "ok",
"config": {
"repo": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777446739/source/adk-python",
"out": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777446739/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": 6,
"scenarios_passed": 6,
"scenarios_failed": 0,
"coverage_weighted": null,
"llm_cost_usd": 0.1822,
"llm_input_tokens": 562568,
"llm_output_tokens": 18389,
"llm_cache_read_input_tokens": 342761,
"llm_cache_creation_input_tokens": 0,
"llm_api_calls": 17,
"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/1777446739/source/adk-python/adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py",
"test_file_hash": "sha256:19aacde7777a8af3b22c5bb85da758a1382cd6648d44b31b654348012efc3db9",
"test_status": "passed",
"iterations": 17,
"pivots": 0,
"scenarios": [
{
"scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#0",
"scenario_name": "test_convert_a2a_task_to_event_none_task",
"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": "test_convert_a2a_task_to_event_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": "test_convert_a2a_task_to_event_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": "test_convert_a2a_task_to_event_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": "test_convert_a2a_task_to_event_minimal_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": "test_convert_a2a_task_to_event_conversion_failure",
"passed": true,
"duration_ms": null,
"failure_reason": null,
"stderr_excerpt": null
}
],
"coverage_pct": null,
"writer_cost_usd": 0.18220855,
"writer_input_tokens": 562568,
"writer_output_tokens": 18389,
"writer_cache_read_input_tokens": 342761,
"writer_cache_creation_input_tokens": 0,
"diagnostics": []
}
],
"files_written": [
{
"path": "adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py",
"hash": "sha256:19aacde7777a8af3b22c5bb85da758a1382cd6648d44b31b654348012efc3db9",
"status": "created"
}
],
"pr_ready": {
"branch_suggestion": "roost/python-tests-20260429-0716",
"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.
131 changes: 131 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,131 @@
# 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] test_convert_a2a_task_to_event_none_task: Verify that passing None as a2a_task raises a ValueError.
# - [happy_path] test_convert_a2a_task_to_event_from_artifacts: Verify that the function extracts the message from the last artifact when artifacts are present.
# - [happy_path] test_convert_a2a_task_to_event_from_status: Verify that the function extracts the message from task.status when artifacts are empty.
# - [happy_path] test_convert_a2a_task_to_event_from_history: Verify that the function extracts the message from the last history entry when artifacts and status are empty.
# - [happy_path] test_convert_a2a_task_to_event_minimal_with_context: Verify that a minimal Event is created with correct metadata when no message source is available.
# - [error_path] test_convert_a2a_task_to_event_conversion_failure: Verify that a RuntimeError is raised if the underlying message conversion fails.

import pytest
from unittest.mock import MagicMock, patch, ANY
import uuid

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

@pytest.mark.generated
@pytest.mark.error_path
def test_convert_a2a_task_to_event_none_task():
"""Verify that passing None as a2a_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
def test_convert_a2a_task_to_event_from_artifacts():
"""Verify that the function extracts the message from the last artifact when artifacts are present."""
task = MagicMock()
task.artifacts = [MagicMock(parts=['part1']), MagicMock(parts=['part2'])]
task.status = None
task.history = []

with patch('google.adk.a2a.converters.event_converter.convert_a2a_message_to_event') as mock_convert, \
patch('google.adk.a2a.converters.event_converter.Message') as mock_message_cls, \
patch('google.adk.a2a.converters.event_converter.Role') as mock_role:

mock_role.agent = "agent_role"
mock_message_instance = MagicMock()
mock_message_cls.return_value = mock_message_instance
mock_convert.return_value = MagicMock(spec=Event)

result = convert_a2a_task_to_event(task)

assert result == mock_convert.return_value
mock_convert.assert_called_once()
# The message passed to mock_convert should be the one created from artifacts
passed_message = mock_convert.call_args[0][0]
assert passed_message == mock_message_instance

# Verify Message was created with correct parts and role
mock_message_cls.assert_called_once_with(
message_id="", role="agent_role", parts=['part2']
)

@pytest.mark.generated
@pytest.mark.happy_path
def test_convert_a2a_task_to_event_from_status():
"""Verify that the function extracts the message from task.status when artifacts are empty."""
task = MagicMock()
task.artifacts = []
task.status = MagicMock()
task.status.message = MagicMock()
task.status.message.parts = ['status_part']
task.history = []

with patch('google.adk.a2a.converters.event_converter.convert_a2a_message_to_event') as mock_convert:
mock_convert.return_value = MagicMock(spec=Event)

result = convert_a2a_task_to_event(task)

assert result == mock_convert.return_value
mock_convert.assert_called_once_with(task.status.message, None, None, part_converter=ANY)

@pytest.mark.generated
@pytest.mark.happy_path
def test_convert_a2a_task_to_event_from_history():
"""Verify that the function extracts the message from the last history entry when artifacts and status are empty."""
task = MagicMock()
task.artifacts = []
task.status = None
task.history = [MagicMock(), MagicMock()]

with patch('google.adk.a2a.converters.event_converter.convert_a2a_message_to_event') as mock_convert:
mock_convert.return_value = MagicMock(spec=Event)

result = convert_a2a_task_to_event(task)

assert result == mock_convert.return_value
mock_convert.assert_called_once_with(task.history[-1], None, None, part_converter=ANY)

@pytest.mark.generated
@pytest.mark.happy_path
def test_convert_a2a_task_to_event_minimal_with_context():
"""Verify that a minimal Event is created with correct metadata when no message source is available."""
task = MagicMock()
task.artifacts = []
task.status = None
task.history = []

ctx = MagicMock(spec=InvocationContext)
ctx.invocation_id = "test-id"
ctx.branch = "test-branch"

result = convert_a2a_task_to_event(task, author="custom author", invocation_context=ctx)

assert isinstance(result, Event)
assert result.invocation_id == "test-id"
assert result.author == "custom author"
assert result.branch == "test-branch"

@pytest.mark.generated
@pytest.mark.error_path
def test_convert_a2a_task_to_event_conversion_failure():
"""Verify that a RuntimeError is raised if the underlying message conversion fails."""
task = MagicMock()
task.artifacts = [MagicMock(parts=['part'])]

with patch('google.adk.a2a.converters.event_converter.convert_a2a_message_to_event', side_effect=Exception("conversion failed")), \
patch('google.adk.a2a.converters.event_converter.Message'), \
patch('google.adk.a2a.converters.event_converter.Role'):
with pytest.raises(RuntimeError, match="Failed to convert task message: conversion failed"):
convert_a2a_task_to_event(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