langfun 0.1.2.dev202509240805__py3-none-any.whl → 0.1.2.dev202509250804__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.

langfun/env/base_test.py CHANGED
@@ -11,384 +11,19 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- import contextlib
15
14
  import time
16
- from typing import Any, Iterator, Type
15
+ from typing import Any
17
16
  import unittest
18
17
 
19
- from langfun.env import base_environment
20
- from langfun.env import base_feature
21
18
  from langfun.env import base_sandbox
22
19
  from langfun.env import interface
23
- import pyglove as pg
20
+ from langfun.env import test_utils
24
21
 
25
22
 
26
- class TestingEnvironment(base_environment.BaseEnvironment):
27
-
28
- simulate_start_error: Type[BaseException] | None = None
29
- simulate_shutdown_error: Type[BaseException] | None = None
30
- simulate_ping_error: Type[BaseException] | None = None
31
- keepalive_interval: float | None = 60.0
32
- offline: bool = False
33
-
34
- @property
35
- def id(self) -> interface.EnvironmentId:
36
- return interface.EnvironmentId('testing-env')
37
-
38
- def wait_for_next_maintenance(self):
39
- maintenance_count = self._maintenance_count
40
- while self._maintenance_count == maintenance_count:
41
- time.sleep(0.1)
42
-
43
- def _create_sandbox(
44
- self,
45
- sandbox_id: str,
46
- reusable: bool,
47
- proactive_session_setup: bool,
48
- ) -> interface.Sandbox:
49
- if self.offline:
50
- raise interface.EnvironmentError(
51
- 'Unknown environment error.',
52
- environment=self,
53
- )
54
- return TestingSandbox(
55
- environment=self,
56
- id=interface.SandboxId(
57
- environment_id=self.id,
58
- sandbox_id=sandbox_id
59
- ),
60
- reusable=reusable,
61
- proactive_session_setup=proactive_session_setup,
62
- simulate_start_error=self.simulate_start_error,
63
- simulate_shutdown_error=self.simulate_shutdown_error,
64
- simulate_ping_error=self.simulate_ping_error,
65
- keepalive_interval=self.keepalive_interval,
66
- )
67
-
68
-
69
- class TestingSandbox(base_sandbox.BaseSandbox):
70
-
71
- simulate_start_error: Type[BaseException] | None = None
72
- simulate_shutdown_error: Type[BaseException] | None = None
73
- simulate_ping_error: Type[BaseException] | None = None
74
-
75
- def _on_bound(self) -> None:
76
- super()._on_bound()
77
- self._shell_history = []
78
- self._ping_history = []
79
-
80
- def _raise_error(self, message, error_type: Type[BaseException], **kwargs):
81
- if (error_type is interface.SandboxStateError or
82
- issubclass(error_type, interface.SandboxStateError)):
83
- kwargs['sandbox'] = self
84
- raise error_type(message, **kwargs)
85
- else:
86
- raise error_type(message)
87
-
88
- def wait_until(
89
- self,
90
- status: interface.Sandbox.Status | tuple[interface.Sandbox.Status, ...]
91
- ) -> None:
92
- if not isinstance(status, tuple):
93
- status = (status,)
94
- while self.status not in status:
95
- time.sleep(0.1)
96
-
97
- def wait_until_not(
98
- self,
99
- status: interface.Sandbox.Status | tuple[interface.Sandbox.Status, ...]
100
- ) -> None:
101
- if not isinstance(status, tuple):
102
- status = (status,)
103
- while self.status in status:
104
- time.sleep(0.1)
105
-
106
- def wait_until_next_housekeep(self) -> None:
107
- housekeep_count = self._housekeep_count
108
- while self._housekeep_count == housekeep_count:
109
- time.sleep(0.1)
110
-
111
- def _start(self) -> None:
112
- if self.simulate_start_error:
113
- self._raise_error('Sandbox start error', self.simulate_start_error)
114
- super()._start()
115
-
116
- def _shutdown(self) -> None:
117
- if self.simulate_shutdown_error:
118
- self._raise_error('Sandbox shutdown error', self.simulate_shutdown_error)
119
- super()._shutdown()
120
-
121
- @base_sandbox.sandbox_service(critical_errors=(RuntimeError,))
122
- def shell(
123
- self,
124
- code: str,
125
- raise_error: Type[BaseException] | None = None,
126
- ) -> str:
127
- self._shell_history.append(code)
128
- if raise_error is not None:
129
- self._raise_error(f'shell "{code}" failed', raise_error)
130
- return f'shell "{code}" succeeded'
131
-
132
- def _ping(self) -> None:
133
- self._ping_history.append(not self.simulate_ping_error)
134
- if self.simulate_ping_error:
135
- self._raise_error('Ping error', self.simulate_ping_error, code='ping')
136
-
137
-
138
- class TestingFeature(base_feature.BaseFeature):
139
- housekeep_interval = 0
140
- setup_session_delay: float = 0.0
141
- simulate_housekeep_error: Type[BaseException] | None = None
142
- simulate_setup_error: Type[BaseException] | None = None
143
- simulate_teardown_error: Type[BaseException] | None = None
144
- simulate_setup_session_error: Type[BaseException] | None = None
145
- simulate_teardown_session_error: Type[BaseException] | None = None
146
-
147
- class Service:
148
- """Sandbox."""
149
-
150
- def __init__(self, sandbox: interface.Sandbox):
151
- self._sandbox = sandbox
152
-
153
- def do(self, code: str, raise_error: Type[BaseException] | None = None):
154
- self._sandbox.shell(code, raise_error=raise_error)
155
-
156
- def _raise_error(self, message, error_type: Type[BaseException], **kwargs):
157
- self._sandbox._raise_error(message, error_type, **kwargs)
158
-
159
- def _setup(self) -> None:
160
- if self.simulate_setup_error:
161
- self._raise_error(f'{self.name} setup error', self.simulate_setup_error)
162
- self.sandbox.shell(f'"{self.name}" setup')
163
-
164
- def _teardown(self) -> None:
165
- if self.simulate_teardown_error:
166
- self._raise_error(
167
- f'{self.name} teardown error', self.simulate_teardown_error
168
- )
169
- self.sandbox.shell(f'"{self.name}" teardown')
170
-
171
- def _setup_session(self) -> None:
172
- if self.setup_session_delay > 0:
173
- time.sleep(self.setup_session_delay)
174
-
175
- if self.simulate_setup_session_error:
176
- self._raise_error(
177
- 'Feature session setup error', self.simulate_setup_session_error
178
- )
179
- self.sandbox.shell(f'"{self.name}" setup session')
180
-
181
- def _teardown_session(self) -> None:
182
- if self.simulate_teardown_session_error:
183
- self._raise_error(
184
- 'Feature session teardown error', self.simulate_teardown_session_error
185
- )
186
- self.sandbox.shell(f'"{self.name}" teardown session')
187
-
188
- @base_sandbox.sandbox_service()
189
- def num_shell_calls(self) -> None:
190
- return len(self.sandbox._shell_history)
191
-
192
- @base_sandbox.sandbox_service()
193
- def bad_shell_call(self) -> None:
194
- self.sandbox.shell('bad command', raise_error=RuntimeError)
195
-
196
- @base_sandbox.sandbox_service()
197
- def show_session_id(self):
198
- return self.session_id
199
-
200
- @base_sandbox.sandbox_service()
201
- def call_with_varargs(self, code: str, *args, **kwargs):
202
- del code, args, kwargs
203
- return 0
204
-
205
- def _on_bound(self) -> None:
206
- super()._on_bound()
207
- self._service = None
208
-
209
- @base_sandbox.sandbox_service()
210
- @contextlib.contextmanager
211
- def my_service(self) -> Iterator[Service]:
212
- try:
213
- self._service = TestingFeature.Service(sandbox=self.sandbox)
214
- yield self._service
215
- finally:
216
- self._service = None
217
-
218
- def _housekeep(self) -> None:
219
- if self.simulate_housekeep_error:
220
- raise interface.SandboxStateError(
221
- 'House keeping error', sandbox=self.sandbox
222
- )
223
-
224
-
225
- class TestingEnvironmentEventHandler(
226
- pg.Object, interface.EnvironmentEventHandler
227
- ):
228
- log_sandbox_status: bool = False
229
- log_feature_setup: bool = True
230
- log_session_setup: bool = False
231
-
232
- def _on_bound(self) -> None:
233
- super()._on_bound()
234
- self._logs = []
235
-
236
- @property
237
- def logs(self) -> list[str]:
238
- return self._logs
239
-
240
- def _add_message(self, message: str, error: Exception | None) -> None:
241
- """Adds a message to the history."""
242
- if error is None:
243
- self._logs.append(message)
244
- else:
245
- self._logs.append(f'{message} with {error.__class__.__name__}')
246
-
247
- def on_environment_start(
248
- self,
249
- environment: interface.Environment,
250
- error: Exception | None
251
- ) -> None:
252
- """Called when the environment is started."""
253
- self._add_message(f'[{environment.id}] environment started', error)
254
-
255
- def on_environment_shutdown(
256
- self,
257
- environment: interface.Environment,
258
- error: Exception | None
259
- ) -> None:
260
- """Called when the environment is shutdown."""
261
- self._add_message(f'[{environment.id}] environment shutdown', error)
262
-
263
- def on_sandbox_start(
264
- self,
265
- environment: interface.Environment,
266
- sandbox: interface.Sandbox,
267
- error: Exception | None
268
- ) -> None:
269
- del environment
270
- self._add_message(f'[{sandbox.id}] sandbox started', error)
271
-
272
- def on_sandbox_status_change(
273
- self,
274
- environment: interface.Environment,
275
- sandbox: interface.Sandbox,
276
- old_status: interface.Sandbox.Status,
277
- new_status: interface.Sandbox.Status,
278
- ) -> None:
279
- if self.log_sandbox_status:
280
- self._add_message(
281
- f'[{sandbox.id}] {old_status.value} -> {new_status.value}',
282
- None,
283
- )
284
-
285
- def on_sandbox_shutdown(
286
- self,
287
- environment: interface.Environment,
288
- sandbox: interface.Sandbox,
289
- error: Exception | None
290
- ) -> None:
291
- self._add_message(f'[{sandbox.id}] sandbox shutdown', error)
292
-
293
- def on_feature_setup(
294
- self,
295
- environment: interface.Environment,
296
- sandbox: interface.Sandbox,
297
- feature: interface.Feature,
298
- error: Exception | None
299
- ) -> None:
300
- """Called when a sandbox feature is setup."""
301
- if self.log_feature_setup:
302
- self._add_message(
303
- f'[{sandbox.id}/{feature.name}] feature setup', error
304
- )
305
-
306
- def on_feature_teardown(
307
- self,
308
- environment: interface.Environment,
309
- sandbox: interface.Sandbox,
310
- feature: interface.Feature,
311
- error: Exception | None
312
- ) -> None:
313
- """Called when a sandbox feature is teardown."""
314
- if self.log_feature_setup:
315
- self._add_message(
316
- f'[{sandbox.id}/{feature.name}] feature teardown', error
317
- )
318
-
319
- def on_feature_setup_session(
320
- self,
321
- environment: interface.Environment,
322
- sandbox: interface.Sandbox,
323
- feature: interface.Feature,
324
- session_id: str | None,
325
- error: Exception | None
326
- ) -> None:
327
- """Called when a sandbox feature is setup."""
328
- if self.log_session_setup:
329
- self._add_message(
330
- f'[{sandbox.id}/{feature.name}] feature setup session', error
331
- )
332
-
333
- def on_feature_teardown_session(
334
- self,
335
- environment: interface.Environment,
336
- sandbox: interface.Sandbox,
337
- feature: interface.Feature,
338
- session_id: str,
339
- error: Exception | None
340
- ) -> None:
341
- """Called when a sandbox feature is teardown."""
342
- if self.log_session_setup:
343
- self._add_message(
344
- f'[{sandbox.id}/{feature.name}] feature teardown session', error
345
- )
346
-
347
- def on_session_start(
348
- self,
349
- environment: interface.Environment,
350
- sandbox: interface.Sandbox,
351
- session_id: str,
352
- error: Exception | None
353
- ) -> None:
354
- """Called when a sandbox session starts."""
355
- self._add_message(
356
- f'[{sandbox.id}] session {session_id!r} started', error
357
- )
358
-
359
- def on_session_end(
360
- self,
361
- environment: interface.Environment,
362
- sandbox: interface.Sandbox,
363
- session_id: str,
364
- error: Exception | None
365
- ) -> None:
366
- """Called when a sandbox session ends."""
367
- self._add_message(
368
- f'[{sandbox.id}] session {session_id!r} ended', error
369
- )
370
-
371
- def on_session_activity(
372
- self,
373
- session_id: str,
374
- name: str,
375
- environment: interface.Environment,
376
- sandbox: interface.Sandbox,
377
- feature: interface.Feature | None,
378
- error: Exception | None,
379
- *,
380
- code: str | None = None,
381
- **kwargs
382
- ) -> None:
383
- """Called when a sandbox activity is performed."""
384
- del environment, kwargs
385
- self._add_message(
386
- f'[{sandbox.id}/{session_id}] {name}: {code}', error
387
- )
388
-
389
- #
390
- # Tests
391
- #
23
+ TestingEnvironment = test_utils.TestingEnvironment
24
+ TestingSandbox = test_utils.TestingSandbox
25
+ TestingFeature = test_utils.TestingFeature
26
+ TestingEnvironmentEventHandler = test_utils.TestingEnvironmentEventHandler
392
27
 
