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