mirror of
https://github.com/EvolutionAPI/adk-python.git
synced 2025-07-13 15:14:50 -06:00
Copybara import of the project:
-- 8baeb0b569eaedc638b20e46894178a3b878dbd6 by Amulya Bhatia <amulya.bhatia@t-online.de>: test: unit tests for built_in_code_executor and unsafe_code_executor -- cfac73b9271557ead96eb5fb419e05d88c6e8cd4 by Amulya Bhatia <amulya.bhatia@t-online.de>: test: unit tests for built_in_code_executor and unsafe_code_executor COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/971 from iamulya:code-executor-tests 55290e27b5e58ef3835905aec88639e936318d01 PiperOrigin-RevId: 764976316
This commit is contained in:
parent
04e07b4a14
commit
face2e8cf2
109
tests/unittests/code_executors/test_built_in_code_executor.py
Normal file
109
tests/unittests/code_executors/test_built_in_code_executor.py
Normal file
@ -0,0 +1,109 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# 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.
|
||||
import pytest
|
||||
from google.genai import types
|
||||
|
||||
from google.adk.code_executors.built_in_code_executor import BuiltInCodeExecutor
|
||||
from google.adk.models.llm_request import LlmRequest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def built_in_executor() -> BuiltInCodeExecutor:
|
||||
return BuiltInCodeExecutor()
|
||||
|
||||
|
||||
def test_process_llm_request_gemini_2_model_config_none(
|
||||
built_in_executor: BuiltInCodeExecutor,
|
||||
):
|
||||
"""Tests processing when llm_request.config is None for Gemini 2."""
|
||||
llm_request = LlmRequest(model="gemini-2.0-flash")
|
||||
built_in_executor.process_llm_request(llm_request)
|
||||
assert llm_request.config is not None
|
||||
assert llm_request.config.tools == [
|
||||
types.Tool(code_execution=types.ToolCodeExecution())
|
||||
]
|
||||
|
||||
|
||||
def test_process_llm_request_gemini_2_model_tools_none(
|
||||
built_in_executor: BuiltInCodeExecutor,
|
||||
):
|
||||
"""Tests processing when llm_request.config.tools is None for Gemini 2."""
|
||||
llm_request = LlmRequest(
|
||||
model="gemini-2.0-pro", config=types.GenerateContentConfig()
|
||||
)
|
||||
built_in_executor.process_llm_request(llm_request)
|
||||
assert llm_request.config.tools == [
|
||||
types.Tool(code_execution=types.ToolCodeExecution())
|
||||
]
|
||||
|
||||
|
||||
def test_process_llm_request_gemini_2_model_tools_empty(
|
||||
built_in_executor: BuiltInCodeExecutor,
|
||||
):
|
||||
"""Tests processing when llm_request.config.tools is empty for Gemini 2."""
|
||||
llm_request = LlmRequest(
|
||||
model="gemini-2.0-ultra",
|
||||
config=types.GenerateContentConfig(tools=[]),
|
||||
)
|
||||
built_in_executor.process_llm_request(llm_request)
|
||||
assert llm_request.config.tools == [
|
||||
types.Tool(code_execution=types.ToolCodeExecution())
|
||||
]
|
||||
|
||||
|
||||
def test_process_llm_request_gemini_2_model_with_existing_tools(
|
||||
built_in_executor: BuiltInCodeExecutor,
|
||||
):
|
||||
"""Tests processing when llm_request.config.tools already has tools for Gemini 2."""
|
||||
existing_tool = types.Tool(
|
||||
function_declarations=[
|
||||
types.FunctionDeclaration(name="test_func", description="A test func")
|
||||
]
|
||||
)
|
||||
llm_request = LlmRequest(
|
||||
model="gemini-2.0-flash-001",
|
||||
config=types.GenerateContentConfig(tools=[existing_tool]),
|
||||
)
|
||||
built_in_executor.process_llm_request(llm_request)
|
||||
assert len(llm_request.config.tools) == 2
|
||||
assert existing_tool in llm_request.config.tools
|
||||
assert types.Tool(
|
||||
code_execution=types.ToolCodeExecution()
|
||||
) in llm_request.config.tools
|
||||
|
||||
|
||||
def test_process_llm_request_non_gemini_2_model(
|
||||
built_in_executor: BuiltInCodeExecutor,
|
||||
):
|
||||
"""Tests that a ValueError is raised for non-Gemini 2 models."""
|
||||
llm_request = LlmRequest(model="gemini-1.5-flash")
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
built_in_executor.process_llm_request(llm_request)
|
||||
assert (
|
||||
"Gemini code execution tool is not supported for model gemini-1.5-flash"
|
||||
in str(excinfo.value)
|
||||
)
|
||||
|
||||
|
||||
def test_process_llm_request_no_model_name(
|
||||
built_in_executor: BuiltInCodeExecutor,
|
||||
):
|
||||
"""Tests that a ValueError is raised if model name is not set."""
|
||||
llm_request = LlmRequest() # Model name defaults to None
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
built_in_executor.process_llm_request(llm_request)
|
||||
assert (
|
||||
"Gemini code execution tool is not supported for model None"
|
||||
in str(excinfo.value)
|
||||
)
|
@ -0,0 +1,87 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# 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.
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
from google.adk.code_executors.unsafe_local_code_executor import UnsafeLocalCodeExecutor
|
||||
from google.adk.code_executors.code_execution_utils import CodeExecutionInput, CodeExecutionResult
|
||||
from google.adk.agents.invocation_context import InvocationContext
|
||||
from google.adk.agents.base_agent import BaseAgent
|
||||
from google.adk.sessions.session import Session
|
||||
from google.adk.sessions.base_session_service import BaseSessionService
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_invocation_context() -> InvocationContext:
|
||||
"""Provides a mock InvocationContext."""
|
||||
mock_agent = MagicMock(spec=BaseAgent)
|
||||
mock_session = MagicMock(spec=Session)
|
||||
mock_session_service = MagicMock(spec=BaseSessionService)
|
||||
return InvocationContext(
|
||||
invocation_id="test_invocation",
|
||||
agent=mock_agent,
|
||||
session=mock_session,
|
||||
session_service=mock_session_service
|
||||
)
|
||||
|
||||
|
||||
class TestUnsafeLocalCodeExecutor:
|
||||
|
||||
def test_init_default(self):
|
||||
executor = UnsafeLocalCodeExecutor()
|
||||
assert not executor.stateful
|
||||
assert not executor.optimize_data_file
|
||||
|
||||
def test_init_stateful_raises_error(self):
|
||||
with pytest.raises(ValueError, match="Cannot set `stateful=True` in UnsafeLocalCodeExecutor."):
|
||||
UnsafeLocalCodeExecutor(stateful=True)
|
||||
|
||||
def test_init_optimize_data_file_raises_error(self):
|
||||
with pytest.raises(ValueError, match="Cannot set `optimize_data_file=True` in UnsafeLocalCodeExecutor."):
|
||||
UnsafeLocalCodeExecutor(optimize_data_file=True)
|
||||
|
||||
def test_execute_code_simple_print(self, mock_invocation_context: InvocationContext):
|
||||
executor = UnsafeLocalCodeExecutor()
|
||||
code_input = CodeExecutionInput(code='print("hello world")')
|
||||
result = executor.execute_code(mock_invocation_context, code_input)
|
||||
|
||||
assert isinstance(result, CodeExecutionResult)
|
||||
assert result.stdout == "hello world\n"
|
||||
assert result.stderr == ""
|
||||
assert result.output_files == []
|
||||
|
||||
def test_execute_code_with_error(self, mock_invocation_context: InvocationContext):
|
||||
executor = UnsafeLocalCodeExecutor()
|
||||
code_input = CodeExecutionInput(code='raise ValueError("Test error")')
|
||||
result = executor.execute_code(mock_invocation_context, code_input)
|
||||
|
||||
assert isinstance(result, CodeExecutionResult)
|
||||
assert result.stdout == ""
|
||||
assert "Test error" in result.stderr
|
||||
assert result.output_files == []
|
||||
|
||||
def test_execute_code_variable_assignment(self, mock_invocation_context: InvocationContext):
|
||||
executor = UnsafeLocalCodeExecutor()
|
||||
code_input = CodeExecutionInput(code='x = 10\nprint(x * 2)')
|
||||
result = executor.execute_code(mock_invocation_context, code_input)
|
||||
|
||||
assert result.stdout == "20\n"
|
||||
assert result.stderr == ""
|
||||
|
||||
def test_execute_code_empty(self, mock_invocation_context: InvocationContext):
|
||||
executor = UnsafeLocalCodeExecutor()
|
||||
code_input = CodeExecutionInput(code='')
|
||||
result = executor.execute_code(mock_invocation_context, code_input)
|
||||
assert result.stdout == ""
|
||||
assert result.stderr == ""
|
Loading…
Reference in New Issue
Block a user