5050import io .fabric8 .kubernetes .client .Watch ;
5151import org .apache .commons .io .output .TeeOutputStream ;
5252import org .apache .commons .lang .RandomStringUtils ;
53+ import org .apache .commons .lang .StringUtils ;
5354import org .csanchez .jenkins .plugins .kubernetes .AllContainersRunningPodWatcher ;
5455import org .csanchez .jenkins .plugins .kubernetes .KubernetesClientProvider ;
5556import org .csanchez .jenkins .plugins .kubernetes .KubernetesCloud ;
@@ -212,7 +213,7 @@ public void run() {
212213 private void command (List <ProcReturn > results , int i ) {
213214 ProcReturn r ;
214215 try {
215- r = execCommand (false , "sh" , "-c" , "cd /tmp; echo [" +i +"] pid is $$$$ > test; cat /tmp/test" );
216+ r = execCommand (false , false , "sh" , "-c" , "cd /tmp; echo [" +i +"] pid is $$$$ > test; cat /tmp/test" );
216217 } catch (Exception e ) {
217218 throw new RuntimeException (e );
218219 }
@@ -221,29 +222,29 @@ private void command(List<ProcReturn> results, int i) {
221222
222223 @ Test
223224 public void testCommandExecutionFailure () throws Exception {
224- ProcReturn r = execCommand (false , "false" );
225+ ProcReturn r = execCommand (false , false , "false" );
225226 assertEquals (1 , r .exitCode );
226227 assertFalse (r .proc .isAlive ());
227228 }
228229
229230 @ Test
230231 public void testCommandExecutionFailureHighError () throws Exception {
231- ProcReturn r = execCommand (false , "sh" , "-c" , "return 127" );
232+ ProcReturn r = execCommand (false , false , "sh" , "-c" , "return 127" );
232233 assertEquals (127 , r .exitCode );
233234 assertFalse (r .proc .isAlive ());
234235 }
235236
236237 @ Test
237238 public void testQuietCommandExecution () throws Exception {
238- ProcReturn r = execCommand (true , "echo" , "pid is 9999" );
239+ ProcReturn r = execCommand (true , false , "echo" , "pid is 9999" );
239240 assertFalse ("Output should not contain command: " + r .output , PID_PATTERN .matcher (r .output ).find ());
240241 assertEquals (0 , r .exitCode );
241242 assertFalse (r .proc .isAlive ());
242243 }
243244
244245 @ Test
245246 public void testCommandExecutionWithNohup () throws Exception {
246- ProcReturn r = execCommand (false , "nohup" , "sh" , "-c" ,
247+ ProcReturn r = execCommand (false , false , "nohup" , "sh" , "-c" ,
247248 "sleep 5; cd /tmp; echo pid is $$$$ > test; cat /tmp/test" );
248249 assertTrue ("Output should contain pid: " + r .output , PID_PATTERN .matcher (r .output ).find ());
249250 assertEquals (0 , r .exitCode );
@@ -261,16 +262,43 @@ public void commandsEscaping() {
261262
262263 @ Test
263264 public void testCommandExecutionWithEscaping () throws Exception {
264- ProcReturn r = execCommand (false , "sh" , "-c" , "cd /tmp; false; echo result is $$? > test; cat /tmp/test" );
265+ ProcReturn r = execCommand (false , false , "sh" , "-c" , "cd /tmp; false; echo result is $$? > test; cat /tmp/test" );
265266 assertTrue ("Output should contain result: " + r .output ,
266267 Pattern .compile ("^(result is 1)$" , Pattern .MULTILINE ).matcher (r .output ).find ());
267268 assertEquals (0 , r .exitCode );
268269 assertFalse (r .proc .isAlive ());
269270 }
270271
272+ @ Test
273+ public void testCommandExecutionOutput () throws Exception {
274+ String testString = "Should appear once" ;
275+
276+ // Check output with quiet=false
277+ ProcReturn r = execCommand (false , false , "sh" , "-c" , "echo " + testString );
278+ assertEquals (0 , r .exitCode );
279+ String output = StringUtils .substringAfter (r .output , "exit" );
280+ assertEquals (testString , output .trim ());
281+
282+ // Check output with quiet=false and outputForCaller same as launcher output
283+ r = execCommand (false , true , "sh" , "-c" , "echo " + testString );
284+ assertEquals (0 , r .exitCode );
285+ output = StringUtils .substringAfter (r .output , "exit" );
286+ assertEquals (testString , output .trim ());
287+
288+ // Check output with quiet=true
289+ r = execCommand (true , false , "sh" , "-c" , "echo " + testString );
290+ assertEquals (0 , r .exitCode );
291+ assertEquals ("" , r .output .trim ());
292+
293+ // Check output with quiet=true and outputForCaller same as launcher output
294+ r = execCommand (true , true , "sh" , "-c" , "echo " + testString );
295+ assertEquals (0 , r .exitCode );
296+ assertEquals (testString , r .output .trim ());
297+ }
298+
271299 @ Test
272300 public void testCommandExecutionWithNohupAndError () throws Exception {
273- ProcReturn r = execCommand (false , "nohup" , "sh" , "-c" , "sleep 5; return 127" );
301+ ProcReturn r = execCommand (false , false , "nohup" , "sh" , "-c" , "sleep 5; return 127" );
274302 assertEquals (127 , r .exitCode );
275303 assertFalse (r .proc .isAlive ());
276304 }
@@ -281,16 +309,16 @@ public void testContainerDoesNotExist() throws Exception {
281309 decorator .setContainerName ("doesNotExist" );
282310 exception .expect (KubernetesClientException .class );
283311 exception .expectMessage (containsString ("container doesNotExist is not valid for pod" ));
284- execCommand (false , "nohup" , "sh" , "-c" , "sleep 5; return 127" );
312+ execCommand (false , false , "nohup" , "sh" , "-c" , "sleep 5; return 127" );
285313 }
286314
287315 /**
288316 * Reproduce JENKINS-55392
289- *
317+ *
290318 * Caused by: java.util.concurrent.RejectedExecutionException: Task okhttp3.RealCall$AsyncCall@30f55c9f rejected
291319 * from java.util.concurrent.ThreadPoolExecutor@25634758[Terminated, pool size = 0, active threads = 0, queued tasks
292320 * = 0, completed tasks = 0]
293- *
321+ *
294322 * @throws Exception
295323 */
296324 @ Test
@@ -310,7 +338,7 @@ public void testRejectedExecutionException() throws Exception {
310338 try {
311339 System .out .println (name + " Connection count: " + httpClient .connectionPool ().connectionCount ()
312340 + " - " + httpClient .connectionPool ().idleConnectionCount ());
313- ProcReturn r = execCommand (false , "echo" , "test" );
341+ ProcReturn r = execCommand (false , false , "echo" , "test" );
314342 } catch (Exception e ) {
315343 errors .incrementAndGet ();
316344 System .out .println (e .getMessage ());
@@ -340,15 +368,15 @@ public void testRejectedExecutionException() throws Exception {
340368 @ Issue ("JENKINS-50429" )
341369 public void testContainerExecPerformance () throws Exception {
342370 for (int i = 0 ; i < 10 ; i ++) {
343- ProcReturn r = execCommand (false , "ls" );
371+ ProcReturn r = execCommand (false , false , "ls" );
344372 }
345373 }
346374
347375 @ Test
348376 @ Issue ("JENKINS-58975" )
349377 public void testContainerExecOnCustomWorkingDir () throws Exception {
350378 doReturn (null ).when ((Node )agent ).toComputer ();
351- ProcReturn r = execCommandInContainer ("busybox1" , agent , false , "env" );
379+ ProcReturn r = execCommandInContainer ("busybox1" , agent , false , false , "env" );
352380 assertTrue ("Environment variable workingDir1 should be changed to /home/jenkins/agent1" ,
353381 r .output .contains ("workingDir1=/home/jenkins/agent1" ));
354382 assertEquals (0 , r .exitCode );
@@ -365,7 +393,7 @@ public void testContainerExecOnCustomWorkingDirWithComputeEnvVars() throws Excep
365393 doReturn (computeEnvVars ).when (computer ).getEnvironment ();
366394
367395 doReturn (computer ).when ((Node )agent ).toComputer ();
368- ProcReturn r = execCommandInContainer ("busybox1" , agent , false , "env" );
396+ ProcReturn r = execCommandInContainer ("busybox1" , agent , false , false , "env" );
369397 assertTrue ("Environment variable workingDir1 should be changed to /home/jenkins/agent1" ,
370398 r .output .contains ("workingDir1=/home/jenkins/agent1" ));
371399 assertTrue ("Environment variable MyCustomDir should be changed to /home/jenkins/agent1" ,
@@ -374,25 +402,28 @@ public void testContainerExecOnCustomWorkingDirWithComputeEnvVars() throws Excep
374402 assertFalse (r .proc .isAlive ());
375403 }
376404
377- private ProcReturn execCommand (boolean quiet , String ... cmd ) throws Exception {
378- return execCommandInContainer (null , null , quiet , cmd );
405+ private ProcReturn execCommand (boolean quiet , boolean launcherStdout , String ... cmd ) throws Exception {
406+ return execCommandInContainer (null , null , quiet , launcherStdout , cmd );
379407 }
380408
381- private ProcReturn execCommandInContainer (String containerName , Node node , boolean quiet , String ... cmd ) throws Exception {
382- if (containerName != null && ! containerName .isEmpty ()) {
409+ private ProcReturn execCommandInContainer (String containerName , Node node , boolean quiet , boolean launcherStdout , String ... cmd ) throws Exception {
410+ if (containerName != null && !containerName .isEmpty ()) {
383411 decorator .setContainerName (containerName );
384412 }
385413 ByteArrayOutputStream out = new ByteArrayOutputStream ();
386- Launcher launcher = decorator
387- .decorate (new DummyLauncher ( new StreamTaskListener ( new TeeOutputStream ( out , System . out ))) , node );
414+ DummyLauncher dummyLauncher = new DummyLauncher ( new StreamTaskListener ( new TeeOutputStream ( out , System . out )));
415+ Launcher launcher = decorator .decorate (dummyLauncher , node );
388416 Map <String , String > envs = new HashMap <>(100 );
389417 for (int i = 0 ; i < 50 ; i ++) {
390418 envs .put ("aaaaaaaa" + i , "bbbbbbbb" );
391419 }
392420 envs .put ("workingDir1" , "/home/jenkins/agent" );
393421
394- ContainerExecProc proc = (ContainerExecProc ) launcher
395- .launch (launcher .new ProcStarter ().pwd ("/tmp" ).cmds (cmd ).envs (envs ).quiet (quiet ));
422+ ProcStarter procStarter = launcher .new ProcStarter ().pwd ("/tmp" ).cmds (cmd ).envs (envs ).quiet (quiet );
423+ if (launcherStdout ) {
424+ procStarter .stdout (dummyLauncher .getListener ());
425+ }
426+ ContainerExecProc proc = (ContainerExecProc ) launcher .launch (procStarter );
396427 // wait for proc to finish (shouldn't take long)
397428 for (int i = 0 ; proc .isAlive () && i < 200 ; i ++) {
398429 Thread .sleep (100 );
0 commit comments