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 
17 package com.android.tradefed.targetprep;
18 
19 import static org.easymock.EasyMock.anyLong;
20 import static org.easymock.EasyMock.expect;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import com.android.tradefed.build.BuildInfo;
25 import com.android.tradefed.build.IBuildInfo;
26 import com.android.tradefed.log.LogUtil.CLog;
27 import com.android.tradefed.util.CommandResult;
28 import com.android.tradefed.util.CommandStatus;
29 import com.android.tradefed.util.FileUtil;
30 import com.android.tradefed.util.IRunUtil;
31 import org.easymock.EasyMock;
32 import org.junit.Before;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.junit.runners.JUnit4;
36 import org.mockito.Mock;
37 import java.io.File;
38 import java.io.IOException;
39 
40 /**
41  * Unit tests for {@link VtsPythonVirtualenvPreparer}.</p>
42  * TODO: add tests to cover a full end-to-end scenario.
43  */
44 @RunWith(JUnit4.class)
45 public class VtsPythonVirtualenvPreparerTest {
46     private MockPythonVirtualenvPreparer mPreparer;
47     private IRunUtil mMockRunUtil;
48     private MockFile mFile;
49     @Mock private IBuildInfo mBuildInfo;
50 
51     class MockFile extends File {
52         public boolean createNewFileSuccess = true;
53 
54         /**
55          * @param name
56          */
MockFile(String name)57         public MockFile(String name) {
58             super(name);
59         }
60 
61         @Override
createNewFile()62         public boolean createNewFile() throws IOException {
63             if (!createNewFileSuccess) {
64                 throw new IOException();
65             };
66 
67             return true;
68         }
69     }
70 
71     class MockPythonVirtualenvPreparer extends VtsPythonVirtualenvPreparer {
72         public int mock_createVirtualenv = -1;
73         public int mock_checkHostReuseVirtualenv = -1;
74         public int mock_checkTestPlanLevelVirtualenv = -1;
75         public int mock_createVirtualenv_waitForOtherProcessToCreateVirtualEnv = -1;
76 
77         @Override
getRunUtil()78         protected IRunUtil getRunUtil() {
79             return mMockRunUtil;
80         }
81 
82         @Override
getVirtualenvCreationMarkFile()83         protected File getVirtualenvCreationMarkFile() {
84             return mFile;
85         }
86 
87         @Override
createVirtualenv()88         protected boolean createVirtualenv() throws IOException {
89             switch (mock_createVirtualenv) {
90                 case 0:
91                     return false;
92                 case 1:
93                     return true;
94                 case 2:
95                     throw new IOException("");
96                 default:
97                     return super.createVirtualenv();
98             }
99         }
100 
101         @Override
checkHostReuseVirtualenv(IBuildInfo buildInfo)102         protected boolean checkHostReuseVirtualenv(IBuildInfo buildInfo) throws IOException {
103             switch (mock_checkHostReuseVirtualenv) {
104                 case 0:
105                     return false;
106                 case 1:
107                     return true;
108                 case 2:
109                     throw new IOException("");
110                 default:
111                     return super.checkHostReuseVirtualenv(buildInfo);
112             }
113         }
114 
115         @SuppressWarnings("deprecation")
116         @Override
checkTestPlanLevelVirtualenv(IBuildInfo buildInfo)117         protected boolean checkTestPlanLevelVirtualenv(IBuildInfo buildInfo)
118                 throws TargetSetupError {
119             switch (mock_checkTestPlanLevelVirtualenv) {
120                 case 0:
121                     return false;
122                 case 1:
123                     return true;
124                 case 2:
125                     throw new TargetSetupError("");
126                 default:
127                     return super.checkTestPlanLevelVirtualenv(buildInfo);
128             }
129         }
130 
131         @SuppressWarnings("deprecation")
132         @Override
createVirtualenv_waitForOtherProcessToCreateVirtualEnv()133         protected boolean createVirtualenv_waitForOtherProcessToCreateVirtualEnv() {
134             switch (mock_createVirtualenv_waitForOtherProcessToCreateVirtualEnv) {
135                 case 0:
136                     return false;
137                 case 1:
138                     return true;
139                 default:
140                     return super.createVirtualenv_waitForOtherProcessToCreateVirtualEnv();
141             }
142         }
143     }
144 
145     @Before
setUp()146     public void setUp() throws Exception {
147         mMockRunUtil = EasyMock.createMock(IRunUtil.class);
148         mFile = new MockFile("");
149 
150         mPreparer = new MockPythonVirtualenvPreparer();
151         VtsPythonVirtualenvPreparer.PIP_RETRY = 0;
152         mPreparer.mVenvDir = new File("");
153         mPreparer.mDepModules.add("enum");
154     }
155 
156     /**
157      * Test that the installation of dependencies and requirements file is as expected.
158      */
159     @Test
testInstallDeps_reqFile_success()160     public void testInstallDeps_reqFile_success() throws Exception {
161         File requirementFile = FileUtil.createTempFile("reqfile", ".txt");
162         try {
163             mPreparer.setRequirementsFile(requirementFile);
164             CommandResult result = new CommandResult(CommandStatus.SUCCESS);
165             result.setStdout("output");
166             result.setStderr("std err");
167             // First check that the install requirements was attempted.
168             expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
169                            EasyMock.eq("install"), EasyMock.eq("-r"),
170                            EasyMock.eq(requirementFile.getAbsolutePath())))
171                     .andReturn(result);
172             // Check that all default modules are installed
173             addDefaultModuleExpectations(mMockRunUtil, result);
174             EasyMock.replay(mMockRunUtil);
175             mPreparer.installDeps();
176             EasyMock.verify(mMockRunUtil);
177         } finally {
178             FileUtil.deleteFile(requirementFile);
179         }
180     }
181 
182     /**
183      * Test that if an extra dependency module is required, we install it too.
184      */
185     @Test
testInstallDeps_depModule_success()186     public void testInstallDeps_depModule_success() throws Exception {
187         mPreparer.addDepModule("blahblah");
188         CommandResult result = new CommandResult(CommandStatus.SUCCESS);
189         result.setStdout("output");
190         result.setStderr("std err");
191         addDefaultModuleExpectations(mMockRunUtil, result);
192         // The non default module provided is also attempted to be installed.
193         expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
194                        EasyMock.eq("install"), EasyMock.eq("blahblah")))
195                 .andReturn(result);
196         mMockRunUtil.sleep(VtsPythonVirtualenvPreparer.PIP_INSTALL_DELAY);
197         EasyMock.replay(mMockRunUtil);
198         mPreparer.installDeps();
199         EasyMock.verify(mMockRunUtil);
200     }
201 
202     /**
203      * Tests the value of PIP_INSTALL_DELAY is at least 1 second.
204      */
205     @Test
test_PIP_INSTALL_DELAY_minimum_value()206     public void test_PIP_INSTALL_DELAY_minimum_value() {
207         assertTrue(VtsPythonVirtualenvPreparer.PIP_INSTALL_DELAY >= 1000);
208     }
209 
210     /**
211      * Test that an installation failure of the requirements file throws a {@link TargetSetupError}.
212      */
213     @Test
testInstallDeps_reqFile_failure()214     public void testInstallDeps_reqFile_failure() throws Exception {
215         File requirementFile = FileUtil.createTempFile("reqfile", ".txt");
216         try {
217             mPreparer.setRequirementsFile(requirementFile);
218             CommandResult result = new CommandResult(CommandStatus.TIMED_OUT);
219             result.setStdout("output");
220             result.setStderr("std err");
221             expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
222                            EasyMock.eq("install"), EasyMock.eq("-r"),
223                            EasyMock.eq(requirementFile.getAbsolutePath())))
224                     .andReturn(result);
225             EasyMock.replay(mMockRunUtil);
226             IBuildInfo buildInfo = new BuildInfo();
227             try {
228                 mPreparer.installDeps();
229                 fail("installDeps succeeded despite a failed command");
230             } catch (TargetSetupError e) {
231                 assertTrue(buildInfo.getFile("PYTHONPATH") == null);
232             }
233             EasyMock.verify(mMockRunUtil);
234         } finally {
235             FileUtil.deleteFile(requirementFile);
236         }
237     }
238 
239     /**
240      * Test that an installation failure of the dep module throws a {@link TargetSetupError}.
241      */
242     @Test
testInstallDeps_depModule_failure()243     public void testInstallDeps_depModule_failure() throws Exception {
244         CommandResult result = new CommandResult(CommandStatus.TIMED_OUT);
245         result.setStdout("output");
246         result.setStderr("std err");
247         expect(mMockRunUtil.runTimedCmd(
248                        anyLong(), EasyMock.eq(mPreparer.getPipPath()), EasyMock.eq("list")))
249                 .andReturn(result);
250         expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
251                        EasyMock.eq("install"), EasyMock.eq("enum")))
252                 .andReturn(result);
253         // If installing the dependency failed, an upgrade is attempted:
254         expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
255                        EasyMock.eq("install"), EasyMock.eq("--upgrade"), EasyMock.eq("enum")))
256                 .andReturn(result);
257         EasyMock.replay(mMockRunUtil);
258         IBuildInfo buildInfo = new BuildInfo();
259         try {
260             mPreparer.installDeps();
261             mPreparer.addPathToBuild(buildInfo);
262             fail("installDeps succeeded despite a failed command");
263         } catch (TargetSetupError e) {
264             assertTrue(buildInfo.getFile("PYTHONPATH") == null);
265         }
266         EasyMock.verify(mMockRunUtil);
267     }
268 
addDefaultModuleExpectations(IRunUtil mockRunUtil, CommandResult result)269     private void addDefaultModuleExpectations(IRunUtil mockRunUtil, CommandResult result) {
270         expect(mockRunUtil.runTimedCmd(
271                        anyLong(), EasyMock.eq(mPreparer.getPipPath()), EasyMock.eq("list")))
272                 .andReturn(result);
273         expect(mockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
274                        EasyMock.eq("install"), EasyMock.eq("enum")))
275                 .andReturn(result);
276         mMockRunUtil.sleep(VtsPythonVirtualenvPreparer.PIP_INSTALL_DELAY);
277     }
278 
279     /**
280      * Tests the functionality of createVirtualenv.
281      * @throws IOException
282      */
283     @Test
test_initVirtualenv_creationSuccess()284     public void test_initVirtualenv_creationSuccess() throws IOException {
285         // Create virutalenv dir command success
286         CommandResult result = new CommandResult();
287         result.setStatus(CommandStatus.SUCCESS);
288         expect(mMockRunUtil.runTimedCmd(EasyMock.anyInt(), EasyMock.eq("virtualenv"),
289                        EasyMock.anyObject(), EasyMock.anyObject(), EasyMock.anyObject()))
290                 .andReturn(result);
291         EasyMock.replay(mMockRunUtil);
292 
293         // Create completion mark file success
294         mFile.createNewFileSuccess = true;
295 
296         assertTrue(mPreparer.createVirtualenv());
297     }
298 
299     /**
300      * Tests the functionality of createVirtualenv.
301      * @throws IOException
302      */
303     @Test
test_initVirtualenv_creationSuccess_completionFail()304     public void test_initVirtualenv_creationSuccess_completionFail() {
305         // Create virutalenv dir command success
306         CommandResult result = new CommandResult();
307         result.setStatus(CommandStatus.SUCCESS);
308         expect(mMockRunUtil.runTimedCmd(EasyMock.anyInt(), EasyMock.eq("virtualenv"),
309                        EasyMock.anyObject(), EasyMock.anyObject(), EasyMock.anyObject()))
310                 .andReturn(result);
311         EasyMock.replay(mMockRunUtil);
312 
313         // Create completion mark file success
314         mFile.createNewFileSuccess = false;
315 
316         try {
317             mPreparer.createVirtualenv();
318             assertTrue("IOException is expected", false);
319         } catch (IOException e) {
320             // Expected. test pass
321         }
322     }
323 
324     /**
325      * Tests the functionality of createVirtualenv.
326      * @throws IOException
327      */
328     @Test
test_initVirtualenv_creationFail_Errno26_waitSucceed()329     public void test_initVirtualenv_creationFail_Errno26_waitSucceed() throws IOException {
330         // Create virutalenv dir command success
331         CommandResult result = new CommandResult();
332         result.setStatus(CommandStatus.FAILED);
333         result.setStderr("...Errno 26...");
334         expect(mMockRunUtil.runTimedCmd(EasyMock.anyInt(), EasyMock.eq("virtualenv"),
335                        EasyMock.anyObject(), EasyMock.anyObject(), EasyMock.anyObject()))
336                 .andReturn(result);
337         EasyMock.replay(mMockRunUtil);
338 
339         // Wait succeed
340         mPreparer.mock_createVirtualenv_waitForOtherProcessToCreateVirtualEnv = 1;
341 
342         assertTrue(mPreparer.createVirtualenv());
343     }
344 
345     /**
346      * Tests the functionality of createVirtualenv.
347      * @throws IOException
348      */
349     @Test
test_initVirtualenv_creationFail_Errno26_waitFailed()350     public void test_initVirtualenv_creationFail_Errno26_waitFailed() throws IOException {
351         // Create virutalenv dir command success
352         CommandResult result = new CommandResult();
353         result.setStatus(CommandStatus.FAILED);
354         result.setStderr("...Errno 26...");
355         expect(mMockRunUtil.runTimedCmd(EasyMock.anyInt(), EasyMock.eq("virtualenv"),
356                        EasyMock.anyObject(), EasyMock.anyObject(), EasyMock.anyObject()))
357                 .andReturn(result);
358         EasyMock.replay(mMockRunUtil);
359 
360         // Wait failed
361         mPreparer.mock_createVirtualenv_waitForOtherProcessToCreateVirtualEnv = 0;
362 
363         assertTrue(!mPreparer.createVirtualenv());
364     }
365 
366     /**
367      * Tests the functionality of createVirtualenv.
368      * @throws IOException
369      */
370     @Test
test_initVirtualenv_creationFail_noErrno26()371     public void test_initVirtualenv_creationFail_noErrno26() throws IOException {
372         // Create virutalenv dir command success
373         CommandResult result = new CommandResult();
374         result.setStatus(CommandStatus.FAILED);
375         result.setStderr("...");
376         expect(mMockRunUtil.runTimedCmd(EasyMock.anyInt(), EasyMock.eq("virtualenv"),
377                        EasyMock.anyObject(), EasyMock.anyObject(), EasyMock.anyObject()))
378                 .andReturn(result);
379         EasyMock.replay(mMockRunUtil);
380 
381         assertTrue(!mPreparer.createVirtualenv());
382     }
383 }