1 /* 2 * Copyright (C) 2021 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.csuite.core; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import static org.junit.Assert.assertThrows; 21 import static org.mockito.Mockito.mock; 22 import static org.mockito.Mockito.times; 23 import static org.mockito.Mockito.when; 24 25 import com.android.csuite.core.DeviceUtils.DeviceTimestamp; 26 import com.android.csuite.core.DeviceUtils.DropboxEntry; 27 import com.android.csuite.core.TestUtils.TestArtifactReceiver; 28 import com.android.tradefed.build.BuildInfo; 29 import com.android.tradefed.device.ITestDevice; 30 import com.android.tradefed.invoker.IInvocationContext; 31 import com.android.tradefed.invoker.InvocationContext; 32 import com.android.tradefed.invoker.TestInformation; 33 import com.android.tradefed.result.FileInputStreamSource; 34 import com.android.tradefed.result.InputStreamSource; 35 36 import com.google.common.jimfs.Jimfs; 37 38 import org.junit.Rule; 39 import org.junit.Test; 40 import org.junit.rules.TemporaryFolder; 41 import org.junit.runner.RunWith; 42 import org.junit.runners.JUnit4; 43 import org.mockito.Mockito; 44 45 import java.io.File; 46 import java.nio.file.FileSystem; 47 import java.nio.file.Files; 48 import java.nio.file.Path; 49 import java.util.Arrays; 50 import java.util.List; 51 import java.util.stream.Collectors; 52 53 @RunWith(JUnit4.class) 54 public final class TestUtilsTest { 55 private final TestArtifactReceiver mMockTestArtifactReceiver = 56 Mockito.mock(TestArtifactReceiver.class); 57 private final ITestDevice mMockDevice = mock(ITestDevice.class); 58 private final DeviceUtils mMockDeviceUtils = Mockito.mock(DeviceUtils.class); 59 private static final String TEST_PACKAGE_NAME = "package.name"; 60 @Rule public final TemporaryFolder mTempFolder = new TemporaryFolder(); 61 private final FileSystem mFileSystem = 62 Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix()); 63 64 @Test listApks_withSplitApksInSubDirectory_returnsApks()65 public void listApks_withSplitApksInSubDirectory_returnsApks() throws Exception { 66 Path root = mFileSystem.getPath("apk"); 67 Files.createDirectories(root); 68 Files.createDirectories(root.resolve("sub")); 69 Files.createFile(root.resolve("sub").resolve("base.apk")); 70 Files.createFile(root.resolve("sub").resolve("config.apk")); 71 72 List<Path> res = TestUtils.listApks(root); 73 74 List<String> fileNames = 75 res.stream() 76 .map(Path::getFileName) 77 .map(Path::toString) 78 .collect(Collectors.toList()); 79 assertThat(fileNames).containsExactly("base.apk", "config.apk"); 80 } 81 82 @Test listApks_withSingleSplitApkDirectory_returnsApks()83 public void listApks_withSingleSplitApkDirectory_returnsApks() throws Exception { 84 Path root = mFileSystem.getPath("apk"); 85 Files.createDirectories(root); 86 Files.createFile(root.resolve("base.apk")); 87 88 List<Path> res = TestUtils.listApks(root); 89 90 List<String> fileNames = 91 res.stream() 92 .map(Path::getFileName) 93 .map(Path::toString) 94 .collect(Collectors.toList()); 95 assertThat(fileNames).containsExactly("base.apk"); 96 } 97 98 @Test listApks_withSplitApkDirectory_returnsListWithBaseApkAsTheFirstElement()99 public void listApks_withSplitApkDirectory_returnsListWithBaseApkAsTheFirstElement() 100 throws Exception { 101 Path root = mFileSystem.getPath("apk"); 102 Files.createDirectories(root); 103 Files.createFile(root.resolve("base.apk")); 104 Files.createFile(root.resolve("a.apk")); 105 Files.createFile(root.resolve("b.apk")); 106 Files.createFile(root.resolve("c.apk")); 107 108 List<Path> res = TestUtils.listApks(root); 109 110 assertThat(res.get(0).getFileName().toString()).isEqualTo("base.apk"); 111 } 112 113 @Test listApks_withSingleApkDirectory_returnsApks()114 public void listApks_withSingleApkDirectory_returnsApks() throws Exception { 115 Path root = mFileSystem.getPath("apk"); 116 Files.createDirectories(root); 117 Files.createFile(root.resolve("single.apk")); 118 119 List<Path> res = TestUtils.listApks(root); 120 121 List<String> fileNames = 122 res.stream() 123 .map(Path::getFileName) 124 .map(Path::toString) 125 .collect(Collectors.toList()); 126 assertThat(fileNames).containsExactly("single.apk"); 127 } 128 129 @Test listApks_withSingleApkFile_returnsApks()130 public void listApks_withSingleApkFile_returnsApks() throws Exception { 131 Path root = mFileSystem.getPath("single.apk"); 132 Files.createFile(root); 133 134 List<Path> res = TestUtils.listApks(root); 135 136 List<String> fileNames = 137 res.stream() 138 .map(Path::getFileName) 139 .map(Path::toString) 140 .collect(Collectors.toList()); 141 assertThat(fileNames).containsExactly("single.apk"); 142 } 143 144 @Test listApks_withApkDirectoryContainingObbFiles_returnsApksWithObb()145 public void listApks_withApkDirectoryContainingObbFiles_returnsApksWithObb() throws Exception { 146 Path root = mFileSystem.getPath("apk"); 147 Files.createDirectories(root); 148 Files.createFile(root.resolve("single.apk")); 149 Files.createFile(root.resolve("single.not_apk")); 150 Files.createFile(root.resolve("main.123.package.obb")); 151 152 List<Path> res = TestUtils.listApks(root); 153 154 List<String> fileNames = 155 res.stream() 156 .map(Path::getFileName) 157 .map(Path::toString) 158 .collect(Collectors.toList()); 159 assertThat(fileNames).containsExactly("single.apk", "main.123.package.obb"); 160 } 161 162 @Test listApks_withApkDirectoryContainingOtherFileTypes_returnsApksOnly()163 public void listApks_withApkDirectoryContainingOtherFileTypes_returnsApksOnly() 164 throws Exception { 165 Path root = mFileSystem.getPath("apk"); 166 Files.createDirectories(root); 167 Files.createFile(root.resolve("single.apk")); 168 Files.createFile(root.resolve("single.not_apk")); 169 170 List<Path> res = TestUtils.listApks(root); 171 172 List<String> fileNames = 173 res.stream() 174 .map(Path::getFileName) 175 .map(Path::toString) 176 .collect(Collectors.toList()); 177 assertThat(fileNames).containsExactly("single.apk"); 178 } 179 180 @Test listApks_withApkDirectoryContainingNoApks_throwException()181 public void listApks_withApkDirectoryContainingNoApks_throwException() throws Exception { 182 Path root = mFileSystem.getPath("apk"); 183 Files.createDirectories(root); 184 Files.createFile(root.resolve("single.not_apk")); 185 186 assertThrows(TestUtils.TestUtilsException.class, () -> TestUtils.listApks(root)); 187 } 188 189 @Test listApks_withApkDirectoryContainingOnlyObbFiles_throwException()190 public void listApks_withApkDirectoryContainingOnlyObbFiles_throwException() throws Exception { 191 Path root = mFileSystem.getPath("apk"); 192 Files.createDirectories(root); 193 Files.createFile(root.resolve("main.123.package.obb")); 194 195 assertThrows(TestUtils.TestUtilsException.class, () -> TestUtils.listApks(root)); 196 } 197 198 @Test listApks_withNonApkFile_throwException()199 public void listApks_withNonApkFile_throwException() throws Exception { 200 Path root = mFileSystem.getPath("single.not_apk"); 201 Files.createFile(root); 202 203 assertThrows(TestUtils.TestUtilsException.class, () -> TestUtils.listApks(root)); 204 } 205 206 @Test listApks_withMultipleSingleApks_throwException()207 public void listApks_withMultipleSingleApks_throwException() throws Exception { 208 Path root = mFileSystem.getPath("apk"); 209 Files.createDirectories(root); 210 Files.createFile(root.resolve("single1.apk")); 211 Files.createFile(root.resolve("single2.apk")); 212 213 assertThrows(TestUtils.TestUtilsException.class, () -> TestUtils.listApks(root)); 214 } 215 216 @Test listApks_withApksInMultipleDirectories_throwException()217 public void listApks_withApksInMultipleDirectories_throwException() throws Exception { 218 Path root = mFileSystem.getPath("apk"); 219 Files.createDirectories(root); 220 Files.createDirectories(root.resolve("1")); 221 Files.createDirectories(root.resolve("2")); 222 Files.createFile(root.resolve("1").resolve("base.apk")); 223 Files.createFile(root.resolve("2").resolve("config.apk")); 224 225 assertThrows(TestUtils.TestUtilsException.class, () -> TestUtils.listApks(root)); 226 } 227 228 @Test listApks_apksInTheSameDirectoryAndObbsInADifferentDirectory_doesNotThrow()229 public void listApks_apksInTheSameDirectoryAndObbsInADifferentDirectory_doesNotThrow() 230 throws Exception { 231 Path root = mFileSystem.getPath("apk"); 232 Files.createDirectories(root); 233 Files.createDirectories(root.resolve("1")); 234 Files.createDirectories(root.resolve("2")); 235 Files.createFile(root.resolve("1").resolve("base.apk")); 236 Files.createFile(root.resolve("1").resolve("config.apk")); 237 Files.createFile(root.resolve("2").resolve("main.123.com.package.obb")); 238 239 TestUtils.listApks(root); 240 } 241 242 @Test collectScreenshot_savesToTestLog()243 public void collectScreenshot_savesToTestLog() throws Exception { 244 TestUtils sut = createSubjectUnderTest(); 245 InputStreamSource screenshotData = new FileInputStreamSource(mTempFolder.newFile()); 246 when(mMockDevice.getScreenshot()).thenReturn(screenshotData); 247 when(mMockDevice.getSerialNumber()).thenReturn("SERIAL"); 248 249 sut.collectScreenshot(TEST_PACKAGE_NAME); 250 251 Mockito.verify(mMockTestArtifactReceiver, times(1)) 252 .addTestArtifact( 253 Mockito.contains("screenshot"), 254 Mockito.any(), 255 Mockito.any(InputStreamSource.class)); 256 } 257 258 @Test saveApks_always_savesOnTestPass()259 public void saveApks_always_savesOnTestPass() throws Exception { 260 TestUtils sut = createSubjectUnderTest(); 261 boolean testPassed = true; 262 263 sut.saveApks( 264 TestUtils.TakeEffectWhen.ALWAYS, testPassed, "apk", Arrays.asList(new File(""))); 265 266 Mockito.verify(mMockTestArtifactReceiver, times(1)) 267 .addTestArtifact(Mockito.contains("apk"), Mockito.any(), Mockito.any(File.class)); 268 } 269 270 @Test saveApks_always_savesOnTestFail()271 public void saveApks_always_savesOnTestFail() throws Exception { 272 TestUtils sut = createSubjectUnderTest(); 273 boolean testPassed = false; 274 275 sut.saveApks( 276 TestUtils.TakeEffectWhen.ALWAYS, testPassed, "apk", Arrays.asList(new File(""))); 277 278 Mockito.verify(mMockTestArtifactReceiver, times(1)) 279 .addTestArtifact(Mockito.contains("apk"), Mockito.any(), Mockito.any(File.class)); 280 } 281 282 @Test saveApks_never_doesNotSaveOnTestPass()283 public void saveApks_never_doesNotSaveOnTestPass() throws Exception { 284 TestUtils sut = createSubjectUnderTest(); 285 boolean testPassed = true; 286 287 sut.saveApks( 288 TestUtils.TakeEffectWhen.NEVER, testPassed, "apk", Arrays.asList(new File(""))); 289 290 Mockito.verify(mMockTestArtifactReceiver, times(0)) 291 .addTestArtifact(Mockito.contains("apk"), Mockito.any(), Mockito.any(File.class)); 292 } 293 294 @Test saveApks_never_doesNotSaveOnTestFail()295 public void saveApks_never_doesNotSaveOnTestFail() throws Exception { 296 TestUtils sut = createSubjectUnderTest(); 297 boolean testPassed = false; 298 299 sut.saveApks( 300 TestUtils.TakeEffectWhen.NEVER, testPassed, "apk", Arrays.asList(new File(""))); 301 302 Mockito.verify(mMockTestArtifactReceiver, times(0)) 303 .addTestArtifact(Mockito.contains("apk"), Mockito.any(), Mockito.any(File.class)); 304 } 305 306 @Test saveApks_onPass_doesNotSaveOnTestFail()307 public void saveApks_onPass_doesNotSaveOnTestFail() throws Exception { 308 TestUtils sut = createSubjectUnderTest(); 309 boolean testPassed = false; 310 311 sut.saveApks( 312 TestUtils.TakeEffectWhen.ON_PASS, testPassed, "apk", Arrays.asList(new File(""))); 313 314 Mockito.verify(mMockTestArtifactReceiver, times(0)) 315 .addTestArtifact(Mockito.contains("apk"), Mockito.any(), Mockito.any(File.class)); 316 } 317 318 @Test saveApks_onPass_savesOnTestPass()319 public void saveApks_onPass_savesOnTestPass() throws Exception { 320 TestUtils sut = createSubjectUnderTest(); 321 boolean testPassed = true; 322 323 sut.saveApks( 324 TestUtils.TakeEffectWhen.ON_PASS, testPassed, "apk", Arrays.asList(new File(""))); 325 326 Mockito.verify(mMockTestArtifactReceiver, times(1)) 327 .addTestArtifact(Mockito.contains("apk"), Mockito.any(), Mockito.any(File.class)); 328 } 329 330 @Test saveApks_onFail_doesNotSaveOnTestPass()331 public void saveApks_onFail_doesNotSaveOnTestPass() throws Exception { 332 TestUtils sut = createSubjectUnderTest(); 333 boolean testPassed = true; 334 335 sut.saveApks( 336 TestUtils.TakeEffectWhen.ON_FAIL, testPassed, "apk", Arrays.asList(new File(""))); 337 338 Mockito.verify(mMockTestArtifactReceiver, times(0)) 339 .addTestArtifact(Mockito.contains("apk"), Mockito.any(), Mockito.any(File.class)); 340 } 341 342 @Test saveApks_onFail_savesOnTestFail()343 public void saveApks_onFail_savesOnTestFail() throws Exception { 344 TestUtils sut = createSubjectUnderTest(); 345 boolean testPassed = false; 346 347 sut.saveApks( 348 TestUtils.TakeEffectWhen.ON_FAIL, testPassed, "apk", Arrays.asList(new File(""))); 349 350 Mockito.verify(mMockTestArtifactReceiver, times(1)) 351 .addTestArtifact(Mockito.contains("apk"), Mockito.any(), Mockito.any(File.class)); 352 } 353 354 @Test getDropboxPackageCrashLog_noEntries_returnsNull()355 public void getDropboxPackageCrashLog_noEntries_returnsNull() throws Exception { 356 TestUtils sut = createSubjectUnderTest(); 357 when(mMockDeviceUtils.getDropboxEntries(Mockito.any())).thenReturn(List.of()); 358 DeviceTimestamp startTime = new DeviceTimestamp(0); 359 360 String result = sut.getDropboxPackageCrashLog(TEST_PACKAGE_NAME, startTime, false); 361 362 assertThat(result).isNull(); 363 } 364 365 @Test getDropboxPackageCrashLog_noEntries_doesNotSaveOutput()366 public void getDropboxPackageCrashLog_noEntries_doesNotSaveOutput() throws Exception { 367 TestUtils sut = createSubjectUnderTest(); 368 when(mMockDeviceUtils.getDropboxEntries(Mockito.any())).thenReturn(List.of()); 369 DeviceTimestamp startTime = new DeviceTimestamp(0); 370 boolean saveToFile = true; 371 372 sut.getDropboxPackageCrashLog(TEST_PACKAGE_NAME, startTime, saveToFile); 373 374 Mockito.verify(mMockTestArtifactReceiver, Mockito.never()) 375 .addTestArtifact( 376 Mockito.contains("dropbox"), Mockito.any(), Mockito.any(byte[].class)); 377 } 378 379 @Test getDropboxPackageCrashLog_appCrashed_saveOutput()380 public void getDropboxPackageCrashLog_appCrashed_saveOutput() throws Exception { 381 TestUtils sut = createSubjectUnderTest(); 382 when(mMockDeviceUtils.getDropboxEntries( 383 Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) 384 .thenReturn( 385 List.of( 386 new DeviceUtils.DropboxEntry( 387 2, 388 DeviceUtils.DROPBOX_APP_CRASH_TAGS 389 .toArray( 390 new String 391 [DeviceUtils.DROPBOX_APP_CRASH_TAGS 392 .size()])[0], 393 "Package: " + TEST_PACKAGE_NAME))); 394 DeviceTimestamp startTime = new DeviceTimestamp(0); 395 boolean saveToFile = true; 396 397 sut.getDropboxPackageCrashLog(TEST_PACKAGE_NAME, startTime, saveToFile); 398 399 Mockito.verify(mMockTestArtifactReceiver, Mockito.times(1)) 400 .addTestArtifact( 401 Mockito.contains("dropbox"), Mockito.any(), Mockito.any(byte[].class)); 402 } 403 404 @Test compileTestFailureMessage_videoStartTimeProvided_returnWithVideoTimeForCrashes()405 public void compileTestFailureMessage_videoStartTimeProvided_returnWithVideoTimeForCrashes() 406 throws Exception { 407 TestUtils sut = createSubjectUnderTest(); 408 int videoStartTime = 10000; 409 int crashTime1 = 12000; 410 int crashTime2 = 72000; 411 String expectedTime1 = "00:02"; 412 String expectedTime2 = "01:02"; 413 List<DropboxEntry> crashEntries = 414 List.of( 415 new DeviceUtils.DropboxEntry( 416 crashTime1, 417 DeviceUtils.DROPBOX_APP_CRASH_TAGS 418 .toArray( 419 new String 420 [DeviceUtils.DROPBOX_APP_CRASH_TAGS 421 .size()])[0], 422 TEST_PACKAGE_NAME + " entry1"), 423 new DeviceUtils.DropboxEntry( 424 crashTime2, 425 DeviceUtils.DROPBOX_APP_CRASH_TAGS 426 .toArray( 427 new String 428 [DeviceUtils.DROPBOX_APP_CRASH_TAGS 429 .size()])[0], 430 TEST_PACKAGE_NAME + " entry2")); 431 432 String crashMessage = 433 sut.compileTestFailureMessage( 434 TEST_PACKAGE_NAME, 435 crashEntries, 436 false, 437 new DeviceTimestamp(videoStartTime)); 438 439 assertThat(crashMessage).contains(expectedTime1); 440 assertThat(crashMessage).contains(expectedTime2); 441 } 442 createSubjectUnderTest()443 private TestUtils createSubjectUnderTest() { 444 return new TestUtils(createTestInfo(), mMockTestArtifactReceiver, mMockDeviceUtils); 445 } 446 createTestInfo()447 private TestInformation createTestInfo() { 448 IInvocationContext context = new InvocationContext(); 449 context.addAllocatedDevice("device1", mMockDevice); 450 context.addDeviceBuildInfo("device1", new BuildInfo()); 451 return TestInformation.newBuilder().setInvocationContext(context).build(); 452 } 453 } 454