diff --git a/.roost/runreport.json b/.roost/runreport.json new file mode 100644 index 0000000000..e2bc644e2f --- /dev/null +++ b/.roost/runreport.json @@ -0,0 +1,99 @@ +{ + "run_id": "c79ae765", + "started_at": "2026-04-29T05:39:55.359628Z", + "ended_at": "2026-04-29T05:44:29.636150Z", + "status": "failed", + "config": { + "repo": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777441129/source/adk-python", + "out": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777441129/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": 3, + "scenarios_passed": 2, + "scenarios_failed": 1, + "coverage_weighted": null, + "llm_cost_usd": 0.9048, + "llm_input_tokens": 1464446, + "llm_output_tokens": 6477, + "llm_cache_read_input_tokens": 1383936, + "llm_cache_creation_input_tokens": 0, + "llm_api_calls": 53, + "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/1777441129/source/adk-python/adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py", + "test_file_hash": "sha256:9583ab6a9a4f8f8f4a58ee212c459672fe0223504b7624f1b39022e7ed7336e2", + "test_status": "partial", + "iterations": 53, + "pivots": 0, + "scenarios": [ + { + "scenario_id": "src.google.adk.a2a.converters.event_converter.convert_a2a_task_to_event#0", + "scenario_name": "happy_path_with_artifacts", + "passed": false, + "duration_ms": null, + "failure_reason": "failed: {\"reprcrash\": {\"path\": \"/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777441129/source/adk-python/src/google/adk/a2a/converters/event_converter.py\", \"lineno\": 230, \"message\": \"pydantic_core._pydantic_core.ValidationError: 3 validation errors for Message\\nparts.0.TextPart\\n Input should be a vali", + "stderr_excerpt": "/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777441129/source/adk-python/src/google/adk/a2a/converters/event_converter.py:230: pydantic_core._pydantic_core.ValidationError: 3 validation errors for Message\nparts.0.TextPart\n Input should be a valid dictionary or instance of TextPart [type=model_type, input_value=, input_type=FakeA2APart]\n For further information visit https://errors.pydantic.dev/2.12/v/model_type\nparts.0.FilePart\n Input should be a valid dictionary or instance of FilePart [type=model_type, input_value=, input_type=FakeA2APart]\n For further information visit https://errors.pydantic.dev/2.12/v/model_type\nparts.0.DataPart\n Input should be a valid dictionary or instance of DataPart [type=model_type, input_value=, input_type=FakeA2APart]\n For further information visit https://errors.pydantic.dev/2.12/v/model_type\n{\"reprcrash\": {\"path\": \"/private/var/tmp/Roost/RoostGPT/unit-adk-python/1777441129/source/adk-python/src/google/adk/a2a/converters/event_converter.py\", \"lineno\": 230, \"message\": \"pydantic_core._pydantic_core.ValidationError: 3 validation errors for Message\\nparts.0.TextPart\\n Input should be a valid dictionary or instance of TextPart [type=model_type, input_value=, input_type=FakeA2APart]\\n For further information visit https://error" + }, + { + "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 + } + ], + "coverage_pct": null, + "writer_cost_usd": 0.9048039999999999, + "writer_input_tokens": 1464446, + "writer_output_tokens": 6477, + "writer_cache_read_input_tokens": 1383936, + "writer_cache_creation_input_tokens": 0, + "diagnostics": [] + } + ], + "files_written": [ + { + "path": "adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py", + "hash": "sha256:9583ab6a9a4f8f8f4a58ee212c459672fe0223504b7624f1b39022e7ed7336e2", + "status": "created" + } + ], + "pr_ready": { + "branch_suggestion": "roost/python-tests-20260429-0544", + "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..d7b698ce82 --- /dev/null +++ b/adk/a2a/converters/event_converter/test_convert_a2a_task_to_event.py @@ -0,0 +1,64 @@ +# 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_with_artifacts: Verifies conversion when a2a_task contains artifacts with parts, producing an Event with content. +# - [edge_case] minimal_event_no_message: Checks that a minimal Event is created when a2a_task has no artifacts, status message, or history. +# - [error_path] error_on_none_task: Ensures ValueError is raised when a2a_task is None. + +import pytest + +from google.adk.a2a.converters.event_converter import convert_a2a_task_to_event + +# Minimal test fakes for required types (since real classes are not importable) +class FakeA2APart: + def __init__(self, text="test"): + self.text = text + +class FakeArtifact: + def __init__(self, parts=None): + self.parts = parts or [] + +class FakeTask: + def __init__(self, artifacts=None, status=None, history=None): + self.artifacts = artifacts or [] + self.status = status + self.history = history or [] + +class FakeEvent: + def __init__(self, content=None): + self.content = content + +@pytest.mark.generated +@pytest.mark.happy_path + +def test_happy_path_with_artifacts(): + """Verifies conversion when a2a_task contains artifacts with parts, producing an Event with content.""" + a2a_task = FakeTask(artifacts=[FakeArtifact(parts=[FakeA2APart()])]) + result = convert_a2a_task_to_event(a2a_task) + assert hasattr(result, 'content') + assert result.content is not None + +@pytest.mark.generated +@pytest.mark.edge_case + +def test_minimal_event_no_message(): + """Checks that a minimal Event is created when a2a_task has no artifacts, status message, or history.""" + a2a_task = FakeTask(artifacts=[], status=None, history=[]) + result = convert_a2a_task_to_event(a2a_task) + assert hasattr(result, 'content') + assert result.content is None + +@pytest.mark.generated +@pytest.mark.error_path + +def test_error_on_none_task(): + """Ensures ValueError is raised when a2a_task is None.""" + with pytest.raises(ValueError): + convert_a2a_task_to_event(None) 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..449533a0cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,6 +136,7 @@ test = [ "rouge-score>=0.1.2", "tabulate>=0.9.0", # go/keep-sorted end + "google" ] docs = [