393
28
 
394
29
  class EnvironmentTests(unittest.TestCase):
@@ -573,7 +208,7 @@ class EnvironmentTests(unittest.TestCase):
573
208
  with self.assertRaises(interface.SandboxStateError):
574
209
  sb.shell('bad command', raise_error=interface.SandboxStateError)
575
210
  self.assertEqual(sb.status, interface.Sandbox.Status.OFFLINE)
576
- env.wait_for_next_maintenance()
211
+ env.wait_for_housekeeping()
577
212
  self.assertFalse(env.is_online)
578
213
 
579
214
 
@@ -618,7 +253,9 @@ class SandboxStatusTests(unittest.TestCase):
618
253
  self.event_handler.logs,
619
254
  [
620
255
  '[testing-env] environment started',
256
+ '[testing-env/0] shell: "feature1" setup',
621
257
  '[testing-env/0/feature1] feature setup',
258
+ '[testing-env/0] shell: "feature2" setup',
622
259
  '[testing-env/0/feature2] feature setup',
623
260
  '[testing-env/0] created -> ready',
624
261
  '[testing-env/0] sandbox started',
@@ -631,14 +268,17 @@ class SandboxStatusTests(unittest.TestCase):
631
268
  '[testing-env/0] setting_up -> in_session',
632
269
  "[testing-env/0] session 'session1' started",
633
270
  '[testing-env/0/session1] shell: echo "hello"',
271
+ '[testing-env/0] in_session -> exiting_session',
634
272
  '[testing-env/0/session1] shell: "feature1" teardown session',
635
273
  '[testing-env/0/feature1] feature teardown session',
636
274
  '[testing-env/0/session1] shell: "feature2" teardown session',
637
275
  '[testing-env/0/feature2] feature teardown session',
638
276
  "[testing-env/0] session 'session1' ended",
639
- '[testing-env/0] in_session -> acquired',
277
+ '[testing-env/0] exiting_session -> acquired',
640
278
  '[testing-env/0] acquired -> shutting_down',
279
+ '[testing-env/0] shell: "feature1" teardown',
641
280
  '[testing-env/0/feature1] feature teardown',
281
+ '[testing-env/0] shell: "feature2" teardown',
642
282
  '[testing-env/0/feature2] feature teardown',
643
283
  '[testing-env/0] shutting_down -> offline',
644
284
  '[testing-env/0] sandbox shutdown'
@@ -667,9 +307,13 @@ class SandboxStatusTests(unittest.TestCase):
667
307
  self.assertEqual(
668
308
  self.event_handler.logs,
669
309
  [
310
+ '[testing-env/0] shell: "feature1" setup',
670
311
  '[testing-env/0/feature1] feature setup',
312
+ '[testing-env/0] shell: "feature2" setup',
671
313
  '[testing-env/0/feature2] feature setup',
314
+ '[testing-env/0] shell: "feature1" setup session',
672
315
  '[testing-env/0/feature1] feature setup session',
316
+ '[testing-env/0] shell: "feature2" setup session',
673
317
  '[testing-env/0/feature2] feature setup session',
674
318
  '[testing-env/0] created -> ready',
675
319
  '[testing-env/0] sandbox started',
@@ -679,13 +323,16 @@ class SandboxStatusTests(unittest.TestCase):
679
323
  '[testing-env/0] setting_up -> in_session',
680
324
  "[testing-env/0] session 'session1' started",
681
325
  '[testing-env/0/session1] shell: echo "hello"',
326
+ '[testing-env/0] in_session -> exiting_session',
682
327
  '[testing-env/0/session1] shell: "feature1" teardown session',
683
328
  '[testing-env/0/feature1] feature teardown session',
684
329
  '[testing-env/0/session1] shell: "feature2" teardown session',
685
330
  '[testing-env/0/feature2] feature teardown session',
686
331
  "[testing-env/0] session 'session1' ended",
687
- '[testing-env/0] in_session -> setting_up',
332
+ '[testing-env/0] exiting_session -> setting_up',
333
+ '[testing-env/0] shell: "feature1" setup session',
688
334
  '[testing-env/0/feature1] feature setup session',
335
+ '[testing-env/0] shell: "feature2" setup session',
689
336
  '[testing-env/0/feature2] feature setup session',
690
337
  '[testing-env/0] setting_up -> ready'
691
338
  ]
@@ -719,12 +366,14 @@ class SandboxStatusTests(unittest.TestCase):
719
366
  self.assertEqual(
720
367
  event_handler.logs,
721
368
  [
369
+ '[testing-env/0] in_session -> exiting_session',
722
370
  '[testing-env/0/session1] shell: "test_feature" teardown session',
723
371
  '[testing-env/0/test_feature] feature teardown session',
724
372
  "[testing-env/0] session 'session1' ended",
725
- '[testing-env/0] in_session -> setting_up',
373
+ '[testing-env/0] exiting_session -> setting_up',
726
374
  '[testing-env/0/test_feature] feature setup session with SandboxStateError', # pylint: disable=line-too-long
727
375
  '[testing-env/0] setting_up -> shutting_down',
376
+ '[testing-env/0] shell: "test_feature" teardown',
728
377
  '[testing-env/0/test_feature] feature teardown',
729
378
  '[testing-env/0] shutting_down -> offline',
730
379
  '[testing-env/0] sandbox shutdown'
@@ -797,7 +446,9 @@ class SandboxStatusTests(unittest.TestCase):
797
446
  self.event_handler.logs,
798
447
  [
799
448
  '[testing-env] environment started',
449
+ '[testing-env/0] shell: "feature1" setup',
800
450
  '[testing-env/0/feature1] feature setup',
451
+ '[testing-env/0] shell: "feature2" setup',
801
452
  '[testing-env/0/feature2] feature setup',
802
453
  '[testing-env/0] created -> ready',
803
454
  '[testing-env/0] sandbox started',
@@ -810,14 +461,17 @@ class SandboxStatusTests(unittest.TestCase):
810
461
  '[testing-env/0] setting_up -> in_session',
811
462
  "[testing-env/0] session 'session1' started",
812
463
  '[testing-env/0/session1] shell: echo "hello"',
464
+ '[testing-env/0] in_session -> exiting_session',
813
465
  '[testing-env/0/session1] shell: "feature1" teardown session',
814
466
  '[testing-env/0/feature1] feature teardown session',
815
467
  '[testing-env/0/session1] shell: "feature2" teardown session',
816
468
  '[testing-env/0/feature2] feature teardown session',
817
469
  "[testing-env/0] session 'session1' ended",
818
- '[testing-env/0] in_session -> acquired',
470
+ '[testing-env/0] exiting_session -> acquired',
819
471
  '[testing-env/0] acquired -> shutting_down',
472
+ '[testing-env/0] shell: "feature1" teardown',
820
473
  '[testing-env/0/feature1] feature teardown',
474
+ '[testing-env/0] shell: "feature2" teardown',
821
475
  '[testing-env/0/feature2] feature teardown',
822
476
  '[testing-env/0] shutting_down -> offline',
823
477
  '[testing-env/0] sandbox shutdown with ValueError',
@@ -841,15 +495,21 @@ class SandboxStatusTests(unittest.TestCase):
841
495
  self.assertEqual(
842
496
  self.event_handler.logs,
843
497
  [
498
+ '[testing-env/0] shell: "feature1" setup',
844
499
  '[testing-env/0/feature1] feature setup',
500
+ '[testing-env/0] shell: "feature2" setup',
845
501
  '[testing-env/0/feature2] feature setup',
502
+ '[testing-env/0] shell: "feature1" setup session',
846
503
  '[testing-env/0/feature1] feature setup session',
504
+ '[testing-env/0] shell: "feature2" setup session',
847
505
  '[testing-env/0/feature2] feature setup session',
848
506
  '[testing-env/0] created -> ready',
849
507
  '[testing-env/0] sandbox started',
850
508
  '[testing-env] environment started',
851
509
  '[testing-env/0] ready -> shutting_down',
510
+ '[testing-env/0] shell: "feature1" teardown',
852
511
  '[testing-env/0/feature1] feature teardown',
512
+ '[testing-env/0] shell: "feature2" teardown',
853
513
  '[testing-env/0/feature2] feature teardown',
854
514
  '[testing-env/0] shutting_down -> offline',
855
515
  '[testing-env/0] sandbox shutdown with ValueError',
@@ -873,7 +533,9 @@ class SandboxStatusTests(unittest.TestCase):
873
533
  self.event_handler.logs,
874
534
  [
875
535
  '[testing-env] environment started',
536
+ '[testing-env/0] shell: "feature1" setup',
876
537
  '[testing-env/0/feature1] feature setup',
538
+ '[testing-env/0] shell: "feature2" setup',
877
539
  '[testing-env/0/feature2] feature setup',
878
540
  '[testing-env/0] created -> ready',
879
541
  '[testing-env/0] sandbox started',
@@ -886,14 +548,17 @@ class SandboxStatusTests(unittest.TestCase):
886
548
  '[testing-env/0] setting_up -> in_session',
887
549
  "[testing-env/0] session 'session1' started",
888
550
  '[testing-env/0/session1] shell: echo "hello"',
551
+ '[testing-env/0] in_session -> exiting_session',
889
552
  '[testing-env/0/session1] shell: "feature1" teardown session',
890
553
  '[testing-env/0/feature1] feature teardown session',
891
554
  '[testing-env/0/session1] shell: "feature2" teardown session',
892
555
  '[testing-env/0/feature2] feature teardown session',
893
556
  "[testing-env/0] session 'session1' ended",
894
- '[testing-env/0] in_session -> acquired',
557
+ '[testing-env/0] exiting_session -> acquired',
895
558
  '[testing-env/0] acquired -> shutting_down',
559
+ '[testing-env/0] shell: "feature1" teardown',
896
560
  '[testing-env/0/feature1] feature teardown',
561
+ '[testing-env/0] shell: "feature2" teardown',
897
562
  '[testing-env/0/feature2] feature teardown',
898
563
  '[testing-env/0] shutting_down -> offline',
899
564
  '[testing-env/0] sandbox shutdown with SandboxStateError',
@@ -918,11 +583,14 @@ class SandboxStatusTests(unittest.TestCase):
918
583
  self.event_handler.logs,
919
584
  [
920
585
  '[testing-env] environment started',
586
+ '[testing-env/0] shell: "feature1" setup',
921
587
  '[testing-env/0/feature1] feature setup',
922
588
  '[testing-env/0/feature2] feature setup with ValueError',
923
589
  '[testing-env/0] sandbox started with ValueError',
924
590
  '[testing-env/0] created -> shutting_down',
591
+ '[testing-env/0] shell: "feature1" teardown',
925
592
  '[testing-env/0/feature1] feature teardown',
593
+ '[testing-env/0] shell: "feature2" teardown',
926
594
  '[testing-env/0/feature2] feature teardown',
927
595
  '[testing-env/0] shutting_down -> offline',
928
596
  '[testing-env/0] sandbox shutdown'
@@ -949,6 +617,7 @@ class SandboxStatusTests(unittest.TestCase):
949
617
  '[testing-env/0/feature1] feature setup with SandboxStateError',
950
618
  '[testing-env/0] sandbox started with SandboxStateError',
951
619
  '[testing-env/0] created -> shutting_down',
620
+ '[testing-env/0] shell: "feature1" teardown',
952
621
  '[testing-env/0/feature1] feature teardown',
953
622
  '[testing-env/0] shutting_down -> offline',
954
623
  '[testing-env/0] sandbox shutdown',
@@ -973,7 +642,9 @@ class SandboxStatusTests(unittest.TestCase):
973
642
  self.event_handler.logs,
974
643
  [
975
644
  '[testing-env] environment started',
645
+ '[testing-env/0] shell: "feature1" setup',
976
646
  '[testing-env/0/feature1] feature setup',
647
+ '[testing-env/0] shell: "feature2" setup',
977
648
  '[testing-env/0/feature2] feature setup',
978
649
  '[testing-env/0] created -> ready',
979
650
  '[testing-env/0] sandbox started',
@@ -985,13 +656,15 @@ class SandboxStatusTests(unittest.TestCase):
985
656
  '[testing-env/0/feature2] feature setup session',
986
657
  '[testing-env/0] setting_up -> in_session',
987
658
  "[testing-env/0] session 'session1' started",
659
+ '[testing-env/0] in_session -> exiting_session',
988
660
  '[testing-env/0/session1] shell: "feature1" teardown session',
989
661
  '[testing-env/0/feature1] feature teardown session',
990
662
  '[testing-env/0/session1] shell: "feature2" teardown session',
991
663
  '[testing-env/0/feature2] feature teardown session',
992
664
  "[testing-env/0] session 'session1' ended",
993
- '[testing-env/0] in_session -> acquired',
665
+ '[testing-env/0] exiting_session -> acquired',
994
666
  '[testing-env/0] acquired -> shutting_down',
667
+ '[testing-env/0] shell: "feature1" teardown',
995
668
  '[testing-env/0/feature1] feature teardown',
996
669
  '[testing-env/0/feature2] feature teardown with ValueError',
997
670
  '[testing-env/0] shutting_down -> offline',
@@ -1017,7 +690,9 @@ class SandboxStatusTests(unittest.TestCase):
1017
690
  self.event_handler.logs,
1018
691
  [
1019
692
  '[testing-env] environment started',
693
+ '[testing-env/0] shell: "feature1" setup',
1020
694
  '[testing-env/0/feature1] feature setup',
695
+ '[testing-env/0] shell: "feature2" setup',
1021
696
  '[testing-env/0/feature2] feature setup',
1022
697
  '[testing-env/0] created -> ready',
1023
698
  '[testing-env/0] sandbox started',
@@ -1029,14 +704,16 @@ class SandboxStatusTests(unittest.TestCase):
1029
704
  '[testing-env/0/feature2] feature setup session',
1030
705
  '[testing-env/0] setting_up -> in_session',
1031
706
  "[testing-env/0] session 'session1' started",
707
+ '[testing-env/0] in_session -> exiting_session',
1032
708
  '[testing-env/0/session1] shell: "feature1" teardown session',
1033
709
  '[testing-env/0/feature1] feature teardown session',
1034
710
  '[testing-env/0/session1] shell: "feature2" teardown session',
1035
711
  '[testing-env/0/feature2] feature teardown session',
1036
712
  "[testing-env/0] session 'session1' ended",
1037
- '[testing-env/0] in_session -> acquired',
713
+ '[testing-env/0] exiting_session -> acquired',
1038
714
  '[testing-env/0] acquired -> shutting_down',
1039
715
  '[testing-env/0/feature1] feature teardown with SandboxStateError', # pylint: disable=line-too-long
716
+ '[testing-env/0] shell: "feature2" teardown',
1040
717
  '[testing-env/0/feature2] feature teardown',
1041
718
  '[testing-env/0] shutting_down -> offline',
1042
719
  '[testing-env/0] sandbox shutdown with FeatureTeardownError'
@@ -1060,7 +737,9 @@ class SandboxStatusTests(unittest.TestCase):
1060
737
  self.event_handler.logs,
1061
738
  [
1062
739
  '[testing-env] environment started',
740
+ '[testing-env/0] shell: "feature1" setup',
1063
741
  '[testing-env/0/feature1] feature setup',
742
+ '[testing-env/0] shell: "feature2" setup',
1064
743
  '[testing-env/0/feature2] feature setup',
1065
744
  '[testing-env/0] created -> ready',
1066
745
  '[testing-env/0] sandbox started',
@@ -1098,7 +777,9 @@ class SandboxStatusTests(unittest.TestCase):
1098
777
  self.event_handler.logs,
1099
778
  [
1100
779
  '[testing-env] environment started',
780
+ '[testing-env/0] shell: "feature1" setup',
1101
781
  '[testing-env/0/feature1] feature setup',
782
+ '[testing-env/0] shell: "feature2" setup',
1102
783
  '[testing-env/0/feature2] feature setup',
1103
784
  '[testing-env/0] created -> ready',
1104
785
  '[testing-env/0] sandbox started',
@@ -1111,13 +792,16 @@ class SandboxStatusTests(unittest.TestCase):
1111
792
  '[testing-env/0] setting_up -> in_session',
1112
793
  "[testing-env/0] session 'session1' started",
1113
794
  '[testing-env/0/session1] shell: echo "hello"',
795
+ '[testing-env/0] in_session -> exiting_session',
1114
796
  '[testing-env/0/feature1] feature teardown session with ValueError', # pylint: disable=line-too-long
1115
797
  '[testing-env/0/session1] shell: "feature2" teardown session',
1116
798
  '[testing-env/0/feature2] feature teardown session',
1117
799
  "[testing-env/0] session 'session1' ended",
1118
- '[testing-env/0] in_session -> acquired',
800
+ '[testing-env/0] exiting_session -> acquired',
1119
801
  '[testing-env/0] acquired -> shutting_down',
802
+ '[testing-env/0] shell: "feature1" teardown',
1120
803
  '[testing-env/0/feature1] feature teardown',
804
+ '[testing-env/0] shell: "feature2" teardown',
1121
805
  '[testing-env/0/feature2] feature teardown',
1122
806
  '[testing-env/0] shutting_down -> offline',
1123
807
  '[testing-env/0] sandbox shutdown'
@@ -1142,7 +826,9 @@ class SandboxStatusTests(unittest.TestCase):
1142
826
  self.event_handler.logs,
1143
827
  [
1144
828
  '[testing-env] environment started',
829
+ '[testing-env/0] shell: "feature1" setup',
1145
830
  '[testing-env/0/feature1] feature setup',
831
+ '[testing-env/0] shell: "feature2" setup',
1146
832
  '[testing-env/0/feature2] feature setup',
1147
833
  '[testing-env/0] created -> ready',
1148
834
  '[testing-env/0] sandbox started',
@@ -1155,13 +841,64 @@ class SandboxStatusTests(unittest.TestCase):
1155
841
  '[testing-env/0] setting_up -> in_session',
1156
842
  "[testing-env/0] session 'session1' started",
1157
843
  '[testing-env/0/session1] shell: echo "hello"',
844
+ '[testing-env/0] in_session -> exiting_session',
1158
845
  '[testing-env/0/feature1] feature teardown session with SandboxStateError', # pylint: disable=line-too-long
1159
846
  '[testing-env/0/session1] shell: "feature2" teardown session',
1160
847
  '[testing-env/0/feature2] feature teardown session',
1161
848
  "[testing-env/0] session 'session1' ended with SandboxStateError",
1162
- '[testing-env/0] in_session -> acquired',
849
+ '[testing-env/0] exiting_session -> acquired',
1163
850
  '[testing-env/0] acquired -> shutting_down',
851
+ '[testing-env/0] shell: "feature1" teardown',
1164
852
  '[testing-env/0/feature1] feature teardown',
853
+ '[testing-env/0] shell: "feature2" teardown',
854
+ '[testing-env/0/feature2] feature teardown',
855
+ '[testing-env/0] shutting_down -> offline',
856
+ '[testing-env/0] sandbox shutdown'
857
+ ]
858
+ )
859
+
860
+ def test_feature_teardown_session_calling_end_session(self):
861
+ env = self._create_env(
862
+ features={
863
+ 'feature1': TestingFeature(
864
+ call_end_session_on_teardown_session=True
865
+ ),
866
+ 'feature2': TestingFeature(),
867
+ },
868
+ )
869
+ with env:
870
+ with env.sandbox('session1') as sb:
871
+ sb.shell('echo "hello"')
872
+ self.assertEqual(
873
+ self.event_handler.logs,
874
+ [
875
+ '[testing-env] environment started',
876
+ '[testing-env/0] shell: "feature1" setup',
877
+ '[testing-env/0/feature1] feature setup',
878
+ '[testing-env/0] shell: "feature2" setup',
879
+ '[testing-env/0/feature2] feature setup',
880
+ '[testing-env/0] created -> ready',
881
+ '[testing-env/0] sandbox started',
882
+ '[testing-env/0] ready -> acquired',
883
+ '[testing-env/0] acquired -> setting_up',
884
+ '[testing-env/0/session1] shell: "feature1" setup session',
885
+ '[testing-env/0/feature1] feature setup session',
886
+ '[testing-env/0/session1] shell: "feature2" setup session',
887
+ '[testing-env/0/feature2] feature setup session',
888
+ '[testing-env/0] setting_up -> in_session',
889
+ "[testing-env/0] session 'session1' started",
890
+ '[testing-env/0/session1] shell: echo "hello"',
891
+ '[testing-env/0] in_session -> exiting_session',
892
+ '[testing-env/0/session1] shell: "feature1" teardown session',
893
+ '[testing-env/0/feature1] feature teardown session',
894
+ '[testing-env/0/session1] shell: "feature2" teardown session',
895
+ '[testing-env/0/feature2] feature teardown session',
896
+ "[testing-env/0] session 'session1' ended",
897
+ '[testing-env/0] exiting_session -> acquired',
898
+ '[testing-env/0] acquired -> shutting_down',
899
+ '[testing-env/0] shell: "feature1" teardown',
900
+ '[testing-env/0/feature1] feature teardown',
901
+ '[testing-env/0] shell: "feature2" teardown',
1165
902
  '[testing-env/0/feature2] feature teardown',
1166
903
  '[testing-env/0] shutting_down -> offline',
1167
904
  '[testing-env/0] sandbox shutdown'
@@ -1186,7 +923,9 @@ class SandboxStatusTests(unittest.TestCase):
1186
923
  self.assertEqual(
1187
924
  self.event_handler.logs,
1188
925
  [
926
+ '[testing-env/0] shell: "feature1" setup',
1189
927
  '[testing-env/0/feature1] feature setup',
928
+ '[testing-env/0] shell: "feature1" setup session',
1190
929
  '[testing-env/0/feature1] feature setup session',
1191
930
  '[testing-env/0] created -> ready',
1192
931
  '[testing-env/0] sandbox started',
@@ -1197,10 +936,12 @@ class SandboxStatusTests(unittest.TestCase):
1197
936
  "[testing-env/0] session 'session1' started",
1198
937
  '[testing-env/0/session1] shell: echo foo with ValueError',
1199
938
  '[testing-env/0/session1] shell: echo bar',
939
+ '[testing-env/0] in_session -> exiting_session',
1200
940
  '[testing-env/0/session1] shell: "feature1" teardown session',
1201
941
  '[testing-env/0/feature1] feature teardown session',
1202
942
  "[testing-env/0] session 'session1' ended",
1203
- '[testing-env/0] in_session -> setting_up',
943
+ '[testing-env/0] exiting_session -> setting_up',
944
+ '[testing-env/0] shell: "feature1" setup session',
1204
945
  '[testing-env/0/feature1] feature setup session',
1205
946
  '[testing-env/0] setting_up -> ready',
1206
947
  ]
@@ -1223,7 +964,9 @@ class SandboxStatusTests(unittest.TestCase):
1223
964
  self.assertEqual(
1224
965
  self.event_handler.logs,
1225
966
  [
967
+ '[testing-env/0] shell: "feature1" setup',
1226
968
  '[testing-env/0/feature1] feature setup',
969
+ '[testing-env/0] shell: "feature1" setup session',
1227
970
  '[testing-env/0/feature1] feature setup session',
1228
971
  '[testing-env/0] created -> ready',
1229
972
  '[testing-env/0] sandbox started',
@@ -1233,14 +976,17 @@ class SandboxStatusTests(unittest.TestCase):
1233
976
  '[testing-env/0] setting_up -> in_session',
1234
977
  "[testing-env/0] session 'session1' started",
1235
978
  '[testing-env/0/session1] shell: echo foo with RuntimeError',
979
+ '[testing-env/0] in_session -> exiting_session',
1236
980
  '[testing-env/0/session1] shell: "feature1" teardown session',
1237
981
  '[testing-env/0/feature1] feature teardown session',
1238
982
  "[testing-env/0] session 'session1' ended with SandboxStateError",
1239
- '[testing-env/0] in_session -> acquired',
983
+ '[testing-env/0] exiting_session -> acquired',
1240
984
  '[testing-env/0] acquired -> shutting_down',
985
+ '[testing-env/0] shell: "feature1" teardown',
1241
986
  '[testing-env/0/feature1] feature teardown',
1242
987
  '[testing-env/0] shutting_down -> offline',
1243
- '[testing-env/0] sandbox shutdown'
988
+ '[testing-env/0] sandbox shutdown',
989
+ '[testing-env/0] shell: echo bar',
1244
990
  ]
1245
991
  )
1246
992
 
@@ -1298,12 +1044,12 @@ class SandboxActivityTests(unittest.TestCase):
1298
1044
  self.assertEqual(len(env.sandbox_pool), 1)
1299
1045
  self.assertEqual(sb.status, interface.Sandbox.Status.IN_SESSION)
1300
1046
  self.assertEqual(sb.session_id, 'session1')
1301
- housekeep_count = sb._housekeep_count
1047
+ housekeep_count = sb.housekeep_counter
1302
1048
  sb.test_feature.rebind(
1303
1049
  simulate_housekeep_error=interface.SandboxStateError,
1304
1050
  skip_notification=True
1305
1051
  )
1306
- while sb._housekeep_count == housekeep_count or (
1052
+ while sb.housekeep_counter == housekeep_count or (
1307
1053
  sb.status == interface.Sandbox.Status.IN_SESSION
1308
1054
  ):
1309
1055
  time.sleep(0.1)
@@ -1355,13 +1101,14 @@ class SandboxServiceTests(unittest.TestCase):
1355
1101
  def __init__(self):
1356
1102
  self.calls = []
1357
1103
 
1358
- def on_session_activity(
1104
+ def on_sandbox_activity(
1359
1105
  self,
1360
- session_id: str,
1361
1106
  name: str,
1362
1107
  environment: interface.Environment,
1363
1108
  sandbox: interface.Sandbox,
1364
1109
  feature: interface.Feature | None,
1110
+ session_id: str | None,
1111
+ duration: float,
1365
1112
  error: BaseException | None,
1366
1113
  **kwargs: Any):
1367
1114
  self.calls.append((session_id, name, kwargs))
@@ -1379,9 +1126,11 @@ class SandboxServiceTests(unittest.TestCase):
1379
1126
  self.assertEqual(
1380
1127
  event_handler.calls,
1381
1128
  [
1129
+ (None, 'shell', {'code': '"test_feature" setup'}),
1382
1130
  ('session1', 'shell', {'code': '"test_feature" setup session'}),
1383
- ('session1', 'call_with_varargs', {'args': (1, 2), 'code': 'sum', 'debug': True}), # pylint: disable=line-too-long
1131
+ ('session1', 'test_feature.call_with_varargs', {'args': (1, 2), 'code': 'sum', 'debug': True}), # pylint: disable=line-too-long
1384
1132
  ('session1', 'shell', {'code': '"test_feature" teardown session'}),
1133
+ (None, 'shell', {'code': '"test_feature" teardown'}),
1385
1134
  ]
1386
1135
  )
1387
1136
 
@@ -1395,14 +1144,16 @@ class SandboxServiceTests(unittest.TestCase):
1395
1144
  [
1396
1145
  # pylint: disable=line-too-long
1397
1146
  '[testing-env] environment started',
1147
+ '[testing-env/0] shell: "test_feature" setup',
1398
1148
  '[testing-env/0/test_feature] feature setup',
1399
1149
  '[testing-env/0] sandbox started',
1400
1150
  '[testing-env/0/session1] shell: "test_feature" setup session',
1401
1151
  "[testing-env/0] session 'session1' started",
1402
- '[testing-env/0/session1] num_shell_calls: None',
1403
- '[testing-env/0/session1] num_shell_calls: None',
1152
+ '[testing-env/0/session1/test_feature] test_feature.num_shell_calls: None',
1153
+ '[testing-env/0/session1/test_feature] test_feature.num_shell_calls: None',
1404
1154
  '[testing-env/0/session1] shell: "test_feature" teardown session',
1405
1155
  "[testing-env/0] session 'session1' ended",
1156
+ '[testing-env/0] shell: "test_feature" teardown',
1406
1157
  '[testing-env/0/test_feature] feature teardown',
1407
1158
  '[testing-env/0] sandbox shutdown',
1408
1159
  '[testing-env] environment shutdown'
@@ -1422,16 +1173,18 @@ class SandboxServiceTests(unittest.TestCase):
1422
1173
  [
1423
1174
  # pylint: disable=line-too-long
1424
1175
  '[testing-env] environment started',
1176
+ '[testing-env/0] shell: "test_feature" setup',
1425
1177
  '[testing-env/0/test_feature] feature setup',
1426
1178
  '[testing-env/0] sandbox started',
1427
1179
  '[testing-env/0/session1] shell: "test_feature" setup session',
1428
1180
  "[testing-env/0] session 'session1' started",
1429
1181
  '[testing-env/0/session1] shell: bad command with RuntimeError',
1182
+ '[testing-env/0/session1/test_feature] test_feature.bad_shell_call: None with SandboxStateError',
1430
1183
  '[testing-env/0/session1] shell: "test_feature" teardown session',
1431
1184
  "[testing-env/0] session 'session1' ended with SandboxStateError",
1185
+ '[testing-env/0] shell: "test_feature" teardown',
1432
1186
  '[testing-env/0/test_feature] feature teardown',
1433
1187
  '[testing-env/0] sandbox shutdown',
1434
- '[testing-env/0/session1] bad_shell_call: None with SandboxStateError',
1435
1188
  '[testing-env] environment shutdown'
1436
1189
  # pylint: enable=line-too-long
1437
1190
  ]
@@ -1445,13 +1198,15 @@ class SandboxServiceTests(unittest.TestCase):
1445
1198
  [
1446
1199
  # pylint: disable=line-too-long
1447
1200
  '[testing-env] environment started',
1201
+ '[testing-env/0] shell: "test_feature" setup',
1448
1202
  '[testing-env/0/test_feature] feature setup',
1449
1203
  '[testing-env/0] sandbox started',
1450
1204
  '[testing-env/0/session-2291d8c] shell: "test_feature" setup session',
1451
1205
  "[testing-env/0] session 'session-2291d8c' started",
1452
- '[testing-env/0/session-2291d8c] num_shell_calls: None',
1206
+ '[testing-env/0/session-2291d8c/test_feature] test_feature.num_shell_calls: None',
1453
1207
  '[testing-env/0/session-2291d8c] shell: "test_feature" teardown session',
1454
1208
  "[testing-env/0] session 'session-2291d8c' ended",
1209
+ '[testing-env/0] shell: "test_feature" teardown',
1455
1210
  '[testing-env/0/test_feature] feature teardown',
1456
1211
  '[testing-env/0] sandbox shutdown',
1457
1212
  '[testing-env] environment shutdown'
@@ -1468,16 +1223,18 @@ class SandboxServiceTests(unittest.TestCase):
1468
1223
  [
1469
1224
  # pylint: disable=line-too-long
1470
1225
  '[testing-env] environment started',
1226
+ '[testing-env/0] shell: "test_feature" setup',
1471
1227
  '[testing-env/0/test_feature] feature setup',
1472
1228
  '[testing-env/0] sandbox started',
1473
1229
  '[testing-env/0/session1] shell: "test_feature" setup session',
1474
1230
  "[testing-env/0] session 'session1' started",
1475
1231
  '[testing-env/0/session1] shell: bad command with RuntimeError',
1232
+ '[testing-env/0/session1/test_feature] test_feature.bad_shell_call: None with SandboxStateError',
1476
1233
  '[testing-env/0/session1] shell: "test_feature" teardown session',
1477
1234
  "[testing-env/0] session 'session1' ended with SandboxStateError",
1235
+ '[testing-env/0] shell: "test_feature" teardown',
1478
1236
  '[testing-env/0/test_feature] feature teardown',
1479
1237
  '[testing-env/0] sandbox shutdown',
1480
- '[testing-env/0/session1] bad_shell_call: None with SandboxStateError',
1481
1238
  '[testing-env] environment shutdown'
1482
1239
  # pylint: enable=line-too-long
1483
1240
  ]
@@ -1495,15 +1252,17 @@ class SandboxServiceTests(unittest.TestCase):
1495
1252
  [
1496
1253
  # pylint: disable=line-too-long
1497
1254
  '[testing-env] environment started',
1255
+ '[testing-env/0] shell: "test_feature" setup',
1498
1256
  '[testing-env/0/test_feature] feature setup',
1499
1257
  '[testing-env/0] sandbox started',
1500
1258
  '[testing-env/0/session1] shell: "test_feature" setup session',
1501
1259
  "[testing-env/0] session 'session1' started",
1502
- '[testing-env/0/session1] my_service: None',
1503
1260
  '[testing-env/0/session1] shell: hello',
1261
+ '[testing-env/0/session1/test_feature] test_feature.my_service: None',
1504
1262
  '[testing-env/0/session1] shell: foo',
1505
1263
  '[testing-env/0/session1] shell: "test_feature" teardown session',
1506
1264
  "[testing-env/0] session 'session1' ended",
1265
+ '[testing-env/0] shell: "test_feature" teardown',
1507
1266
  '[testing-env/0/test_feature] feature teardown',
1508
1267
  '[testing-env/0] sandbox shutdown',
1509
1268
  '[testing-env] environment shutdown'
@@ -1523,14 +1282,16 @@ class SandboxServiceTests(unittest.TestCase):
1523
1282
  [
1524
1283
  # pylint: disable=line-too-long
1525
1284
  '[testing-env] environment started',
1285
+ '[testing-env/0] shell: "test_feature" setup',
1526
1286
  '[testing-env/0/test_feature] feature setup',
1527
1287
  '[testing-env/0] sandbox started',
1528
1288
  '[testing-env/0/session1] shell: "test_feature" setup session',
1529
1289
  "[testing-env/0] session 'session1' started",
1530
- '[testing-env/0/session1] my_service: None',
1531
1290
  '[testing-env/0/session1] shell: hello with SandboxStateError',
1291
+ '[testing-env/0/session1/test_feature] test_feature.my_service: None with SandboxStateError',
1532
1292
  '[testing-env/0/session1] shell: "test_feature" teardown session',
1533
1293
  "[testing-env/0] session 'session1' ended with SandboxStateError",
1294
+ '[testing-env/0] shell: "test_feature" teardown',
1534
1295
  '[testing-env/0/test_feature] feature teardown',
1535
1296
  '[testing-env/0] sandbox shutdown',
1536
1297
  '[testing-env] environment shutdown'
@@ -1549,24 +1310,28 @@ class SandboxServiceTests(unittest.TestCase):
1549
1310
  [
1550
1311
  # pylint: disable=line-too-long
1551
1312
  '[testing-env] environment started',
1313
+ '[testing-env/0] shell: "test_feature" setup',
1552
1314
  '[testing-env/0/test_feature] feature setup',
1553
1315
  '[testing-env/0] sandbox started',
1554
1316
  '[testing-env/0/session1] shell: "test_feature" setup session',
1555
1317
  "[testing-env/0] session 'session1' started",
1556
- '[testing-env/0/session1] my_service: None',
1557
1318
  '[testing-env/0/session1] shell: foo',
1319
+ '[testing-env/0/session1/test_feature] test_feature.my_service: None',
1558
1320
  '[testing-env/0/session1] shell: "test_feature" teardown session',
1559
1321
  "[testing-env/0] session 'session1' ended",
1322
+ '[testing-env/0] shell: "test_feature" teardown',
1560
1323
  '[testing-env/0/test_feature] feature teardown',
1561
1324
  '[testing-env/0] sandbox shutdown',
1325
+ '[testing-env/1] shell: "test_feature" setup',
1562
1326
  '[testing-env/1/test_feature] feature setup',
1563
1327
  '[testing-env/1] sandbox started',
1564
1328
  '[testing-env/1/session-2291d8c] shell: "test_feature" setup session',
1565
1329
  "[testing-env/1] session 'session-2291d8c' started",
1566
- '[testing-env/1/session-2291d8c] my_service: None',
1567
1330
  '[testing-env/1/session-2291d8c] shell: bar',
1331
+ '[testing-env/1/session-2291d8c/test_feature] test_feature.my_service: None',
1568
1332
  '[testing-env/1/session-2291d8c] shell: "test_feature" teardown session',
1569
1333
  "[testing-env/1] session 'session-2291d8c' ended",
1334
+ '[testing-env/1] shell: "test_feature" teardown',
1570
1335
  '[testing-env/1/test_feature] feature teardown',
1571
1336
  '[testing-env/1] sandbox shutdown',
1572
1337
  '[testing-env] environment shutdown'
@@ -1584,14 +1349,16 @@ class SandboxServiceTests(unittest.TestCase):
1584
1349
  [
1585
1350
  # pylint: disable=line-too-long
1586
1351
  '[testing-env] environment started',
1352
+ '[testing-env/0] shell: "test_feature" setup',
1587
1353
  '[testing-env/0/test_feature] feature setup',
1588
1354
  '[testing-env/0] sandbox started',
1589
1355
  '[testing-env/0/session-2291d8c] shell: "test_feature" setup session',
1590
1356
  "[testing-env/0] session 'session-2291d8c' started",
1591
- '[testing-env/0/session-2291d8c] my_service: None',
1592
1357
  '[testing-env/0/session-2291d8c] shell: hello with SandboxStateError',
1358
+ '[testing-env/0/session-2291d8c/test_feature] test_feature.my_service: None with SandboxStateError',
1593
1359
  '[testing-env/0/session-2291d8c] shell: "test_feature" teardown session',
1594
1360
  "[testing-env/0] session 'session-2291d8c' ended with SandboxStateError",
1361
+ '[testing-env/0] shell: "test_feature" teardown',
1595
1362
  '[testing-env/0/test_feature] feature teardown',
1596
1363
  '[testing-env/0] sandbox shutdown',
1597
1364
  '[testing-env] environment shutdown'