scalebox-sdk 0.1.25__py3-none-any.whl → 1.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. scalebox/__init__.py +2 -2
  2. scalebox/api/__init__.py +3 -1
  3. scalebox/api/client/api/sandboxes/get_sandboxes.py +1 -1
  4. scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
  5. scalebox/api/client/models/connect_sandbox.py +59 -0
  6. scalebox/api/client/models/error.py +2 -2
  7. scalebox/api/client/models/listed_sandbox.py +24 -3
  8. scalebox/api/client/models/new_sandbox.py +10 -0
  9. scalebox/api/client/models/sandbox.py +13 -0
  10. scalebox/api/client/models/sandbox_detail.py +24 -0
  11. scalebox/cli.py +125 -125
  12. scalebox/client/aclient.py +57 -57
  13. scalebox/client/client.py +102 -102
  14. scalebox/code_interpreter/__init__.py +12 -12
  15. scalebox/code_interpreter/charts.py +230 -230
  16. scalebox/code_interpreter/code_interpreter_async.py +3 -1
  17. scalebox/code_interpreter/code_interpreter_sync.py +3 -1
  18. scalebox/code_interpreter/constants.py +3 -3
  19. scalebox/code_interpreter/exceptions.py +13 -13
  20. scalebox/code_interpreter/models.py +485 -485
  21. scalebox/connection_config.py +36 -1
  22. scalebox/csx_connect/__init__.py +1 -1
  23. scalebox/csx_connect/client.py +485 -485
  24. scalebox/csx_desktop/main.py +651 -651
  25. scalebox/exceptions.py +83 -83
  26. scalebox/generated/api.py +61 -61
  27. scalebox/generated/api_pb2.py +203 -203
  28. scalebox/generated/api_pb2.pyi +956 -956
  29. scalebox/generated/api_pb2_connect.py +1407 -1407
  30. scalebox/generated/rpc.py +50 -50
  31. scalebox/sandbox/main.py +146 -139
  32. scalebox/sandbox/sandbox_api.py +105 -91
  33. scalebox/sandbox/signature.py +40 -40
  34. scalebox/sandbox/utils.py +34 -34
  35. scalebox/sandbox_async/main.py +226 -44
  36. scalebox/sandbox_async/sandbox_api.py +124 -3
  37. scalebox/sandbox_sync/main.py +205 -130
  38. scalebox/sandbox_sync/sandbox_api.py +119 -3
  39. scalebox/test/CODE_INTERPRETER_TESTS_READY.md +323 -323
  40. scalebox/test/README.md +329 -329
  41. scalebox/test/bedrock_openai_adapter.py +73 -0
  42. scalebox/test/code_interpreter_test.py +34 -34
  43. scalebox/test/code_interpreter_test_sync.py +34 -34
  44. scalebox/test/run_stress_code_interpreter_sync.py +178 -0
  45. scalebox/test/simple_upload_example.py +131 -0
  46. scalebox/test/stabitiy_test.py +323 -0
  47. scalebox/test/test_browser_use.py +27 -0
  48. scalebox/test/test_browser_use_scalebox.py +62 -0
  49. scalebox/test/test_code_interpreter_execcode.py +289 -211
  50. scalebox/test/test_code_interpreter_sync_comprehensive.py +116 -69
  51. scalebox/test/test_connect_pause_async.py +300 -0
  52. scalebox/test/test_connect_pause_sync.py +300 -0
  53. scalebox/test/test_csx_desktop_examples.py +3 -3
  54. scalebox/test/test_desktop_sandbox_sf.py +112 -0
  55. scalebox/test/test_download_url.py +41 -0
  56. scalebox/test/test_existing_sandbox.py +1037 -0
  57. scalebox/test/test_sandbox_async_comprehensive.py +5 -3
  58. scalebox/test/test_sandbox_object_storage_example.py +151 -0
  59. scalebox/test/test_sandbox_object_storage_example_async.py +159 -0
  60. scalebox/test/test_sandbox_sync_comprehensive.py +1 -1
  61. scalebox/test/test_sf.py +141 -0
  62. scalebox/test/test_watch_dir_async.py +58 -0
  63. scalebox/test/testacreate.py +1 -1
  64. scalebox/test/testagetinfo.py +1 -3
  65. scalebox/test/testcomputeuse.py +243 -243
  66. scalebox/test/testsandbox_api.py +5 -5
  67. scalebox/test/testsandbox_async.py +17 -47
  68. scalebox/test/testsandbox_sync.py +19 -15
  69. scalebox/test/upload_100mb_example.py +377 -0
  70. scalebox/utils/httpcoreclient.py +297 -297
  71. scalebox/utils/httpxclient.py +403 -403
  72. scalebox/version.py +2 -2
  73. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/METADATA +1 -1
  74. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/RECORD +78 -60
  75. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/WHEEL +1 -1
  76. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/entry_points.txt +0 -0
  77. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/licenses/LICENSE +0 -0
  78. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/top_level.txt +0 -0
