blob: 771270fe185ca59ce1ede95ade300572edc5cd8d [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +00002//
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.
14package com.google.devtools.build.lib.shell;
15
Ulf Adams795895a2015-03-06 15:58:35 +000016import static com.google.common.truth.Truth.assertThat;
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +000017import static com.google.devtools.build.lib.shell.TestUtil.assertArrayEquals;
18import static org.junit.Assert.assertEquals;
19import static org.junit.Assert.assertFalse;
20import static org.junit.Assert.assertTrue;
21import static org.junit.Assert.fail;
22
Dmitry Lomov8efc3ef2016-02-17 09:50:03 +000023import com.google.common.collect.ImmutableMap;
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +000024import com.google.devtools.build.lib.testutil.BlazeTestUtils;
25import com.google.devtools.build.lib.testutil.TestConstants;
26
27import org.junit.Before;
28import org.junit.Test;
29import org.junit.runner.RunWith;
30import org.junit.runners.JUnit4;
31
32import java.io.ByteArrayInputStream;
33import java.io.ByteArrayOutputStream;
34import java.io.File;
35import java.io.IOException;
36import java.io.InputStream;
37import java.io.OutputStream;
38import java.util.Collections;
39import java.util.Map;
40import java.util.logging.Level;
41import java.util.logging.Logger;
42
43/**
44 * Unit tests for {@link Command}. This test will only succeed on Linux,
45 * currently, because of its non-portable nature.
46 */
47@RunWith(JUnit4.class)
48public class CommandTest {
49
50 private static final long LONG_TIME = 10000;
51 private static final long SHORT_TIME = 250;
52
53 // Platform-independent tests ----------------------------------------------
54
55 @Before
Florian Weikert2c71a822015-12-02 17:22:38 +000056 public final void configureLogger() throws Exception {
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +000057 // enable all log statements to ensure there are no problems with
58 // logging code
59 Logger.getLogger("com.google.devtools.build.lib.shell.Command").setLevel(Level.FINEST);
60 }
61
62 @Test
63 public void testIllegalArgs() throws Exception {
64
65 try {
66 new Command((String[]) null);
67 fail("Should have thrown IllegalArgumentException");
68 } catch (IllegalArgumentException iae) {
69 // good
70 }
71
72 try {
73 new Command(new String[] {"/bin/true", null}).execute();
74 fail("Should have thrown NullPointerException");
75 } catch (NullPointerException npe) {
76 // good
77 }
78
79 try {
80 new Command(new String[] {"foo"}).execute(null);
81 fail("Should have thrown NullPointerException");
82 } catch (NullPointerException npe) {
83 // good
84 }
85
86 }
87
88 @Test
89 public void testProcessBuilderConstructor() throws Exception {
90 String helloWorld = "Hello, world";
91 ProcessBuilder builder = new ProcessBuilder("/bin/echo", helloWorld);
92 byte[] stdout = new Command(builder).execute().getStdout();
93 assertEquals(helloWorld + '\n', new String(stdout, "UTF-8"));
94 }
95
96 @Test
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +000097 public void testGetters() {
98 final File workingDir = new File(".");
99 final Map<String,String> env = Collections.singletonMap("foo", "bar");
100 final String[] commandArgs = new String[] { "command" };
101 final Command command = new Command(commandArgs, env, workingDir);
102 assertArrayEquals(commandArgs, command.getCommandLineElements());
103 for (final String key : env.keySet()) {
Ulf Adams795895a2015-03-06 15:58:35 +0000104 assertThat(command.getEnvironmentVariables()).containsEntry(key, env.get(key));
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000105 }
106 assertEquals(workingDir, command.getWorkingDirectory());
107 }
108
109 // Platform-dependent tests ------------------------------------------------
110
111 @Test
112 public void testSimpleCommand() throws Exception {
113 final Command command = new Command(new String[] {"ls"});
114 final CommandResult result = command.execute();
115 assertTrue(result.getTerminationStatus().success());
Ulf Adams795895a2015-03-06 15:58:35 +0000116 assertEquals(0, result.getStderr().length);
117 assertThat(result.getStdout().length).isGreaterThan(0);
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000118 }
119
120 @Test
121 public void testArguments() throws Exception {
122 final Command command = new Command(new String[] {"echo", "foo"});
123 checkSuccess(command.execute(), "foo\n");
124 }
125
126 @Test
127 public void testEnvironment() throws Exception {
128 final Map<String,String> env = Collections.singletonMap("FOO", "BAR");
Han-Wen Nienhuysefe7f662015-02-16 13:34:57 +0000129 final Command command = new Command(new String[] {"/bin/sh", "-c", "echo $FOO"}, env,
130 null);
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000131 checkSuccess(command.execute(), "BAR\n");
132 }
133
134 @Test
135 public void testWorkingDir() throws Exception {
136 final Command command = new Command(new String[] {"pwd"}, null, new File("/"));
137 checkSuccess(command.execute(), "/\n");
138 }
139
140 @Test
141 public void testStdin() throws Exception {
142 final Command command = new Command(new String[] {"grep", "bar"});
143 checkSuccess(command.execute("foobarbaz".getBytes()), "foobarbaz\n");
144 }
145
146 @Test
147 public void testRawCommand() throws Exception {
148 final Command command = new Command(new String[] { "perl",
149 "-e",
150 "print 'a'x100000" });
151 final CommandResult result = command.execute();
152 assertTrue(result.getTerminationStatus().success());
Ulf Adams795895a2015-03-06 15:58:35 +0000153 assertEquals(0, result.getStderr().length);
154 assertThat(result.getStdout().length).isGreaterThan(0);
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000155 }
156
157 @Test
158 public void testRawCommandWithDir() throws Exception {
159 final Command command = new Command(new String[] { "pwd" },
160 null,
161 new File("/"));
162 final CommandResult result = command.execute();
163 checkSuccess(result, "/\n");
164 }
165
166 @Test
167 public void testHugeOutput() throws Exception {
168 final Command command = new Command(new String[] {"perl", "-e", "print 'a'x100000"});
169 final CommandResult result = command.execute();
170 assertTrue(result.getTerminationStatus().success());
171 assertEquals(0, result.getStderr().length);
172 assertEquals(100000, result.getStdout().length);
173 }
174
175 @Test
176 public void testIgnoreOutput() throws Exception {
177 final Command command = new Command(new String[] {"perl", "-e", "print 'a'x100000"});
178 final CommandResult result = command.execute(Command.NO_INPUT, null, true);
179 assertTrue(result.getTerminationStatus().success());
180 try {
181 result.getStdout();
182 fail("Should have thrown IllegalStateException");
183 } catch (IllegalStateException ise) {
184 // good
185 }
186 try {
187 result.getStderr();
188 fail("Should have thrown IllegalStateException");
189 } catch (IllegalStateException ise) {
190 // good
191 }
192 }
193
194 @Test
195 public void testNoStreamingInputForCat() throws Exception {
196 final Command command = new Command(new String[]{"/bin/cat"});
197 ByteArrayInputStream emptyInput = new ByteArrayInputStream(new byte[0]);
198 ByteArrayOutputStream out = new ByteArrayOutputStream();
199 ByteArrayOutputStream err = new ByteArrayOutputStream();
200 CommandResult result = command.execute(emptyInput,
201 Command.NO_OBSERVER, out, err);
202 assertTrue(result.getTerminationStatus().success());
Ulf Adams795895a2015-03-06 15:58:35 +0000203 assertThat(out.toString("UTF-8")).isEmpty();
204 assertThat(err.toString("UTF-8")).isEmpty();
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000205 }
206
207 @Test
208 public void testNoInputForCat() throws Exception {
209 final Command command = new Command(new String[]{"/bin/cat"});
210 CommandResult result = command.execute();
211 assertTrue(result.getTerminationStatus().success());
Ulf Adams795895a2015-03-06 15:58:35 +0000212 assertThat(new String(result.getStdout(), "UTF-8")).isEmpty();
213 assertThat(new String(result.getStderr(), "UTF-8")).isEmpty();
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000214 }
215
216 @Test
217 public void testProvidedOutputStreamCapturesHelloWorld() throws Exception {
218 String helloWorld = "Hello, world.";
219 final Command command = new Command(new String[]{"/bin/echo", helloWorld});
220 ByteArrayOutputStream stdOut = new ByteArrayOutputStream();
221 ByteArrayOutputStream stdErr = new ByteArrayOutputStream();
222 command.execute(Command.NO_INPUT, Command.NO_OBSERVER, stdOut, stdErr);
223 assertEquals(helloWorld + "\n", stdOut.toString("UTF-8"));
224 assertEquals(0, stdErr.toByteArray().length);
225 }
226
227 @Test
228 public void testAsynchronous() throws Exception {
229 final File tempFile = File.createTempFile("googlecron-test", "tmp");
230 tempFile.delete();
231 final Command command = new Command(new String[] {"touch", tempFile.getAbsolutePath()});
232 // Shouldn't throw any exceptions:
233 FutureCommandResult result =
234 command.executeAsynchronously(Command.NO_INPUT);
235 result.get();
236 assertTrue(tempFile.exists());
237 assertTrue(result.isDone());
238 tempFile.delete();
239 }
240
241 @Test
242 public void testAsynchronousWithKillable() throws Exception {
243 final Command command = new Command(new String[] {"sleep", "5"});
244 final SimpleKillableObserver observer = new SimpleKillableObserver();
245 FutureCommandResult result =
246 command.executeAsynchronously(Command.NO_INPUT, observer);
247 assertFalse(result.isDone());
248 observer.kill();
249 try {
250 result.get();
251 } catch (AbnormalTerminationException e) {
252 // Expects, but does not insist on termination with a signal.
253 }
254 assertTrue(result.isDone());
255 }
256
257 @Test
258 public void testAsynchronousWithOutputStreams() throws Exception {
259
260 final String helloWorld = "Hello, world.";
261 final Command command = new Command(new String[]{"/bin/echo", helloWorld});
262 final ByteArrayInputStream emptyInput =
263 new ByteArrayInputStream(new byte[0]);
264 final ByteArrayOutputStream stdOut = new ByteArrayOutputStream();
265 final ByteArrayOutputStream stdErr = new ByteArrayOutputStream();
266 FutureCommandResult result = command.executeAsynchronously(emptyInput,
267 Command.NO_OBSERVER,
268 stdOut,
269 stdErr);
270 result.get(); // Make sure the process actually finished
271 assertEquals(helloWorld + "\n", stdOut.toString("UTF-8"));
272 assertEquals(0, stdErr.toByteArray().length);
273 }
274
275 @Test
276 public void testSimpleKillableObserver() throws Exception {
277 final Command command = new Command(new String[] {"sleep", "5"});
278 final SimpleKillableObserver observer = new SimpleKillableObserver();
279 new Thread() {
280 @Override
281 public void run() {
282 try {
283 command.execute(Command.NO_INPUT, observer, true);
284 fail();
285 } catch (CommandException e) {
286 // Good.
Ulf Adams051256d2015-04-21 13:05:22 +0000287 checkCommandElements(e, "sleep", "5");
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000288 }
289 }
290 }.start();
Ulf Adams051256d2015-04-21 13:05:22 +0000291 // We're racing against the actual startup of the other command. Wait for 10ms so it can start.
292 Thread.sleep(10);
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000293 observer.kill();
294 }
295
296 @Test
297 public void testTimeout() throws Exception {
298 // Sleep for 3 seconds,
299 final Command command = new Command(new String[] {"sleep", "3"});
300 try {
301 // but timeout after 1 second
302 command.execute(Command.NO_INPUT, 1000L, false);
303 fail("Should have thrown AbnormalTerminationException");
304 } catch (AbnormalTerminationException ate) {
305 // good
306 checkCommandElements(ate, "sleep", "3");
307 checkATE(ate);
308 }
309 }
310
311 @Test
312 public void testTimeoutDoesntFire() throws Exception {
313 final Command command = new Command(new String[] {"cat"});
314 command.execute(new byte[]{'H', 'i', '!'}, 2000L, false);
315 }
316
317 @Test
318 public void testCommandDoesNotExist() throws Exception {
319 final Command command = new Command(new String[]{"thisisnotreal"});
320 try {
321 command.execute();
322 fail();
323 } catch (ExecFailedException e){
324 // Good.
325 checkCommandElements(e, "thisisnotreal");
326 }
327 }
328
329 @Test
330 public void testNoSuchCommand() throws Exception {
331 final Command command = new Command(new String[] {"thisisnotreal"});
332 try {
333 command.execute();
334 fail("Should have thrown ExecFailedException");
335 } catch (ExecFailedException expected) {
336 // good
337 }
338 }
339
340 @Test
341 public void testExitCodes() throws Exception {
342 // 0 => success
343 {
344 String args[] = { "/bin/sh", "-c", "exit 0" };
345 CommandResult result = new Command(args).execute();
346 TerminationStatus status = result.getTerminationStatus();
347 assertTrue(status.success());
348 assertTrue(status.exited());
349 assertEquals(0, status.getExitCode());
350 }
351
352 // Every exit value in range [1-255] is reported as such (except [129-191],
353 // which map to signals).
354 for (int exit : new int[] { 1, 2, 3, 127, 128, 192, 255 }) {
355 try {
356 String args[] = { "/bin/sh", "-c", "exit " + exit };
357 new Command(args).execute();
358 fail("Should have exited with status " + exit);
359 } catch (BadExitStatusException e) {
Ulf Adams795895a2015-03-06 15:58:35 +0000360 assertThat(e).hasMessage("Process exited with status " + exit);
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000361 checkCommandElements(e, "/bin/sh", "-c", "exit " + exit);
362 TerminationStatus status = e.getResult().getTerminationStatus();
363 assertFalse(status.success());
364 assertTrue(status.exited());
365 assertEquals(exit, status.getExitCode());
366 assertEquals("Exit " + exit , status.toShortString());
367 }
368 }
369
370 // negative exit values are modulo 256:
371 for (int exit : new int[] { -1, -2, -3 }) {
372 int expected = 256 + exit;
373 try {
Kristina Chodorow31ccc992015-04-10 19:10:59 +0000374 String args[] = { "/bin/bash", "-c", "exit " + exit };
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000375 new Command(args).execute();
376 fail("Should have exited with status " + expected);
377 } catch (BadExitStatusException e) {
Ulf Adams795895a2015-03-06 15:58:35 +0000378 assertThat(e).hasMessage("Process exited with status " + expected);
Kristina Chodorow31ccc992015-04-10 19:10:59 +0000379 checkCommandElements(e, "/bin/bash", "-c", "exit " + exit);
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000380 TerminationStatus status = e.getResult().getTerminationStatus();
381 assertFalse(status.success());
382 assertTrue(status.exited());
383 assertEquals(expected, status.getExitCode());
384 assertEquals("Exit " + expected, status.toShortString());
385 }
386 }
387 }
388
389 @Test
390 public void testFailedWithSignal() throws Exception {
391 // SIGHUP, SIGINT, SIGKILL, SIGTERM
392 for (int signal : new int[] { 1, 2, 9, 15 }) {
393 // Invoke a C++ program (killmyself.cc) that will die
394 // with the specified signal.
395 String killmyself = BlazeTestUtils.runfilesDir() + "/"
396 + TestConstants.JAVATESTS_ROOT
397 + "/com/google/devtools/build/lib/shell/killmyself";
398 try {
399 String args[] = { killmyself, "" + signal };
400 new Command(args).execute();
401 fail("Expected signal " + signal);
402 } catch (AbnormalTerminationException e) {
Ulf Adams795895a2015-03-06 15:58:35 +0000403 assertThat(e).hasMessage("Process terminated by signal " + signal);
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000404 checkCommandElements(e, killmyself, "" + signal);
405 TerminationStatus status = e.getResult().getTerminationStatus();
406 assertFalse(status.success());
407 assertFalse(status.exited());
408 assertEquals(signal, status.getTerminatingSignal());
409
410 switch (signal) {
411 case 1: assertEquals("Hangup", status.toShortString()); break;
412 case 2: assertEquals("Interrupt", status.toShortString()); break;
413 case 9: assertEquals("Killed", status.toShortString()); break;
414 case 15: assertEquals("Terminated", status.toShortString()); break;
415 }
416 }
417 }
418 }
419
420 @Test
421 public void testDestroy() throws Exception {
422
423 // Sleep for 10 seconds,
424 final Command command = new Command(new String[] {"sleep", "10"});
425
426 // but kill it after 1
427 final KillableObserver killer = new KillableObserver() {
428 @Override
429 public void startObserving(final Killable killable) {
430 final Thread t = new Thread() {
431 @Override
432 public void run() {
433 try {
434 Thread.sleep(1000L);
435 } catch (InterruptedException ie) {
436 // continue
437 }
438 killable.kill();
439 }
440 };
441 t.start();
442 }
443 @Override
444 public void stopObserving(final Killable killable) {
445 // do nothing
446 }
447 };
448
449 try {
450 command.execute(Command.NO_INPUT, killer, false);
451 fail("Should have thrown AbnormalTerminationException");
452 } catch (AbnormalTerminationException ate) {
453 // Good.
454 checkCommandElements(ate, "sleep", "10");
455 checkATE(ate);
456 }
457 }
458
459 @Test
460 public void testOnlyReadsPartialInput() throws Exception {
Han-Wen Nienhuys924daad2015-02-16 15:01:06 +0000461 // -c == --bytes, but -c also works on Darwin.
462 Command command = new Command(new String[] {"head", "-c", "500"});
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000463 OutputStream out = new ByteArrayOutputStream();
464 InputStream in = new InputStream() {
465
466 @Override
467 public int read() {
468 return 0; // write an unbounded amount
469 }
470
471 };
472
473 CommandResult result = command.execute(in, Command.NO_OBSERVER, out, out);
474 TerminationStatus status = result.getTerminationStatus();
475 assertTrue(status.success());
476 }
477
478 @Test
479 public void testFlushing() throws Exception {
480 final Command command = new Command(
Han-Wen Nienhuys8dff4292015-02-16 14:38:06 +0000481 // On darwin, /bin/sh does not support -n for the echo builtin.
482 new String[] {"/bin/bash", "-c", "echo -n Foo; sleep 0.1; echo Bar"});
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000483 // We run this command, passing in a special output stream
484 // that records when each flush() occurs.
485 // We test that a flush occurs after writing "Foo"
486 // and that another flush occurs after writing "Bar\n".
487 final boolean[] flushed = new boolean[8];
488 OutputStream out = new OutputStream() {
489 private int count = 0;
490 @Override
491 public void write(int b) throws IOException {
492 count++;
493 }
494 @Override
495 public void flush() throws IOException {
496 flushed[count] = true;
497 }
498 };
499 command.execute(Command.NO_INPUT, Command.NO_OBSERVER, out, System.err);
500 assertFalse(flushed[0]);
501 assertFalse(flushed[1]); // 'F'
502 assertFalse(flushed[2]); // 'o'
503 assertTrue(flushed[3]); // 'o' <- expect flush here.
504 assertFalse(flushed[4]); // 'B'
505 assertFalse(flushed[5]); // 'a'
506 assertFalse(flushed[6]); // 'r'
507 assertTrue(flushed[7]); // '\n'
508 }
509
510 // See also InterruptibleTest.
511 @Test
512 public void testInterrupt() throws Exception {
513
514 // Sleep for 10 seconds,
515 final Command command = new Command(new String[] {"sleep", "10"});
516 // Easy but hacky way to let this thread "return" a result to this method
517 final CommandResult[] resultContainer = new CommandResult[1];
518 final Thread commandThread = new Thread() {
519 @Override
520 public void run() {
521 try {
522 resultContainer[0] = command.execute();
523 } catch (CommandException ce) {
524 fail(ce.toString());
525 }
526 }
527 };
528 commandThread.start();
529
530 Thread.sleep(1000L);
531
532 // but interrupt it after 1
533 commandThread.interrupt();
534
535 // should continue to wait and exit normally
536 commandThread.join();
537
538 final CommandResult result = resultContainer[0];
539 assertTrue(result.getTerminationStatus().success());
Ulf Adams795895a2015-03-06 15:58:35 +0000540 assertEquals(0, result.getStderr().length);
541 assertEquals(0, result.getStdout().length);
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000542 }
543
544 @Test
545 public void testOutputStreamThrowsException() throws Exception {
546 OutputStream out = new OutputStream () {
547 @Override
548 public void write(int b) throws IOException {
549 throw new IOException();
550 }
551 };
552 Command command = new Command(new String[] {"/bin/echo", "foo"});
553 try {
554 command.execute(Command.NO_INPUT, Command.NO_OBSERVER, out, out);
555 fail();
556 } catch (AbnormalTerminationException e) {
557 // Good.
558 checkCommandElements(e, "/bin/echo", "foo");
Ulf Adams795895a2015-03-06 15:58:35 +0000559 assertThat(e).hasMessage("java.io.IOException");
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000560 }
561 }
562
563 @Test
564 public void testOutputStreamThrowsExceptionAndCommandFails()
565 throws Exception {
566 OutputStream out = new OutputStream () {
567 @Override
568 public void write(int b) throws IOException {
569 throw new IOException();
570 }
571 };
572 Command command = new Command(new String[] {"cat", "/dev/thisisnotreal"});
573 try {
574 command.execute(Command.NO_INPUT, Command.NO_OBSERVER, out, out);
575 fail();
576 } catch (AbnormalTerminationException e) {
577 checkCommandElements(e, "cat", "/dev/thisisnotreal");
578 TerminationStatus status = e.getResult().getTerminationStatus();
579 // Subprocess either gets a SIGPIPE trying to write to our output stream,
580 // or it exits with failure. Both are observed, nondetermistically.
581 assertTrue(status.exited()
582 ? status.getExitCode() == 1
583 : status.getTerminatingSignal() == 13);
584 assertTrue(e.getMessage(),
585 e.getMessage().endsWith("also encountered an error while attempting "
586 + "to retrieve output"));
587 }
588 }
589
590 /**
591 * Helper to test KillableObserver classes.
592 */
593 private class KillableTester implements Killable {
594 private boolean isKilled = false;
595 private boolean timedOut = false;
596 @Override
597 public synchronized void kill() {
598 isKilled = true;
599 notifyAll();
600 }
601 public synchronized boolean getIsKilled() {
602 return isKilled;
603 }
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000604 /**
605 * Wait for a specified time or until the {@link #kill()} is called.
606 */
607 public synchronized void sleepUntilKilled(final long timeoutMS) {
608 long nowTime = System.currentTimeMillis();
609 long endTime = nowTime + timeoutMS;
610 while (!isKilled && !timedOut) {
611 long waitTime = endTime - nowTime;
612 if (waitTime <= 0) {
613 // Process has timed out, needs killing.
614 timedOut = true;
615 break;
616 }
617 try {
618 wait(waitTime); // Suffers "spurious wakeup", hence the while() loop.
619 nowTime = System.currentTimeMillis();
620 } catch (InterruptedException exception) {
621 break;
622 }
623 }
624 }
625 }
626
627 @Test
628 public void testTimeOutKillableObserverNoKill() throws Exception {
629 KillableTester killable = new KillableTester();
630 TimeoutKillableObserver observer = new TimeoutKillableObserver(LONG_TIME);
631 observer.startObserving(killable);
632 observer.stopObserving(killable);
633 assertFalse(observer.hasTimedOut());
634 assertFalse(killable.getIsKilled());
635 }
636
637 @Test
638 public void testTimeOutKillableObserverNoKillWithDelay() throws Exception {
639 KillableTester killable = new KillableTester();
640 TimeoutKillableObserver observer = new TimeoutKillableObserver(LONG_TIME);
641 observer.startObserving(killable);
642 killable.sleepUntilKilled(SHORT_TIME);
643 observer.stopObserving(killable);
644 assertFalse(observer.hasTimedOut());
645 assertFalse(killable.getIsKilled());
646 }
647
648 @Test
649 public void testTimeOutKillableObserverWithKill() throws Exception {
650 KillableTester killable = new KillableTester();
651 TimeoutKillableObserver observer = new TimeoutKillableObserver(SHORT_TIME);
652 observer.startObserving(killable);
653 killable.sleepUntilKilled(LONG_TIME);
654 observer.stopObserving(killable);
655 assertTrue(observer.hasTimedOut());
656 assertTrue(killable.getIsKilled());
657 }
658
659 @Test
660 public void testTimeOutKillableObserverWithKillZeroMillis() throws Exception {
661 KillableTester killable = new KillableTester();
662 TimeoutKillableObserver observer = new TimeoutKillableObserver(0);
663 observer.startObserving(killable);
664 killable.sleepUntilKilled(LONG_TIME);
665 observer.stopObserving(killable);
666 assertTrue(observer.hasTimedOut());
667 assertTrue(killable.getIsKilled());
668 }
669
670 private static void checkCommandElements(CommandException e,
671 String... expected) {
672 assertArrayEquals(expected, e.getCommand().getCommandLineElements());
673 }
674
675 private static void checkATE(final AbnormalTerminationException ate) {
676 final CommandResult result = ate.getResult();
677 assertFalse(result.getTerminationStatus().success());
678 }
679
680 private static void checkSuccess(final CommandResult result,
681 final String expectedOutput) {
682 assertTrue(result.getTerminationStatus().success());
Ulf Adams795895a2015-03-06 15:58:35 +0000683 assertEquals(0, result.getStderr().length);
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000684 assertEquals(expectedOutput, new String(result.getStdout()));
685 }
Dmitry Lomov8efc3ef2016-02-17 09:50:03 +0000686
687 @Test
688 public void testRelativePath() throws Exception {
689 Command command = new Command(new String[]{"relative/path/to/binary"},
690 ImmutableMap.<String, String>of(),
691 new File("/working/directory"));
692 assertThat(command.getCommandLineElements()[0])
693 .isEqualTo("/working/directory/relative/path/to/binary");
694 }
Han-Wen Nienhuysb0e387b2015-02-12 13:27:06 +0000695}