langfun 0.1.2.dev202510230805__py3-none-any.whl → 0.1.2.dev202511270805__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.

Potentially problematic release.


This version of langfun might be problematic. Click here for more details.

Files changed (155) hide show
  1. langfun/core/__init__.py +2 -0
  2. langfun/core/agentic/__init__.py +4 -1
  3. langfun/core/agentic/action.py +447 -29
  4. langfun/core/agentic/action_eval.py +9 -2
  5. langfun/core/agentic/action_test.py +149 -21
  6. langfun/core/async_support.py +32 -3
  7. langfun/core/coding/python/correction.py +19 -9
  8. langfun/core/coding/python/execution.py +14 -12
  9. langfun/core/coding/python/generation.py +21 -16
  10. langfun/core/coding/python/sandboxing.py +23 -3
  11. langfun/core/component.py +42 -3
  12. langfun/core/concurrent.py +70 -6
  13. langfun/core/concurrent_test.py +1 -0
  14. langfun/core/console.py +1 -1
  15. langfun/core/data/conversion/anthropic.py +12 -3
  16. langfun/core/data/conversion/anthropic_test.py +8 -6
  17. langfun/core/data/conversion/gemini.py +9 -2
  18. langfun/core/data/conversion/gemini_test.py +12 -9
  19. langfun/core/data/conversion/openai.py +145 -31
  20. langfun/core/data/conversion/openai_test.py +161 -17
  21. langfun/core/eval/base.py +47 -43
  22. langfun/core/eval/base_test.py +5 -5
  23. langfun/core/eval/matching.py +5 -2
  24. langfun/core/eval/patching.py +3 -3
  25. langfun/core/eval/scoring.py +4 -3
  26. langfun/core/eval/v2/__init__.py +1 -0
  27. langfun/core/eval/v2/checkpointing.py +64 -6
  28. langfun/core/eval/v2/checkpointing_test.py +9 -2
  29. langfun/core/eval/v2/eval_test_helper.py +103 -2
  30. langfun/core/eval/v2/evaluation.py +91 -16
  31. langfun/core/eval/v2/evaluation_test.py +9 -3
  32. langfun/core/eval/v2/example.py +50 -40
  33. langfun/core/eval/v2/example_test.py +16 -8
  34. langfun/core/eval/v2/experiment.py +74 -8
  35. langfun/core/eval/v2/experiment_test.py +19 -0
  36. langfun/core/eval/v2/metric_values.py +31 -3
  37. langfun/core/eval/v2/metric_values_test.py +32 -0
  38. langfun/core/eval/v2/metrics.py +157 -44
  39. langfun/core/eval/v2/metrics_test.py +39 -18
  40. langfun/core/eval/v2/progress.py +30 -1
  41. langfun/core/eval/v2/progress_test.py +27 -0
  42. langfun/core/eval/v2/progress_tracking.py +12 -3
  43. langfun/core/eval/v2/progress_tracking_test.py +6 -1
  44. langfun/core/eval/v2/reporting.py +90 -71
  45. langfun/core/eval/v2/reporting_test.py +24 -6
  46. langfun/core/eval/v2/runners/__init__.py +30 -0
  47. langfun/core/eval/v2/{runners.py → runners/base.py} +59 -142
  48. langfun/core/eval/v2/runners/beam.py +341 -0
  49. langfun/core/eval/v2/runners/beam_test.py +131 -0
  50. langfun/core/eval/v2/runners/ckpt_monitor.py +294 -0
  51. langfun/core/eval/v2/runners/ckpt_monitor_test.py +162 -0
  52. langfun/core/eval/v2/runners/debug.py +40 -0
  53. langfun/core/eval/v2/runners/debug_test.py +76 -0
  54. langfun/core/eval/v2/runners/parallel.py +100 -0
  55. langfun/core/eval/v2/runners/parallel_test.py +95 -0
  56. langfun/core/eval/v2/runners/sequential.py +47 -0
  57. langfun/core/eval/v2/runners/sequential_test.py +172 -0
  58. langfun/core/langfunc.py +45 -130
  59. langfun/core/langfunc_test.py +7 -5
  60. langfun/core/language_model.py +141 -21
  61. langfun/core/language_model_test.py +54 -3
  62. langfun/core/llms/__init__.py +9 -1
  63. langfun/core/llms/anthropic.py +157 -2
  64. langfun/core/llms/azure_openai.py +29 -17
  65. langfun/core/llms/cache/base.py +25 -3
  66. langfun/core/llms/cache/in_memory.py +48 -7
  67. langfun/core/llms/cache/in_memory_test.py +14 -4
  68. langfun/core/llms/compositional.py +25 -1
  69. langfun/core/llms/deepseek.py +30 -2
  70. langfun/core/llms/fake.py +32 -1
  71. langfun/core/llms/gemini.py +55 -17
  72. langfun/core/llms/gemini_test.py +84 -0
  73. langfun/core/llms/google_genai.py +34 -1
  74. langfun/core/llms/groq.py +28 -3
  75. langfun/core/llms/llama_cpp.py +23 -4
  76. langfun/core/llms/openai.py +36 -3
  77. langfun/core/llms/openai_compatible.py +148 -27
  78. langfun/core/llms/openai_compatible_test.py +207 -20
  79. langfun/core/llms/openai_test.py +0 -2
  80. langfun/core/llms/rest.py +12 -1
  81. langfun/core/llms/vertexai.py +58 -8
  82. langfun/core/logging.py +1 -1
  83. langfun/core/mcp/client.py +77 -22
  84. langfun/core/mcp/client_test.py +8 -35
  85. langfun/core/mcp/session.py +94 -29
  86. langfun/core/mcp/session_test.py +54 -0
  87. langfun/core/mcp/tool.py +151 -22
  88. langfun/core/mcp/tool_test.py +197 -0
  89. langfun/core/memory.py +1 -0
  90. langfun/core/message.py +160 -55
  91. langfun/core/message_test.py +65 -81
  92. langfun/core/modalities/__init__.py +8 -0
  93. langfun/core/modalities/audio.py +21 -1
  94. langfun/core/modalities/image.py +19 -1
  95. langfun/core/modalities/mime.py +64 -3
  96. langfun/core/modalities/mime_test.py +11 -0
  97. langfun/core/modalities/pdf.py +19 -1
  98. langfun/core/modalities/video.py +21 -1
  99. langfun/core/modality.py +167 -29
  100. langfun/core/modality_test.py +42 -12
  101. langfun/core/natural_language.py +1 -1
  102. langfun/core/sampling.py +4 -4
  103. langfun/core/sampling_test.py +20 -4
  104. langfun/core/structured/__init__.py +2 -24
  105. langfun/core/structured/completion.py +34 -44
  106. langfun/core/structured/completion_test.py +23 -43
  107. langfun/core/structured/description.py +54 -50
  108. langfun/core/structured/function_generation.py +29 -12
  109. langfun/core/structured/mapping.py +81 -37
  110. langfun/core/structured/parsing.py +95 -79
  111. langfun/core/structured/parsing_test.py +0 -3
  112. langfun/core/structured/querying.py +215 -142
  113. langfun/core/structured/querying_test.py +65 -29
  114. langfun/core/structured/schema/__init__.py +49 -0
  115. langfun/core/structured/schema/base.py +664 -0
  116. langfun/core/structured/schema/base_test.py +531 -0
  117. langfun/core/structured/schema/json.py +174 -0
  118. langfun/core/structured/schema/json_test.py +121 -0
  119. langfun/core/structured/schema/python.py +316 -0
  120. langfun/core/structured/schema/python_test.py +410 -0
  121. langfun/core/structured/schema_generation.py +33 -14
  122. langfun/core/structured/scoring.py +47 -36
  123. langfun/core/structured/tokenization.py +26 -11
  124. langfun/core/subscription.py +2 -2
  125. langfun/core/template.py +174 -49
  126. langfun/core/template_test.py +123 -17
  127. langfun/env/__init__.py +8 -2
  128. langfun/env/base_environment.py +320 -128
  129. langfun/env/base_environment_test.py +473 -0
  130. langfun/env/base_feature.py +92 -15
  131. langfun/env/base_feature_test.py +228 -0
  132. langfun/env/base_sandbox.py +84 -361
  133. langfun/env/base_sandbox_test.py +1235 -0
  134. langfun/env/event_handlers/__init__.py +1 -1
  135. langfun/env/event_handlers/chain.py +233 -0
  136. langfun/env/event_handlers/chain_test.py +253 -0
  137. langfun/env/event_handlers/event_logger.py +95 -98
  138. langfun/env/event_handlers/event_logger_test.py +21 -21
  139. langfun/env/event_handlers/metric_writer.py +225 -140
  140. langfun/env/event_handlers/metric_writer_test.py +23 -6
  141. langfun/env/interface.py +854 -40
  142. langfun/env/interface_test.py +112 -2
  143. langfun/env/load_balancers_test.py +23 -2
  144. langfun/env/test_utils.py +126 -84
  145. {langfun-0.1.2.dev202510230805.dist-info → langfun-0.1.2.dev202511270805.dist-info}/METADATA +1 -1
  146. langfun-0.1.2.dev202511270805.dist-info/RECORD +215 -0
  147. langfun/core/eval/v2/runners_test.py +0 -343
  148. langfun/core/structured/schema.py +0 -987
  149. langfun/core/structured/schema_test.py +0 -982
  150. langfun/env/base_test.py +0 -1481
  151. langfun/env/event_handlers/base.py +0 -350
  152. langfun-0.1.2.dev202510230805.dist-info/RECORD +0 -195
  153. {langfun-0.1.2.dev202510230805.dist-info → langfun-0.1.2.dev202511270805.dist-info}/WHEEL +0 -0
  154. {langfun-0.1.2.dev202510230805.dist-info → langfun-0.1.2.dev202511270805.dist-info}/licenses/LICENSE +0 -0
  155. {langfun-0.1.2.dev202510230805.dist-info → langfun-0.1.2.dev202511270805.dist-info}/top_level.txt +0 -0
