Home | History | Annotate | Download | only in util
      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
     42         public void cancel() {
     43             mCanceled = true;
     44         }
     45     }
     46 
     47     /**
     48      * Test timeout case for {@link RunUtil#runTimed(long, IRunnableResult, boolean)}.
     49      */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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