1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.util; 17 18 import com.android.tradefed.log.LogUtil.CLog; 19 import com.android.tradefed.util.IRunUtil.IRunnableResult; 20 21 import junit.framework.TestCase; 22 23 import java.io.BufferedWriter; 24 import java.io.File; 25 import java.io.FileWriter; 26 import java.io.IOException; 27 import java.io.Writer; 28 29 /** 30 * Longer running tests for {@link RunUtilFuncTest} 31 */ 32 public class RunUtilFuncTest extends TestCase { 33 34 private static final long VERY_SHORT_TIMEOUT_MS = 10l; 35 private static final long SHORT_TIMEOUT_MS = 500l; 36 private static final long LONG_TIMEOUT_MS = 5000l; 37 38 private abstract class MyRunnable implements IRunUtil.IRunnableResult { 39 boolean mCanceled = false; 40 41 @Override cancel()42 public void cancel() { 43 mCanceled = true; 44 } 45 } 46 47 /** 48 * Test timeout case for {@link RunUtil#runTimed(long, IRunnableResult, boolean)}. 49 */ testRunTimed_timeout()50 public void testRunTimed_timeout() { 51 MyRunnable mockRunnable = new MyRunnable() { 52 @Override 53 public boolean run() { 54 try { 55 Thread.sleep(SHORT_TIMEOUT_MS * 5); 56 } catch (InterruptedException e) { 57 // ignore 58 } 59 return true; 60 } 61 }; 62 assertEquals(CommandStatus.TIMED_OUT, RunUtil.getDefault().runTimed(SHORT_TIMEOUT_MS, 63 mockRunnable, true)); 64 assertTrue(mockRunnable.mCanceled); 65 } 66 67 /** 68 * Test method for {@link RunUtil#runTimedRetry(long, long, int, IRunnableResult)}. 69 * Verify that multiple attempts are made. 70 */ testRunTimedRetry()71 public void testRunTimedRetry() { 72 final int maxAttempts = 5; 73 IRunUtil.IRunnableResult mockRunnable = new IRunUtil.IRunnableResult() { 74 int attempts = 0; 75 @Override 76 public boolean run() { 77 attempts++; 78 return attempts == maxAttempts; 79 } 80 @Override 81 public void cancel() { 82 // ignore 83 } 84 }; 85 final long startTime = System.currentTimeMillis(); 86 assertTrue(RunUtil.getDefault().runTimedRetry(100, SHORT_TIMEOUT_MS, maxAttempts, 87 mockRunnable)); 88 final long actualTime = System.currentTimeMillis() - startTime; 89 // assert that time actually taken is at least, and no more than twice expected 90 final long expectedPollTime = SHORT_TIMEOUT_MS * (maxAttempts-1); 91 assertTrue(String.format("Expected poll time %d, got %d", expectedPollTime, actualTime), 92 expectedPollTime <= actualTime && actualTime <= (2 * expectedPollTime)); 93 } 94 95 /** 96 * Test timeout case for {@link RunUtil#runTimedCmd(long, String...)} and ensure we 97 * consistently get the right stdout for a fast running command. 98 */ testRunTimedCmd_repeatedOutput()99 public void testRunTimedCmd_repeatedOutput() { 100 for (int i = 0; i < 1000; i++) { 101 CommandResult result = 102 RunUtil.getDefault().runTimedCmd(LONG_TIMEOUT_MS, "echo", "hello"); 103 assertTrue("Failed at iteration " + i, 104 CommandStatus.SUCCESS.equals(result.getStatus())); 105 CLog.d(result.getStdout()); 106 assertTrue(result.getStdout().trim().equals("hello")); 107 } 108 } 109 110 /** 111 * Test that that running a command with a 0 timeout results in no timeout being applied to it. 112 */ testRunTimedCmd_noTimeout()113 public void testRunTimedCmd_noTimeout() { 114 // When there is no timeout, max_poll interval will be 30sec so we need a test with more 115 // than 30sec 116 CommandResult result = RunUtil.getDefault().runTimedCmd(0l, "sleep", "35"); 117 assertTrue(CommandStatus.SUCCESS.equals(result.getStatus())); 118 assertTrue(result.getStdout().isEmpty()); 119 } 120 121 /** 122 * Test case for {@link RunUtil#runTimedCmd(long, String...)} for a command that produces 123 * a large amount of output 124 * @throws IOException 125 */ testRunTimedCmd_largeOutput()126 public void testRunTimedCmd_largeOutput() throws IOException { 127 // 1M chars 128 int dataSize = 1000000; 129 File f = FileUtil.createTempFile("foo", ".txt"); 130 Writer s = null; 131 try { 132 s = new BufferedWriter(new FileWriter(f)); 133 for (int i=0; i < dataSize; i++) { 134 s.write('a'); 135 } 136 s.close(); 137 138 // FIXME: this test case is not ideal, as it will only work on platforms that support 139 // cat command. 140 CommandResult result = 141 RunUtil.getDefault() 142 .runTimedCmd(3 * LONG_TIMEOUT_MS, "cat", f.getAbsolutePath()); 143 assertEquals( 144 String.format( 145 "We expected SUCCESS but got %s, with stdout: '%s'\nstderr: %s", 146 result.getStatus(), result.getStdout(), result.getStderr()), 147 CommandStatus.SUCCESS, 148 result.getStatus()); 149 assertTrue(result.getStdout().length() == dataSize); 150 } finally { 151 f.delete(); 152 StreamUtil.close(s); 153 } 154 } 155 156 /** 157 * Test case for {@link RunUtil#unsetEnvVariable(String key)} 158 */ testUnsetEnvVariable()159 public void testUnsetEnvVariable() { 160 RunUtil runUtil = new RunUtil(); 161 runUtil.setEnvVariable("bar", "foo"); 162 // FIXME: this test case is not ideal, as it will only work on platforms that support 163 // printenv 164 CommandResult result = 165 runUtil.runTimedCmdRetry(SHORT_TIMEOUT_MS, SHORT_TIMEOUT_MS, 3, "printenv", "bar"); 166 assertEquals( 167 String.format( 168 "We expected SUCCESS but got %s, with stdout: '%s'\nstderr: %s", 169 result.getStatus(), result.getStdout(), result.getStderr()), 170 CommandStatus.SUCCESS, 171 result.getStatus()); 172 assertEquals("foo", result.getStdout().trim()); 173 174 // remove env variable 175 runUtil.unsetEnvVariable("bar"); 176 // printenv with non-exist variable will fail 177 result = runUtil.runTimedCmd(SHORT_TIMEOUT_MS, "printenv", "bar"); 178 assertEquals(CommandStatus.FAILED, result.getStatus()); 179 assertEquals("", result.getStdout().trim()); 180 } 181 182 /** 183 * Test that {@link RunUtil#runTimedCmd(long, String[])} returns timeout when the command is too 184 * short and also clean up all its thread. 185 */ testRunTimedCmd_timeout()186 public void testRunTimedCmd_timeout() throws InterruptedException { 187 RunUtil runUtil = new RunUtil(); 188 String[] command = {"sleep", "10000"}; 189 CommandResult result = runUtil.runTimedCmd(VERY_SHORT_TIMEOUT_MS, command); 190 assertEquals( 191 String.format( 192 "We expected TIMED_OUT but got %s, with stdout: '%s'\nstderr: %s", 193 result.getStatus(), result.getStdout(), result.getStderr()), 194 CommandStatus.TIMED_OUT, 195 result.getStatus()); 196 assertEquals("", result.getStdout()); 197 assertEquals("", result.getStderr()); 198 // We give it some times to clean up the process 199 Thread.sleep(5000); 200 Thread[] list = new Thread[Thread.currentThread().getThreadGroup().activeCount()]; 201 Thread.currentThread().getThreadGroup().enumerate(list); 202 // Ensure the list of Threads does not contain the RunnableNotifier or InheritIO threads. 203 for (Thread t : list) { 204 assertFalse( 205 String.format("We found a thread: %s", t.getName()), 206 t.getName().contains(RunUtil.RUNNABLE_NOTIFIER_NAME)); 207 assertFalse( 208 String.format("We found a thread: %s", t.getName()), 209 t.getName().contains(RunUtil.INHERITIO_PREFIX)); 210 } 211 } 212 } 213