@@ -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