Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2018 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 static org.junit.Assert.assertEquals;
     19 import static org.junit.Assert.assertNotEquals;
     20 import static org.junit.Assert.fail;
     21 
     22 import com.android.tradefed.build.IBuildInfo;
     23 import com.android.tradefed.build.IFolderBuildInfo;
     24 import com.android.tradefed.log.LogUtil.CLog;
     25 import com.android.tradefed.util.CommandResult;
     26 import com.android.tradefed.util.CommandStatus;
     27 import com.android.tradefed.util.FileUtil;
     28 import com.android.tradefed.util.IRunUtil;
     29 import com.android.tradefed.util.ProcessHelper;
     30 import com.android.tradefed.util.RunInterruptedException;
     31 import com.android.tradefed.util.VtsPythonRunnerHelper;
     32 import java.io.File;
     33 import java.io.IOException;
     34 import org.easymock.EasyMock;
     35 import org.junit.Before;
     36 import org.junit.Test;
     37 import org.junit.runner.RunWith;
     38 import org.junit.runners.JUnit4;
     39 
     40 /**
     41  * Unit tests for {@link VtsPythonRunnerHelper}.
     42  */
     43 @RunWith(JUnit4.class)
     44 public class VtsPythonRunnerHelperTest {
     45     private static final String OS_NAME = VtsPythonRunnerHelper.OS_NAME;
     46     private static final String WINDOWS = VtsPythonRunnerHelper.WINDOWS;
     47     private static final String VTS = VtsPythonRunnerHelper.VTS;
     48     private static final String PYTHONPATH = VtsPythonRunnerHelper.PYTHONPATH;
     49     private static final String VIRTUAL_ENV_PATH = VtsPythonRunnerHelper.VIRTUAL_ENV_PATH;
     50     private static final String ANDROID_BUILD_TOP = VtsPythonRunnerHelper.ANDROID_BUILD_TOP;
     51     private static final String ALT_HOST_TESTCASE_DIR = "ANDROID_HOST_OUT_TESTCASES";
     52     private static final String LINUX = "Linux";
     53     private static final String[] mPythonCmd = {"python"};
     54     private static final long mTestTimeout = 1000 * 5;
     55 
     56     private ProcessHelper mProcessHelper = null;
     57     private VtsPythonRunnerHelper mVtsPythonRunnerHelper = null;
     58 
     59     @Before
     60     public void setUp() throws Exception {
     61         IFolderBuildInfo buildInfo = EasyMock.createNiceMock(IFolderBuildInfo.class);
     62         EasyMock.replay(buildInfo);
     63         mVtsPythonRunnerHelper = new VtsPythonRunnerHelper(buildInfo) {
     64             @Override
     65             protected ProcessHelper createProcessHelper(String[] cmd) {
     66                 return mProcessHelper;
     67             }
     68         };
     69     }
     70 
     71     /**
     72      * Create a process helper which mocks status of a running process.
     73      */
     74     private static ProcessHelper createMockProcessHelper(
     75             CommandStatus status, boolean interrupted, boolean keepRunning) {
     76         Process process;
     77         try {
     78             process = new ProcessBuilder("true").start();
     79         } catch (IOException e) {
     80             throw new RuntimeException(e);
     81         }
     82         return new ProcessHelper(process) {
     83             @Override
     84             public CommandStatus waitForProcess(long timeoutMsecs) throws RunInterruptedException {
     85                 if (interrupted) {
     86                     throw new RunInterruptedException();
     87                 }
     88                 return status;
     89             }
     90 
     91             @Override
     92             public boolean isRunning() {
     93                 return keepRunning;
     94             }
     95         };
     96     }
     97 
     98     private static ProcessHelper createMockProcessHelper(
     99             CommandStatus status, boolean interrupted) {
    100         return createMockProcessHelper(status, interrupted, /*keepRunning=*/false);
    101     }
    102 
    103     private static ProcessHelper createMockProcessHelper(CommandStatus status) {
    104         return createMockProcessHelper(status, /*interrupted=*/false, /*keepRunning=*/false);
    105     }
    106 
    107     /**
    108      * Create a mock runUtil with returns the expected results.
    109      */
    110     private IRunUtil createMockRunUtil(CommandResult result) {
    111         IRunUtil runUtil = EasyMock.createMock(IRunUtil.class);
    112         EasyMock.expect(runUtil.runTimedCmd(
    113                                 EasyMock.anyLong(), EasyMock.eq("which"), EasyMock.eq("python")))
    114                 .andReturn(result)
    115                 .anyTimes();
    116         EasyMock.expect(runUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq("where"),
    117                                 EasyMock.eq("python.exe")))
    118                 .andReturn(result)
    119                 .anyTimes();
    120         EasyMock.replay(runUtil);
    121         return runUtil;
    122     }
    123 
    124     @Test
    125     public void testProcessRunSuccess() {
    126         CommandResult commandResult = new CommandResult();
    127         mProcessHelper = createMockProcessHelper(CommandStatus.SUCCESS);
    128         String interruptMessage =
    129                 mVtsPythonRunnerHelper.runPythonRunner(mPythonCmd, commandResult, mTestTimeout);
    130         assertEquals(interruptMessage, null);
    131         assertEquals(commandResult.getStatus(), CommandStatus.SUCCESS);
    132     }
    133 
    134     @Test
    135     public void testProcessRunFailed() {
    136         CommandResult commandResult = new CommandResult();
    137         mProcessHelper = createMockProcessHelper(CommandStatus.FAILED);
    138         String interruptMessage =
    139                 mVtsPythonRunnerHelper.runPythonRunner(mPythonCmd, commandResult, mTestTimeout);
    140         assertEquals(interruptMessage, null);
    141         assertEquals(commandResult.getStatus(), CommandStatus.FAILED);
    142     }
    143 
    144     @Test
    145     public void testProcessRunTimeout() {
    146         CommandResult commandResult = new CommandResult();
    147         mProcessHelper = createMockProcessHelper(CommandStatus.TIMED_OUT);
    148         String interruptMessage =
    149                 mVtsPythonRunnerHelper.runPythonRunner(mPythonCmd, commandResult, mTestTimeout);
    150         assertEquals(interruptMessage, null);
    151         assertEquals(commandResult.getStatus(), CommandStatus.TIMED_OUT);
    152     }
    153 
    154     @Test
    155     public void testProcessRunInterrupted() {
    156         CommandResult commandResult = new CommandResult();
    157         mProcessHelper = createMockProcessHelper(null, /*interrupted=*/true);
    158         String interruptMessage =
    159                 mVtsPythonRunnerHelper.runPythonRunner(mPythonCmd, commandResult, mTestTimeout);
    160         assertNotEquals(interruptMessage, null);
    161         assertEquals(commandResult.getStatus(), CommandStatus.TIMED_OUT);
    162     }
    163 
    164     @Test
    165     public void testGetPythonBinaryNullBuildInfo() {
    166         CommandResult findPythonresult = new CommandResult();
    167         findPythonresult.setStatus(CommandStatus.SUCCESS);
    168         findPythonresult.setStdout("/user/bin/python");
    169         IRunUtil runUtil = createMockRunUtil(findPythonresult);
    170         mVtsPythonRunnerHelper = new VtsPythonRunnerHelper(null);
    171         mVtsPythonRunnerHelper.setRunUtil(runUtil);
    172         String pythonBinary = mVtsPythonRunnerHelper.getPythonBinary();
    173         assertEquals(pythonBinary, "/user/bin/python");
    174     }
    175 
    176     @Test
    177     public void testGetPythonBinaryPythonBinaryNotExists() {
    178         CommandResult findPythonresult = new CommandResult();
    179         findPythonresult.setStatus(CommandStatus.SUCCESS);
    180         findPythonresult.setStdout("/user/bin/python");
    181         IRunUtil runUtil = createMockRunUtil(findPythonresult);
    182         IBuildInfo mockBuildInfo = EasyMock.createNiceMock(IBuildInfo.class);
    183         EasyMock.expect(mockBuildInfo.getFile(EasyMock.eq("VIRTUALENVPATH")))
    184                 .andReturn(new File("NonExists"))
    185                 .atLeastOnce();
    186         EasyMock.replay(mockBuildInfo);
    187         mVtsPythonRunnerHelper = new VtsPythonRunnerHelper(mockBuildInfo);
    188         mVtsPythonRunnerHelper.setRunUtil(runUtil);
    189         try {
    190             String pythonBinary = mVtsPythonRunnerHelper.getPythonBinary();
    191             assertEquals(pythonBinary, "/user/bin/python");
    192         } catch (RuntimeException e) {
    193             fail();
    194         }
    195 
    196         EasyMock.verify(mockBuildInfo);
    197     }
    198 
    199     @Test
    200     public void testGetPythonBinaryException() {
    201         CommandResult findPythonresult = new CommandResult();
    202         findPythonresult.setStatus(CommandStatus.FAILED);
    203         findPythonresult.setStdout("");
    204         IRunUtil runUtil = createMockRunUtil(findPythonresult);
    205         mVtsPythonRunnerHelper = new VtsPythonRunnerHelper(null);
    206         mVtsPythonRunnerHelper.setRunUtil(runUtil);
    207         try {
    208             String pythonBinary = mVtsPythonRunnerHelper.getPythonBinary();
    209         } catch (RuntimeException e) {
    210             assertEquals("Could not find python binary on host machine", e.getMessage());
    211             return;
    212         }
    213         fail();
    214     }
    215 
    216     @Test
    217     public void testGetPythonBinaryNormalOnLinux() {
    218         String originalName = System.getProperty(OS_NAME);
    219         if (originalName.contains(WINDOWS)) {
    220             System.setProperty(OS_NAME, LINUX);
    221         }
    222         try {
    223             runTestPythonBinaryNormal(false);
    224         } catch (IOException e) {
    225             fail();
    226         } finally {
    227             System.setProperty(OS_NAME, originalName);
    228         }
    229     }
    230 
    231     @Test
    232     public void testGetPythonBinaryNormalOnWindows() {
    233         String originalName = System.getProperty(OS_NAME);
    234         if (!originalName.contains(WINDOWS)) {
    235             System.setProperty(OS_NAME, WINDOWS);
    236         }
    237         try {
    238             runTestPythonBinaryNormal(true);
    239         } catch (IOException e) {
    240             fail();
    241         } finally {
    242             System.setProperty(OS_NAME, originalName);
    243         }
    244     }
    245 
    246     public void runTestPythonBinaryNormal(boolean isWindows) throws IOException {
    247         String python = isWindows ? "python.exe" : "python";
    248         String binDir = isWindows ? "Scripts" : "bin";
    249         File testDir = FileUtil.createTempDir("testVirtualEnv");
    250         File testPython = new File(testDir, binDir + File.separator + python);
    251         testPython.getParentFile().mkdirs();
    252         testPython.createNewFile();
    253         CLog.i("creating test file: " + testPython.getAbsolutePath());
    254         IBuildInfo mockBuildInfo = EasyMock.createNiceMock(IBuildInfo.class);
    255         EasyMock.expect(mockBuildInfo.getFile(EasyMock.eq("VIRTUALENVPATH")))
    256                 .andReturn(testDir)
    257                 .atLeastOnce();
    258         EasyMock.replay(mockBuildInfo);
    259         mVtsPythonRunnerHelper = new VtsPythonRunnerHelper(mockBuildInfo);
    260         String pythonBinary = mVtsPythonRunnerHelper.getPythonBinary();
    261         assertEquals(pythonBinary, testPython.getAbsolutePath());
    262         FileUtil.recursiveDelete(testDir);
    263         EasyMock.verify(mockBuildInfo);
    264     }
    265 
    266     @Test
    267     public void testGetPythonPath() {
    268         StringBuilder sb = new StringBuilder();
    269         String separator = File.pathSeparator;
    270         if (System.getenv(PYTHONPATH) != null) {
    271             sb.append(separator);
    272             sb.append(System.getenv(PYTHONPATH));
    273         }
    274 
    275         File testVts = new File("TEST_VTS");
    276         File testPythonPath = new File("TEST_PYTHON_PATH");
    277 
    278         String altTestsDir = System.getenv().get(ALT_HOST_TESTCASE_DIR);
    279         if (altTestsDir != null) {
    280             File testsDir = new File(altTestsDir);
    281             sb.append(separator);
    282             sb.append(testsDir.getAbsolutePath());
    283         } else {
    284             sb.append(separator);
    285             sb.append(testVts.getAbsolutePath()).append("/..");
    286         }
    287 
    288         sb.append(separator);
    289         sb.append(testPythonPath.getAbsolutePath());
    290         if (System.getenv("ANDROID_BUILD_TOP") != null) {
    291             sb.append(separator);
    292             sb.append(System.getenv("ANDROID_BUILD_TOP")).append("/test");
    293         }
    294 
    295         IBuildInfo mockBuildInfo = EasyMock.createNiceMock(IBuildInfo.class);
    296         EasyMock.expect(mockBuildInfo.getFile(EasyMock.eq(VTS))).andReturn(testVts).anyTimes();
    297         EasyMock.expect(mockBuildInfo.getFile(EasyMock.eq(PYTHONPATH)))
    298                 .andReturn(testPythonPath)
    299                 .times(2);
    300         EasyMock.replay(mockBuildInfo);
    301 
    302         mVtsPythonRunnerHelper = new VtsPythonRunnerHelper(mockBuildInfo);
    303         assertEquals(sb.substring(1), mVtsPythonRunnerHelper.getPythonPath());
    304 
    305         EasyMock.verify(mockBuildInfo);
    306     }
    307 }
    308