langfun/env/base_test.py DELETED
@@ -1,1481 +0,0 @@
1
- # Copyright 2025 The Langfun Authors
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 time
15
- from typing import Any
16
- import unittest
17
-
18
- from langfun.env import base_sandbox
19
- from langfun.env import interface
20
- from langfun.env import test_utils
21
- from langfun.env.event_handlers import base as event_handler_base
22
-
23
-
24
- TestingEnvironment = test_utils.TestingEnvironment
25
- TestingSandbox = test_utils.TestingSandbox
26
- TestingFeature = test_utils.TestingFeature
27
- TestingEventHandler = test_utils.TestingEventHandler
28
-
29
-
30
- class EnvironmentTests(unittest.TestCase):
31
-
32
- def test_basics(self):
33
- env = TestingEnvironment(
34
- root_dir='/tmp',
35
- pool_size=0,
36
- features={'test_feature': TestingFeature()},
37
- outage_grace_period=1,
38
- outage_retry_interval=0,
39
- )
40
- self.assertIsNone(interface.Environment.current())
41
- self.assertEqual(env.status, interface.Environment.Status.CREATED)
42
- self.assertFalse(env.is_online)
43
- self.assertEqual(env.min_pool_size, 0)
44
- self.assertEqual(env.max_pool_size, 0)
45
- self.assertEqual(env.sandbox_pool, [])
46
- self.assertEqual(env.id, interface.Environment.Id('testing-env'))
47
- self.assertEqual(env.outage_grace_period, 1)
48
- self.assertEqual(env.features['test_feature'].name, 'test_feature')
49
-
50
- self.assertIsNone(env.start_time)
51
-
52
- with env:
53
- self.assertEqual(env.status, interface.Environment.Status.ONLINE)
54
- self.assertIs(interface.Environment.current(), env)
55
- self.assertTrue(env.is_online)
56
- self.assertIsNotNone(env.start_time)
57
- self.assertEqual(env.offline_duration, 0.0)
58
- self.assertEqual(env.sandbox_pool, [])
59
- self.assertEqual(env.working_dir, '/tmp/testing-env')
60
-
61
- with env.sandbox('session1') as sb:
62
- self.assertEqual(
63
- sb.id, interface.Sandbox.Id(environment_id=env.id, sandbox_id='0')
64
- )
65
- self.assertEqual(sb.session_id, 'session1')
66
- self.assertEqual(sb.working_dir, '/tmp/testing-env/0')
67
- self.assertTrue(sb.is_online)
68
- self.assertIs(sb.test_feature, sb.features['test_feature'])
69
- self.assertEqual(
70
- sb.test_feature.working_dir,
71
- '/tmp/testing-env/0/test_feature'
72
- )
73
- with self.assertRaises(AttributeError):
74
- _ = sb.test_feature2
75
- self.assertFalse(sb.is_online)
76
-
77
- self.assertIsInstance(env.test_feature, TestingFeature)
78
- with self.assertRaises(AttributeError):
79
- _ = env.test_feature2
80
-
81
- def test_del(self):
82
- env = TestingEnvironment(
83
- features={'test_feature': TestingFeature()},
84
- pool_size=0,
85
- outage_grace_period=1,
86
- outage_retry_interval=0,
87
- sandbox_keepalive_interval=0,
88
- )
89
- env.start()
90
- sb = env.acquire()
91
- del sb
92
- del env
93
-
94
- def test_acquire_env_offline(self):
95
- env = TestingEnvironment(
96
- features={'test_feature': TestingFeature()},
97
- pool_size=0,
98
- outage_grace_period=1,
99
- outage_retry_interval=0,
100
- sandbox_keepalive_interval=0,
101
- )
102
- with self.assertRaises(interface.EnvironmentOutageError):
103
- env.acquire()
104
-
105
- def test_acquire_no_pooling(self):
106
- env = TestingEnvironment(
107
- features={'test_feature': TestingFeature()},
108
- pool_size=0,
109
- outage_grace_period=1,
110
- outage_retry_interval=0,
111
- sandbox_keepalive_interval=0,
112
- )
113
- with env:
114
- sb = env.acquire()
115
- self.assertEqual(sb.status, interface.Sandbox.Status.ACQUIRED)
116
- self.assertIsNone(env.working_dir)
117
- self.assertIsNone(sb.working_dir)
118
- self.assertIsNone(sb.test_feature.working_dir)
119
-
120
- def test_acquire_no_pooling_with_error(self):
121
- env = TestingEnvironment(
122
- features={
123
- 'test_feature': TestingFeature(
124
- simulate_setup_error=interface.SandboxStateError
125
- )
126
- },
127
- pool_size=0,
128
- outage_grace_period=1,
129
- outage_retry_interval=0,
130
- sandbox_keepalive_interval=0,
131
- )
132
- with env:
133
- with self.assertRaises(interface.EnvironmentOutageError):
134
- env.acquire()
135
-
136
- def test_acquire_with_pooling(self):
137
- env = TestingEnvironment(
138
- features={'test_feature': TestingFeature()},
139
- pool_size=1,
140
- outage_grace_period=1,
141
- outage_retry_interval=0,
142
- sandbox_keepalive_interval=0,
143
- )
144
- with env:
145
- sb = env.acquire()
146
- self.assertEqual(sb.status, interface.Sandbox.Status.ACQUIRED)
147
-
148
- def test_acquire_with_pooling_overload(self):
149
- env = TestingEnvironment(
150
- features={'test_feature': TestingFeature()},
151
- pool_size=1,
152
- outage_grace_period=1,
153
- outage_retry_interval=0,
154
- sandbox_keepalive_interval=0,
155
- )
156
- with env:
157
- sb = env.acquire()
158
- self.assertEqual(sb.status, interface.Sandbox.Status.ACQUIRED)
159
- with self.assertRaises(interface.EnvironmentOverloadError):
160
- env.acquire()
161
-
162
- def test_acquire_with_growing_pool(self):
163
- env = TestingEnvironment(
164
- features={'test_feature': TestingFeature()},
165
- pool_size=(1, 3),
166
- outage_grace_period=1,
167
- outage_retry_interval=0,
168
- sandbox_keepalive_interval=0,
169
- )
170
- with env:
171
- self.assertEqual(len(env.sandbox_pool), 1)
172
- self.assertEqual(
173
- env.stats(),
174
- {
175
- 'sandbox': {
176
- 'created': 0,
177
- 'setting_up': 0,
178
- 'ready': 1,
179
- 'acquired': 0,
180
- 'in_session': 0,
181
- 'exiting_session': 0,
182
- 'shutting_down': 0,
183
- 'offline': 0,
184
- }
185
- }
186
- )
187
- sb = env.acquire()
188
- self.assertEqual(sb.status, interface.Sandbox.Status.ACQUIRED)
189
- self.assertEqual(
190
- env.stats(),
191
- {
192
- 'sandbox': {
193
- 'created': 0,
194
- 'setting_up': 0,
195
- 'ready': 0,
196
- 'acquired': 1,
197
- 'in_session': 0,
198
- 'exiting_session': 0,
199
- 'shutting_down': 0,
200
- 'offline': 0,
201
- }
202
- }
203
- )
204
- self.assertEqual(len(env.sandbox_pool), 1)
205
- sb2 = env.acquire()
206
- self.assertEqual(sb2.status, interface.Sandbox.Status.ACQUIRED)
207
- self.assertEqual(len(env.sandbox_pool), 2)
208
- self.assertEqual(
209
- env.stats(),
210
- {
211
- 'sandbox': {
212
- 'created': 0,
213
- 'setting_up': 0,
214
- 'ready': 0,
215
- 'acquired': 2,
216
- 'in_session': 0,
217
- 'exiting_session': 0,
218
- 'shutting_down': 0,
219
- 'offline': 0,
220
- }
221
- }
222
- )
223
- self.assertEqual(
224
- env.stats(),
225
- {
226
- 'sandbox': {
227
- 'created': 0,
228
- 'setting_up': 0,
229
- 'ready': 0,
230
- 'acquired': 0,
231
- 'in_session': 0,
232
- 'exiting_session': 0,
233
- 'shutting_down': 0,
234
- 'offline': 0,
235
- }
236
- }
237
- )
238
-
239
- def test_acquire_with_growing_pool_failure(self):
240
- env = TestingEnvironment(
241
- features={'test_feature': TestingFeature()},
242
- pool_size=(1, 3),
243
- outage_grace_period=1,
244
- outage_retry_interval=0,
245
- sandbox_keepalive_interval=0,
246
- )
247
- with env:
248
- self.assertEqual(len(env.sandbox_pool), 1)
249
- sb = env.acquire()
250
- self.assertEqual(sb.status, interface.Sandbox.Status.ACQUIRED)
251
-
252
- # Make future sandbox setup to fail.
253
- env.features.test_feature.rebind(
254
- simulate_setup_error=interface.SandboxStateError,
255
- skip_notification=True
256
- )
257
- with self.assertRaises(interface.EnvironmentOutageError):
258
- env.acquire()
259
-
260
- def test_housekeep_error(self):
261
- env = TestingEnvironment(
262
- features={'test_feature': TestingFeature()},
263
- pool_size=1,
264
- proactive_session_setup=True,
265
- outage_grace_period=1,
266
- outage_retry_interval=0,
267
- sandbox_keepalive_interval=0,
268
- )
269
- with env:
270
- self.assertEqual(len(env.sandbox_pool), 1)
271
- self.assertEqual(
272
- env.sandbox_pool[0].status, interface.Sandbox.Status.READY
273
- )
274
- # Make future sandbox setup to fail.
275
- env.features.test_feature.rebind(
276
- simulate_setup_error=interface.SandboxStateError,
277
- skip_notification=True
278
- )
279
- with env.sandbox() as sb:
280
- with self.assertRaises(interface.SandboxStateError):
281
- sb.shell('bad command', raise_error=interface.SandboxStateError)
282
- self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
283
- sb_offline_time = time.time()
284
- while time.time() - sb_offline_time < 10:
285
- if not env.is_online:
286
- break
287
- time.sleep(0.5)
288
- self.assertFalse(env.is_online)
289
-
290
-
291
- class SandboxStatusTests(unittest.TestCase):
292
-
293
- def setUp(self):
294
- super().setUp()
295
- self.event_handler = TestingEventHandler(
296
- log_sandbox_status=True,
297
- log_feature_setup=True,
298
- log_session_setup=True,
299
- )
300
- self.maxDiff = None
301
-
302
- def _create_env(
303
- self,
304
- features,
305
- *,
306
- pool_size=0,
307
- **kwargs
308
- ) -> TestingEnvironment:
309
- return TestingEnvironment(
310
- pool_size=pool_size,
311
- features=features,
312
- outage_grace_period=0,
313
- event_handlers=[self.event_handler],
314
- outage_retry_interval=0,
315
- **kwargs
316
- )
317
-
318
- def test_passive_session_setup(self):
319
- env = self._create_env(
320
- features={
321
- 'feature1': TestingFeature(),
322
- 'feature2': TestingFeature(),
323
- },
324
- )
325
- self.assertFalse(env.enable_pooling)
326
- with env:
327
- with env.sandbox('session1') as sb:
328
- sb.shell('echo "hello"')
329
- self.assertEqual(
330
- self.event_handler.logs,
331
- [
332
- '[testing-env] environment started',
333
- '[testing-env/0] shell: "feature1" setup',
334
- '[testing-env/0/feature1] feature setup',
335
- '[testing-env/0] shell: "feature2" setup',
336
- '[testing-env/0/feature2] feature setup',
337
- '[testing-env/0] created -> ready',
338
- '[testing-env/0] sandbox started',
339
- '[testing-env/0] ready -> acquired',
340
- '[testing-env/0] acquired -> setting_up',
341
- '[testing-env/0/session1] shell: "feature1" setup session',
342
- '[testing-env/0/feature1] feature setup session',
343
- '[testing-env/0/session1] shell: "feature2" setup session',
344
- '[testing-env/0/feature2] feature setup session',
345
- '[testing-env/0] setting_up -> in_session',
346
- "[testing-env/0] session 'session1' started",
347
- '[testing-env/0/session1] shell: echo "hello"',
348
- '[testing-env/0] in_session -> exiting_session',
349
- '[testing-env/0/session1] shell: "feature1" teardown session',
350
- '[testing-env/0/feature1] feature teardown session',
351
- '[testing-env/0/session1] shell: "feature2" teardown session',
352
- '[testing-env/0/feature2] feature teardown session',
353
- "[testing-env/0] session 'session1' ended",
354
- '[testing-env/0] exiting_session -> acquired',
355
- '[testing-env/0] acquired -> shutting_down',
356
- '[testing-env/0] shell: "feature1" teardown',
357
- '[testing-env/0/feature1] feature teardown',
358
- '[testing-env/0] shell: "feature2" teardown',
359
- '[testing-env/0/feature2] feature teardown',
360
- '[testing-env/0] shutting_down -> offline',
361
- '[testing-env/0] sandbox shutdown'
362
- ]
363
- )
364
-
365
- def test_proactive_session_setup(self):
366
- env = self._create_env(
367
- features={
368
- 'feature1': TestingFeature(setup_session_delay=0.1),
369
- 'feature2': TestingFeature(),
370
- },
371
- pool_size=1,
372
- proactive_session_setup=True,
373
- )
374
- self.assertTrue(env.enable_pooling)
375
- with env:
376
- with env.sandbox('session1') as sb:
377
- sb.shell('echo "hello"')
378
- sb.wait_until_not(
379
- (
380
- interface.Sandbox.Status.IN_SESSION,
381
- interface.Sandbox.Status.SETTING_UP
382
- )
383
- )
384
- self.assertEqual(sb.status, interface.Sandbox.Status.READY)
385
- self.assertEqual(
386
- self.event_handler.logs,
387
- [
388
- '[testing-env/0:0] shell: "feature1" setup',
389
- '[testing-env/0:0/feature1] feature setup',
390
- '[testing-env/0:0] shell: "feature2" setup',
391
- '[testing-env/0:0/feature2] feature setup',
392
- '[testing-env/0:0] shell: "feature1" setup session',
393
- '[testing-env/0:0/feature1] feature setup session',
394
- '[testing-env/0:0] shell: "feature2" setup session',
395
- '[testing-env/0:0/feature2] feature setup session',
396
- '[testing-env/0:0] created -> ready',
397
- '[testing-env/0:0] sandbox started',
398
- '[testing-env] environment started',
399
- '[testing-env/0:0] ready -> acquired',
400
- '[testing-env/0:0] acquired -> setting_up',
401
- '[testing-env/0:0] setting_up -> in_session',
402
- "[testing-env/0:0] session 'session1' started",
403
- '[testing-env/0:0/session1] shell: echo "hello"',
404
- '[testing-env/0:0] in_session -> exiting_session',
405
- '[testing-env/0:0/session1] shell: "feature1" teardown session',
406
- '[testing-env/0:0/feature1] feature teardown session',
407
- '[testing-env/0:0/session1] shell: "feature2" teardown session',
408
- '[testing-env/0:0/feature2] feature teardown session',
409
- "[testing-env/0:0] session 'session1' ended",
410
- '[testing-env/0:0] exiting_session -> setting_up',
411
- '[testing-env/0:0] shell: "feature1" setup session',
412
- '[testing-env/0:0/feature1] feature setup session',
413
- '[testing-env/0:0] shell: "feature2" setup session',
414
- '[testing-env/0:0/feature2] feature setup session',
415
- '[testing-env/0:0] setting_up -> ready'
416
- ]
417
- )
418
-
419
- def test_practive_session_setup_with_setup_session_error(self):
420
- env = self._create_env(
421
- features={'test_feature': TestingFeature(setup_session_delay=0.5)},
422
- pool_size=1,
423
- )
424
- event_handler = TestingEventHandler(
425
- log_sandbox_status=True,
426
- log_feature_setup=True,
427
- log_session_setup=True,
428
- )
429
- with env:
430
- with env.sandbox('session1') as sb:
431
- sb.add_event_handler(event_handler)
432
- sb.test_feature.rebind(
433
- simulate_setup_session_error=interface.SandboxStateError,
434
- skip_notification=True
435
- )
436
- sb.wait_until_not(
437
- (
438
- interface.Sandbox.Status.SETTING_UP,
439
- interface.Sandbox.Status.SHUTTING_DOWN
440
- )
441
- )
442
- self.assertEqual(len(sb.state_errors), 1)
443
- self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
444
- self.assertEqual(
445
- event_handler.logs,
446
- [
447
- # pylint: disable=line-too-long
448
- '[testing-env/0:0] in_session -> exiting_session',
449
- '[testing-env/0:0/session1] shell: "test_feature" teardown session',
450
- '[testing-env/0:0/test_feature] feature teardown session',
451
- "[testing-env/0:0] session 'session1' ended",
452
- '[testing-env/0:0] exiting_session -> setting_up',
453
- '[testing-env/0:0/test_feature] feature setup session with SandboxStateError', # pylint: disable=line-too-long
454
- '[testing-env/0:0] setting_up -> shutting_down',
455
- '[testing-env/0:0] shell: "test_feature" teardown',
456
- '[testing-env/0:0/test_feature] feature teardown',
457
- '[testing-env/0:0] shutting_down -> offline',
458
- '[testing-env/0:0] sandbox shutdown'
459
- # pylint: enable=line-too-long
460
- ]
461
- )
462
-
463
- def test_sandbox_start_non_state_error(self):
464
- env = self._create_env(
465
- features={
466
- 'feature1': TestingFeature(),
467
- 'feature2': TestingFeature(),
468
- },
469
- simulate_start_error=ValueError,
470
- )
471
- with env:
472
- with self.assertRaises(ValueError):
473
- with env.sandbox('session1'):
474
- pass
475
- self.assertTrue(env.is_online)
476
- self.assertEqual(
477
- self.event_handler.logs,
478
- [
479
- '[testing-env] environment started',
480
- '[testing-env/0] sandbox started with ValueError',
481
- '[testing-env/0] created -> shutting_down',
482
- '[testing-env/0] shutting_down -> offline',
483
- '[testing-env/0] sandbox shutdown'
484
- ]
485
- )
486
-
487
- def test_sandbox_start_state_error(self):
488
- env = self._create_env(
489
- features={
490
- 'feature1': TestingFeature(),
491
- 'feature2': TestingFeature(),
492
- },
493
- pool_size=1,
494
- simulate_start_error=interface.SandboxStateError,
495
- )
496
- with self.assertRaises(interface.EnvironmentOutageError):
497
- with env:
498
- pass
499
- self.assertEqual(
500
- self.event_handler.logs,
501
- [
502
- '[testing-env/0:0] sandbox started with SandboxStateError',
503
- '[testing-env/0:0] created -> shutting_down',
504
- '[testing-env/0:0] shutting_down -> offline',
505
- '[testing-env/0:0] sandbox shutdown',
506
- '[testing-env] environment started with EnvironmentOutageError',
507
- '[testing-env] environment shutdown'
508
- ]
509
- )
510
-
511
- def test_sandbox_shutdown_non_state_error(self):
512
- env = self._create_env(
513
- features={
514
- 'feature1': TestingFeature(),
515
- 'feature2': TestingFeature(),
516
- },
517
- simulate_shutdown_error=ValueError,
518
- )
519
- with env:
520
- with self.assertRaises(ValueError):
521
- with env.sandbox('session1') as sb:
522
- sb.shell('echo "hello"')
523
- self.assertEqual(len(sb.state_errors), 0)
524
-
525
- self.assertEqual(
526
- self.event_handler.logs,
527
- [
528
- '[testing-env] environment started',
529
- '[testing-env/0] shell: "feature1" setup',
530
- '[testing-env/0/feature1] feature setup',
531
- '[testing-env/0] shell: "feature2" setup',
532
- '[testing-env/0/feature2] feature setup',
533
- '[testing-env/0] created -> ready',
534
- '[testing-env/0] sandbox started',
535
- '[testing-env/0] ready -> acquired',
536
- '[testing-env/0] acquired -> setting_up',
537
- '[testing-env/0/session1] shell: "feature1" setup session',
538
- '[testing-env/0/feature1] feature setup session',
539
- '[testing-env/0/session1] shell: "feature2" setup session',
540
- '[testing-env/0/feature2] feature setup session',
541
- '[testing-env/0] setting_up -> in_session',
542
- "[testing-env/0] session 'session1' started",
543
- '[testing-env/0/session1] shell: echo "hello"',
544
- '[testing-env/0] in_session -> exiting_session',
545
- '[testing-env/0/session1] shell: "feature1" teardown session',
546
- '[testing-env/0/feature1] feature teardown session',
547
- '[testing-env/0/session1] shell: "feature2" teardown session',
548
- '[testing-env/0/feature2] feature teardown session',
549
- "[testing-env/0] session 'session1' ended",
550
- '[testing-env/0] exiting_session -> acquired',
551
- '[testing-env/0] acquired -> shutting_down',
552
- '[testing-env/0] shell: "feature1" teardown',
553
- '[testing-env/0/feature1] feature teardown',
554
- '[testing-env/0] shell: "feature2" teardown',
555
- '[testing-env/0/feature2] feature teardown',
556
- '[testing-env/0] shutting_down -> offline',
557
- '[testing-env/0] sandbox shutdown with ValueError',
558
- '[testing-env] environment shutdown'
559
- ]
560
- )
561
-
562
- def test_env_shutdown_non_state_error(self):
563
- env = self._create_env(
564
- pool_size=1,
565
- features={
566
- 'feature1': TestingFeature(),
567
- 'feature2': TestingFeature(),
568
- },
569
- simulate_shutdown_error=ValueError,
570
- )
571
- with self.assertRaises(ValueError):
572
- with env:
573
- pass
574
-
575
- self.assertEqual(
576
- self.event_handler.logs,
577
- [
578
- '[testing-env/0:0] shell: "feature1" setup',
579
- '[testing-env/0:0/feature1] feature setup',
580
- '[testing-env/0:0] shell: "feature2" setup',
581
- '[testing-env/0:0/feature2] feature setup',
582
- '[testing-env/0:0] shell: "feature1" setup session',
583
- '[testing-env/0:0/feature1] feature setup session',
584
- '[testing-env/0:0] shell: "feature2" setup session',
585
- '[testing-env/0:0/feature2] feature setup session',
586
- '[testing-env/0:0] created -> ready',
587
- '[testing-env/0:0] sandbox started',
588
- '[testing-env] environment started',
589
- '[testing-env/0:0] ready -> shutting_down',
590
- '[testing-env/0:0] shell: "feature1" teardown',
591
- '[testing-env/0:0/feature1] feature teardown',
592
- '[testing-env/0:0] shell: "feature2" teardown',
593
- '[testing-env/0:0/feature2] feature teardown',
594
- '[testing-env/0:0] shutting_down -> offline',
595
- '[testing-env/0:0] sandbox shutdown with ValueError',
596
- '[testing-env] environment shutdown with ValueError'
597
- ]
598
- )
599
-
600
- def test_sandbox_shutdown_state_error(self):
601
- env = self._create_env(
602
- features={
603
- 'feature1': TestingFeature(),
604
- 'feature2': TestingFeature(),
605
- },
606
- simulate_shutdown_error=interface.SandboxStateError,
607
- )
608
- with env:
609
- with env.sandbox('session1') as sb:
610
- sb.shell('echo "hello"')
611
- self.assertEqual(len(sb.state_errors), 1)
612
- self.assertEqual(
613
- self.event_handler.logs,
614
- [
615
- '[testing-env] environment started',
616
- '[testing-env/0] shell: "feature1" setup',
617
- '[testing-env/0/feature1] feature setup',
618
- '[testing-env/0] shell: "feature2" setup',
619
- '[testing-env/0/feature2] feature setup',
620
- '[testing-env/0] created -> ready',
621
- '[testing-env/0] sandbox started',
622
- '[testing-env/0] ready -> acquired',
623
- '[testing-env/0] acquired -> setting_up',
624
- '[testing-env/0/session1] shell: "feature1" setup session',
625
- '[testing-env/0/feature1] feature setup session',
626
- '[testing-env/0/session1] shell: "feature2" setup session',
627
- '[testing-env/0/feature2] feature setup session',
628
- '[testing-env/0] setting_up -> in_session',
629
- "[testing-env/0] session 'session1' started",
630
- '[testing-env/0/session1] shell: echo "hello"',
631
- '[testing-env/0] in_session -> exiting_session',
632
- '[testing-env/0/session1] shell: "feature1" teardown session',
633
- '[testing-env/0/feature1] feature teardown session',
634
- '[testing-env/0/session1] shell: "feature2" teardown session',
635
- '[testing-env/0/feature2] feature teardown session',
636
- "[testing-env/0] session 'session1' ended",
637
- '[testing-env/0] exiting_session -> acquired',
638
- '[testing-env/0] acquired -> shutting_down',
639
- '[testing-env/0] shell: "feature1" teardown',
640
- '[testing-env/0/feature1] feature teardown',
641
- '[testing-env/0] shell: "feature2" teardown',
642
- '[testing-env/0/feature2] feature teardown',
643
- '[testing-env/0] shutting_down -> offline',
644
- '[testing-env/0] sandbox shutdown with SandboxStateError',
645
- '[testing-env] environment shutdown'
646
- ]
647
- )
648
-
649
- def test_feature_setup_non_state_error(self):
650
- env = self._create_env(
651
- features={
652
- 'feature1': TestingFeature(),
653
- 'feature2': TestingFeature(
654
- simulate_setup_error=ValueError
655
- ),
656
- },
657
- )
658
- with env:
659
- with self.assertRaises(ValueError):
660
- with env.sandbox('session1'):
661
- pass
662
- self.assertEqual(
663
- self.event_handler.logs,
664
- [
665
- '[testing-env] environment started',
666
- '[testing-env/0] shell: "feature1" setup',
667
- '[testing-env/0/feature1] feature setup',
668
- '[testing-env/0/feature2] feature setup with ValueError',
669
- '[testing-env/0] sandbox started with ValueError',
670
- '[testing-env/0] created -> shutting_down',
671
- '[testing-env/0] shell: "feature1" teardown',
672
- '[testing-env/0/feature1] feature teardown',
673
- '[testing-env/0] shell: "feature2" teardown',
674
- '[testing-env/0/feature2] feature teardown',
675
- '[testing-env/0] shutting_down -> offline',
676
- '[testing-env/0] sandbox shutdown'
677
- ]
678
- )
679
-
680
- def test_feature_setup_state_error(self):
681
- env = self._create_env(
682
- features={
683
- 'feature1': TestingFeature(
684
- simulate_setup_error=interface.SandboxStateError
685
- ),
686
- 'feature2': TestingFeature(),
687
- },
688
- )
689
- with env:
690
- with self.assertRaises(interface.EnvironmentOutageError):
691
- with env.sandbox('session1'):
692
- pass
693
- self.assertEqual(
694
- self.event_handler.logs,
695
- [
696
- '[testing-env] environment started',
697
- '[testing-env/0/feature1] feature setup with SandboxStateError',
698
- '[testing-env/0] sandbox started with SandboxStateError',
699
- '[testing-env/0] created -> shutting_down',
700
- '[testing-env/0] shell: "feature1" teardown',
701
- '[testing-env/0/feature1] feature teardown',
702
- '[testing-env/0] shutting_down -> offline',
703
- '[testing-env/0] sandbox shutdown',
704
- '[testing-env] environment shutdown'
705
- ]
706
- )
707
-
708
- def test_feature_teardown_non_state_error(self):
709
- env = self._create_env(
710
- features={
711
- 'feature1': TestingFeature(),
712
- 'feature2': TestingFeature(
713
- simulate_teardown_error=ValueError
714
- ),
715
- },
716
- )
717
- with env:
718
- with self.assertRaises(interface.FeatureTeardownError):
719
- with env.sandbox('session1'):
720
- pass
721
- self.assertEqual(
722
- self.event_handler.logs,
723
- [
724
- '[testing-env] environment started',
725
- '[testing-env/0] shell: "feature1" setup',
726
- '[testing-env/0/feature1] feature setup',
727
- '[testing-env/0] shell: "feature2" setup',
728
- '[testing-env/0/feature2] feature setup',
729
- '[testing-env/0] created -> ready',
730
- '[testing-env/0] sandbox started',
731
- '[testing-env/0] ready -> acquired',
732
- '[testing-env/0] acquired -> setting_up',
733
- '[testing-env/0/session1] shell: "feature1" setup session',
734
- '[testing-env/0/feature1] feature setup session',
735
- '[testing-env/0/session1] shell: "feature2" setup session',
736
- '[testing-env/0/feature2] feature setup session',
737
- '[testing-env/0] setting_up -> in_session',
738
- "[testing-env/0] session 'session1' started",
739
- '[testing-env/0] in_session -> exiting_session',
740
- '[testing-env/0/session1] shell: "feature1" teardown session',
741
- '[testing-env/0/feature1] feature teardown session',
742
- '[testing-env/0/session1] shell: "feature2" teardown session',
743
- '[testing-env/0/feature2] feature teardown session',
744
- "[testing-env/0] session 'session1' ended",
745
- '[testing-env/0] exiting_session -> acquired',
746
- '[testing-env/0] acquired -> shutting_down',
747
- '[testing-env/0] shell: "feature1" teardown',
748
- '[testing-env/0/feature1] feature teardown',
749
- '[testing-env/0/feature2] feature teardown with ValueError',
750
- '[testing-env/0] shutting_down -> offline',
751
- '[testing-env/0] sandbox shutdown with FeatureTeardownError',
752
- ]
753
- )
754
-
755
- def test_feature_teardown_state_error(self):
756
- env = self._create_env(
757
- features={
758
- 'feature1': TestingFeature(
759
- simulate_teardown_error=interface.SandboxStateError
760
- ),
761
- 'feature2': TestingFeature(
762
- ),
763
- },
764
- )
765
- with env:
766
- with env.sandbox('session1') as sb:
767
- pass
768
- self.assertEqual(len(sb.state_errors), 1)
769
- self.assertEqual(
770
- self.event_handler.logs,
771
- [
772
- '[testing-env] environment started',
773
- '[testing-env/0] shell: "feature1" setup',
774
- '[testing-env/0/feature1] feature setup',
775
- '[testing-env/0] shell: "feature2" setup',
776
- '[testing-env/0/feature2] feature setup',
777
- '[testing-env/0] created -> ready',
778
- '[testing-env/0] sandbox started',
779
- '[testing-env/0] ready -> acquired',
780
- '[testing-env/0] acquired -> setting_up',
781
- '[testing-env/0/session1] shell: "feature1" setup session',
782
- '[testing-env/0/feature1] feature setup session',
783
- '[testing-env/0/session1] shell: "feature2" setup session',
784
- '[testing-env/0/feature2] feature setup session',
785
- '[testing-env/0] setting_up -> in_session',
786
- "[testing-env/0] session 'session1' started",
787
- '[testing-env/0] in_session -> exiting_session',
788
- '[testing-env/0/session1] shell: "feature1" teardown session',
789
- '[testing-env/0/feature1] feature teardown session',
790
- '[testing-env/0/session1] shell: "feature2" teardown session',
791
- '[testing-env/0/feature2] feature teardown session',
792
- "[testing-env/0] session 'session1' ended",
793
- '[testing-env/0] exiting_session -> acquired',
794
- '[testing-env/0] acquired -> shutting_down',
795
- '[testing-env/0/feature1] feature teardown with SandboxStateError', # pylint: disable=line-too-long
796
- '[testing-env/0] shell: "feature2" teardown',
797
- '[testing-env/0/feature2] feature teardown',
798
- '[testing-env/0] shutting_down -> offline',
799
- '[testing-env/0] sandbox shutdown with FeatureTeardownError'
800
- ]
801
- )
802
-
803
- def test_feature_setup_session_non_state_error(self):
804
- env = self._create_env(
805
- features={
806
- 'feature1': TestingFeature(),
807
- 'feature2': TestingFeature(
808
- simulate_setup_session_error=ValueError
809
- ),
810
- },
811
- )
812
- with env:
813
- with self.assertRaises(ValueError):
814
- with env.sandbox('session1') as sb:
815
- sb.shell('echo "hello"')
816
- self.assertEqual(
817
- self.event_handler.logs,
818
- [
819
- '[testing-env] environment started',
820
- '[testing-env/0] shell: "feature1" setup',
821
- '[testing-env/0/feature1] feature setup',
822
- '[testing-env/0] shell: "feature2" setup',
823
- '[testing-env/0/feature2] feature setup',
824
- '[testing-env/0] created -> ready',
825
- '[testing-env/0] sandbox started',
826
- '[testing-env/0] ready -> acquired',
827
- '[testing-env/0] acquired -> setting_up',
828
- '[testing-env/0/session1] shell: "feature1" setup session',
829
- '[testing-env/0/feature1] feature setup session',
830
- '[testing-env/0/feature2] feature setup session with ValueError',
831
- "[testing-env/0] session 'session1' started with ValueError",
832
- '[testing-env/0] setting_up -> shutting_down',
833
- '[testing-env/0/session1] shell: "feature1" teardown',
834
- '[testing-env/0/feature1] feature teardown',
835
- '[testing-env/0/session1] shell: "feature2" teardown',
836
- '[testing-env/0/feature2] feature teardown',
837
- '[testing-env/0] shutting_down -> offline',
838
- '[testing-env/0] sandbox shutdown'
839
- ]
840
- )
841
-
842
- def test_feature_teardown_session_non_state_error(self):
843
- env = self._create_env(
844
- features={
845
- 'feature1': TestingFeature(
846
- simulate_teardown_session_error=ValueError
847
- ),
848
- 'feature2': TestingFeature(),
849
- },
850
- )
851
- with env:
852
- with self.assertRaises(interface.SessionTeardownError):
853
- with env.sandbox('session1') as sb:
854
- sb.shell('echo "hello"')
855
- self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
856
- self.assertEqual(
857
- self.event_handler.logs,
858
- [
859
- '[testing-env] environment started',
860
- '[testing-env/0] shell: "feature1" setup',
861
- '[testing-env/0/feature1] feature setup',
862
- '[testing-env/0] shell: "feature2" setup',
863
- '[testing-env/0/feature2] feature setup',
864
- '[testing-env/0] created -> ready',
865
- '[testing-env/0] sandbox started',
866
- '[testing-env/0] ready -> acquired',
867
- '[testing-env/0] acquired -> setting_up',
868
- '[testing-env/0/session1] shell: "feature1" setup session',
869
- '[testing-env/0/feature1] feature setup session',
870
- '[testing-env/0/session1] shell: "feature2" setup session',
871
- '[testing-env/0/feature2] feature setup session',
872
- '[testing-env/0] setting_up -> in_session',
873
- "[testing-env/0] session 'session1' started",
874
- '[testing-env/0/session1] shell: echo "hello"',
875
- '[testing-env/0] in_session -> exiting_session',
876
- '[testing-env/0/feature1] feature teardown session with ValueError', # pylint: disable=line-too-long
877
- '[testing-env/0/session1] shell: "feature2" teardown session',
878
- '[testing-env/0/feature2] feature teardown session',
879
- "[testing-env/0] session 'session1' ended",
880
- '[testing-env/0] exiting_session -> acquired',
881
- '[testing-env/0] acquired -> shutting_down',
882
- '[testing-env/0] shell: "feature1" teardown',
883
- '[testing-env/0/feature1] feature teardown',
884
- '[testing-env/0] shell: "feature2" teardown',
885
- '[testing-env/0/feature2] feature teardown',
886
- '[testing-env/0] shutting_down -> offline',
887
- '[testing-env/0] sandbox shutdown'
888
- ]
889
- )
890
-
891
- def test_feature_teardown_session_state_error(self):
892
- env = self._create_env(
893
- features={
894
- 'feature1': TestingFeature(
895
- simulate_teardown_session_error=interface.SandboxStateError
896
- ),
897
- 'feature2': TestingFeature(),
898
- },
899
- )
900
- with env:
901
- with env.sandbox('session1') as sb:
902
- sb.shell('echo "hello"')
903
- self.assertEqual(len(sb.state_errors), 1)
904
- self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
905
- self.assertEqual(
906
- self.event_handler.logs,
907
- [
908
- '[testing-env] environment started',
909
- '[testing-env/0] shell: "feature1" setup',
910
- '[testing-env/0/feature1] feature setup',
911
- '[testing-env/0] shell: "feature2" setup',
912
- '[testing-env/0/feature2] feature setup',
913
- '[testing-env/0] created -> ready',
914
- '[testing-env/0] sandbox started',
915
- '[testing-env/0] ready -> acquired',
916
- '[testing-env/0] acquired -> setting_up',
917
- '[testing-env/0/session1] shell: "feature1" setup session',
918
- '[testing-env/0/feature1] feature setup session',
919
- '[testing-env/0/session1] shell: "feature2" setup session',
920
- '[testing-env/0/feature2] feature setup session',
921
- '[testing-env/0] setting_up -> in_session',
922
- "[testing-env/0] session 'session1' started",
923
- '[testing-env/0/session1] shell: echo "hello"',
924
- '[testing-env/0] in_session -> exiting_session',
925
- '[testing-env/0/feature1] feature teardown session with SandboxStateError', # pylint: disable=line-too-long
926
- '[testing-env/0/session1] shell: "feature2" teardown session',
927
- '[testing-env/0/feature2] feature teardown session',
928
- "[testing-env/0] session 'session1' ended with SandboxStateError",
929
- '[testing-env/0] exiting_session -> acquired',
930
- '[testing-env/0] acquired -> shutting_down',
931
- '[testing-env/0] shell: "feature1" teardown',
932
- '[testing-env/0/feature1] feature teardown',
933
- '[testing-env/0] shell: "feature2" teardown',
934
- '[testing-env/0/feature2] feature teardown',
935
- '[testing-env/0] shutting_down -> offline',
936
- '[testing-env/0] sandbox shutdown'
937
- ]
938
- )
939
-
940
- def test_feature_teardown_session_calling_end_session(self):
941
- env = self._create_env(
942
- features={
943
- 'feature1': TestingFeature(
944
- call_end_session_on_teardown_session=True
945
- ),
946
- 'feature2': TestingFeature(),
947
- },
948
- )
949
- with env:
950
- with env.sandbox('session1') as sb:
951
- sb.shell('echo "hello"')
952
- self.assertEqual(
953
- self.event_handler.logs,
954
- [
955
- '[testing-env] environment started',
956
- '[testing-env/0] shell: "feature1" setup',
957
- '[testing-env/0/feature1] feature setup',
958
- '[testing-env/0] shell: "feature2" setup',
959
- '[testing-env/0/feature2] feature setup',
960
- '[testing-env/0] created -> ready',
961
- '[testing-env/0] sandbox started',
962
- '[testing-env/0] ready -> acquired',
963
- '[testing-env/0] acquired -> setting_up',
964
- '[testing-env/0/session1] shell: "feature1" setup session',
965
- '[testing-env/0/feature1] feature setup session',
966
- '[testing-env/0/session1] shell: "feature2" setup session',
967
- '[testing-env/0/feature2] feature setup session',
968
- '[testing-env/0] setting_up -> in_session',
969
- "[testing-env/0] session 'session1' started",
970
- '[testing-env/0/session1] shell: echo "hello"',
971
- '[testing-env/0] in_session -> exiting_session',
972
- '[testing-env/0/session1] shell: "feature1" teardown session',
973
- '[testing-env/0/feature1] feature teardown session',
974
- '[testing-env/0/session1] shell: "feature2" teardown session',
975
- '[testing-env/0/feature2] feature teardown session',
976
- "[testing-env/0] session 'session1' ended",
977
- '[testing-env/0] exiting_session -> acquired',
978
- '[testing-env/0] acquired -> shutting_down',
979
- '[testing-env/0] shell: "feature1" teardown',
980
- '[testing-env/0/feature1] feature teardown',
981
- '[testing-env/0] shell: "feature2" teardown',
982
- '[testing-env/0/feature2] feature teardown',
983
- '[testing-env/0] shutting_down -> offline',
984
- '[testing-env/0] sandbox shutdown'
985
- ]
986
- )
987
-
988
- def test_session_activity_non_state_error(self):
989
- env = self._create_env(
990
- pool_size=1,
991
- features={
992
- 'feature1': TestingFeature(),
993
- },
994
- )
995
- with env:
996
- with env.sandbox('session1') as sb:
997
- with self.assertRaises(ValueError):
998
- sb.shell('echo foo', raise_error=ValueError)
999
- self.assertEqual(len(sb.state_errors), 0)
1000
- sb.shell('echo bar')
1001
- self.assertEqual(sb.status, interface.Sandbox.Status.IN_SESSION)
1002
- sb.wait_until_not(interface.Sandbox.Status.SETTING_UP)
1003
- self.assertEqual(sb.status, interface.Sandbox.Status.READY)
1004
- self.assertEqual(
1005
- self.event_handler.logs,
1006
- [
1007
- '[testing-env/0:0] shell: "feature1" setup',
1008
- '[testing-env/0:0/feature1] feature setup',
1009
- '[testing-env/0:0] shell: "feature1" setup session',
1010
- '[testing-env/0:0/feature1] feature setup session',
1011
- '[testing-env/0:0] created -> ready',
1012
- '[testing-env/0:0] sandbox started',
1013
- '[testing-env] environment started',
1014
- '[testing-env/0:0] ready -> acquired',
1015
- '[testing-env/0:0] acquired -> setting_up',
1016
- '[testing-env/0:0] setting_up -> in_session',
1017
- "[testing-env/0:0] session 'session1' started",
1018
- '[testing-env/0:0/session1] shell: echo foo with ValueError',
1019
- '[testing-env/0:0/session1] shell: echo bar',
1020
- '[testing-env/0:0] in_session -> exiting_session',
1021
- '[testing-env/0:0/session1] shell: "feature1" teardown session',
1022
- '[testing-env/0:0/feature1] feature teardown session',
1023
- "[testing-env/0:0] session 'session1' ended",
1024
- '[testing-env/0:0] exiting_session -> setting_up',
1025
- '[testing-env/0:0] shell: "feature1" setup session',
1026
- '[testing-env/0:0/feature1] feature setup session',
1027
- '[testing-env/0:0] setting_up -> ready',
1028
- ]
1029
- )
1030
-
1031
- def test_session_activity_state_error(self):
1032
- env = self._create_env(
1033
- pool_size=1,
1034
- features={
1035
- 'feature1': TestingFeature(),
1036
- },
1037
- )
1038
- with env:
1039
- with env.sandbox('session1') as sb:
1040
- with self.assertRaises(interface.SandboxStateError):
1041
- sb.shell('echo foo', raise_error=RuntimeError)
1042
- self.assertEqual(len(sb.state_errors), 1)
1043
- self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
1044
- sb.shell('echo bar')
1045
- self.assertEqual(
1046
- self.event_handler.logs,
1047
- [
1048
- # pylint: disable=line-too-long
1049
- '[testing-env/0:0] shell: "feature1" setup',
1050
- '[testing-env/0:0/feature1] feature setup',
1051
- '[testing-env/0:0] shell: "feature1" setup session',
1052
- '[testing-env/0:0/feature1] feature setup session',
1053
- '[testing-env/0:0] created -> ready',
1054
- '[testing-env/0:0] sandbox started',
1055
- '[testing-env] environment started',
1056
- '[testing-env/0:0] ready -> acquired',
1057
- '[testing-env/0:0] acquired -> setting_up',
1058
- '[testing-env/0:0] setting_up -> in_session',
1059
- "[testing-env/0:0] session 'session1' started",
1060
- '[testing-env/0:0/session1] shell: echo foo with RuntimeError',
1061
- '[testing-env/0:0] in_session -> exiting_session',
1062
- '[testing-env/0:0/session1] shell: "feature1" teardown session',
1063
- '[testing-env/0:0/feature1] feature teardown session',
1064
- "[testing-env/0:0] session 'session1' ended with SandboxStateError",
1065
- '[testing-env/0:0] exiting_session -> acquired',
1066
- '[testing-env/0:0] acquired -> shutting_down',
1067
- '[testing-env/0:0] shell: "feature1" teardown',
1068
- '[testing-env/0:0/feature1] feature teardown',
1069
- '[testing-env/0:0] shutting_down -> offline',
1070
- '[testing-env/0:0] sandbox shutdown',
1071
- '[testing-env/0:0] shell: echo bar',
1072
- # pylint: enable=line-too-long
1073
- ]
1074
- )
1075
-
1076
-
1077
- class SandboxActivityTests(unittest.TestCase):
1078
-
1079
- def test_session_id(self):
1080
- env = TestingEnvironment(
1081
- features={'test_feature': TestingFeature()},
1082
- pool_size=0
1083
- )
1084
- with env:
1085
- with env.sandbox() as sb:
1086
- self.assertRegex(sb.session_id, r'session-[0-9a-f]{7}')
1087
-
1088
- self.assertEqual(
1089
- env.test_feature.show_session_id(session_id='session1'),
1090
- 'session1'
1091
- )
1092
- self.assertRegex(
1093
- env.test_feature.show_session_id(),
1094
- r'session-[0-9a-f]{7}'
1095
- )
1096
-
1097
- with self.assertRaisesRegex(ValueError, '`session_id` should not be used'):
1098
- @base_sandbox.sandbox_service()
1099
- def foo(session_id: str):
1100
- del session_id
1101
-
1102
- def test_ping_error(self):
1103
- env = TestingEnvironment(
1104
- features={'test_feature': TestingFeature(housekeep_interval=0)},
1105
- pool_size=1,
1106
- sandbox_keepalive_interval=0,
1107
- )
1108
- with env:
1109
- with env.sandbox('session1') as sb:
1110
- sb.rebind(
1111
- simulate_ping_error=interface.SandboxStateError,
1112
- skip_notification=True
1113
- )
1114
- sb.wait_until_next_housekeep()
1115
- self.assertEqual(sb.status, sb.Status.OFFLINE)
1116
-
1117
- def test_housekeep_error(self):
1118
- event_handler = TestingEventHandler(log_housekeep=False)
1119
- env = TestingEnvironment(
1120
- features={'test_feature': TestingFeature(housekeep_interval=0)},
1121
- pool_size=1,
1122
- housekeep_interval=1.0,
1123
- outage_grace_period=0,
1124
- outage_retry_interval=0.1,
1125
- sandbox_keepalive_interval=0,
1126
- event_handlers=[event_handler],
1127
- )
1128
- with env:
1129
- with env.sandbox('session1') as sb:
1130
- self.assertEqual(len(env.sandbox_pool), 1)
1131
- self.assertEqual(sb.status, interface.Sandbox.Status.IN_SESSION)
1132
- self.assertEqual(sb.session_id, 'session1')
1133
- housekeep_count = sb.housekeep_counter
1134
- sb.test_feature.rebind(
1135
- simulate_housekeep_error=interface.SandboxStateError,
1136
- skip_notification=True
1137
- )
1138
- while sb.housekeep_counter == housekeep_count or (
1139
- sb.status == interface.Sandbox.Status.IN_SESSION
1140
- ):
1141
- time.sleep(0.01)
1142
- self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
1143
- env.wait_for_housekeeping()
1144
- self.assertEqual(
1145
- event_handler.logs,
1146
- [
1147
- '[testing-env/0:0] shell: "test_feature" setup',
1148
- '[testing-env/0:0/test_feature] feature setup',
1149
- '[testing-env/0:0] shell: "test_feature" setup session',
1150
- '[testing-env/0:0] sandbox started',
1151
- '[testing-env] environment started',
1152
- "[testing-env/0:0] session 'session1' started",
1153
- '[testing-env/0:0/session1] shell: "test_feature" teardown session',
1154
- "[testing-env/0:0] session 'session1' ended with SandboxStateError",
1155
- '[testing-env/0:0] shell: "test_feature" teardown',
1156
- '[testing-env/0:0/test_feature] feature teardown',
1157
- '[testing-env/0:0] sandbox shutdown',
1158
- '[testing-env/0:1] shell: "test_feature" setup',
1159
- '[testing-env/0:1/test_feature] feature setup',
1160
- '[testing-env/0:1] shell: "test_feature" setup session',
1161
- '[testing-env/0:1] sandbox started',
1162
- '[testing-env/0:1] shell: "test_feature" teardown',
1163
- '[testing-env/0:1/test_feature] feature teardown',
1164
- '[testing-env/0:1] sandbox shutdown',
1165
- '[testing-env] environment shutdown'
1166
- ]
1167
- )
1168
-
1169
- def test_remove_event_handler(self):
1170
- env = TestingEnvironment(
1171
- features={'test_feature': TestingFeature(housekeep_interval=0)},
1172
- pool_size=1,
1173
- outage_grace_period=0,
1174
- outage_retry_interval=0,
1175
- sandbox_keepalive_interval=0,
1176
- )
1177
- event_handler = TestingEventHandler()
1178
- with env:
1179
- with env.sandbox('session1') as sb:
1180
- sb.add_event_handler(event_handler)
1181
- sb.shell('test_feature')
1182
- sb.remove_event_handler(event_handler)
1183
- events = list(event_handler.logs)
1184
- sb.wait_until_not(interface.Sandbox.Status.SETTING_UP)
1185
- self.assertGreater(len(events), 0)
1186
- with env.sandbox('session2') as sb:
1187
- sb.shell('test_feature')
1188
- self.assertEqual(len(events), len(event_handler.logs))
1189
-
1190
-
1191
- class SandboxServiceTests(unittest.TestCase):
1192
-
1193
- def setUp(self):
1194
- super().setUp()
1195
- self.maxDiff = None
1196
- self.event_handler = TestingEventHandler()
1197
- self.env = TestingEnvironment(
1198
- features={'test_feature': TestingFeature()},
1199
- pool_size=0,
1200
- outage_grace_period=0,
1201
- outage_retry_interval=0,
1202
- sandbox_keepalive_interval=0,
1203
- event_handlers=[self.event_handler],
1204
- random_seed=1,
1205
- )
1206
-
1207
- def test_service_call_activity_log(self):
1208
-
1209
- class CustomEventHandler(event_handler_base.EventHandler):
1210
-
1211
- def __init__(self):
1212
- self.calls = []
1213
-
1214
- def on_sandbox_activity(
1215
- self,
1216
- name: str,
1217
- environment: interface.Environment,
1218
- sandbox: interface.Sandbox,
1219
- feature: interface.Feature | None,
1220
- session_id: str | None,
1221
- duration: float,
1222
- error: BaseException | None,
1223
- **kwargs: Any):
1224
- self.calls.append((session_id, name, kwargs))
1225
-
1226
- event_handler = CustomEventHandler()
1227
- env = TestingEnvironment(
1228
- features={'test_feature': TestingFeature()},
1229
- pool_size=0,
1230
- event_handlers=[event_handler],
1231
- )
1232
- with env:
1233
- env.test_feature.call_with_varargs(
1234
- 'sum', 1, 2, debug=True, session_id='session1'
1235
- )
1236
- self.assertEqual(
1237
- event_handler.calls,
1238
- [
1239
- (None, 'shell', {'code': '"test_feature" setup'}),
1240
- ('session1', 'shell', {'code': '"test_feature" setup session'}),
1241
- ('session1', 'test_feature.call_with_varargs', {'args': (1, 2), 'code': 'sum', 'debug': True}), # pylint: disable=line-too-long
1242
- ('session1', 'shell', {'code': '"test_feature" teardown session'}),
1243
- (None, 'shell', {'code': '"test_feature" teardown'}),
1244
- ]
1245
- )
1246
-
1247
- def test_service_call_from_feature(self):
1248
- with self.env:
1249
- with self.env.sandbox('session1') as sb:
1250
- self.assertEqual(sb.test_feature.num_shell_calls(), 2)
1251
- self.assertEqual(sb.test_feature.num_shell_calls(), 2)
1252
- self.assertEqual(
1253
- self.event_handler.logs,
1254
- [
1255
- # pylint: disable=line-too-long
1256
- '[testing-env] environment started',
1257
- '[testing-env/0] shell: "test_feature" setup',
1258
- '[testing-env/0/test_feature] feature setup',
1259
- '[testing-env/0] sandbox started',
1260
- '[testing-env/0/session1] shell: "test_feature" setup session',
1261
- "[testing-env/0] session 'session1' started",
1262
- '[testing-env/0/session1/test_feature] test_feature.num_shell_calls: None',
1263
- '[testing-env/0/session1/test_feature] test_feature.num_shell_calls: None',
1264
- '[testing-env/0/session1] shell: "test_feature" teardown session',
1265
- "[testing-env/0] session 'session1' ended",
1266
- '[testing-env/0] shell: "test_feature" teardown',
1267
- '[testing-env/0/test_feature] feature teardown',
1268
- '[testing-env/0] sandbox shutdown',
1269
- '[testing-env] environment shutdown'
1270
- # pylint: enable=line-too-long
1271
- ]
1272
- )
1273
-
1274
- def test_service_call_from_feature_with_error(self):
1275
- with self.env:
1276
- with self.env.sandbox('session1') as sb:
1277
- with self.assertRaises(interface.SandboxStateError):
1278
- sb.test_feature.bad_shell_call()
1279
- self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
1280
-
1281
- self.assertEqual(
1282
- self.event_handler.logs,
1283
- [
1284
- # pylint: disable=line-too-long
1285
- '[testing-env] environment started',
1286
- '[testing-env/0] shell: "test_feature" setup',
1287
- '[testing-env/0/test_feature] feature setup',
1288
- '[testing-env/0] sandbox started',
1289
- '[testing-env/0/session1] shell: "test_feature" setup session',
1290
- "[testing-env/0] session 'session1' started",
1291
- '[testing-env/0/session1] shell: bad command with RuntimeError',
1292
- '[testing-env/0/session1/test_feature] test_feature.bad_shell_call: None with SandboxStateError',
1293
- '[testing-env/0/session1] shell: "test_feature" teardown session',
1294
- "[testing-env/0] session 'session1' ended with SandboxStateError",
1295
- '[testing-env/0] shell: "test_feature" teardown',
1296
- '[testing-env/0/test_feature] feature teardown',
1297
- '[testing-env/0] sandbox shutdown',
1298
- '[testing-env] environment shutdown'
1299
- # pylint: enable=line-too-long
1300
- ]
1301
- )
1302
-
1303
- def test_service_call_from_environment(self):
1304
- with self.env:
1305
- self.assertEqual(self.env.test_feature.num_shell_calls(), 2)
1306
- self.assertEqual(
1307
- self.event_handler.logs,
1308
- [
1309
- # pylint: disable=line-too-long
1310
- '[testing-env] environment started',
1311
- '[testing-env/0] shell: "test_feature" setup',
1312
- '[testing-env/0/test_feature] feature setup',
1313
- '[testing-env/0] sandbox started',
1314
- '[testing-env/0/session-2291d8c] shell: "test_feature" setup session',
1315
- "[testing-env/0] session 'session-2291d8c' started",
1316
- '[testing-env/0/session-2291d8c/test_feature] test_feature.num_shell_calls: None',
1317
- '[testing-env/0/session-2291d8c] shell: "test_feature" teardown session',
1318
- "[testing-env/0] session 'session-2291d8c' ended",
1319
- '[testing-env/0] shell: "test_feature" teardown',
1320
- '[testing-env/0/test_feature] feature teardown',
1321
- '[testing-env/0] sandbox shutdown',
1322
- '[testing-env] environment shutdown'
1323
- # pylint: enable=line-too-long
1324
- ]
1325
- )
1326
-
1327
- def test_service_call_from_environment_with_error(self):
1328
- with self.env:
1329
- with self.assertRaises(interface.SandboxStateError):
1330
- self.env.test_feature.bad_shell_call(session_id='session1')
1331
- self.assertEqual(
1332
- self.event_handler.logs,
1333
- [
1334
- # pylint: disable=line-too-long
1335
- '[testing-env] environment started',
1336
- '[testing-env/0] shell: "test_feature" setup',
1337
- '[testing-env/0/test_feature] feature setup',
1338
- '[testing-env/0] sandbox started',
1339
- '[testing-env/0/session1] shell: "test_feature" setup session',
1340
- "[testing-env/0] session 'session1' started",
1341
- '[testing-env/0/session1] shell: bad command with RuntimeError',
1342
- '[testing-env/0/session1/test_feature] test_feature.bad_shell_call: None with SandboxStateError',
1343
- '[testing-env/0/session1] shell: "test_feature" teardown session',
1344
- "[testing-env/0] session 'session1' ended with SandboxStateError",
1345
- '[testing-env/0] shell: "test_feature" teardown',
1346
- '[testing-env/0/test_feature] feature teardown',
1347
- '[testing-env/0] sandbox shutdown',
1348
- '[testing-env] environment shutdown'
1349
- # pylint: enable=line-too-long
1350
- ]
1351
- )
1352
-
1353
- def test_service_context_manager_from_feature(self):
1354
- with self.env:
1355
- with self.env.sandbox('session1') as sb:
1356
- with sb.test_feature.my_service() as service:
1357
- service.do('hello')
1358
- sb.shell('foo')
1359
- self.assertEqual(sb.status, interface.Sandbox.Status.IN_SESSION)
1360
- self.assertEqual(
1361
- self.event_handler.logs,
1362
- [
1363
- # pylint: disable=line-too-long
1364
- '[testing-env] environment started',
1365
- '[testing-env/0] shell: "test_feature" setup',
1366
- '[testing-env/0/test_feature] feature setup',
1367
- '[testing-env/0] sandbox started',
1368
- '[testing-env/0/session1] shell: "test_feature" setup session',
1369
- "[testing-env/0] session 'session1' started",
1370
- '[testing-env/0/session1] shell: hello',
1371
- '[testing-env/0/session1/test_feature] test_feature.my_service: None',
1372
- '[testing-env/0/session1] shell: foo',
1373
- '[testing-env/0/session1] shell: "test_feature" teardown session',
1374
- "[testing-env/0] session 'session1' ended",
1375
- '[testing-env/0] shell: "test_feature" teardown',
1376
- '[testing-env/0/test_feature] feature teardown',
1377
- '[testing-env/0] sandbox shutdown',
1378
- '[testing-env] environment shutdown'
1379
- # pylint: enable=line-too-long
1380
- ]
1381
- )
1382
-
1383
- def test_service_context_manager_from_feature_with_error(self):
1384
- with self.env:
1385
- with self.env.sandbox('session1') as sb:
1386
- with self.assertRaises(interface.SandboxStateError):
1387
- with sb.test_feature.my_service() as service:
1388
- service.do('hello', raise_error=interface.SandboxStateError)
1389
- self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
1390
- self.assertEqual(
1391
- self.event_handler.logs,
1392
- [
1393
- # pylint: disable=line-too-long
1394
- '[testing-env] environment started',
1395
- '[testing-env/0] shell: "test_feature" setup',
1396
- '[testing-env/0/test_feature] feature setup',
1397
- '[testing-env/0] sandbox started',
1398
- '[testing-env/0/session1] shell: "test_feature" setup session',
1399
- "[testing-env/0] session 'session1' started",
1400
- '[testing-env/0/session1] shell: hello with SandboxStateError',
1401
- '[testing-env/0/session1/test_feature] test_feature.my_service: None with SandboxStateError',
1402
- '[testing-env/0/session1] shell: "test_feature" teardown session',
1403
- "[testing-env/0] session 'session1' ended with SandboxStateError",
1404
- '[testing-env/0] shell: "test_feature" teardown',
1405
- '[testing-env/0/test_feature] feature teardown',
1406
- '[testing-env/0] sandbox shutdown',
1407
- '[testing-env] environment shutdown'
1408
- # pylint: enable=line-too-long
1409
- ]
1410
- )
1411
-
1412
- def test_service_context_manager_from_environment(self):
1413
- with self.env:
1414
- with self.env.test_feature.my_service(session_id='session1') as service:
1415
- service.do('foo')
1416
- with self.env.test_feature.my_service() as service:
1417
- service.do('bar')
1418
- self.assertEqual(
1419
- self.event_handler.logs,
1420
- [
1421
- # pylint: disable=line-too-long
1422
- '[testing-env] environment started',
1423
- '[testing-env/0] shell: "test_feature" setup',
1424
- '[testing-env/0/test_feature] feature setup',
1425
- '[testing-env/0] sandbox started',
1426
- '[testing-env/0/session1] shell: "test_feature" setup session',
1427
- "[testing-env/0] session 'session1' started",
1428
- '[testing-env/0/session1] shell: foo',
1429
- '[testing-env/0/session1/test_feature] test_feature.my_service: None',
1430
- '[testing-env/0/session1] shell: "test_feature" teardown session',
1431
- "[testing-env/0] session 'session1' ended",
1432
- '[testing-env/0] shell: "test_feature" teardown',
1433
- '[testing-env/0/test_feature] feature teardown',
1434
- '[testing-env/0] sandbox shutdown',
1435
- '[testing-env/1] shell: "test_feature" setup',
1436
- '[testing-env/1/test_feature] feature setup',
1437
- '[testing-env/1] sandbox started',
1438
- '[testing-env/1/session-2291d8c] shell: "test_feature" setup session',
1439
- "[testing-env/1] session 'session-2291d8c' started",
1440
- '[testing-env/1/session-2291d8c] shell: bar',
1441
- '[testing-env/1/session-2291d8c/test_feature] test_feature.my_service: None',
1442
- '[testing-env/1/session-2291d8c] shell: "test_feature" teardown session',
1443
- "[testing-env/1] session 'session-2291d8c' ended",
1444
- '[testing-env/1] shell: "test_feature" teardown',
1445
- '[testing-env/1/test_feature] feature teardown',
1446
- '[testing-env/1] sandbox shutdown',
1447
- '[testing-env] environment shutdown'
1448
- # pylint: enable=line-too-long
1449
- ]
1450
- )
1451
-
1452
- def test_service_context_manager_from_environment_with_error(self):
1453
- with self.env:
1454
- with self.assertRaises(interface.SandboxStateError):
1455
- with self.env.test_feature.my_service() as service:
1456
- service.do('hello', raise_error=interface.SandboxStateError)
1457
- self.assertEqual(
1458
- self.event_handler.logs,
1459
- [
1460
- # pylint: disable=line-too-long
1461
- '[testing-env] environment started',
1462
- '[testing-env/0] shell: "test_feature" setup',
1463
- '[testing-env/0/test_feature] feature setup',
1464
- '[testing-env/0] sandbox started',
1465
- '[testing-env/0/session-2291d8c] shell: "test_feature" setup session',
1466
- "[testing-env/0] session 'session-2291d8c' started",
1467
- '[testing-env/0/session-2291d8c] shell: hello with SandboxStateError',
1468
- '[testing-env/0/session-2291d8c/test_feature] test_feature.my_service: None with SandboxStateError',
1469
- '[testing-env/0/session-2291d8c] shell: "test_feature" teardown session',
1470
- "[testing-env/0] session 'session-2291d8c' ended with SandboxStateError",
1471
- '[testing-env/0] shell: "test_feature" teardown',
1472
- '[testing-env/0/test_feature] feature teardown',
1473
- '[testing-env/0] sandbox shutdown',
1474
- '[testing-env] environment shutdown'
1475
- # pylint: enable=line-too-long
1476
- ]
1477
- )
1478
-
1479
-
1480
- if __name__ == '__main__':
1481
- unittest.main()