1 /*
2  * Copyright (C) 2015 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.compatibility.common.tradefed.targetprep;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
26 
27 import com.android.ddmlib.IDevice;
28 import com.android.tradefed.build.DeviceBuildInfo;
29 import com.android.tradefed.config.Configuration;
30 import com.android.tradefed.config.OptionSetter;
31 import com.android.tradefed.device.DeviceNotAvailableException;
32 import com.android.tradefed.device.ITestDevice;
33 import com.android.tradefed.invoker.IInvocationContext;
34 import com.android.tradefed.invoker.InvocationContext;
35 import com.android.tradefed.invoker.TestInformation;
36 import com.android.tradefed.targetprep.ITargetPreparer;
37 import com.android.tradefed.targetprep.TargetSetupError;
38 import com.android.tradefed.util.FileUtil;
39 
40 import org.junit.After;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.junit.runners.JUnit4;
45 import org.mockito.Mockito;
46 
47 import java.io.File;
48 import java.util.ArrayList;
49 import java.util.List;
50 
51 /** Unit tests for {@link MediaPreparer}. */
52 @RunWith(JUnit4.class)
53 public class MediaPreparerTest {
54 
55     private static final String RUN_TESTS_AS_USER_KEY = "RUN_TESTS_AS_USER";
56     private static final int TEST_USER_ID = 99;
57 
58     private MediaPreparer mMediaPreparer;
59     private DeviceBuildInfo mMockBuildInfo;
60     private ITestDevice mMockDevice;
61     private OptionSetter mOptionSetter;
62     private TestInformation mTestInfo;
63     private File mTestsDir;
64 
65     @Before
setUp()66     public void setUp() throws Exception {
67         mMediaPreparer =
68                 new MediaPreparer() {
69                     @Override
70                     protected void setMaxRes(TestInformation testInfo)
71                             throws DeviceNotAvailableException, TargetSetupError {
72                         if (mMaxRes != null) return;
73                         super.setMaxRes(testInfo);
74                     }
75                 };
76         mMediaPreparer.setUserId(TEST_USER_ID);
77         mMockDevice = Mockito.mock(ITestDevice.class);
78         mMockBuildInfo = new DeviceBuildInfo("0", "");
79         mTestsDir = FileUtil.createTempDir("media-unit-tests");
80         mMockBuildInfo.setTestsDir(mTestsDir, "1");
81         new File(mTestsDir, "CtsMediaPreparerApp.apk").createNewFile();
82         mOptionSetter = new OptionSetter(mMediaPreparer);
83         IInvocationContext context = new InvocationContext();
84         context.addDeviceBuildInfo("device", mMockBuildInfo);
85         context.addAllocatedDevice("device", mMockDevice);
86         mTestInfo = TestInformation.newBuilder().setInvocationContext(context).build();
87     }
88 
89     @After
tearDown()90     public void tearDown() throws Exception {
91         FileUtil.recursiveDelete(mTestsDir);
92     }
93 
94     @Test
testLegacySetMountPoint()95     public void testLegacySetMountPoint() throws Exception {
96         when(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).thenReturn(
97                 "/sdcard");
98 
99         mMediaPreparer.setMountPoint(mMockDevice);
100         assertEquals(mMediaPreparer.mBaseDeviceShortDir, "/sdcard/test/bbb_short/");
101         assertEquals(mMediaPreparer.mBaseDeviceFullDir, "/sdcard/test/bbb_full/");
102     }
103 
104     @Test
testSetMountPoint()105     public void testSetMountPoint() throws Exception {
106         String mediaFolderName = "unittest";
107         mOptionSetter.setOptionValue("media-folder-name", mediaFolderName);
108         mOptionSetter.setOptionValue("use-legacy-folder-structure", "false");
109         when(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).thenReturn("/sdcard");
110 
111         mMediaPreparer.setMountPoint(mMockDevice);
112         String baseDir = "/sdcard/test/" + mediaFolderName;
113         assertEquals(mMediaPreparer.mBaseDeviceShortDir, baseDir + "/bbb_short/");
114         assertEquals(mMediaPreparer.mBaseDeviceFullDir, baseDir + "/bbb_full/");
115     }
116 
117     @Test
testDefaultModuleDirMountPoint()118     public void testDefaultModuleDirMountPoint() throws Exception {
119         when(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).thenReturn(
120                 "/sdcard");
121 
122         mMediaPreparer.setMountPoint(mMockDevice);
123         assertEquals(mMediaPreparer.mBaseDeviceModuleDir, "/sdcard/test/android-cts-media/");
124         assertEquals(mMediaPreparer.getMediaDir().getName(), "android-cts-media");
125     }
126 
127     @Test
testSetModuleDirMountPoint()128     public void testSetModuleDirMountPoint() throws Exception {
129         mOptionSetter.setOptionValue("media-folder-name", "unittest");
130         when(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).thenReturn(
131                 "/sdcard");
132 
133         mMediaPreparer.setMountPoint(mMockDevice);
134         assertEquals(mMediaPreparer.mBaseDeviceModuleDir, "/sdcard/test/unittest/");
135         assertEquals(mMediaPreparer.getMediaDir().getName(), "unittest");
136     }
137 
138     @Test
testCopyMediaFiles()139     public void testCopyMediaFiles() throws Exception {
140         mMediaPreparer.mMaxRes = MediaPreparer.RESOLUTIONS[1];
141         mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
142         mMediaPreparer.mBaseDeviceFullDir = "/sdcard/test/bbb_full/";
143         mMediaPreparer.mBaseDeviceModuleDir = "/sdcard/test/android-cts-media/";
144         for (MediaPreparer.Resolution resolution : MediaPreparer.RESOLUTIONS) {
145             if (resolution.getWidth() > MediaPreparer.RESOLUTIONS[1].getWidth()) {
146                 // Stop when we reach the default max resolution
147                 continue;
148             }
149             String shortFile = String.format("%s%s", mMediaPreparer.mBaseDeviceShortDir,
150                     resolution.toString());
151             String fullFile = String.format("%s%s", mMediaPreparer.mBaseDeviceFullDir,
152                     resolution.toString());
153             when(mMockDevice.doesFileExist(shortFile, TEST_USER_ID)).thenReturn(true);
154             when(mMockDevice.doesFileExist(fullFile, TEST_USER_ID)).thenReturn(true);
155         }
156         when(mMockDevice.doesFileExist(mMediaPreparer.mBaseDeviceModuleDir, TEST_USER_ID))
157                 .thenReturn(false);
158 
159         mMediaPreparer.copyMediaFiles(mMockDevice);
160     }
161 
162     @Test
testMediaFilesExistOnDeviceTrue()163     public void testMediaFilesExistOnDeviceTrue() throws Exception {
164         mMediaPreparer.mMaxRes = MediaPreparer.RESOLUTIONS[1];
165         mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
166         mMediaPreparer.mBaseDeviceFullDir = "/sdcard/test/bbb_full/";
167         for (MediaPreparer.Resolution resolution : MediaPreparer.RESOLUTIONS) {
168             String shortFile = String.format("%s%s", mMediaPreparer.mBaseDeviceShortDir,
169                     resolution.toString());
170             String fullFile = String.format("%s%s", mMediaPreparer.mBaseDeviceFullDir,
171                     resolution.toString());
172             when(mMockDevice.doesFileExist(shortFile, TEST_USER_ID)).thenReturn(true);
173             when(mMockDevice.doesFileExist(fullFile, TEST_USER_ID)).thenReturn(true);
174         }
175         assertTrue(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
176     }
177 
178     @Test
testMediaFilesExistOnDeviceTrueWithPushAll()179     public void testMediaFilesExistOnDeviceTrueWithPushAll() throws Exception {
180         mOptionSetter.setOptionValue("push-all", "true");
181         mMediaPreparer.mBaseDeviceModuleDir = "/sdcard/test/android-cts-media/";
182         when(mMockDevice.doesFileExist(mMediaPreparer.mBaseDeviceModuleDir, TEST_USER_ID))
183                 .thenReturn(true);
184 
185         assertTrue(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
186     }
187 
188     @Test
testMediaFilesExistOnDeviceFalse()189     public void testMediaFilesExistOnDeviceFalse() throws Exception {
190         mMediaPreparer.mMaxRes = MediaPreparer.RESOLUTIONS[1];
191         mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
192         String firstFileChecked = "/sdcard/test/bbb_short/176x144";
193         when(mMockDevice.doesFileExist(firstFileChecked, TEST_USER_ID)).thenReturn(false);
194 
195         assertFalse(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
196     }
197 
198     @Test
testMediaFilesExistOnDevice_differentUserId()199     public void testMediaFilesExistOnDevice_differentUserId() throws Exception {
200         mOptionSetter.setOptionValue("push-all", "true");
201         mMediaPreparer.mBaseDeviceModuleDir = "/sdcard/test/android-cts-media/";
202         when(mMockDevice.doesFileExist(mMediaPreparer.mBaseDeviceModuleDir, TEST_USER_ID))
203                 .thenReturn(true);
204 
205         assertTrue(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
206 
207         // The file exists for TEST_USER_ID, but not for other users.
208         mMediaPreparer.setUserId(TEST_USER_ID + 1);
209         assertFalse(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
210     }
211 
212     @Test
testSetUp_setsUserIdFromProperty()213     public void testSetUp_setsUserIdFromProperty() throws Exception {
214         mOptionSetter.setOptionValue("skip-media-download", "true");
215         mOptionSetter.setOptionValue("push-all", "true");
216         mMediaPreparer.mBaseDeviceModuleDir = "/sdcard/test/android-cts-media/";
217         int newTestUserId = TEST_USER_ID + 1;
218         when(mMockDevice.doesFileExist(mMediaPreparer.mBaseDeviceModuleDir, newTestUserId))
219                 .thenReturn(true);
220 
221         // The file exists for newTestUserId, not for TEST_USER_ID.
222         assertFalse(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
223 
224         mTestInfo.properties().put(RUN_TESTS_AS_USER_KEY, String.valueOf(newTestUserId));
225         // userId is set to newTestUser by setUp().
226         mMediaPreparer.setUp(mTestInfo);
227 
228         assertTrue(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
229     }
230 
231     @Test
testSkipMediaDownload()232     public void testSkipMediaDownload() throws Exception {
233         mOptionSetter.setOptionValue("skip-media-download", "true");
234 
235         mMediaPreparer.setUp(mTestInfo);
236     }
237 
238     @Test
testPushAll()239     public void testPushAll() throws Exception {
240         mOptionSetter.setOptionValue("push-all", "true");
241         mOptionSetter.setOptionValue("media-folder-name", "unittest");
242         mMediaPreparer.mBaseDeviceModuleDir = "/sdcard/test/unittest/";
243         mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
244         mMediaPreparer.mBaseDeviceFullDir = "/sdcard/test/bbb_full/";
245         when(mMockDevice.doesFileExist(mMediaPreparer.mBaseDeviceModuleDir, TEST_USER_ID))
246                 .thenReturn(true);
247         when(mMockDevice.doesFileExist(mMediaPreparer.mBaseDeviceShortDir, TEST_USER_ID))
248                 .thenReturn(false);
249         when(mMockDevice.doesFileExist(mMediaPreparer.mBaseDeviceFullDir, TEST_USER_ID))
250                 .thenReturn(false);
251 
252         mMediaPreparer.copyMediaFiles(mMockDevice);
253     }
254 
255     /** Test that if we decide to run and files are on the device, we don't download again. */
256     @Test
testMediaDownloadOnly_existsOnDevice()257     public void testMediaDownloadOnly_existsOnDevice() throws Exception {
258         mMediaPreparer.mMaxRes = MediaPreparer.RESOLUTIONS[3];
259         mOptionSetter.setOptionValue("local-media-path", "/fake/media/dir");
260         mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
261         mMediaPreparer.mBaseDeviceFullDir = "/sdcard/test/bbb_full/";
262 
263         when(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE))
264                 .thenReturn("/sdcard");
265         for (MediaPreparer.Resolution resolution : MediaPreparer.RESOLUTIONS) {
266             if (resolution.getWidth() > MediaPreparer.RESOLUTIONS[1].getWidth()) {
267                 // Stop when we reach the default max resolution
268                 continue;
269             }
270             String shortFile =
271                     String.format(
272                             "%s%s", mMediaPreparer.mBaseDeviceShortDir, resolution.toString());
273             String fullFile =
274                     String.format("%s%s", mMediaPreparer.mBaseDeviceFullDir, resolution.toString());
275             when(mMockDevice.doesFileExist(shortFile, TEST_USER_ID)).thenReturn(true);
276             when(mMockDevice.doesFileExist(fullFile, TEST_USER_ID)).thenReturn(true);
277         }
278 
279         mMediaPreparer.setUp(mTestInfo);
280     }
281 
setUpTocTests()282     private void setUpTocTests() throws Exception {
283         mOptionSetter.setOptionValue("push-all", "true");
284         mOptionSetter.setOptionValue("media-folder-name", "toc");
285         mOptionSetter.setOptionValue("simple-caching-semantics", "false");
286         mMediaPreparer.mBaseDeviceModuleDir = "/sdcard/test/toc/";
287 
288         when(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE))
289                 .thenReturn("/sdcard");
290         when(mMockDevice.doesFileExist(Mockito.any(), Mockito.anyInt())).thenReturn(false);
291         when(mMockDevice.getDeviceDescriptor()).thenReturn(null);
292         when(mMockDevice.pushDir(Mockito.any(), Mockito.any(), Mockito.anyInt())).thenReturn(true);
293         when(mMockDevice.executeShellCommand(Mockito.any()))
294                 .thenReturn("");
295     }
296 
297     /** Test that if TOC doesn't exist, we download again */
298     @Test
testMissingTOC()299     public void testMissingTOC() throws Exception {
300         setUpTocTests();
301 
302         File mediaFolder = mMediaPreparer.getMediaDir();
303         mediaFolder.mkdirs();
304 
305         // In order to test non-existent TOC triggers a download, need to ensure there is at
306         // least a file in the folder, otherwise empty folder triggers a download */
307         File file = new File(mediaFolder, "file");
308         file.createNewFile();
309 
310         try {
311             mMediaPreparer.setUp(mTestInfo);
312             fail("TargetSetupError expected");
313         } catch (TargetSetupError e) {
314             // Expected
315         } finally {
316             FileUtil.recursiveDelete(mediaFolder);
317         }
318     }
319 
320     /** Test that if TOC has a non-existent file, we download again */
321     @Test
testNonExistentFileInTOC()322     public void testNonExistentFileInTOC() throws Exception {
323         setUpTocTests();
324         File mediaFolder = mMediaPreparer.getMediaDir();
325         mediaFolder.mkdirs();
326 
327         File file = new File(mediaFolder, "file");
328         file.createNewFile();
329 
330         File tocFile = new File(mediaFolder, MediaPreparer.TOC_NAME);
331         String content = "file\n" + "non-existent-file";
332         FileUtil.writeToFile(content, tocFile);
333 
334         try {
335             mMediaPreparer.setUp(mTestInfo);
336             fail("TargetSetupError expected");
337         } catch (TargetSetupError e) {
338             // Expected
339         } finally {
340             FileUtil.recursiveDelete(mediaFolder);
341         }
342     }
343 
344     /** Test that if TOC is valid, we don't download again */
345     @Test
testValidTOC()346     public void testValidTOC() throws Exception {
347         setUpTocTests();
348 
349         File mediaFolder = mMediaPreparer.getMediaDir();
350         mediaFolder.mkdirs();
351         File file = new File(mediaFolder, "file");
352         file.createNewFile();
353 
354         File tocFile = new File(mediaFolder, MediaPreparer.TOC_NAME);
355         String content = "file\n";
356         FileUtil.writeToFile(content, tocFile);
357 
358         try {
359             mMediaPreparer.setUp(mTestInfo);
360         } finally {
361             FileUtil.recursiveDelete(mediaFolder);
362         }
363     }
364 
365     @Test
testGetDynamicConfig()366     public void testGetDynamicConfig() throws Exception {
367         Configuration config = new Configuration("name", "test");
368         mMediaPreparer.setConfiguration(config);
369         List<ITargetPreparer> preparers = new ArrayList<>();
370         DynamicConfigPusher pusher = new DynamicConfigPusher();
371         pusher.setModuleName("CtsModuleName");
372         preparers.add(pusher);
373         preparers.add(mMediaPreparer);
374         config.setTargetPreparers(preparers);
375         assertEquals("CtsModuleName", mMediaPreparer.getDynamicModuleName());
376     }
377 
378     @Test
testGetDynamicConfig_outOfOrder()379     public void testGetDynamicConfig_outOfOrder() throws Exception {
380         Configuration config = new Configuration("name", "test");
381         mMediaPreparer.setConfiguration(config);
382         List<ITargetPreparer> preparers = new ArrayList<>();
383         preparers.add(mMediaPreparer);
384         DynamicConfigPusher pusher = new DynamicConfigPusher();
385         pusher.setModuleName("CtsModuleName");
386         preparers.add(pusher);
387         config.setTargetPreparers(preparers);
388         try {
389             mMediaPreparer.getDynamicModuleName();
390             fail("Should have thrown an exception.");
391         } catch (TargetSetupError expected) {
392             // Expected
393         }
394     }
395 
396     @Test
testDownloadOnly()397     public void testDownloadOnly() throws Exception {
398         mOptionSetter.setOptionValue("media-download-only", "true");
399         mOptionSetter.setOptionValue("local-media-path", "/fake/media/dir");
400         mMediaPreparer.setUp(mTestInfo);
401 
402         verify(mMockDevice, never()).getMountPoint(Mockito.any());
403         verify(mMockDevice, never()).doesFileExist(Mockito.any(), Mockito.anyInt());
404     }
405 }
406 
407