@@ -106,8 +106,9 @@ result = {"x": x, "y": y}
106
106
  print(result)
107
107
  """
108
108
 
109
- execution = self.sandbox.run_code(code, language="python")
109
+ execution = self.sandbox.run_code(code, envs={"CI_TEST": "sync_test1"})
110
110
  print(execution.to_json())
111
+ # time.sleep(1000)
111
112
  assert isinstance(execution, Execution)
112
113
  assert execution.error is None
113
114
  assert len(execution.logs.stdout) > 0
@@ -147,7 +148,7 @@ print(f"标准差: {std_val:.3f}")
147
148
  }
148
149
  """
149
150
 
150
- execution = self.sandbox.run_code(code, language="python")
151
+ execution = self.sandbox.run_code(code)
151
152
  print(execution.to_json())
152
153
  assert execution.error is None
153
154
  assert any("圆的面积" in line for line in execution.logs.stdout)
@@ -197,7 +198,7 @@ result = {
197
198
  print(f"\\n处理结果: {json.dumps(result, indent=2)}")
198
199
  """
199
200
 
200
- execution = self.sandbox.run_code(code, language="python")
201
+ execution = self.sandbox.run_code(code)
201
202
  print(execution.to_json())
202
203
  assert execution.error is None
203
204
  assert any("原始数据" in line for line in execution.logs.stdout)
@@ -365,10 +366,7 @@ print(f"结果: {result}")
365
366
  assert self.sandbox is not None
366
367
 
367
368
  # 创建Python上下文
368
- python_context = self.sandbox.create_code_context(
369
- language="python",
370
- cwd="/tmp"
371
- )
369
+ python_context = self.sandbox.create_code_context(language="python", cwd="/tmp")
372
370
  print(python_context)
373
371
  assert isinstance(python_context, Context)
374
372
  assert python_context.id is not None
@@ -799,6 +797,55 @@ print("生成HTML格式结果")
799
797
  from IPython.display import HTML
800
798
  HTML(html_content)
801
799
  """
800
+ # code = """
801
+ # import sys
802
+ # try:
803
+ # import matplotlib
804
+ # matplotlib.use('Agg') # Non-interactive backend
805
+ # import matplotlib.pyplot as plt
806
+ # import numpy as np
807
+ # from IPython.display import display
808
+ #
809
+ # print("✅ All imports successful")
810
+ #
811
+ # # Generate a simple plot
812
+ # x = np.linspace(0, 2 * np.pi, 100)
813
+ # y = np.sin(x)
814
+ #
815
+ # fig, ax = plt.subplots(figsize=(8, 6))
816
+ # ax.plot(x, y, 'b-', linewidth=2, label='sin(x)')
817
+ # ax.set_xlabel('X axis')
818
+ # ax.set_ylabel('Y axis')
819
+ # ax.set_title('Sine Wave - Test Plot')
820
+ # ax.legend()
821
+ # ax.grid(True, alpha=0.3)
822
+ #
823
+ # plt.tight_layout()
824
+ #
825
+ # # 🎯 KEY: Save to bytes and display as Image
826
+ # import io
827
+ # from IPython.display import Image
828
+ #
829
+ # buf = io.BytesIO()
830
+ # plt.savefig(buf, format='png', bbox_inches='tight', dpi=100)
831
+ # buf.seek(0)
832
+ # plt.close(fig)
833
+ #
834
+ # # Display the image data
835
+ # display(Image(data=buf.getvalue()))
836
+ # #
837
+ # # print("SUCCESS: Plot generated and displayed")
838
+ # # "plot_created"
839
+ #
840
+ # except ImportError as e:
841
+ # print(f"SKIP: matplotlib not available - {e}")
842
+ # "matplotlib_not_installed"
843
+ # except Exception as e:
844
+ # print(f"ERROR: {e}")
845
+ # import traceback
846
+ # traceback.print_exc()
847
+ # "error_occurred"
848
+ # """
802
849
 
803
850
  execution = self.sandbox.run_code(code, language="python")
804
851
  print(execution.to_json())
@@ -3292,68 +3339,68 @@ print(f"\\n完成 {len(results)} 个API调用")
3292
3339
  self.test_file_operations_simulation, "File Operations Simulation"
3293
3340
  )
