blob: 190bc2e3eed41c4364d6e858e75aca6b0c504cec [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.util.IRunUtil.IRunnableResult;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
/** Longer running tests for {@link RunUtilFuncTest} */
@RunWith(JUnit4.class)
public class RunUtilFuncTest {
private static final long VERY_SHORT_TIMEOUT_MS = 10L;
private static final long SHORT_TIMEOUT_MS = 500L;
private static final long LONG_TIMEOUT_MS = 5000L;
private abstract class MyRunnable implements IRunUtil.IRunnableResult {
boolean mCanceled = false;
@Override
public void cancel() {
mCanceled = true;
}
}
/** Test timeout case for {@link RunUtil#runTimed(long, IRunnableResult, boolean)}. */
@Test
public void testRunTimed_timeout() {
MyRunnable mockRunnable = new MyRunnable() {
@Override
public boolean run() {
try {
Thread.sleep(SHORT_TIMEOUT_MS * 5);
} catch (InterruptedException e) {
// ignore
}
return true;
}
};
assertEquals(CommandStatus.TIMED_OUT, RunUtil.getDefault().runTimed(SHORT_TIMEOUT_MS,
mockRunnable, true));
assertTrue(mockRunnable.mCanceled);
}
/**
* Test method for {@link RunUtil#runTimedRetry(long, long, int, IRunnableResult)}. Verify that
* multiple attempts are made.
*/
@Test
public void testRunTimedRetry() {
final int maxAttempts = 5;
IRunUtil.IRunnableResult mockRunnable = new IRunUtil.IRunnableResult() {
int attempts = 0;
@Override
public boolean run() {
attempts++;
return attempts == maxAttempts;
}
@Override
public void cancel() {
// ignore
}
};
final long startTime = System.currentTimeMillis();
assertTrue(RunUtil.getDefault().runTimedRetry(100, SHORT_TIMEOUT_MS, maxAttempts,
mockRunnable));
final long actualTime = System.currentTimeMillis() - startTime;
// assert that time actually taken is at least, and no more than twice expected
final long expectedPollTime = SHORT_TIMEOUT_MS * (maxAttempts-1);
assertTrue(String.format("Expected poll time %d, got %d", expectedPollTime, actualTime),
expectedPollTime <= actualTime && actualTime <= (2 * expectedPollTime));
}
/**
* Test timeout case for {@link RunUtil#runTimedCmd(long, String...)} and ensure we consistently
* get the right stdout for a fast running command.
*/
@Test
public void testRunTimedCmd_repeatedOutput() {
for (int i = 0; i < 1000; i++) {
CommandResult result =
RunUtil.getDefault().runTimedCmd(LONG_TIMEOUT_MS, "echo", "hello");
assertTrue("Failed at iteration " + i,
CommandStatus.SUCCESS.equals(result.getStatus()));
CLog.d(result.getStdout());
assertTrue(result.getStdout().trim().equals("hello"));
}
}
/**
* Test that that running a command with a 0 timeout results in no timeout being applied to it.
*/
@Test
public void testRunTimedCmd_noTimeout() {
// When there is no timeout, max_poll interval will be 30sec so we need a test with more
// than 30sec
CommandResult result = RunUtil.getDefault().runTimedCmd(0L, "sleep", "35");
assertTrue(CommandStatus.SUCCESS.equals(result.getStatus()));
assertTrue(result.getStdout().isEmpty());
}
/**
* Test case for {@link RunUtil#runTimedCmd(long, String...)} for a command that produces a
* large amount of output
*
* @throws IOException
*/
@Test
public void testRunTimedCmd_largeOutput() throws IOException {
// 1M chars
int dataSize = 1000000;
File f = FileUtil.createTempFile("foo", ".txt");
Writer s = null;
try {
s = new BufferedWriter(new FileWriter(f));
for (int i=0; i < dataSize; i++) {
s.write('a');
}
s.close();
// FIXME: this test case is not ideal, as it will only work on platforms that support
// cat command.
CommandResult result =
RunUtil.getDefault()
.runTimedCmd(3 * LONG_TIMEOUT_MS, "cat", f.getAbsolutePath());
assertEquals(
String.format(
"We expected SUCCESS but got %s, with stdout: '%s'\nstderr: %s",
result.getStatus(), result.getStdout(), result.getStderr()),
CommandStatus.SUCCESS,
result.getStatus());
assertTrue(result.getStdout().length() == dataSize);
} finally {
f.delete();
StreamUtil.close(s);
}
}
/** Test case for {@link RunUtil#unsetEnvVariable(String key)} */
@Test
public void testUnsetEnvVariable() {
RunUtil runUtil = new RunUtil();
runUtil.setEnvVariable("bar", "foo");
// FIXME: this test case is not ideal, as it will only work on platforms that support
// printenv
CommandResult result =
runUtil.runTimedCmdRetry(SHORT_TIMEOUT_MS, SHORT_TIMEOUT_MS, 3, "printenv", "bar");
assertEquals(
String.format(
"We expected SUCCESS but got %s, with stdout: '%s'\nstderr: %s",
result.getStatus(), result.getStdout(), result.getStderr()),
CommandStatus.SUCCESS,
result.getStatus());
assertEquals("foo", result.getStdout().trim());
// remove env variable
runUtil.unsetEnvVariable("bar");
// printenv with non-exist variable will fail
result = runUtil.runTimedCmd(SHORT_TIMEOUT_MS, "printenv", "bar");
assertEquals(CommandStatus.FAILED, result.getStatus());
assertEquals("", result.getStdout().trim());
}
/**
* Test that {@link RunUtil#runTimedCmd(long, String[])} returns timeout when the command is too
* short and also clean up all its thread.
*/
@Test
public void testRunTimedCmd_timeout() throws InterruptedException {
RunUtil runUtil = new RunUtil();
String[] command = {"sleep", "10000"};
CommandResult result = runUtil.runTimedCmd(VERY_SHORT_TIMEOUT_MS, command);
assertEquals(
String.format(
"We expected TIMED_OUT but got %s, with stdout: '%s'\nstderr: %s",
result.getStatus(), result.getStdout(), result.getStderr()),
CommandStatus.TIMED_OUT,
result.getStatus());
assertEquals("", result.getStdout());
assertEquals("", result.getStderr());
// We give it some times to clean up the process
Thread.sleep(5000);
Thread[] list = new Thread[Thread.currentThread().getThreadGroup().activeCount()];
Thread.currentThread().getThreadGroup().enumerate(list);
// Ensure the list of Threads does not contain the RunnableNotifier or InheritIO threads.
for (Thread t : list) {
assertFalse(
String.format("We found a thread: %s", t.getName()),
t.getName().contains(RunUtil.RUNNABLE_NOTIFIER_NAME));
assertFalse(
String.format("We found a thread: %s", t.getName()),
t.getName().contains(RunUtil.INHERITIO_PREFIX));
}
}
/** Test running a command with redirecting input from a file. */
@Test
public void testRunTimedCmd_WithInputRedirect() throws IOException {
File inputRedirect = FileUtil.createTempFile("input_redirect", ".txt");
try {
FileUtil.writeToFile("TEST_INPUT", inputRedirect);
CommandResult result =
RunUtil.getDefault()
.runTimedCmdWithInputRedirect(SHORT_TIMEOUT_MS, inputRedirect, "cat");
assertTrue(CommandStatus.SUCCESS.equals(result.getStatus()));
assertEquals("TEST_INPUT", result.getStdout());
} finally {
FileUtil.deleteFile(inputRedirect);
}
}
/** Test running a command with redirecting output to a file. */
@Test
public void testRunTimedCmd_WithOutputRedirect() throws IOException {
File outputRedirect = FileUtil.createTempFile("output_redirect", ".txt");
FileOutputStream outputStream = new FileOutputStream(outputRedirect);
try {
CommandResult result =
RunUtil.getDefault()
.runTimedCmd(
SHORT_TIMEOUT_MS,
outputStream,
/* stderr= */ null,
"echo",
"TEST_OUTPUT");
assertTrue(CommandStatus.SUCCESS.equals(result.getStatus()));
assertEquals("TEST_OUTPUT\n", FileUtil.readStringFromFile(outputRedirect));
} finally {
FileUtil.deleteFile(outputRedirect);
outputStream.close();
}
}
}