@@ -178,3 +178,46 @@ def test_execute_process_with_output_dictionary():
178178 ls = LaunchService ()
179179 ls .include_launch_description (ld )
180180 assert 0 == ls .run ()
181+
182+
183+ def test_execute_process_with_shutdown_on_error ():
184+ exited_processes = 0
185+
186+ def on_exit (event , context ):
187+ nonlocal exited_processes
188+ print (event , context )
189+ exited_processes += 1
190+
191+ executable_1 = ExecuteLocal (
192+ process_description = Executable (
193+ cmd = [sys .executable , '-c' , 'while True: pass' ]
194+ ),
195+ output = {'stdout' : 'screen' , 'stderr' : 'screen' },
196+ on_exit = on_exit ,
197+ )
198+ executable_2 = ExecuteLocal (
199+ process_description = Executable (
200+ cmd = [sys .executable , '-c' , 'while True: pass' ]
201+ ),
202+ output = {'stdout' : 'screen' , 'stderr' : 'screen' },
203+ on_exit = on_exit ,
204+ )
205+
206+ # It's slightly tricky to coerce the standard implementation to fail in
207+ # this way. However, launch_ros's Node class can fail similar to this and
208+ # this case therefore needs to be handled correctly.
209+ class ExecutableThatFails (ExecuteLocal ):
210+ def execute (self , context ):
211+ raise Exception ('Execute Local failed' )
212+
213+ executable_invalid = ExecutableThatFails (
214+ process_description = Executable (
215+ cmd = ['fake_process_that_doesnt_exists' ]
216+ ),
217+ output = {'stdout' : 'screen' , 'stderr' : 'screen' },
218+ )
219+ ld = LaunchDescription ([executable_1 , executable_2 , executable_invalid ])
220+ ls = LaunchService ()
221+ ls .include_launch_description (ld )
222+ assert ls .run () == 1
223+ assert exited_processes == 2
0 commit comments