3294
3341
 
3295
- # 性能测试
3296
- self.run_test(
3297
- self.test_performance_simple_calculations, "Performance Simple Calculations"
3298
- )
3299
- self.run_test(
3300
- self.test_performance_concurrent_simulation,
3301
- "Performance Concurrent Simulation",
3302
- )
3303
-
3304
- # 结果格式测试
3305
- self.run_test(self.test_text_result, "Text Result Format")
3306
- self.run_test(self.test_html_result, "HTML Result Format")
3307
- self.run_test(self.test_markdown_result, "Markdown Result Format")
3308
- self.run_test(self.test_svg_result, "SVG Result Format")
3309
- self.run_test(self.test_image_results, "Image Result Formats (PNG/JPEG)")
3310
- self.run_test(self.test_latex_result, "LaTeX Result Format")
3311
- self.run_test(self.test_json_data_result, "JSON Data Result Format")
3312
- self.run_test(self.test_javascript_result, "JavaScript Result Format")
3313
- self.run_test(self.test_chart_data_result, "Chart Data Result Format")
3314
- self.run_test(self.test_mixed_format_result, "Mixed Format Result")
3315
-
3316
- # R语言测试
3317
- self.run_test(
3318
- self.test_r_language_basic_execution, "R Language Basic Execution"
3319
- )
3320
- self.run_test(self.test_r_language_data_analysis, "R Language Data Analysis")
3321
- self.run_test(self.test_r_language_visualization, "R Language Visualization")
3322
- self.run_test(self.test_r_language_statistics, "R Language Statistics")
3323
- self.run_test(
3324
- self.test_r_language_context_management, "R Language Context Management"
3325
- )
3326
-
3327
- # Node.js/JavaScript 测试
3328
- self.run_test(self.test_nodejs_basic_execution, "Node.js Basic Execution")
3329
- self.run_test(self.test_nodejs_async_promises, "Node.js Async Promises")
3330
- self.run_test(self.test_nodejs_data_processing, "Node.js Data Processing")
3331
- self.run_test(self.test_nodejs_chart_data, "Node.js Chart Data Generation")
3332
- self.run_test(self.test_nodejs_context_management, "Node.js Context Management")
3333
-
3334
- # Bash 测试
3335
- self.run_test(self.test_bash_basic_execution, "Bash Basic Execution")
3336
- self.run_test(self.test_bash_file_operations, "Bash File Operations")
3337
- self.run_test(self.test_bash_pipelines_and_grep, "Bash Pipelines and Grep")
3338
- # self.run_test(self.test_bash_env_and_exit_codes, "Bash Env and Exit Codes")
3339
- self.run_test(self.test_bash_context_management, "Bash Context Management")
3340
-
3341
- # IJAVA 测试
3342
- self.run_test(self.test_ijava_basic_execution, "IJAVA Basic Execution")
3343
- self.run_test(self.test_ijava_oop_features, "IJAVA OOP Features")
3344
- self.run_test(self.test_ijava_collections, "IJAVA Collections")
3345
- self.run_test(self.test_ijava_file_io, "IJAVA File I/O")
3346
- self.run_test(self.test_ijava_context_management, "IJAVA Context Management")
3347
-
3348
- # Deno 测试
3349
- self.run_test(self.test_deno_basic_execution, "Deno Basic Execution")
3350
- self.run_test(self.test_deno_typescript_features, "Deno TypeScript Features")
3351
- self.run_test(self.test_deno_async_await, "Deno Async/Await")
3352
- self.run_test(self.test_deno_file_operations, "Deno File Operations")
3353
- self.run_test(self.test_deno_context_management, "Deno Context Management")
3354
-
3355
- # 高级功能测试
3356
- self.run_test(self.test_web_request_simulation, "Web Request Simulation")
3342
+ # # 性能测试
3343
+ # self.run_test(
3344
+ # self.test_performance_simple_calculations, "Performance Simple Calculations"
3345
+ # )
3346
+ # self.run_test(
3347
+ # self.test_performance_concurrent_simulation,
3348
+ # "Performance Concurrent Simulation",
3349
+ # )
3350
+
3351
+ # # 结果格式测试
3352
+ # self.run_test(self.test_text_result, "Text Result Format")
3353
+ # self.run_test(self.test_html_result, "HTML Result Format")
3354
+ # self.run_test(self.test_markdown_result, "Markdown Result Format")
3355
+ # self.run_test(self.test_svg_result, "SVG Result Format")
3356
+ # self.run_test(self.test_image_results, "Image Result Formats (PNG/JPEG)")
3357
+ # self.run_test(self.test_latex_result, "LaTeX Result Format")
3358
+ # self.run_test(self.test_json_data_result, "JSON Data Result Format")
3359
+ # self.run_test(self.test_javascript_result, "JavaScript Result Format")
3360
+ # self.run_test(self.test_chart_data_result, "Chart Data Result Format")
3361
+ # self.run_test(self.test_mixed_format_result, "Mixed Format Result")
3362
+ #
3363
+ # # R语言测试
3364
+ # self.run_test(
3365
+ # self.test_r_language_basic_execution, "R Language Basic Execution"
3366
+ # )
3367
+ # self.run_test(self.test_r_language_data_analysis, "R Language Data Analysis")
3368
+ # self.run_test(self.test_r_language_visualization, "R Language Visualization")
3369
+ # self.run_test(self.test_r_language_statistics, "R Language Statistics")
3370
+ # self.run_test(
3371
+ # self.test_r_language_context_management, "R Language Context Management"
3372
+ # )
3373
+ #
3374
+ # # Node.js/JavaScript 测试
3375
+ # self.run_test(self.test_nodejs_basic_execution, "Node.js Basic Execution")
3376
+ # self.run_test(self.test_nodejs_async_promises, "Node.js Async Promises")
3377
+ # self.run_test(self.test_nodejs_data_processing, "Node.js Data Processing")
3378
+ # self.run_test(self.test_nodejs_chart_data, "Node.js Chart Data Generation")
3379
+ # self.run_test(self.test_nodejs_context_management, "Node.js Context Management")
3380
+ #
3381
+ # # Bash 测试
3382
+ # self.run_test(self.test_bash_basic_execution, "Bash Basic Execution")
3383
+ # self.run_test(self.test_bash_file_operations, "Bash File Operations")
3384
+ # self.run_test(self.test_bash_pipelines_and_grep, "Bash Pipelines and Grep")
3385
+ # # self.run_test(self.test_bash_env_and_exit_codes, "Bash Env and Exit Codes")
3386
+ # self.run_test(self.test_bash_context_management, "Bash Context Management")
3387
+ #
3388
+ # # IJAVA 测试
3389
+ # self.run_test(self.test_ijava_basic_execution, "IJAVA Basic Execution")
3390
+ # self.run_test(self.test_ijava_oop_features, "IJAVA OOP Features")
3391
+ # self.run_test(self.test_ijava_collections, "IJAVA Collections")
3392
+ # self.run_test(self.test_ijava_file_io, "IJAVA File I/O")
3393
+ # self.run_test(self.test_ijava_context_management, "IJAVA Context Management")
3394
+ #
3395
+ # # Deno 测试
3396
+ # self.run_test(self.test_deno_basic_execution, "Deno Basic Execution")
3397
+ # # self.run_test(self.test_deno_typescript_features, "Deno TypeScript Features")
3398
+ # self.run_test(self.test_deno_async_await, "Deno Async/Await")
3399
+ # self.run_test(self.test_deno_file_operations, "Deno File Operations")
3400
+ # self.run_test(self.test_deno_context_management, "Deno Context Management")
3401
+ #
3402
+ # # 高级功能测试
3403
+ # self.run_test(self.test_web_request_simulation, "Web Request Simulation")
3357
3404
 
