8000 Copybara import of the project: · charsoft/adk-python@face2e8 · GitHub
[go: up one dir, main page]

Skip to content

Commit face2e8

Browse files
iamulyacopybara-github
authored andcommitted
Copybara import of the project:
-- 8baeb0b by Amulya Bhatia <amulya.bhatia@t-online.de>: test: unit tests for built_in_code_executor and unsafe_code_executor -- cfac73b by Amulya Bhatia <amulya.bhatia@t-online.de>: test: unit tests for built_in_code_executor and unsafe_code_executor COPYBARA_INTEGRATE_REVIEW=google#971 from iamulya:code-executor-tests 55290e2 PiperOrigin-RevId: 764976316
1 parent 04e07b4 commit face2e8

File tree

2 files changed

+196
-0
lines changed

2 files changed

+196
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import pytest
15+
from google.genai import types
16+
17+
from google.adk.code_executors.built_in_code_executor import BuiltInCodeExecutor
18+
from google.adk.models.llm_request import LlmRequest
19+
20+
21+
@pytest.fixture
22+
def built_in_executor() -> BuiltInCodeExecutor:
23+
return BuiltInCodeExecutor()
24+
25+
26+
def test_process_llm_request_gemini_2_model_config_none(
27+
built_in_executor: BuiltInCodeExecutor,
28+
):
29+
"""Tests processing when llm_request.config is None for Gemini 2."""
30+
llm_request = LlmRequest(model="gemini-2.0-flash")
31+
built_in_executor.process_llm_request(llm_request)
32+
assert llm_request.config is not None
33+
assert llm_request.config.tools == [
34+
types.Tool(code_execution=types.ToolCodeExecution())
35+
]
36+
37+
38+
def test_process_llm_request_gemini_2_model_tools_none(
39+
built_in_executor: BuiltInCodeExecutor,
40+
):
41+
"""Tests processing when llm_request.config.tools is None for Gemini 2."""
42+
llm_request = LlmRequest(
43+
model="gemini-2.0-pro", config=types.GenerateContentConfig()
44+
)
45+
built_in_executor.process_llm_request(llm_request)
46+
assert llm_request.config.tools == [
47+
types.Tool(code_execution=types.ToolCodeExecution())
48+
]
49+
50+
51+
def test_process_llm_request_gemini_2_model_tools_empty(
52+
built_in_executor: BuiltInCodeExecutor,
53+
):
54+
"""Tests processing when llm_request.config.tools is empty for Gemini 2."""
55+
llm_request = LlmRequest(
56+
model="gemini-2.0-ultra",
57+
config=types.GenerateContentConfig(tools=[]),
58+
)
59+
built_in_executor.process_llm_request(llm_request)
60+
assert llm_request.config.tools == [
61+
types.Tool(code_execution=types.ToolCodeExecution())
62+
]
63+
64+
65+
def test_process_llm_request_gemini_2_model_with_existing_tools(
66+
built_in_executor: BuiltInCodeExecutor,
67+
):
68+
"""Tests processing when llm_request.config.tools already has tools for Gemini 2."""
69+
existing_tool = types.Tool(
70+
function_declarations=[
71+
types.FunctionDeclaration(name="test_func", description="A test func")
72+
]
73+
)
74+
llm_request = LlmRequest(
75+
model="gemini-2.0-flash-001",
76+
config=types.GenerateContentConfig(tools=[existing_tool]),
77+
)
78+
built_in_executor.process_llm_request(llm_request)
79+
assert len(llm_request.config.tools) == 2
80+
assert existing_tool in llm_request.config.tools
81+
assert types.Tool(
82+
code_execution=types.ToolCodeExecution()
83+
) in llm_request.config.tools
84+
85+
86+
def test_process_llm_request_non_gemini_2_model(
87+
built_in_executor: BuiltInCodeExecutor,
88+
):
89+
"""Tests that a ValueError is raised for non-Gemini 2 models."""
90+
llm_request = LlmRequest(model="gemini-1.5-flash")
91+
with pytest.raises(ValueError) as excinfo:
92+
built_in_executor.process_llm_request(llm_request)
93+
assert (
94+
"Gemini code execution tool is not supported for model gemini-1.5-flash"
95+
in str(excinfo.value)
96+
)
97+
98+
99+
def test_process_llm_request_no_model_name(
100+
built_in_executor: BuiltInCodeExecutor,
101+
):
102+
"""Tests that a ValueError is raised if model name is not set."""
103+
llm_request = LlmRequest() # Model name defaults to None
104+
with pytest.raises(ValueError) as excinfo:
105+
built_in_executor.process_llm_request(llm_request)
106+
assert (
107+
"Gemini code execution tool is not supported for model None"
108+
in str(excinfo.value)
109+
)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
from unittest.mock import MagicMock
17+
from google.adk.code_executors.unsafe_local_code_executor import UnsafeLocalCodeExecutor
18+
from google.adk.code_executors.code_execution_utils import CodeExecutionInput, CodeExecutionResult
19+
from google.adk.agents.invocation_context import InvocationContext
20+
from google.adk.agents.base_agent import BaseAgent
21+
from google.adk.sessions.session import Session
22+
from google.adk.sessions.base_session_service import BaseSessionService
23+
24+
25+
@pytest.fixture
26+
def mock_invocation_context() -> InvocationContext:
27+
"""Provides a mock InvocationContext."""
28+
mock_agent = MagicMock(spec=BaseAgent)
29+
mock_session = MagicMock(spec=Session)
30+
mock_session_service = MagicMock(spec=BaseSessionService)
31+
return InvocationContext(
32+
invocation_id="test_invocation",
33+
agent=mock_agent,
34+
session=mock_session,
35+
session_service=mock_session_service
36+
)
37+
38+
39+
class TestUnsafeLocalCodeExecutor:
40+
41+
def test_init_default(self):
42+
executor = UnsafeLocalCodeExecutor()
43+
assert not executor.stateful
44+
assert not executor.optimize_data_file
45+
46+
def test_init_stateful_raises_error(self):
47+
with pytest.raises(ValueError, match="Cannot set `stateful=True` in UnsafeLocalCodeExecutor."):
48+
UnsafeLocalCodeExecutor(stateful=True)
49+
50+
def test_init_optimize_data_file_raises_error(self):
51+
with pytest.raises(ValueError, match="Cannot set `optimize_data_file=True` in UnsafeLocalCodeExecutor."):
52+
UnsafeLocalCodeExecutor(optimize_data_file=True)
53+
54+
def test_execute_code_simple_print(self, mock_invocation_context: InvocationContext):
55+
executor = UnsafeLocalCodeExecutor()
56+
code_input = CodeExecutionInput(code='print("hello world")')
57+
result = executor.execute_code(mock_invocation_context, code_input)
58+
59+
assert isinstance(result, CodeExecutionResult)
60+
assert result.stdout == "hello world\n"
61+
assert result.stderr == ""
62+
assert result.output_files == []
63+
64+
def test_execute_code_with_error(self, mock_invocation_context: InvocationContext):
65+
executor = UnsafeLocalCodeExecutor()
66+
code_input = CodeExecutionInput(code='raise ValueError("Test error")')
67+
result = executor.execute_code(mock_invocation_context, code_input)
68+
69+
assert isinstance(result, CodeExecutionResult)
70+
assert result.stdout == ""
71+
assert "Test error" in result.stderr
72+
assert result.output_files == []
73+
74+
def test_execute_code_variable_assignment(self, mock_invocation_context: InvocationContext):
75+
executor = UnsafeLocalCodeExecutor()
76+
code_input = CodeExecutionInput(code='x = 10\nprint(x * 2)')
77+
result = executor.execute_code(mock_invocation_context, code_input)
78+
79+
assert result.stdout == "20\n"
80+
assert result.stderr == ""
81+
82+
def test_execute_code_empty(self, mock_invocation_context: InvocationContext):
83+
executor = UnsafeLocalCodeExecutor()
84+
code_input = CodeExecutionInput(code='')
85+
result = executor.execute_code(mock_invocation_context, code_input)
86+
assert result.stdout == ""
87+
assert result.stderr == ""

0 commit comments

Comments
 (0)
0