Home | History | Annotate | Download | only in command
      1 /*
      2  * Copyright (C) 2016 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.command;
     17 
     18 import static org.junit.Assert.assertEquals;
     19 import static org.junit.Assert.assertNull;
     20 import static org.junit.Assert.assertTrue;
     21 import static org.mockito.Mockito.doNothing;
     22 import static org.mockito.Mockito.doReturn;
     23 
     24 import com.android.tradefed.command.CommandRunner.ExitCode;
     25 import com.android.tradefed.config.ConfigurationException;
     26 import com.android.tradefed.config.GlobalConfiguration;
     27 import com.android.tradefed.device.MockDeviceManager;
     28 import com.android.tradefed.util.FileUtil;
     29 
     30 import org.junit.After;
     31 import org.junit.Before;
     32 import org.junit.Test;
     33 import org.junit.runner.RunWith;
     34 import org.junit.runners.JUnit4;
     35 import org.mockito.Mockito;
     36 
     37 import java.io.ByteArrayOutputStream;
     38 import java.io.File;
     39 import java.io.PrintWriter;
     40 
     41 /**
     42  * Unit tests for {@link CommandRunner}. Always attempt to run on null-device (-n) to avoid hanging
     43  * if no physical device are available.
     44  */
     45 @RunWith(JUnit4.class)
     46 public class CommandRunnerTest {
     47 
     48     private static final String FAKE_CONFIG = "doesnotexit";
     49     private String mStackTraceOutput = null;
     50     private ICommandScheduler mMockScheduler;
     51 
     52 
     53     private static final String EMPTY_CONF_CONTENT =
     54             "<configuration description=\"Empty Config\" />";
     55     private File mConfig;
     56     private File mLogDir;
     57 
     58     @Before
     59     public void setUp() throws Exception {
     60         mStackTraceOutput = null;
     61         mConfig = FileUtil.createTempFile("empty", ".xml");
     62         FileUtil.writeToFile(EMPTY_CONF_CONTENT, mConfig);
     63         mLogDir = FileUtil.createTempDir("command-runner-unit-test");
     64         mMockScheduler =
     65                 new CommandScheduler() {
     66                     @Override
     67                     protected void initLogging() {}
     68 
     69                     @Override
     70                     protected void cleanUp() {}
     71 
     72                     @Override
     73                     void initDeviceManager() {
     74                         try {
     75                             super.initDeviceManager();
     76                         } catch (IllegalStateException e) {
     77                             // ignore re-init
     78                         }
     79                     }
     80                 };
     81     }
     82 
     83     @After
     84     public void tearDown() {
     85         GlobalConfiguration.getInstance()
     86                 .getCommandScheduler()
     87                 .setLastInvocationExitCode(ExitCode.NO_ERROR, null);
     88         FileUtil.deleteFile(mConfig);
     89         FileUtil.recursiveDelete(mLogDir);
     90     }
     91 
     92     private class TestableCommandRunner extends CommandRunner {
     93 
     94         @Override
     95         void initGlobalConfig(String[] args) throws ConfigurationException {
     96             try {
     97                 GlobalConfiguration.createGlobalConfiguration(args);
     98             } catch (IllegalStateException e) {
     99                 // ignore re-init.
    100             }
    101         }
    102 
    103         @Override
    104         ICommandScheduler getCommandScheduler() {
    105             return mMockScheduler;
    106         }
    107 
    108         /** We capture the stack trace if any. */
    109         @Override
    110         void printStackTrace(Throwable e) {
    111             ByteArrayOutputStream out = new ByteArrayOutputStream();
    112             PrintWriter pw = new PrintWriter(out);
    113             e.printStackTrace(pw);
    114             pw.flush();
    115             mStackTraceOutput = out.toString();
    116         }
    117     }
    118 
    119     /**
    120      * Run with a known empty config, should always pass.
    121      */
    122     @Test
    123     public void testRun_noError() throws Exception {
    124         mStackTraceOutput = null;
    125         CommandRunner mRunner = new TestableCommandRunner();
    126         String[] args = {
    127             mConfig.getAbsolutePath(),
    128             "-n",
    129             "--no-return-null",
    130             "--no-throw-build-error",
    131             "--log-file-path",
    132             mLogDir.getAbsolutePath()
    133         };
    134         mRunner.run(args);
    135         assertEquals(0, mRunner.getErrorCode().getCodeValue());
    136         assertNull(mStackTraceOutput);
    137     }
    138 
    139     /**
    140      * Run with a known empty config but fake a device unresponsive.
    141      */
    142     @Test
    143     public void testRun_deviceUnresponsive() {
    144         CommandRunner mRunner = new TestableCommandRunner();
    145         String[] args = {
    146             mConfig.getAbsolutePath(),
    147             "-n",
    148             "--test-throw-unresponsive",
    149             "--log-file-path",
    150             mLogDir.getAbsolutePath()
    151         };
    152         mRunner.run(args);
    153         assertEquals(ExitCode.DEVICE_UNRESPONSIVE, mRunner.getErrorCode());
    154         assertTrue(
    155                 String.format("%s does not contains the expected output", mStackTraceOutput),
    156                 mStackTraceOutput.contains(
    157                         "com.android.tradefed.device.DeviceUnresponsiveException: "
    158                                 + "StubTest DeviceUnresponsiveException"));
    159     }
    160 
    161     /**
    162      * Run with a known empty config but fake a device unavailable.
    163      */
    164     @Test
    165     public void testRun_deviceUnavailable() {
    166         CommandRunner mRunner = new TestableCommandRunner();
    167         String[] args = {
    168             mConfig.getAbsolutePath(),
    169             "-n",
    170             "--test-throw-not-available",
    171             "--log-file-path",
    172             mLogDir.getAbsolutePath()
    173         };
    174         mRunner.run(args);
    175         assertEquals(ExitCode.DEVICE_UNAVAILABLE, mRunner.getErrorCode());
    176         assertTrue(
    177                 String.format("%s does not contains the expected output", mStackTraceOutput),
    178                 mStackTraceOutput.contains(
    179                         "com.android.tradefed.device.DeviceNotAvailableException: "
    180                                 + "StubTest DeviceNotAvailableException"));
    181     }
    182 
    183     /**
    184      * Run with a known empty config but a throwable exception is caught.
    185      */
    186     @Test
    187     public void testRun_throwable() {
    188         CommandRunner mRunner = new TestableCommandRunner();
    189         String[] args = {
    190             mConfig.getAbsolutePath(),
    191             "-n",
    192             "--test-throw-runtime",
    193             "--log-file-path",
    194             mLogDir.getAbsolutePath()
    195         };
    196         mRunner.run(args);
    197         assertEquals(ExitCode.THROWABLE_EXCEPTION, mRunner.getErrorCode());
    198         assertTrue(
    199                 String.format("%s does not contains the expected output", mStackTraceOutput),
    200                 mStackTraceOutput.contains(
    201                         "java.lang.RuntimeException: StubTest RuntimeException"));
    202     }
    203 
    204     /**
    205      * Run with a non existant config and expect a configuration exception because of it.
    206      */
    207     @Test
    208     public void testRun_ConfigError() {
    209         String[] args = {FAKE_CONFIG};
    210         CommandRunner mRunner = new TestableCommandRunner();
    211         mRunner.run(args);
    212         assertEquals(ExitCode.CONFIG_EXCEPTION, mRunner.getErrorCode());
    213         assertTrue(
    214                 "Stack does not contain expected message: " + mStackTraceOutput,
    215                 mStackTraceOutput.contains(FAKE_CONFIG));
    216     }
    217 
    218     /** Test that if the device is not allocated after a timeout, we throw a NoDeviceException. */
    219     @Test
    220     public void testRun_noDevice() throws Exception {
    221         CommandScheduler mockScheduler = Mockito.spy(CommandScheduler.class);
    222         CommandRunner mRunner =
    223                 new TestableCommandRunner() {
    224                     @Override
    225                     long getCheckDeviceTimeout() {
    226                         return 200l;
    227                     }
    228 
    229                     @Override
    230                     ICommandScheduler getCommandScheduler() {
    231                         return mockScheduler;
    232                     }
    233                 };
    234         String[] args = {
    235             mConfig.getAbsolutePath(),
    236             "-s",
    237             "impossibleSerialThatWillNotBeFound",
    238             "--log-file-path",
    239             mLogDir.getAbsolutePath()
    240         };
    241         doNothing().when(mockScheduler).initDeviceManager();
    242         doReturn(new MockDeviceManager(1)).when(mockScheduler).getDeviceManager();
    243         doNothing().when(mockScheduler).shutdownOnEmpty();
    244         doNothing().when(mockScheduler).initLogging();
    245         doNothing().when(mockScheduler).cleanUp();
    246         mRunner.run(args);
    247         Mockito.verify(mockScheduler).shutdownOnEmpty();
    248         mockScheduler.join(5000);
    249         assertEquals(ExitCode.NO_DEVICE_ALLOCATED, mRunner.getErrorCode());
    250         assertTrue(
    251                 String.format("%s does not contains the expected output", mStackTraceOutput),
    252                 mStackTraceOutput.contains(
    253                         "com.android.tradefed.device.NoDeviceException: No device was allocated "
    254                                 + "for the command."));
    255     }
    256 }
    257