forked from microsoft/autogen
-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathtest_commandline_code_executor.py
198 lines (158 loc) · 7.46 KB
/
test_commandline_code_executor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import sys
import tempfile
import pytest
from autogen.agentchat.conversable_agent import ConversableAgent
from autogen.coding.base import CodeBlock, CodeExecutor
from autogen.coding.factory import CodeExecutorFactory
from autogen.coding.local_commandline_code_executor import LocalCommandLineCodeExecutor
from autogen.oai.openai_utils import config_list_from_json
from conftest import MOCK_OPEN_AI_API_KEY, skip_openai
def test_create() -> None:
config = {"executor": "commandline-local"}
executor = CodeExecutorFactory.create(config)
assert isinstance(executor, LocalCommandLineCodeExecutor)
config = {"executor": LocalCommandLineCodeExecutor()}
executor = CodeExecutorFactory.create(config)
assert executor is config["executor"]
def test_local_commandline_executor_init() -> None:
executor = LocalCommandLineCodeExecutor(timeout=10, work_dir=".")
assert executor.timeout == 10 and executor.work_dir == "."
# Try invalid working directory.
with pytest.raises(ValueError, match="Working directory .* does not exist."):
executor = LocalCommandLineCodeExecutor(timeout=111, work_dir="/invalid/directory")
def test_local_commandline_executor_execute_code() -> None:
with tempfile.TemporaryDirectory() as temp_dir:
executor = LocalCommandLineCodeExecutor(work_dir=temp_dir)
_test_execute_code(executor=executor)
def _test_execute_code(executor: CodeExecutor) -> None:
# Test single code block.
code_blocks = [CodeBlock(code="import sys; print('hello world!')", language="python")]
code_result = executor.execute_code_blocks(code_blocks)
assert code_result.exit_code == 0 and "hello world!" in code_result.output and code_result.code_file is not None
# Test multiple code blocks.
code_blocks = [
CodeBlock(code="import sys; print('hello world!')", language="python"),
CodeBlock(code="a = 100 + 100; print(a)", language="python"),
]
code_result = executor.execute_code_blocks(code_blocks)
assert (
code_result.exit_code == 0
and "hello world!" in code_result.output
and "200" in code_result.output
and code_result.code_file is not None
)
# Test bash script.
if sys.platform not in ["win32"]:
code_blocks = [CodeBlock(code="echo 'hello world!'", language="bash")]
code_result = executor.execute_code_blocks(code_blocks)
assert code_result.exit_code == 0 and "hello world!" in code_result.output and code_result.code_file is not None
# Test running code.
file_lines = ["import sys", "print('hello world!')", "a = 100 + 100", "print(a)"]
code_blocks = [CodeBlock(code="\n".join(file_lines), language="python")]
code_result = executor.execute_code_blocks(code_blocks)
assert (
code_result.exit_code == 0
and "hello world!" in code_result.output
and "200" in code_result.output
and code_result.code_file is not None
)
# Check saved code file.
with open(code_result.code_file) as f:
code_lines = f.readlines()
for file_line, code_line in zip(file_lines, code_lines):
assert file_line.strip() == code_line.strip()
@pytest.mark.skipif(sys.platform in ["win32"], reason="do not run on windows")
def test_local_commandline_code_executor_timeout() -> None:
with tempfile.TemporaryDirectory() as temp_dir:
executor = LocalCommandLineCodeExecutor(timeout=1, work_dir=temp_dir)
_test_timeout(executor)
def _test_timeout(executor: CodeExecutor) -> None:
code_blocks = [CodeBlock(code="import time; time.sleep(10); print('hello world!')", language="python")]
code_result = executor.execute_code_blocks(code_blocks)
assert code_result.exit_code and "Timeout" in code_result.output
def test_local_commandline_code_executor_restart() -> None:
executor = LocalCommandLineCodeExecutor()
_test_restart(executor)
def _test_restart(executor: CodeExecutor) -> None:
# Check warning.
with pytest.warns(UserWarning, match=r".*No action is taken."):
executor.restart()
@pytest.mark.skipif(skip_openai, reason="requested to skip openai tests")
def test_local_commandline_executor_conversable_agent_capability() -> None:
with tempfile.TemporaryDirectory() as temp_dir:
executor = LocalCommandLineCodeExecutor(work_dir=temp_dir)
_test_conversable_agent_capability(executor=executor)
def _test_conversable_agent_capability(executor: CodeExecutor) -> None:
KEY_LOC = "notebook"
OAI_CONFIG_LIST = "OAI_CONFIG_LIST"
config_list = config_list_from_json(
OAI_CONFIG_LIST,
file_location=KEY_LOC,
filter_dict={
"model": {
"gpt-3.5-turbo",
"gpt-35-turbo",
},
},
)
llm_config = {"config_list": config_list}
agent = ConversableAgent(
"coding_agent",
llm_config=llm_config,
code_execution_config=False,
)
executor.user_capability.add_to_agent(agent)
# Test updated system prompt.
assert executor.DEFAULT_SYSTEM_MESSAGE_UPDATE in agent.system_message
# Test code generation.
reply = agent.generate_reply(
[{"role": "user", "content": "write a python script to print 'hello world' to the console"}],
sender=ConversableAgent(name="user", llm_config=False, code_execution_config=False),
)
# Test code extraction.
code_blocks = executor.code_extractor.extract_code_blocks(reply) # type: ignore[arg-type]
assert len(code_blocks) == 1 and code_blocks[0].language == "python"
# Test code execution.
code_result = executor.execute_code_blocks(code_blocks)
assert code_result.exit_code == 0 and "hello world" in code_result.output.lower().replace(",", "")
def test_local_commandline_executor_conversable_agent_code_execution() -> None:
with tempfile.TemporaryDirectory() as temp_dir:
executor = LocalCommandLineCodeExecutor(work_dir=temp_dir)
with pytest.MonkeyPatch.context() as mp:
mp.setenv("OPENAI_API_KEY", MOCK_OPEN_AI_API_KEY)
_test_conversable_agent_code_execution(executor)
def _test_conversable_agent_code_execution(executor: CodeExecutor) -> None:
agent = ConversableAgent(
"user_proxy",
code_execution_config={"executor": executor},
llm_config=False,
)
assert agent.code_executor is executor
message = """
Example:
```python
print("hello extract code")
```
"""
reply = agent.generate_reply(
[{"role": "user", "content": message}],
sender=ConversableAgent("user", llm_config=False, code_execution_config=False),
)
assert "hello extract code" in reply # type: ignore[operator]
# Test cases for dangerous commands that should be caught by the sanitizer
@pytest.mark.parametrize(
"lang, code, expected_message",
[
("bash", "rm -rf /", "Use of 'rm -rf' command is not allowed."),
("bash", "mv myFile /dev/null", "Moving files to /dev/null is not allowed."),
("bash", "dd if=/dev/zero of=/dev/sda", "Use of 'dd' command is not allowed."),
("bash", "echo Hello > /dev/sda", "Overwriting disk blocks directly is not allowed."),
("bash", ":(){ :|:& };:", "Fork bombs are not allowed."),
],
)
def test_dangerous_commands(lang, code, expected_message):
with pytest.raises(ValueError) as exc_info:
LocalCommandLineCodeExecutor.sanitize_command(lang, code)
assert expected_message in str(
exc_info.value
), f"Expected message '{expected_message}' not found in '{str(exc_info.value)}'"