From ba609036b87a67962fe633cc23e699b55d5de429 Mon Sep 17 00:00:00 2001 From: roost-io <8110509+mgdevstack@users.noreply.github.com> Date: Wed, 29 Apr 2026 10:23:03 +0530 Subject: [PATCH] Unit test generated by RoostGPT Using AI Model gpt-4.1 --- .roost/runreport.json | 115 ++++++++++++++ __init__.py | 0 adk/__init__.py | 0 adk/a2a/__init__.py | 0 adk/a2a/converters/__init__.py | 0 .../converters/event_converter/__init__.py | 0 .../test_convert_a2a_task_to_event.py | 145 ++++++++++++++++++ conftest.py | 27 ++++ pyproject.toml | 10 +- 9 files changed, 293 insertions(+), 4 deletions(-) create mode 100644 .roost/runreport.json create mode 100644 __init__.py create mode 100644 adk/__init__.py create mode 100644 adk/a2a/__init__.py create mode 100644 adk/a2a/converters/__init__.py create mode 100644 adk/a2a/converters/event_converter/__init__.py create mode 100644 adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py create mode 100644 conftest.py diff --git a/.roost/runreport.json b/.roost/runreport.json new file mode 100644 index 0000000000..2d30557326 --- /dev/null +++ b/.roost/runreport.json @@ -0,0 +1,115 @@ +{ + "run_id": "a19da768", + "started_at": "2026-04-29T04:46:52.523840Z", + "ended_at": "2026-04-29T04:53:01.404346Z", + "status": "failed", + "config": { + "repo": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777437937/source/adk-python", + "out": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777437937/source/adk-python", + "workers": 5, + "scenarios_from": "planner", + "provider": "env:AI_TYPE", + "model": "azure/gpt-4.1", + "jedi": true + }, + "summary": { + "targets_total": 1, + "targets_passed": 0, + "targets_failed": 0, + "targets_partial": 1, + "targets_skipped": 0, + "scenarios_total": 5, + "scenarios_passed": 3, + "scenarios_failed": 2, + "coverage_weighted": null, + "llm_cost_usd": 1.3646, + "llm_input_tokens": 2165294, + "llm_output_tokens": 17975, + "llm_cache_read_input_tokens": 2073216, + "llm_cache_creation_input_tokens": 0, + "llm_api_calls": 71, + "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/1777437937/source/adk-python/adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py", + "test_file_hash": "sha256:50bdffbc2dd5f1d294f674928c299b522b69b8a72f3df57e9ab8734e00b94e40", + "test_status": "partial", + "iterations": 71, + "pivots": 0, + "scenarios": [ + { + "scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#0", + "scenario_name": "happy_path_task_with_artifacts", + "passed": false, + "duration_ms": null, + "failure_reason": "failed", + "stderr_excerpt": null + }, + { + "scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#1", + "scenario_name": "minimal_event_no_message", + "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": "error_on_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#3", + "scenario_name": "runtime_error_on_message_conversion_failure", + "passed": false, + "duration_ms": null, + "failure_reason": "failed", + "stderr_excerpt": null + }, + { + "scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#4", + "scenario_name": "invocation_context_branch_and_id_propagation", + "passed": true, + "duration_ms": null, + "failure_reason": null, + "stderr_excerpt": null + } + ], + "coverage_pct": null, + "writer_cost_usd": 1.3645639999999999, + "writer_input_tokens": 2165294, + "writer_output_tokens": 17975, + "writer_cache_read_input_tokens": 2073216, + "writer_cache_creation_input_tokens": 0, + "diagnostics": [] + } + ], + "files_written": [ + { + "path": "adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py", + "hash": "sha256:50bdffbc2dd5f1d294f674928c299b522b69b8a72f3df57e9ab8734e00b94e40", + "status": "created" + } + ], + "pr_ready": { + "branch_suggestion": "roost/python-tests-20260429-0453", + "commit_message": "roost-pytest: add 1 test file(s)", + "pr_title": "Auto-generated Python unit tests (1 file(s))", + "pr_body_markdown": "## Summary\n- 0 targets with fully green tests\n- 1 targets with partial coverage\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": [] +} \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/adk/__init__.py b/adk/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/adk/a2a/__init__.py b/adk/a2a/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/adk/a2a/converters/__init__.py b/adk/a2a/converters/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/adk/a2a/converters/event_converter/__init__.py b/adk/a2a/converters/event_converter/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py b/adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py new file mode 100644 index 0000000000..d9cc2679ce --- /dev/null +++ b/adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py @@ -0,0 +1,145 @@ +# 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: +# - [happy_path] happy_path_task_with_artifacts: Verifies conversion when the Task has artifacts with parts, producing a valid Event. +# - [edge_case] minimal_event_no_message: Checks that a minimal Event is created when Task has no artifacts, status, or history. +# - [error_path] error_on_none_task: Ensures ValueError is raised if a2a_task is None. +# - [error_path] runtime_error_on_message_conversion_failure: Ensures RuntimeError is raised if message conversion fails internally. +# - [property] invocation_context_branch_and_id_propagation: Checks that branch and invocation_id from InvocationContext are propagated to the Event. + +import pytest +from unittest import mock + +from google.adk.a2a.converters.event_converter import convert_a2a_task_to_event + +# Minimal fakes for required types (since real ones are unavailable in the workspace) +def make_part(text=None): + class FakeTextPart: + def __init__(self, text): + self.text = text + return FakeTextPart(text) + +class Artifact: + def __init__(self, parts=None): + self.parts = parts or [] + +class Task: + def __init__(self, artifacts=None, status=None, history=None): + self.artifacts = artifacts or [] + self.status = status + self.history = history or [] + +class Message: + def __init__(self, message_id="", role=None, parts=None): + self.message_id = message_id + self.role = role + self.parts = parts or [] + +class Event: + def __init__(self, invocation_id=None, author=None, branch=None, content=None): + self.invocation_id = invocation_id + self.author = author + self.branch = branch + self.content = content + +class InvocationContext: + def __init__(self, invocation_id=None, branch=None): + self.invocation_id = invocation_id + self.branch = branch + +def fake_convert_a2a_message_to_event(message, author, invocation_context, part_converter=None): + # Simulate conversion: just wrap the message's parts in Event.content + class Content: + def __init__(self, parts): + self.parts = parts + return Event( + invocation_id=invocation_context.invocation_id if invocation_context else "iid", + author=author or "a2a agent", + branch=invocation_context.branch if invocation_context else None, + content=Content(message.parts) + ) + +@pytest.fixture(autouse=True) +def patch_types(monkeypatch): + monkeypatch.setattr("a2a.types.Task", Task) + monkeypatch.setattr("a2a.types.Artifact", Artifact) + monkeypatch.setattr("a2a.types.Part", make_part) + monkeypatch.setattr("a2a.types.TextPart", make_part) + monkeypatch.setattr("a2a.types.Message", Message) + monkeypatch.setattr("google.adk.a2a.converters.event_converter.Event", Event) + monkeypatch.setattr("google.adk.a2a.converters.event_converter.InvocationContext", InvocationContext) + +@pytest.mark.generated +@pytest.mark.happy_path +def test_happy_path_task_with_artifacts(monkeypatch): + """Verifies conversion when the Task has artifacts with parts, producing a valid Event.""" + # Patch convert_a2a_message_to_event to our fake + monkeypatch.setattr( + "google.adk.a2a.converters.event_converter.convert_a2a_message_to_event", + fake_convert_a2a_message_to_event + ) + a2a_task = Task(artifacts=[Artifact(parts=[make_part(text='foo')])], status=None, history=None) + result = convert_a2a_task_to_event(a2a_task) + assert isinstance(result, Event) + assert hasattr(result, "content") + assert getattr(result.content.parts[0], 'text', None) == 'foo' + +@pytest.mark.generated +@pytest.mark.edge_case +def test_minimal_event_no_message(monkeypatch): + """Checks that a minimal Event is created when Task has no artifacts, status, or history.""" + # Patch convert_a2a_message_to_event to ensure it's not called + monkeypatch.setattr( + "google.adk.a2a.converters.event_converter.convert_a2a_message_to_event", + lambda *a, **kw: pytest.fail("Should not be called") + ) + a2a_task = Task(artifacts=[], status=None, history=[]) + result = convert_a2a_task_to_event(a2a_task) + assert isinstance(result, Event) + assert getattr(result, "content", None) is None + +@pytest.mark.generated +@pytest.mark.error_path +def test_error_on_none_task(): + """Ensures ValueError is raised if a2a_task is None.""" + with pytest.raises(ValueError): + convert_a2a_task_to_event(None) + +@pytest.mark.generated +@pytest.mark.error_path +def test_runtime_error_on_message_conversion_failure(monkeypatch): + """Ensures RuntimeError is raised if message conversion fails internally.""" + def part_converter(_): + raise Exception('fail') + # Patch convert_a2a_message_to_event to raise Exception + def fail_convert(*a, **kw): + raise Exception('fail') + monkeypatch.setattr( + "google.adk.a2a.converters.event_converter.convert_a2a_message_to_event", + fail_convert + ) + a2a_task = Task(artifacts=[Artifact(parts=[make_part(text='foo')])], status=None, history=None) + with pytest.raises(RuntimeError): + convert_a2a_task_to_event(a2a_task, part_converter=part_converter) + +@pytest.mark.generated +@pytest.mark.property +def test_invocation_context_branch_and_id_propagation(monkeypatch): + """Checks that branch and invocation_id from InvocationContext are propagated to the Event.""" + # Patch convert_a2a_message_to_event to our fake + monkeypatch.setattr( + "google.adk.a2a.converters.event_converter.convert_a2a_message_to_event", + fake_convert_a2a_message_to_event + ) + ctx = InvocationContext(invocation_id='123', branch='main') + a2a_task = Task(artifacts=[], status=None, history=[]) + result = convert_a2a_task_to_event(a2a_task, invocation_context=ctx) + assert result.invocation_id == '123' + assert result.branch == 'main' diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000000..5964a6943d --- /dev/null +++ b/conftest.py @@ -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}") diff --git a/pyproject.toml b/pyproject.toml index 69ba9984e6..9f81eaa619 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -116,10 +116,12 @@ eval = [ ] test = [ - # go/keep-sorted start - "a2a-sdk>=0.3.0,<0.4.0", - "anthropic>=0.43.0", # For anthropic model tests - "crewai[tools];python_version>='3.11' and python_version<'3.12'", # For CrewaiTool tests; chromadb/pypika fail on 3.12+ + "# go/keep-sorted start\n "a2a-sdk>=0.3.0", + "<0.4.0", + "anthropic>=0.43.0", + "# For anthropic model tests\n "crewai[tools", + "google", +];python_version>='3.11' and python_version<'3.12'", # For CrewaiTool tests; chromadb/pypika fail on 3.12+ "kubernetes>=29.0.0", # For GkeCodeExecutor "langchain-community>=0.3.17", "langgraph>=0.2.60, <0.4.8", # For LangGraphAgent