3358
3405
  def cleanup(self):
3359
3406
  """清理资源"""
@@ -0,0 +1,300 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test cases for connect and pause functionality (asynchronous version).
4
+
5
+ This test suite validates:
6
+ - Creating a sandbox
7
+ - Adding and deleting files before pause
8
+ - Pausing the sandbox
9
+ - Connecting to the paused sandbox
10
+ - Verifying file operations after connect
11
+ """
12
+
13
+ import asyncio
14
+ import time
15
+
16
+ from scalebox.sandbox.filesystem.filesystem import WriteInfo, FileType
17
+ from scalebox.sandbox_async.main import AsyncSandbox
18
+
19
+
20
+ class ConnectPauseAsyncTest:
21
+ """Test suite for connect and pause functionality (async)."""
22
+
23
+ def __init__(self):
24
+ self.sandbox = None
25
+ self.sandbox_id = None
26
+ self.test_results = []
27
+
28
+ def log_test_result(self, test_name: str, success: bool, message: str = ""):
29
+ """记录测试结果"""
30
+ status = "✅ PASS" if success else "❌ FAIL"
31
+ result = {
32
+ "test": test_name,
33
+ "success": success,
34
+ "message": message,
35
+ }
36
+ self.test_results.append(result)
37
+ print(f"{status} {test_name}: {message}")
38
+
39
+ async def test_connect_pause_with_files(self):
40
+ """测试connect和pause功能,包含文件操作"""
41
+ try:
42
+ # 1. 创建沙箱
43
+ print("Step 1: Creating sandbox...")
44
+ self.sandbox = await AsyncSandbox.create(
45
+ template="base",
46
+ timeout=3600,
47
+ metadata={"test": "connect_pause_async"},
48
+ envs={"TEST_ENV": "async_test"},
49
+ )
50
+ self.sandbox_id = self.sandbox.sandbox_id
51
+ assert self.sandbox is not None
52
+ assert self.sandbox_id is not None
53
+ print(f"Created sandbox with ID: {self.sandbox_id}")
54
+
55
+ # 2. 在pause之前增加文件
56
+ print("Step 2: Adding files before pause...")
57
+ test_files = {
58
+ "/tmp/test_file1.txt": "Content of test file 1",
59
+ "/tmp/test_file2.txt": "Content of test file 2",
60
+ "/tmp/test_file3.bin": b"Binary content for test file 3",
61
+ }
62
+
63
+ for file_path, content in test_files.items():
64
+ result = await self.sandbox.files.write(file_path, content)
65
+ assert isinstance(result, WriteInfo)
66
+ exists = await self.sandbox.files.exists(file_path)
67
+ assert exists
68
+ print(f"Created file: {file_path}")
69
+
70
+ # 3. 在pause之前删除一个文件
71
+ print("Step 3: Deleting a file before pause...")
72
+ file_to_delete = "/tmp/test_file2.txt"
73
+ await self.sandbox.files.remove(file_to_delete)
74
+ exists = await self.sandbox.files.exists(file_to_delete)
75
+ assert not exists
76
+ print(f"Deleted file: {file_to_delete}")
77
+
78
+ # 4. 创建目录和文件
79
+ print("Step 4: Creating directory and nested files...")
80
+ await self.sandbox.files.make_dir("/tmp/test_dir")
81
+ await self.sandbox.files.write(
82
+ "/tmp/test_dir/nested_file.txt", "Nested file content"
83
+ )
84
+ assert await self.sandbox.files.exists("/tmp/test_dir")
85
+ assert await self.sandbox.files.exists("/tmp/test_dir/nested_file.txt")
86
+ print("Created directory and nested file")
87
+
88
+ # 5. Pause沙箱
89
+ print("Step 5: Pausing sandbox...")
90
+ await self.sandbox.beta_pause()
91
+ print("Sandbox paused successfully")
92
+
93
+ # 等待一小段时间确保pause完成
94
+ await asyncio.sleep(2)
95
+
96
+ # 6. Connect到暂停的沙箱
97
+ print("Step 6: Connecting to paused sandbox...")
98
+ connected_sandbox = await AsyncSandbox.connect(self.sandbox_id)
99
+ assert connected_sandbox.sandbox_id == self.sandbox_id
100
+ print("Connected to sandbox successfully")
101
+
102
+ # 等待一小段时间确保connect完成
103
+ await asyncio.sleep(2)
104
+
105
+ # 7. 在connect之后校验文件操作结果
106
+ print("Step 7: Verifying file operations after connect...")
107
+
108
+ # 校验应该存在的文件
109
+ exists = await connected_sandbox.files.exists("/tmp/test_file1.txt")
110
+ assert exists, "test_file1.txt should exist"
111
+ file1_content = await connected_sandbox.files.read(
112
+ "/tmp/test_file1.txt", format="text"
113
+ )
114
+ assert "Content of test file 1" in file1_content
115
+ print("✅ Verified test_file1.txt exists and content is correct")
116
+
117
+ exists = await connected_sandbox.files.exists("/tmp/test_file3.bin")
118
+ assert exists, "test_file3.bin should exist"
119
+ file3_content = await connected_sandbox.files.read(
120
+ "/tmp/test_file3.bin", format="bytes"
121
+ )
122
+ assert bytes(file3_content) == b"Binary content for test file 3"
123
+ print("✅ Verified test_file3.bin exists and content is correct")
124
+
125
+ # 校验应该不存在的文件(被删除的)
126
+ exists = await connected_sandbox.files.exists("/tmp/test_file2.txt")
127
+ assert not exists, "test_file2.txt should not exist"
128
+ print("✅ Verified test_file2.txt was deleted correctly")
129
+
130
+ # 校验目录和嵌套文件
131
+ exists = await connected_sandbox.files.exists("/tmp/test_dir")
132
+ assert exists, "test_dir should exist"
133
+ exists = await connected_sandbox.files.exists(
134
+ "/tmp/test_dir/nested_file.txt"
135
+ )
136
+ assert exists, "nested_file.txt should exist"
137
+ nested_content = await connected_sandbox.files.read(
138
+ "/tmp/test_dir/nested_file.txt", format="text"
139
+ )
140
+ assert "Nested file content" in nested_content
141
+ print("✅ Verified directory and nested file exist and content is correct")
142
+
143
+ # 8. 在connect后的沙箱中执行一些操作验证功能正常
144
+ print("Step 8: Verifying sandbox functionality after connect...")
145
+ result = await connected_sandbox.commands.run(
146
+ "echo 'Test command after connect'"
147
+ )
148
+ assert result.exit_code == 0
149
+ assert "Test command after connect" in result.stdout
150
+ print("✅ Verified sandbox commands work after connect")
151
+
152
+ # 9. 创建新文件验证写入功能正常
153
+ print("Step 9: Testing file write after connect...")
154
+ new_file_path = "/tmp/new_file_after_connect.txt"
155
+ await connected_sandbox.files.write(
156
+ new_file_path, "New file created after connect"
157
+ )
158
+ exists = await connected_sandbox.files.exists(new_file_path)
159
+ assert exists
160
+ new_content = await connected_sandbox.files.read(
161
+ new_file_path, format="text"
162
+ )
163
+ assert "New file created after connect" in new_content
164
+ print("✅ Verified file write works after connect")
165
+
166
+ self.log_test_result(
167
+ "Connect and Pause with Files", True, "All verifications passed"
168
+ )
169
+ return True
170
+
171
+ except Exception as e:
172
+ self.log_test_result("Connect and Pause with Files", False, str(e))
173
+ print(f"Test failed with error: {e}")
174
+ import traceback
175
+
176
+ traceback.print_exc()
177
+ return False
178
+
179
+ async def test_connect_pause_multiple_operations(self):
180
+ """测试多次pause和connect操作"""
181
+ try:
182
+ # 1. 创建沙箱
183
+ print("Test 2: Creating sandbox for multiple operations test...")
184
+ sandbox = await AsyncSandbox.create(
185
+ template="base",
186
+ timeout=3600,
187
+ metadata={"test": "connect_pause_multiple_async"},
188
+ )
189
+ sandbox_id = sandbox.sandbox_id
190
+ print(f"Created sandbox with ID: {sandbox_id}")
191
+
192
+ # 2. 第一次操作:创建文件
193
+ print("First operation: Creating files...")
194
+ await sandbox.files.write("/tmp/multi_test1.txt", "First batch")
195
+ await sandbox.files.write("/tmp/multi_test2.txt", "First batch")
196
+
197
+ # 3. 第一次pause
198
+ print("First pause...")
199
+ await sandbox.beta_pause()
200
+ await asyncio.sleep(2)
201
+
202
+ # 4. 第一次connect
203
+ print("First connect...")
204
+ sandbox = await AsyncSandbox.connect(sandbox_id)
205
+ await asyncio.sleep(2)
206
+
207
+ # 5. 验证第一次的文件存在
208
+ assert await sandbox.files.exists("/tmp/multi_test1.txt")
209
+ assert await sandbox.files.exists("/tmp/multi_test2.txt")
210
+
211
+ # 6. 第二次操作:删除一个文件,创建新文件
212
+ print("Second operation: Deleting and creating files...")
213
+ await sandbox.files.remove("/tmp/multi_test1.txt")
214
+ await sandbox.files.write("/tmp/multi_test3.txt", "Second batch")
215
+
216
+ # 7. 第二次pause
217
+ print("Second pause...")
218
+ await sandbox.beta_pause()
219
+ await asyncio.sleep(2)
220
+
221
+ # 8. 第二次connect
222
+ print("Second connect...")
223
+ sandbox = await AsyncSandbox.connect(sandbox_id)
224
+ await asyncio.sleep(2)
225
+
226
+ # 9. 验证第二次操作的结果
227
+ exists = await sandbox.files.exists("/tmp/multi_test1.txt")
228
+ assert not exists, "multi_test1.txt should be deleted"
229
+ exists = await sandbox.files.exists("/tmp/multi_test2.txt")
230
+ assert exists, "multi_test2.txt should exist"
231
+ exists = await sandbox.files.exists("/tmp/multi_test3.txt")
232
+ assert exists, "multi_test3.txt should exist"
233
+ content = await sandbox.files.read("/tmp/multi_test3.txt", format="text")
234
+ assert "Second batch" in content
235
+
236
+ # 清理
237
+ await sandbox.kill()
238
+
239
+ self.log_test_result(
240
+ "Multiple Connect and Pause Operations",
241
+ True,
242
+ "All verifications passed",
243
+ )
244
+ return True
245
+
246
+ except Exception as e:
247
+ self.log_test_result("Multiple Connect and Pause Operations", False, str(e))
248
+ print(f"Test failed with error: {e}")
249
+ import traceback
250
+
251
+ traceback.print_exc()
252
+ return False
253
+
254
+ async def cleanup(self):
255
+ """清理资源"""
256
+ if self.sandbox:
257
+ try:
258
+ await self.sandbox.kill()
259
+ print("Sandbox cleaned up successfully")
260
+ except Exception as e:
261
+ print(f"Error cleaning up sandbox: {e}")
262
+
263
+ def print_summary(self):
264
+ """打印测试摘要"""
265
+ total_tests = len(self.test_results)
266
+ passed_tests = sum(1 for r in self.test_results if r["success"])
267
+ failed_tests = total_tests - passed_tests
268
+
269
+ print("\n" + "=" * 60)
270
+ print("Connect and Pause Test Report (Async)")
271
+ print("=" * 60)
272
+ print(f"总测试数: {total_tests}")
273
+ print(f"通过数: {passed_tests}")
274
+ print(f"失败数: {failed_tests}")
275
+ print(f"成功率: {(passed_tests/total_tests*100):.1f}%")
276
+
277
+ if failed_tests > 0:
278
+ print(f"\n失败的测试:")
279
+ for result in self.test_results:
280
+ if not result["success"]:
281
+ print(f" ❌ {result['test']}: {result['message']}")
282
+
283
+ print("=" * 60)
284
+
285
+
286
+ async def main():
287
+ """主函数"""
288
+ test_suite = ConnectPauseAsyncTest()
289
+
290
+ try:
291
+ # 运行测试
292
+ await test_suite.test_connect_pause_with_files()
293
+ await test_suite.test_connect_pause_multiple_operations()
294
+ finally:
295
+ await test_suite.cleanup()
296
+ test_suite.print_summary()
297
+
298
+
299
+ if __name__ == "__main__":
300
+ asyncio.run(main())