From ff8a3c9b43baf420a0115650a448d63c740b0e92 Mon Sep 17 00:00:00 2001 From: "Xiang (Sean) Zhou" Date: Thu, 22 May 2025 09:43:03 -0700 Subject: [PATCH] chore: reformat the codes using autoformat.sh PiperOrigin-RevId: 762004002 --- tests/unittests/agents/test_base_agent.py | 2 + .../agents/test_live_request_queue.py | 10 +- .../unittests/agents/test_llm_agent_fields.py | 4 +- .../unittests/agents/test_readonly_context.py | 5 +- tests/unittests/agents/test_run_config.py | 8 +- .../artifacts/test_artifact_service.py | 3 +- tests/unittests/auth/test_auth_handler.py | 3 +- tests/unittests/cli/utils/test_cli.py | 237 +++++++------- tests/unittests/cli/utils/test_cli_create.py | 295 ++++++++++-------- tests/unittests/cli/utils/test_cli_deploy.py | 196 ++++++------ tests/unittests/code_executors/__init__.py | 2 +- .../test_code_executor_context.py | 18 +- .../evaluation/test_trajectory_evaluator.py | 1 + tests/unittests/fast_api/test_fast_api.py | 4 +- .../flows/llm_flows/test_instructions.py | 1 + tests/unittests/models/test_litellm.py | 94 +++--- .../sessions/test_session_service.py | 2 +- .../test_vertex_ai_session_service.py | 1 - .../apihub_tool/clients/test_apihub_client.py | 8 +- .../tools/openapi_tool/common/test_common.py | 3 +- .../test_openapi_spec_parser.py | 4 +- .../openapi_spec_parser/test_rest_api_tool.py | 18 +- tests/unittests/tools/test_function_tool.py | 24 +- 23 files changed, 496 insertions(+), 447 deletions(-) diff --git a/tests/unittests/agents/test_base_agent.py b/tests/unittests/agents/test_base_agent.py index 95048ea..624bd28 100644 --- a/tests/unittests/agents/test_base_agent.py +++ b/tests/unittests/agents/test_base_agent.py @@ -21,6 +21,7 @@ from typing import List from typing import Optional from typing import Union from unittest import mock + from google.adk.agents.base_agent import BaseAgent from google.adk.agents.callback_context import CallbackContext from google.adk.agents.invocation_context import InvocationContext @@ -30,6 +31,7 @@ from google.genai import types import pytest import pytest_mock from typing_extensions import override + from .. import testing_utils diff --git a/tests/unittests/agents/test_live_request_queue.py b/tests/unittests/agents/test_live_request_queue.py index 2827100..ab98894 100644 --- a/tests/unittests/agents/test_live_request_queue.py +++ b/tests/unittests/agents/test_live_request_queue.py @@ -1,7 +1,11 @@ -import pytest -from unittest.mock import MagicMock, AsyncMock, patch -from google.adk.agents.live_request_queue import LiveRequest, LiveRequestQueue +from unittest.mock import AsyncMock +from unittest.mock import MagicMock +from unittest.mock import patch + +from google.adk.agents.live_request_queue import LiveRequest +from google.adk.agents.live_request_queue import LiveRequestQueue from google.genai import types +import pytest @pytest.mark.asyncio diff --git a/tests/unittests/agents/test_llm_agent_fields.py b/tests/unittests/agents/test_llm_agent_fields.py index 287ef3b..9b3a4ab 100644 --- a/tests/unittests/agents/test_llm_agent_fields.py +++ b/tests/unittests/agents/test_llm_agent_fields.py @@ -15,7 +15,8 @@ """Unit tests for canonical_xxx fields in LlmAgent.""" from typing import Any -from typing import Optional, cast +from typing import cast +from typing import Optional from google.adk.agents.callback_context import CallbackContext from google.adk.agents.invocation_context import InvocationContext @@ -146,6 +147,7 @@ async def test_canonical_global_instruction(): assert canonical_global_instruction == 'global instruction: state_value' assert bypass_state_injection + async def test_async_canonical_global_instruction(): async def _global_instruction_provider(ctx: ReadonlyContext) -> str: return f'global instruction: {ctx.state["state_var"]}' diff --git a/tests/unittests/agents/test_readonly_context.py b/tests/unittests/agents/test_readonly_context.py index 8068b6f..c2ffa6e 100644 --- a/tests/unittests/agents/test_readonly_context.py +++ b/tests/unittests/agents/test_readonly_context.py @@ -1,7 +1,8 @@ -import pytest -from unittest.mock import MagicMock from types import MappingProxyType +from unittest.mock import MagicMock + from google.adk.agents.readonly_context import ReadonlyContext +import pytest @pytest.fixture diff --git a/tests/unittests/agents/test_run_config.py b/tests/unittests/agents/test_run_config.py index 7bfb9ce..11f9bad 100644 --- a/tests/unittests/agents/test_run_config.py +++ b/tests/unittests/agents/test_run_config.py @@ -1,8 +1,10 @@ -import pytest -import sys import logging -from unittest.mock import patch, ANY +import sys +from unittest.mock import ANY +from unittest.mock import patch + from google.adk.agents.run_config import RunConfig +import pytest def test_validate_max_llm_calls_valid(): diff --git a/tests/unittests/artifacts/test_artifact_service.py b/tests/unittests/artifacts/test_artifact_service.py index b0952a7..0b232f4 100644 --- a/tests/unittests/artifacts/test_artifact_service.py +++ b/tests/unittests/artifacts/test_artifact_service.py @@ -17,12 +17,11 @@ import enum from typing import Optional from typing import Union +from unittest import mock from google.adk.artifacts import GcsArtifactService from google.adk.artifacts import InMemoryArtifactService from google.genai import types - -from unittest import mock import pytest Enum = enum.Enum diff --git a/tests/unittests/auth/test_auth_handler.py b/tests/unittests/auth/test_auth_handler.py index 6bad2a3..bdac989 100644 --- a/tests/unittests/auth/test_auth_handler.py +++ b/tests/unittests/auth/test_auth_handler.py @@ -15,19 +15,18 @@ import copy from unittest.mock import patch -import pytest from fastapi.openapi.models import APIKey from fastapi.openapi.models import APIKeyIn from fastapi.openapi.models import OAuth2 from fastapi.openapi.models import OAuthFlowAuthorizationCode from fastapi.openapi.models import OAuthFlows - from google.adk.auth.auth_credential import AuthCredential from google.adk.auth.auth_credential import AuthCredentialTypes from google.adk.auth.auth_credential import OAuth2Auth from google.adk.auth.auth_handler import AuthHandler from google.adk.auth.auth_schemes import OpenIdConnectWithConfig from google.adk.auth.auth_tool import AuthConfig +import pytest # Mock classes for testing diff --git a/tests/unittests/cli/utils/test_cli.py b/tests/unittests/cli/utils/test_cli.py index 50307f3..a9b4284 100644 --- a/tests/unittests/cli/utils/test_cli.py +++ b/tests/unittests/cli/utils/test_cli.py @@ -16,182 +16,195 @@ from __future__ import annotations -import click import json -import pytest +from pathlib import Path import sys import types +from typing import Any +from typing import Dict +from typing import List +from typing import Tuple +import click import google.adk.cli.cli as cli +import pytest -from pathlib import Path -from typing import Any, Dict, List, Tuple # Helpers class _Recorder: - """Callable that records every invocation.""" + """Callable that records every invocation.""" - def __init__(self) -> None: - self.calls: List[Tuple[Tuple[Any, ...], Dict[str, Any]]] = [] + def __init__(self) -> None: + self.calls: List[Tuple[Tuple[Any, ...], Dict[str, Any]]] = [] - def __call__(self, *args: Any, **kwargs: Any) -> None: - self.calls.append((args, kwargs)) + def __call__(self, *args: Any, **kwargs: Any) -> None: + self.calls.append((args, kwargs)) # Fixtures @pytest.fixture(autouse=True) def _mute_click(monkeypatch: pytest.MonkeyPatch) -> None: - """Silence click output in every test.""" - monkeypatch.setattr(click, "echo", lambda *a, **k: None) - monkeypatch.setattr(click, "secho", lambda *a, **k: None) + """Silence click output in every test.""" + monkeypatch.setattr(click, "echo", lambda *a, **k: None) + monkeypatch.setattr(click, "secho", lambda *a, **k: None) @pytest.fixture(autouse=True) def _patch_types_and_runner(monkeypatch: pytest.MonkeyPatch) -> None: - """Replace google.genai.types and Runner with lightweight fakes.""" + """Replace google.genai.types and Runner with lightweight fakes.""" - # Dummy Part / Content - class _Part: - def __init__(self, text: str | None = "") -> None: - self.text = text + # Dummy Part / Content + class _Part: - class _Content: - def __init__(self, role: str, parts: List[_Part]) -> None: - self.role = role - self.parts = parts + def __init__(self, text: str | None = "") -> None: + self.text = text - monkeypatch.setattr(cli.types, "Part", _Part) - monkeypatch.setattr(cli.types, "Content", _Content) + class _Content: - # Fake Runner yielding a single assistant echo - class _FakeRunner: - def __init__(self, *a: Any, **k: Any) -> None: ... + def __init__(self, role: str, parts: List[_Part]) -> None: + self.role = role + self.parts = parts - async def run_async(self, *a: Any, **k: Any): - message = a[2] if len(a) >= 3 else k["new_message"] - text = message.parts[0].text if message.parts else "" - response = _Content("assistant", [_Part(f"echo:{text}")]) - yield types.SimpleNamespace(author="assistant", content=response) + monkeypatch.setattr(cli.types, "Part", _Part) + monkeypatch.setattr(cli.types, "Content", _Content) - monkeypatch.setattr(cli, "Runner", _FakeRunner) + # Fake Runner yielding a single assistant echo + class _FakeRunner: + + def __init__(self, *a: Any, **k: Any) -> None: + ... + + async def run_async(self, *a: Any, **k: Any): + message = a[2] if len(a) >= 3 else k["new_message"] + text = message.parts[0].text if message.parts else "" + response = _Content("assistant", [_Part(f"echo:{text}")]) + yield types.SimpleNamespace(author="assistant", content=response) + + monkeypatch.setattr(cli, "Runner", _FakeRunner) @pytest.fixture() def fake_agent(tmp_path: Path, monkeypatch: pytest.MonkeyPatch): - """Create a minimal importable agent package and patch importlib.""" + """Create a minimal importable agent package and patch importlib.""" - parent_dir = tmp_path / "agents" - parent_dir.mkdir() - agent_dir = parent_dir / "fake_agent" - agent_dir.mkdir() - # __init__.py exposes root_agent with .name - (agent_dir / "__init__.py").write_text( - "from types import SimpleNamespace\n" - "root_agent = SimpleNamespace(name='fake_root')\n" - ) + parent_dir = tmp_path / "agents" + parent_dir.mkdir() + agent_dir = parent_dir / "fake_agent" + agent_dir.mkdir() + # __init__.py exposes root_agent with .name + (agent_dir / "__init__.py").write_text( + "from types import SimpleNamespace\n" + "root_agent = SimpleNamespace(name='fake_root')\n" + ) - # Ensure importable via sys.path - sys.path.insert(0, str(parent_dir)) + # Ensure importable via sys.path + sys.path.insert(0, str(parent_dir)) - import importlib + import importlib - module = importlib.import_module("fake_agent") - fake_module = types.SimpleNamespace(agent=module) + module = importlib.import_module("fake_agent") + fake_module = types.SimpleNamespace(agent=module) - monkeypatch.setattr(importlib, "import_module", lambda n: fake_module) - monkeypatch.setattr(cli.envs, "load_dotenv_for_agent", lambda *a, **k: None) + monkeypatch.setattr(importlib, "import_module", lambda n: fake_module) + monkeypatch.setattr(cli.envs, "load_dotenv_for_agent", lambda *a, **k: None) - yield parent_dir, "fake_agent" + yield parent_dir, "fake_agent" - # Cleanup - sys.path.remove(str(parent_dir)) - del sys.modules["fake_agent"] + # Cleanup + sys.path.remove(str(parent_dir)) + del sys.modules["fake_agent"] # _run_input_file @pytest.mark.asyncio -async def test_run_input_file_outputs(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - """run_input_file should echo user & assistant messages and return a populated session.""" - recorder: List[str] = [] +async def test_run_input_file_outputs( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """run_input_file should echo user & assistant messages and return a populated session.""" + recorder: List[str] = [] - def _echo(msg: str) -> None: - recorder.append(msg) + def _echo(msg: str) -> None: + recorder.append(msg) - monkeypatch.setattr(click, "echo", _echo) + monkeypatch.setattr(click, "echo", _echo) - input_json = { - "state": {"foo": "bar"}, - "queries": ["hello world"], - } - input_path = tmp_path / "input.json" - input_path.write_text(json.dumps(input_json)) + input_json = { + "state": {"foo": "bar"}, + "queries": ["hello world"], + } + input_path = tmp_path / "input.json" + input_path.write_text(json.dumps(input_json)) - artifact_service = cli.InMemoryArtifactService() - session_service = cli.InMemorySessionService() - dummy_root = types.SimpleNamespace(name="root") + artifact_service = cli.InMemoryArtifactService() + session_service = cli.InMemorySessionService() + dummy_root = types.SimpleNamespace(name="root") - session = await cli.run_input_file( - app_name="app", - user_id="user", - root_agent=dummy_root, - artifact_service=artifact_service, - session_service=session_service, - input_path=str(input_path), - ) + session = await cli.run_input_file( + app_name="app", + user_id="user", + root_agent=dummy_root, + artifact_service=artifact_service, + session_service=session_service, + input_path=str(input_path), + ) - assert session.state["foo"] == "bar" - assert any("[user]:" in line for line in recorder) - assert any("[assistant]:" in line for line in recorder) + assert session.state["foo"] == "bar" + assert any("[user]:" in line for line in recorder) + assert any("[assistant]:" in line for line in recorder) # _run_cli (input_file branch) @pytest.mark.asyncio async def test_run_cli_with_input_file(fake_agent, tmp_path: Path) -> None: - """run_cli should process an input file without raising and without saving.""" - parent_dir, folder_name = fake_agent - input_json = {"state": {}, "queries": ["ping"]} - input_path = tmp_path / "in.json" - input_path.write_text(json.dumps(input_json)) + """run_cli should process an input file without raising and without saving.""" + parent_dir, folder_name = fake_agent + input_json = {"state": {}, "queries": ["ping"]} + input_path = tmp_path / "in.json" + input_path.write_text(json.dumps(input_json)) - await cli.run_cli( - agent_parent_dir=str(parent_dir), - agent_folder_name=folder_name, - input_file=str(input_path), - saved_session_file=None, - save_session=False, - ) + await cli.run_cli( + agent_parent_dir=str(parent_dir), + agent_folder_name=folder_name, + input_file=str(input_path), + saved_session_file=None, + save_session=False, + ) # _run_cli (interactive + save session branch) @pytest.mark.asyncio -async def test_run_cli_save_session(fake_agent, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - """run_cli should save a session file when save_session=True.""" - parent_dir, folder_name = fake_agent +async def test_run_cli_save_session( + fake_agent, tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + """run_cli should save a session file when save_session=True.""" + parent_dir, folder_name = fake_agent - # Simulate user typing 'exit' followed by session id 'sess123' - responses = iter(["exit", "sess123"]) - monkeypatch.setattr("builtins.input", lambda *_a, **_k: next(responses)) + # Simulate user typing 'exit' followed by session id 'sess123' + responses = iter(["exit", "sess123"]) + monkeypatch.setattr("builtins.input", lambda *_a, **_k: next(responses)) - session_file = Path(parent_dir) / folder_name / "sess123.session.json" - if session_file.exists(): - session_file.unlink() + session_file = Path(parent_dir) / folder_name / "sess123.session.json" + if session_file.exists(): + session_file.unlink() - await cli.run_cli( - agent_parent_dir=str(parent_dir), - agent_folder_name=folder_name, - input_file=None, - saved_session_file=None, - save_session=True, - ) + await cli.run_cli( + agent_parent_dir=str(parent_dir), + agent_folder_name=folder_name, + input_file=None, + saved_session_file=None, + save_session=True, + ) - assert session_file.exists() - data = json.loads(session_file.read_text()) - # The saved JSON should at least contain id and events keys - assert "id" in data and "events" in data + assert session_file.exists() + data = json.loads(session_file.read_text()) + # The saved JSON should at least contain id and events keys + assert "id" in data and "events" in data @pytest.mark.asyncio -async def test_run_interactively_whitespace_and_exit(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: +async def test_run_interactively_whitespace_and_exit( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: """run_interactively should skip blank input, echo once, then exit.""" # make a session that belongs to dummy agent svc = cli.InMemorySessionService() diff --git a/tests/unittests/cli/utils/test_cli_create.py b/tests/unittests/cli/utils/test_cli_create.py index 7ae9c22..1b33a88 100644 --- a/tests/unittests/cli/utils/test_cli_create.py +++ b/tests/unittests/cli/utils/test_cli_create.py @@ -17,214 +17,239 @@ from __future__ import annotations -import click import os -import pytest -import subprocess - -import google.adk.cli.cli_create as cli_create - from pathlib import Path -from typing import Any, Dict, List, Tuple +import subprocess +from typing import Any +from typing import Dict +from typing import List +from typing import Tuple + +import click +import google.adk.cli.cli_create as cli_create +import pytest + # Helpers class _Recorder: - """A callable object that records every invocation.""" + """A callable object that records every invocation.""" - def __init__(self) -> None: - self.calls: List[Tuple[Tuple[Any, ...], Dict[str, Any]]] = [] + def __init__(self) -> None: + self.calls: List[Tuple[Tuple[Any, ...], Dict[str, Any]]] = [] - def __call__(self, *args: Any, **kwargs: Any) -> None: # noqa: D401 - self.calls.append((args, kwargs)) + def __call__(self, *args: Any, **kwargs: Any) -> None: # noqa: D401 + self.calls.append((args, kwargs)) # Fixtures @pytest.fixture(autouse=True) def _mute_click(monkeypatch: pytest.MonkeyPatch) -> None: - """Silence click output in every test.""" - monkeypatch.setattr(click, "echo", lambda *a, **k: None) - monkeypatch.setattr(click, "secho", lambda *a, **k: None) + """Silence click output in every test.""" + monkeypatch.setattr(click, "echo", lambda *a, **k: None) + monkeypatch.setattr(click, "secho", lambda *a, **k: None) @pytest.fixture() def agent_folder(tmp_path: Path) -> Path: - """Return a temporary path that will hold generated agent sources.""" - return tmp_path / "agent" + """Return a temporary path that will hold generated agent sources.""" + return tmp_path / "agent" # _generate_files def test_generate_files_with_api_key(agent_folder: Path) -> None: - """Files should be created with the API-key backend and correct .env flags.""" - cli_create._generate_files( - str(agent_folder), - google_api_key="dummy-key", - model="gemini-2.0-flash-001", - ) + """Files should be created with the API-key backend and correct .env flags.""" + cli_create._generate_files( + str(agent_folder), + google_api_key="dummy-key", + model="gemini-2.0-flash-001", + ) - env_content = (agent_folder / ".env").read_text() - assert "GOOGLE_API_KEY=dummy-key" in env_content - assert "GOOGLE_GENAI_USE_VERTEXAI=0" in env_content - assert (agent_folder / "agent.py").exists() - assert (agent_folder / "__init__.py").exists() + env_content = (agent_folder / ".env").read_text() + assert "GOOGLE_API_KEY=dummy-key" in env_content + assert "GOOGLE_GENAI_USE_VERTEXAI=0" in env_content + assert (agent_folder / "agent.py").exists() + assert (agent_folder / "__init__.py").exists() def test_generate_files_with_gcp(agent_folder: Path) -> None: - """Files should be created with Vertex AI backend and correct .env flags.""" - cli_create._generate_files( - str(agent_folder), - google_cloud_project="proj", - google_cloud_region="us-central1", - model="gemini-2.0-flash-001", - ) + """Files should be created with Vertex AI backend and correct .env flags.""" + cli_create._generate_files( + str(agent_folder), + google_cloud_project="proj", + google_cloud_region="us-central1", + model="gemini-2.0-flash-001", + ) - env_content = (agent_folder / ".env").read_text() - assert "GOOGLE_CLOUD_PROJECT=proj" in env_content - assert "GOOGLE_CLOUD_LOCATION=us-central1" in env_content - assert "GOOGLE_GENAI_USE_VERTEXAI=1" in env_content + env_content = (agent_folder / ".env").read_text() + assert "GOOGLE_CLOUD_PROJECT=proj" in env_content + assert "GOOGLE_CLOUD_LOCATION=us-central1" in env_content + assert "GOOGLE_GENAI_USE_VERTEXAI=1" in env_content def test_generate_files_overwrite(agent_folder: Path) -> None: - """Existing files should be overwritten when generating again.""" - agent_folder.mkdir(parents=True, exist_ok=True) - (agent_folder / ".env").write_text("OLD") + """Existing files should be overwritten when generating again.""" + agent_folder.mkdir(parents=True, exist_ok=True) + (agent_folder / ".env").write_text("OLD") - cli_create._generate_files( - str(agent_folder), - google_api_key="new-key", - model="gemini-2.0-flash-001", - ) + cli_create._generate_files( + str(agent_folder), + google_api_key="new-key", + model="gemini-2.0-flash-001", + ) - assert "GOOGLE_API_KEY=new-key" in (agent_folder / ".env").read_text() + assert "GOOGLE_API_KEY=new-key" in (agent_folder / ".env").read_text() -def test_generate_files_permission_error(monkeypatch: pytest.MonkeyPatch, agent_folder: Path) -> None: - """PermissionError raised by os.makedirs should propagate.""" - monkeypatch.setattr(os, "makedirs", lambda *a, **k: (_ for _ in ()).throw(PermissionError())) - with pytest.raises(PermissionError): - cli_create._generate_files(str(agent_folder), model="gemini-2.0-flash-001") +def test_generate_files_permission_error( + monkeypatch: pytest.MonkeyPatch, agent_folder: Path +) -> None: + """PermissionError raised by os.makedirs should propagate.""" + monkeypatch.setattr( + os, "makedirs", lambda *a, **k: (_ for _ in ()).throw(PermissionError()) + ) + with pytest.raises(PermissionError): + cli_create._generate_files(str(agent_folder), model="gemini-2.0-flash-001") def test_generate_files_no_params(agent_folder: Path) -> None: - """No backend parameters → minimal .env file is generated.""" - cli_create._generate_files(str(agent_folder), model="gemini-2.0-flash-001") + """No backend parameters → minimal .env file is generated.""" + cli_create._generate_files(str(agent_folder), model="gemini-2.0-flash-001") - env_content = (agent_folder / ".env").read_text() - for key in ("GOOGLE_API_KEY", "GOOGLE_CLOUD_PROJECT", "GOOGLE_CLOUD_LOCATION", "GOOGLE_GENAI_USE_VERTEXAI"): - assert key not in env_content + env_content = (agent_folder / ".env").read_text() + for key in ( + "GOOGLE_API_KEY", + "GOOGLE_CLOUD_PROJECT", + "GOOGLE_CLOUD_LOCATION", + "GOOGLE_GENAI_USE_VERTEXAI", + ): + assert key not in env_content # run_cmd -def test_run_cmd_overwrite_reject(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: - """User rejecting overwrite should trigger click.Abort.""" - agent_name = "agent" - agent_dir = tmp_path / agent_name - agent_dir.mkdir() - (agent_dir / "dummy.txt").write_text("dummy") +def test_run_cmd_overwrite_reject( + monkeypatch: pytest.MonkeyPatch, tmp_path: Path +) -> None: + """User rejecting overwrite should trigger click.Abort.""" + agent_name = "agent" + agent_dir = tmp_path / agent_name + agent_dir.mkdir() + (agent_dir / "dummy.txt").write_text("dummy") - monkeypatch.setattr(os, "getcwd", lambda: str(tmp_path)) - monkeypatch.setattr(os.path, "exists", lambda _p: True) - monkeypatch.setattr(os, "listdir", lambda _p: ["dummy.txt"]) - monkeypatch.setattr(click, "confirm", lambda *a, **k: False) + monkeypatch.setattr(os, "getcwd", lambda: str(tmp_path)) + monkeypatch.setattr(os.path, "exists", lambda _p: True) + monkeypatch.setattr(os, "listdir", lambda _p: ["dummy.txt"]) + monkeypatch.setattr(click, "confirm", lambda *a, **k: False) - with pytest.raises(click.Abort): - cli_create.run_cmd( - agent_name, - model="gemini-2.0-flash-001", - google_api_key=None, - google_cloud_project=None, - google_cloud_region=None, - ) + with pytest.raises(click.Abort): + cli_create.run_cmd( + agent_name, + model="gemini-2.0-flash-001", + google_api_key=None, + google_cloud_project=None, + google_cloud_region=None, + ) # Prompt helpers def test_prompt_for_google_cloud(monkeypatch: pytest.MonkeyPatch) -> None: - """Prompt should return the project input.""" - monkeypatch.setattr(click, "prompt", lambda *a, **k: "test-proj") - assert cli_create._prompt_for_google_cloud(None) == "test-proj" + """Prompt should return the project input.""" + monkeypatch.setattr(click, "prompt", lambda *a, **k: "test-proj") + assert cli_create._prompt_for_google_cloud(None) == "test-proj" -def test_prompt_for_google_cloud_region(monkeypatch: pytest.MonkeyPatch) -> None: - """Prompt should return the region input.""" - monkeypatch.setattr(click, "prompt", lambda *a, **k: "asia-northeast1") - assert cli_create._prompt_for_google_cloud_region(None) == "asia-northeast1" +def test_prompt_for_google_cloud_region( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Prompt should return the region input.""" + monkeypatch.setattr(click, "prompt", lambda *a, **k: "asia-northeast1") + assert cli_create._prompt_for_google_cloud_region(None) == "asia-northeast1" def test_prompt_for_google_api_key(monkeypatch: pytest.MonkeyPatch) -> None: - """Prompt should return the API-key input.""" - monkeypatch.setattr(click, "prompt", lambda *a, **k: "api-key") - assert cli_create._prompt_for_google_api_key(None) == "api-key" + """Prompt should return the API-key input.""" + monkeypatch.setattr(click, "prompt", lambda *a, **k: "api-key") + assert cli_create._prompt_for_google_api_key(None) == "api-key" def test_prompt_for_model_gemini(monkeypatch: pytest.MonkeyPatch) -> None: - """Selecting option '1' should return the default Gemini model string.""" - monkeypatch.setattr(click, "prompt", lambda *a, **k: "1") - assert cli_create._prompt_for_model() == "gemini-2.0-flash-001" + """Selecting option '1' should return the default Gemini model string.""" + monkeypatch.setattr(click, "prompt", lambda *a, **k: "1") + assert cli_create._prompt_for_model() == "gemini-2.0-flash-001" def test_prompt_for_model_other(monkeypatch: pytest.MonkeyPatch) -> None: - """Selecting option '2' should return placeholder and call secho.""" - called: Dict[str, bool] = {} + """Selecting option '2' should return placeholder and call secho.""" + called: Dict[str, bool] = {} - monkeypatch.setattr(click, "prompt", lambda *a, **k: "2") + monkeypatch.setattr(click, "prompt", lambda *a, **k: "2") - def _fake_secho(*_a: Any, **_k: Any) -> None: - called["secho"] = True - - monkeypatch.setattr(click, "secho", _fake_secho) - assert cli_create._prompt_for_model() == "" - assert called.get("secho") is True + def _fake_secho(*_a: Any, **_k: Any) -> None: + called["secho"] = True + monkeypatch.setattr(click, "secho", _fake_secho) + assert cli_create._prompt_for_model() == "" + assert called.get("secho") is True # Backend selection helper def test_prompt_to_choose_backend_api(monkeypatch: pytest.MonkeyPatch) -> None: - """Choosing API-key backend returns (api_key, None, None).""" - monkeypatch.setattr(click, "prompt", lambda *a, **k: "1") - monkeypatch.setattr(cli_create, "_prompt_for_google_api_key", lambda _v: "api-key") + """Choosing API-key backend returns (api_key, None, None).""" + monkeypatch.setattr(click, "prompt", lambda *a, **k: "1") + monkeypatch.setattr( + cli_create, "_prompt_for_google_api_key", lambda _v: "api-key" + ) - api_key, proj, region = cli_create._prompt_to_choose_backend(None, None, None) - assert api_key == "api-key" - assert proj is None and region is None + api_key, proj, region = cli_create._prompt_to_choose_backend(None, None, None) + assert api_key == "api-key" + assert proj is None and region is None -def test_prompt_to_choose_backend_vertex(monkeypatch: pytest.MonkeyPatch) -> None: - """Choosing Vertex backend returns (None, project, region).""" - monkeypatch.setattr(click, "prompt", lambda *a, **k: "2") - monkeypatch.setattr(cli_create, "_prompt_for_google_cloud", lambda _v: "proj") - monkeypatch.setattr(cli_create, "_prompt_for_google_cloud_region", lambda _v: "region") - - api_key, proj, region = cli_create._prompt_to_choose_backend(None, None, None) - assert api_key is None - assert proj == "proj" - assert region == "region" +def test_prompt_to_choose_backend_vertex( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Choosing Vertex backend returns (None, project, region).""" + monkeypatch.setattr(click, "prompt", lambda *a, **k: "2") + monkeypatch.setattr(cli_create, "_prompt_for_google_cloud", lambda _v: "proj") + monkeypatch.setattr( + cli_create, "_prompt_for_google_cloud_region", lambda _v: "region" + ) + api_key, proj, region = cli_create._prompt_to_choose_backend(None, None, None) + assert api_key is None + assert proj == "proj" + assert region == "region" # prompt_str def test_prompt_str_non_empty(monkeypatch: pytest.MonkeyPatch) -> None: - """_prompt_str should retry until a non-blank string is provided.""" - responses = iter(["", " ", "valid"]) - monkeypatch.setattr(click, "prompt", lambda *_a, **_k: next(responses)) - assert cli_create._prompt_str("dummy") == "valid" - + """_prompt_str should retry until a non-blank string is provided.""" + responses = iter(["", " ", "valid"]) + monkeypatch.setattr(click, "prompt", lambda *_a, **_k: next(responses)) + assert cli_create._prompt_str("dummy") == "valid" # gcloud fallback helpers -def test_get_gcp_project_from_gcloud_fail(monkeypatch: pytest.MonkeyPatch) -> None: - """Failure of gcloud project lookup should return empty string.""" - monkeypatch.setattr( - subprocess, - "run", - lambda *_a, **_k: (_ for _ in ()).throw(FileNotFoundError()), - ) - assert cli_create._get_gcp_project_from_gcloud() == "" +def test_get_gcp_project_from_gcloud_fail( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Failure of gcloud project lookup should return empty string.""" + monkeypatch.setattr( + subprocess, + "run", + lambda *_a, **_k: (_ for _ in ()).throw(FileNotFoundError()), + ) + assert cli_create._get_gcp_project_from_gcloud() == "" -def test_get_gcp_region_from_gcloud_fail(monkeypatch: pytest.MonkeyPatch) -> None: - """CalledProcessError should result in empty region string.""" - monkeypatch.setattr( - subprocess, - "run", - lambda *_a, **_k: (_ for _ in ()).throw(subprocess.CalledProcessError(1, "gcloud")), - ) - assert cli_create._get_gcp_region_from_gcloud() == "" +def test_get_gcp_region_from_gcloud_fail( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """CalledProcessError should result in empty region string.""" + monkeypatch.setattr( + subprocess, + "run", + lambda *_a, **_k: (_ for _ in ()).throw( + subprocess.CalledProcessError(1, "gcloud") + ), + ) + assert cli_create._get_gcp_region_from_gcloud() == "" diff --git a/tests/unittests/cli/utils/test_cli_deploy.py b/tests/unittests/cli/utils/test_cli_deploy.py index f1f7bf3..6f8c291 100644 --- a/tests/unittests/cli/utils/test_cli_deploy.py +++ b/tests/unittests/cli/utils/test_cli_deploy.py @@ -17,70 +17,74 @@ from __future__ import annotations -import click +from pathlib import Path import shutil -import pytest import subprocess import tempfile import types - -import google.adk.cli.cli_deploy as cli_deploy - -from pathlib import Path -from typing import Any, Callable, Dict, List, Tuple +from typing import Any +from typing import Callable +from typing import Dict +from typing import List +from typing import Tuple from unittest import mock +import click +import google.adk.cli.cli_deploy as cli_deploy +import pytest + + # Helpers class _Recorder: - """A callable object that records every invocation.""" + """A callable object that records every invocation.""" - def __init__(self) -> None: - self.calls: List[Tuple[Tuple[Any, ...], Dict[str, Any]]] = [] + def __init__(self) -> None: + self.calls: List[Tuple[Tuple[Any, ...], Dict[str, Any]]] = [] - def __call__(self, *args: Any, **kwargs: Any) -> None: - self.calls.append((args, kwargs)) + def __call__(self, *args: Any, **kwargs: Any) -> None: + self.calls.append((args, kwargs)) # Fixtures @pytest.fixture(autouse=True) def _mute_click(monkeypatch: pytest.MonkeyPatch) -> None: - """Suppress click.echo to keep test output clean.""" - monkeypatch.setattr(click, "echo", lambda *a, **k: None) + """Suppress click.echo to keep test output clean.""" + monkeypatch.setattr(click, "echo", lambda *a, **k: None) @pytest.fixture() def agent_dir(tmp_path: Path) -> Callable[[bool], Path]: - """Return a factory that creates a dummy agent directory tree.""" + """Return a factory that creates a dummy agent directory tree.""" - def _factory(include_requirements: bool) -> Path: - base = tmp_path / "agent" - base.mkdir() - (base / "agent.py").write_text("# dummy agent") - (base / "__init__.py").touch() - if include_requirements: - (base / "requirements.txt").write_text("pytest\n") - return base + def _factory(include_requirements: bool) -> Path: + base = tmp_path / "agent" + base.mkdir() + (base / "agent.py").write_text("# dummy agent") + (base / "__init__.py").touch() + if include_requirements: + (base / "requirements.txt").write_text("pytest\n") + return base - return _factory + return _factory # _resolve_project def test_resolve_project_with_option() -> None: - """It should return the explicit project value untouched.""" - assert cli_deploy._resolve_project("my-project") == "my-project" + """It should return the explicit project value untouched.""" + assert cli_deploy._resolve_project("my-project") == "my-project" def test_resolve_project_from_gcloud(monkeypatch: pytest.MonkeyPatch) -> None: - """It should fall back to `gcloud config get-value project` when no value supplied.""" - monkeypatch.setattr( - subprocess, - "run", - lambda *a, **k: types.SimpleNamespace(stdout="gcp-proj\n"), - ) + """It should fall back to `gcloud config get-value project` when no value supplied.""" + monkeypatch.setattr( + subprocess, + "run", + lambda *a, **k: types.SimpleNamespace(stdout="gcp-proj\n"), + ) - with mock.patch("click.echo") as mocked_echo: - assert cli_deploy._resolve_project(None) == "gcp-proj" - mocked_echo.assert_called_once() + with mock.patch("click.echo") as mocked_echo: + assert cli_deploy._resolve_project(None) == "gcp-proj" + mocked_echo.assert_called_once() # to_cloud_run @@ -90,81 +94,83 @@ def test_to_cloud_run_happy_path( agent_dir: Callable[[bool], Path], include_requirements: bool, ) -> None: - """ - End-to-end execution test for `to_cloud_run` covering both presence and - absence of *requirements.txt*. - """ - tmp_dir = Path(tempfile.mkdtemp()) - src_dir = agent_dir(include_requirements) + """ + End-to-end execution test for `to_cloud_run` covering both presence and + absence of *requirements.txt*. + """ + tmp_dir = Path(tempfile.mkdtemp()) + src_dir = agent_dir(include_requirements) - copy_recorder = _Recorder() - run_recorder = _Recorder() + copy_recorder = _Recorder() + run_recorder = _Recorder() - # Cache the ORIGINAL copytree before patching - original_copytree = cli_deploy.shutil.copytree + # Cache the ORIGINAL copytree before patching + original_copytree = cli_deploy.shutil.copytree - def _recording_copytree(*args: Any, **kwargs: Any): - copy_recorder(*args, **kwargs) - return original_copytree(*args, **kwargs) + def _recording_copytree(*args: Any, **kwargs: Any): + copy_recorder(*args, **kwargs) + return original_copytree(*args, **kwargs) - monkeypatch.setattr(cli_deploy.shutil, "copytree", _recording_copytree) - # Skip actual cleanup so that we can inspect generated files later. - monkeypatch.setattr(cli_deploy.shutil, "rmtree", lambda *_a, **_k: None) - monkeypatch.setattr(subprocess, "run", run_recorder) + monkeypatch.setattr(cli_deploy.shutil, "copytree", _recording_copytree) + # Skip actual cleanup so that we can inspect generated files later. + monkeypatch.setattr(cli_deploy.shutil, "rmtree", lambda *_a, **_k: None) + monkeypatch.setattr(subprocess, "run", run_recorder) - cli_deploy.to_cloud_run( - agent_folder=str(src_dir), - project="proj", - region="asia-northeast1", - service_name="svc", - app_name="app", - temp_folder=str(tmp_dir), - port=8080, - trace_to_cloud=True, - with_ui=True, - verbosity="info", - session_db_url="sqlite://", - adk_version="0.0.5", - ) + cli_deploy.to_cloud_run( + agent_folder=str(src_dir), + project="proj", + region="asia-northeast1", + service_name="svc", + app_name="app", + temp_folder=str(tmp_dir), + port=8080, + trace_to_cloud=True, + with_ui=True, + verbosity="info", + session_db_url="sqlite://", + adk_version="0.0.5", + ) - # Assertions - assert len(copy_recorder.calls) == 1, "Agent sources must be copied exactly once." - assert run_recorder.calls, "gcloud command should be executed at least once." - assert (tmp_dir / "Dockerfile").exists(), "Dockerfile must be generated." + # Assertions + assert ( + len(copy_recorder.calls) == 1 + ), "Agent sources must be copied exactly once." + assert run_recorder.calls, "gcloud command should be executed at least once." + assert (tmp_dir / "Dockerfile").exists(), "Dockerfile must be generated." - # Manual cleanup because we disabled rmtree in the monkeypatch. - shutil.rmtree(tmp_dir, ignore_errors=True) + # Manual cleanup because we disabled rmtree in the monkeypatch. + shutil.rmtree(tmp_dir, ignore_errors=True) def test_to_cloud_run_cleans_temp_dir( monkeypatch: pytest.MonkeyPatch, agent_dir: Callable[[bool], Path], ) -> None: - """`to_cloud_run` should always delete the temporary folder on exit.""" - tmp_dir = Path(tempfile.mkdtemp()) - src_dir = agent_dir(False) + """`to_cloud_run` should always delete the temporary folder on exit.""" + tmp_dir = Path(tempfile.mkdtemp()) + src_dir = agent_dir(False) - deleted: Dict[str, Path] = {} + deleted: Dict[str, Path] = {} - def _fake_rmtree(path: str | Path, *a: Any, **k: Any) -> None: - deleted["path"] = Path(path) + def _fake_rmtree(path: str | Path, *a: Any, **k: Any) -> None: + deleted["path"] = Path(path) - monkeypatch.setattr(cli_deploy.shutil, "rmtree", _fake_rmtree) - monkeypatch.setattr(subprocess, "run", _Recorder()) + monkeypatch.setattr(cli_deploy.shutil, "rmtree", _fake_rmtree) + monkeypatch.setattr(subprocess, "run", _Recorder()) - cli_deploy.to_cloud_run( - agent_folder=str(src_dir), - project="proj", - region=None, - service_name="svc", - app_name="app", - temp_folder=str(tmp_dir), - port=8080, - trace_to_cloud=False, - with_ui=False, - verbosity="info", - session_db_url=None, - adk_version="0.0.5", - ) + cli_deploy.to_cloud_run( + agent_folder=str(src_dir), + project="proj", + region=None, + service_name="svc", + app_name="app", + temp_folder=str(tmp_dir), + port=8080, + trace_to_cloud=False, + with_ui=False, + verbosity="info", + session_db_url=None, + adk_version="0.0.5", + ) - assert deleted["path"] == tmp_dir + assert deleted["path"] == tmp_dir diff --git a/tests/unittests/code_executors/__init__.py b/tests/unittests/code_executors/__init__.py index 60cac4f..0a2669d 100644 --- a/tests/unittests/code_executors/__init__.py +++ b/tests/unittests/code_executors/__init__.py @@ -10,4 +10,4 @@ # 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. \ No newline at end of file +# limitations under the License. diff --git a/tests/unittests/code_executors/test_code_executor_context.py b/tests/unittests/code_executors/test_code_executor_context.py index 1802fb2..5f3a237 100644 --- a/tests/unittests/code_executors/test_code_executor_context.py +++ b/tests/unittests/code_executors/test_code_executor_context.py @@ -137,11 +137,15 @@ def test_get_input_files_not_exists(empty_state: State): def test_add_input_files_new(empty_state: State): """Test adding input files to an empty session state.""" ctx = CodeExecutorContext(empty_state) - new_files = [File(name="new.dat", content="Yg==", mime_type="application/octet-stream")] - ctx.add_input_files(new_files) - assert empty_state["_code_executor_input_files"] == [ - {"name": "new.dat", "content": "Yg==", "mime_type": "application/octet-stream"} + new_files = [ + File(name="new.dat", content="Yg==", mime_type="application/octet-stream") ] + ctx.add_input_files(new_files) + assert empty_state["_code_executor_input_files"] == [{ + "name": "new.dat", + "content": "Yg==", + "mime_type": "application/octet-stream", + }] def test_add_input_files_append(context_with_data: CodeExecutorContext): @@ -239,9 +243,7 @@ def test_reset_error_count_no_error_key(empty_state: State): def test_update_code_execution_result_new_invocation(empty_state: State): """Test updating code execution result for a new invocation.""" ctx = CodeExecutorContext(empty_state) - ctx.update_code_execution_result( - "inv1", "print('hi')", "hi", "" - ) + ctx.update_code_execution_result("inv1", "print('hi')", "hi", "") results = empty_state["_code_execution_results"]["inv1"] assert len(results) == 1 assert results[0]["code"] == "print('hi')" @@ -272,4 +274,4 @@ def test_update_code_execution_result_append( assert len(results) == 2 assert results[1]["code"] == "new_code" assert results[1]["result_stdout"] == "new_out" - assert results[1]["result_stderr"] == "new_err" \ No newline at end of file + assert results[1]["result_stderr"] == "new_err" diff --git a/tests/unittests/evaluation/test_trajectory_evaluator.py b/tests/unittests/evaluation/test_trajectory_evaluator.py index 7b1426c..f3622a5 100644 --- a/tests/unittests/evaluation/test_trajectory_evaluator.py +++ b/tests/unittests/evaluation/test_trajectory_evaluator.py @@ -15,6 +15,7 @@ """Testings for the Trajectory Evaluator.""" import math + from google.adk.evaluation.trajectory_evaluator import TrajectoryEvaluator import pytest diff --git a/tests/unittests/fast_api/test_fast_api.py b/tests/unittests/fast_api/test_fast_api.py index b285908..c206821 100644 --- a/tests/unittests/fast_api/test_fast_api.py +++ b/tests/unittests/fast_api/test_fast_api.py @@ -18,7 +18,8 @@ import os import sys import time import types as ptypes -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock +from unittest.mock import patch from fastapi.testclient import TestClient from google.adk.agents.base_agent import BaseAgent @@ -31,7 +32,6 @@ from google.adk.sessions.base_session_service import ListSessionsResponse from google.genai import types import pytest - # Configure logging to help diagnose server startup issues logging.basicConfig( level=logging.INFO, diff --git a/tests/unittests/flows/llm_flows/test_instructions.py b/tests/unittests/flows/llm_flows/test_instructions.py index 8d95dc2..8ef3148 100644 --- a/tests/unittests/flows/llm_flows/test_instructions.py +++ b/tests/unittests/flows/llm_flows/test_instructions.py @@ -100,6 +100,7 @@ async def test_function_system_instruction(): " test_id." ) + @pytest.mark.asyncio async def test_async_function_system_instruction(): async def build_function_instruction( diff --git a/tests/unittests/models/test_litellm.py b/tests/unittests/models/test_litellm.py index 44a14e1..771fd93 100644 --- a/tests/unittests/models/test_litellm.py +++ b/tests/unittests/models/test_litellm.py @@ -15,6 +15,7 @@ from unittest.mock import AsyncMock from unittest.mock import Mock + from google.adk.models.lite_llm import _content_to_message_param from google.adk.models.lite_llm import _function_declaration_to_tool_param from google.adk.models.lite_llm import _get_content @@ -169,6 +170,7 @@ STREAMING_MODEL_RESPONSE = [ ), ] + @pytest.fixture def mock_response(): return ModelResponse( @@ -264,57 +266,59 @@ async def test_generate_content_async(mock_acompletion, lite_llm_instance): litellm_append_user_content_test_cases = [ - pytest.param( - LlmRequest( - contents=[ - types.Content( - role="developer", - parts=[types.Part.from_text(text="Test prompt")] - ) - ] - ), - 2, - id="litellm request without user content" - ), - pytest.param( - LlmRequest( - contents=[ - types.Content( - role="user", - parts=[types.Part.from_text(text="user prompt")] - ) - ] - ), - 1, - id="litellm request with user content" - ), - pytest.param( - LlmRequest( - contents=[ - types.Content( - role="model", - parts=[types.Part.from_text(text="model prompt")] + pytest.param( + LlmRequest( + contents=[ + types.Content( + role="developer", + parts=[types.Part.from_text(text="Test prompt")], + ) + ] ), - types.Content( - role="user", - parts=[types.Part.from_text(text="user prompt")] - ), - types.Content( - role="model", - parts=[types.Part.from_text(text="model prompt")] - ) - ] + 2, + id="litellm request without user content", + ), + pytest.param( + LlmRequest( + contents=[ + types.Content( + role="user", + parts=[types.Part.from_text(text="user prompt")], + ) + ] + ), + 1, + id="litellm request with user content", + ), + pytest.param( + LlmRequest( + contents=[ + types.Content( + role="model", + parts=[types.Part.from_text(text="model prompt")], + ), + types.Content( + role="user", + parts=[types.Part.from_text(text="user prompt")], + ), + types.Content( + role="model", + parts=[types.Part.from_text(text="model prompt")], + ), + ] + ), + 4, + id="user content is not the last message scenario", ), - 4, - id="user content is not the last message scenario" - ) ] + @pytest.mark.parametrize( - "llm_request, expected_output", - litellm_append_user_content_test_cases + "llm_request, expected_output", litellm_append_user_content_test_cases ) -def test_maybe_append_user_content(lite_llm_instance, llm_request, expected_output): +def test_maybe_append_user_content( + lite_llm_instance, llm_request, expected_output +): lite_llm_instance._maybe_append_user_content(llm_request) diff --git a/tests/unittests/sessions/test_session_service.py b/tests/unittests/sessions/test_session_service.py index 6bdc8c9..59f2443 100644 --- a/tests/unittests/sessions/test_session_service.py +++ b/tests/unittests/sessions/test_session_service.py @@ -13,7 +13,6 @@ # limitations under the License. import enum -import pytest from google.adk.events import Event from google.adk.events import EventActions @@ -21,6 +20,7 @@ from google.adk.sessions import DatabaseSessionService from google.adk.sessions import InMemorySessionService from google.adk.sessions.base_session_service import GetSessionConfig from google.genai import types +import pytest class SessionServiceType(enum.Enum): diff --git a/tests/unittests/sessions/test_vertex_ai_session_service.py b/tests/unittests/sessions/test_vertex_ai_session_service.py index ba9f945..71145ce 100644 --- a/tests/unittests/sessions/test_vertex_ai_session_service.py +++ b/tests/unittests/sessions/test_vertex_ai_session_service.py @@ -24,7 +24,6 @@ from google.adk.sessions import VertexAiSessionService from google.genai import types import pytest - MOCK_SESSION_JSON_1 = { 'name': ( 'projects/test-project/locations/test-location/' diff --git a/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py b/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py index 9a84ee9..7fccec6 100644 --- a/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py +++ b/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py @@ -14,7 +14,9 @@ import base64 import json -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock +from unittest.mock import patch + from google.adk.tools.apihub_tool.clients.apihub_client import APIHubClient import pytest from requests.exceptions import HTTPError @@ -464,9 +466,7 @@ class TestAPIHubClient: MagicMock( status_code=200, json=lambda: { - "name": ( - "projects/test-project/locations/us-central1/apis/api1/versions/v1" - ), + "name": "projects/test-project/locations/us-central1/apis/api1/versions/v1", "specs": [], }, ), # No specs diff --git a/tests/unittests/tools/openapi_tool/common/test_common.py b/tests/unittests/tools/openapi_tool/common/test_common.py index f20de57..c188367 100644 --- a/tests/unittests/tools/openapi_tool/common/test_common.py +++ b/tests/unittests/tools/openapi_tool/common/test_common.py @@ -16,7 +16,8 @@ from typing import Any from typing import Dict from typing import List -from fastapi.openapi.models import Response, Schema +from fastapi.openapi.models import Response +from fastapi.openapi.models import Schema from google.adk.tools.openapi_tool.common.common import ApiParameter from google.adk.tools.openapi_tool.common.common import PydocHelper from google.adk.tools.openapi_tool.common.common import rename_python_keywords diff --git a/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py b/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py index de3156e..8fbee55 100644 --- a/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py +++ b/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py @@ -371,9 +371,7 @@ def test_parse_external_ref_raises_error(openapi_spec_generator): "content": { "application/json": { "schema": { - "$ref": ( - "external_file.json#/components/schemas/ExternalSchema" - ) + "$ref": "external_file.json#/components/schemas/ExternalSchema" } } }, diff --git a/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py b/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py index 6b4e27f..adc6ba0 100644 --- a/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py +++ b/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py @@ -14,9 +14,11 @@ import json -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock +from unittest.mock import patch -from fastapi.openapi.models import MediaType, Operation +from fastapi.openapi.models import MediaType +from fastapi.openapi.models import Operation from fastapi.openapi.models import Parameter as OpenAPIParameter from fastapi.openapi.models import RequestBody from fastapi.openapi.models import Schema as OpenAPISchema @@ -25,13 +27,13 @@ from google.adk.tools.openapi_tool.auth.auth_helpers import token_to_scheme_cred from google.adk.tools.openapi_tool.common.common import ApiParameter from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_spec_parser import OperationEndpoint from google.adk.tools.openapi_tool.openapi_spec_parser.operation_parser import OperationParser -from google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool import ( - RestApiTool, - snake_to_lower_camel, - to_gemini_schema, -) +from google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool import RestApiTool +from google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool import snake_to_lower_camel +from google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool import to_gemini_schema from google.adk.tools.tool_context import ToolContext -from google.genai.types import FunctionDeclaration, Schema, Type +from google.genai.types import FunctionDeclaration +from google.genai.types import Schema +from google.genai.types import Type import pytest diff --git a/tests/unittests/tools/test_function_tool.py b/tests/unittests/tools/test_function_tool.py index ece1f53..26f37e6 100644 --- a/tests/unittests/tools/test_function_tool.py +++ b/tests/unittests/tools/test_function_tool.py @@ -161,11 +161,9 @@ async def test_run_async_1_missing_arg_sync_func(): args = {"arg1": "test_value_1"} result = await tool.run_async(args=args, tool_context=MagicMock()) assert result == { - "error": ( - """Invoking `function_for_testing_with_2_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: + "error": """Invoking `function_for_testing_with_2_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: arg2 You could retry calling this tool, but it is IMPORTANT for you to provide all the mandatory parameters.""" - ) } @@ -176,11 +174,9 @@ async def test_run_async_1_missing_arg_async_func(): args = {"arg2": "test_value_1"} result = await tool.run_async(args=args, tool_context=MagicMock()) assert result == { - "error": ( - """Invoking `async_function_for_testing_with_2_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: + "error": """Invoking `async_function_for_testing_with_2_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: arg1 You could retry calling this tool, but it is IMPORTANT for you to provide all the mandatory parameters.""" - ) } @@ -191,13 +187,11 @@ async def test_run_async_3_missing_arg_sync_func(): args = {"arg2": "test_value_1"} result = await tool.run_async(args=args, tool_context=MagicMock()) assert result == { - "error": ( - """Invoking `function_for_testing_with_4_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: + "error": """Invoking `function_for_testing_with_4_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: arg1 arg3 arg4 You could retry calling this tool, but it is IMPORTANT for you to provide all the mandatory parameters.""" - ) } @@ -208,13 +202,11 @@ async def test_run_async_3_missing_arg_async_func(): args = {"arg3": "test_value_1"} result = await tool.run_async(args=args, tool_context=MagicMock()) assert result == { - "error": ( - """Invoking `async_function_for_testing_with_4_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: + "error": """Invoking `async_function_for_testing_with_4_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: arg1 arg2 arg4 You could retry calling this tool, but it is IMPORTANT for you to provide all the mandatory parameters.""" - ) } @@ -225,14 +217,12 @@ async def test_run_async_missing_all_arg_sync_func(): args = {} result = await tool.run_async(args=args, tool_context=MagicMock()) assert result == { - "error": ( - """Invoking `function_for_testing_with_4_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: + "error": """Invoking `function_for_testing_with_4_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: arg1 arg2 arg3 arg4 You could retry calling this tool, but it is IMPORTANT for you to provide all the mandatory parameters.""" - ) } @@ -243,14 +233,12 @@ async def test_run_async_missing_all_arg_async_func(): args = {} result = await tool.run_async(args=args, tool_context=MagicMock()) assert result == { - "error": ( - """Invoking `async_function_for_testing_with_4_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: + "error": """Invoking `async_function_for_testing_with_4_arg_and_no_tool_context()` failed as the following mandatory input parameters are not present: arg1 arg2 arg3 arg4 You could retry calling this tool, but it is IMPORTANT for you to provide all the mandatory parameters.""" - ) }