You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_kubernetes_commandline_code_executor.py 8.5 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. import importlib
  2. import os
  3. import sys
  4. from pathlib import Path
  5. import pytest
  6. from autogen.code_utils import TIMEOUT_MSG
  7. from autogen.coding.base import CodeBlock, CodeExecutor
  8. try:
  9. from autogen.coding.kubernetes import PodCommandLineCodeExecutor
  10. client = importlib.import_module("kubernetes.client")
  11. config = importlib.import_module("kubernetes.config")
  12. kubeconfig = Path(".kube/config")
  13. if os.environ.get("KUBECONFIG", None):
  14. kubeconfig = Path(os.environ["KUBECONFIG"])
  15. elif sys.platform == "win32":
  16. kubeconfig = os.environ["userprofile"] / kubeconfig
  17. else:
  18. kubeconfig = os.environ["HOME"] / kubeconfig
  19. if kubeconfig.is_file():
  20. config.load_config(config_file=str(kubeconfig))
  21. api_client = client.CoreV1Api()
  22. api_client.list_namespace()
  23. skip_kubernetes_tests = False
  24. else:
  25. skip_kubernetes_tests = True
  26. pod_spec = client.V1Pod(
  27. metadata=client.V1ObjectMeta(
  28. name="abcd", namespace="default", annotations={"sidecar.istio.io/inject": "false"}
  29. ),
  30. spec=client.V1PodSpec(
  31. restart_policy="Never",
  32. containers=[
  33. client.V1Container(
  34. args=["-c", "while true;do sleep 5; done"],
  35. command=["/bin/sh"],
  36. name="abcd",
  37. image="python:3.11-slim",
  38. env=[
  39. client.V1EnvVar(name="TEST", value="TEST"),
  40. client.V1EnvVar(
  41. name="POD_NAME",
  42. value_from=client.V1EnvVarSource(
  43. field_ref=client.V1ObjectFieldSelector(field_path="metadata.name")
  44. ),
  45. ),
  46. ],
  47. )
  48. ],
  49. ),
  50. )
  51. except Exception:
  52. skip_kubernetes_tests = True
  53. @pytest.mark.skipif(skip_kubernetes_tests, reason="kubernetes not accessible")
  54. def test_create_default_pod_executor():
  55. with PodCommandLineCodeExecutor(namespace="default", kube_config_file=str(kubeconfig)) as executor:
  56. assert executor.timeout == 60
  57. assert executor.work_dir == Path("/workspace")
  58. assert executor._container_name == "autogen-code-exec"
  59. assert executor._pod.metadata.name.startswith("autogen-code-exec-")
  60. _test_execute_code(executor)
  61. @pytest.mark.skipif(skip_kubernetes_tests, reason="kubernetes not accessible")
  62. def test_create_node_pod_executor():
  63. with PodCommandLineCodeExecutor(
  64. image="node:22-alpine",
  65. namespace="default",
  66. work_dir="./app",
  67. timeout=30,
  68. kube_config_file=str(kubeconfig),
  69. execution_policies={"javascript": True},
  70. ) as executor:
  71. assert executor.timeout == 30
  72. assert executor.work_dir == Path("./app")
  73. assert executor._container_name == "autogen-code-exec"
  74. assert executor._pod.metadata.name.startswith("autogen-code-exec-")
  75. assert executor.execution_policies["javascript"]
  76. # Test single code block.
  77. code_blocks = [CodeBlock(code="console.log('hello world!')", language="javascript")]
  78. code_result = executor.execute_code_blocks(code_blocks)
  79. assert code_result.exit_code == 0 and "hello world!" in code_result.output and code_result.code_file is not None
  80. # Test multiple code blocks.
  81. code_blocks = [
  82. CodeBlock(code="console.log('hello world!')", language="javascript"),
  83. CodeBlock(code="let a = 100 + 100; console.log(a)", language="javascript"),
  84. ]
  85. code_result = executor.execute_code_blocks(code_blocks)
  86. assert (
  87. code_result.exit_code == 0
  88. and "hello world!" in code_result.output
  89. and "200" in code_result.output
  90. and code_result.code_file is not None
  91. )
  92. # Test running code.
  93. file_lines = ["console.log('hello world!')", "let a = 100 + 100", "console.log(a)"]
  94. code_blocks = [CodeBlock(code="\n".join(file_lines), language="javascript")]
  95. code_result = executor.execute_code_blocks(code_blocks)
  96. assert (
  97. code_result.exit_code == 0
  98. and "hello world!" in code_result.output
  99. and "200" in code_result.output
  100. and code_result.code_file is not None
  101. )
  102. @pytest.mark.skipif(skip_kubernetes_tests, reason="kubernetes not accessible")
  103. def test_create_pod_spec_pod_executor():
  104. with PodCommandLineCodeExecutor(
  105. pod_spec=pod_spec, container_name="abcd", kube_config_file=str(kubeconfig)
  106. ) as executor:
  107. assert executor.timeout == 60
  108. assert executor._container_name == "abcd"
  109. assert executor._pod.metadata.name == pod_spec.metadata.name
  110. assert executor._pod.metadata.namespace == pod_spec.metadata.namespace
  111. _test_execute_code(executor)
  112. # Test bash script.
  113. if sys.platform not in ["win32"]:
  114. code_blocks = [CodeBlock(code="echo $TEST $POD_NAME", language="bash")]
  115. code_result = executor.execute_code_blocks(code_blocks)
  116. assert (
  117. code_result.exit_code == 0 and "TEST abcd" in code_result.output and code_result.code_file is not None
  118. )
  119. @pytest.mark.skipif(skip_kubernetes_tests, reason="kubernetes not accessible")
  120. def test_pod_executor_timeout():
  121. with PodCommandLineCodeExecutor(namespace="default", timeout=5, kube_config_file=str(kubeconfig)) as executor:
  122. assert executor.timeout == 5
  123. assert executor.work_dir == Path("/workspace")
  124. assert executor._container_name == "autogen-code-exec"
  125. assert executor._pod.metadata.name.startswith("autogen-code-exec-")
  126. # Test running code.
  127. file_lines = ["import time", "time.sleep(10)", "a = 100 + 100", "print(a)"]
  128. code_blocks = [CodeBlock(code="\n".join(file_lines), language="python")]
  129. code_result = executor.execute_code_blocks(code_blocks)
  130. assert code_result.exit_code == 124 and TIMEOUT_MSG in code_result.output and code_result.code_file is not None
  131. def _test_execute_code(executor: CodeExecutor) -> None:
  132. # Test single code block.
  133. code_blocks = [CodeBlock(code="import sys; print('hello world!')", language="python")]
  134. code_result = executor.execute_code_blocks(code_blocks)
  135. assert code_result.exit_code == 0 and "hello world!" in code_result.output and code_result.code_file is not None
  136. # Test multiple code blocks.
  137. code_blocks = [
  138. CodeBlock(code="import sys; print('hello world!')", language="python"),
  139. CodeBlock(code="a = 100 + 100; print(a)", language="python"),
  140. ]
  141. code_result = executor.execute_code_blocks(code_blocks)
  142. assert (
  143. code_result.exit_code == 0
  144. and "hello world!" in code_result.output
  145. and "200" in code_result.output
  146. and code_result.code_file is not None
  147. )
  148. # Test bash script.
  149. if sys.platform not in ["win32"]:
  150. code_blocks = [CodeBlock(code="echo 'hello world!'", language="bash")]
  151. code_result = executor.execute_code_blocks(code_blocks)
  152. assert code_result.exit_code == 0 and "hello world!" in code_result.output and code_result.code_file is not None
  153. # Test running code.
  154. file_lines = ["import sys", "print('hello world!')", "a = 100 + 100", "print(a)"]
  155. code_blocks = [CodeBlock(code="\n".join(file_lines), language="python")]
  156. code_result = executor.execute_code_blocks(code_blocks)
  157. assert (
  158. code_result.exit_code == 0
  159. and "hello world!" in code_result.output
  160. and "200" in code_result.output
  161. and code_result.code_file is not None
  162. )
  163. # Test running code has filename.
  164. file_lines = ["# filename: test.py", "import sys", "print('hello world!')", "a = 100 + 100", "print(a)"]
  165. code_blocks = [CodeBlock(code="\n".join(file_lines), language="python")]
  166. code_result = executor.execute_code_blocks(code_blocks)
  167. print(code_result.code_file)
  168. assert (
  169. code_result.exit_code == 0
  170. and "hello world!" in code_result.output
  171. and "200" in code_result.output
  172. and code_result.code_file.find("test.py") > 0
  173. )
  174. # Test error code.
  175. code_blocks = [CodeBlock(code="print(sys.platform)", language="python")]
  176. code_result = executor.execute_code_blocks(code_blocks)
  177. assert code_result.exit_code == 1 and "Traceback" in code_result.output and code_result.code_file is not None