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.assertFalse; 21 import static org.junit.Assert.assertThrows; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.Mockito.when; 24 25 import android.service.dropbox.DropBoxManagerServiceDumpProto; 26 27 import com.android.csuite.core.DeviceUtils.DeviceTimestamp; 28 import com.android.csuite.core.DeviceUtils.DeviceUtilsException; 29 import com.android.csuite.core.DeviceUtils.DropboxEntry; 30 import com.android.tradefed.device.DeviceRuntimeException; 31 import com.android.tradefed.device.ITestDevice; 32 import com.android.tradefed.util.CommandResult; 33 import com.android.tradefed.util.CommandStatus; 34 import com.android.tradefed.util.IRunUtil; 35 36 import com.google.common.jimfs.Jimfs; 37 import com.google.protobuf.ByteString; 38 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 import org.junit.runners.JUnit4; 42 import org.mockito.ArgumentMatcher; 43 import org.mockito.Mockito; 44 45 import java.io.IOException; 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.Iterator; 51 import java.util.List; 52 import java.util.Set; 53 import java.util.concurrent.atomic.AtomicBoolean; 54 55 @RunWith(JUnit4.class) 56 public final class DeviceUtilsTest { 57 private ITestDevice mDevice = Mockito.mock(ITestDevice.class); 58 private IRunUtil mRunUtil = Mockito.mock(IRunUtil.class); 59 private final FileSystem mFileSystem = 60 Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix()); 61 62 @Test isPackageInstalled_packageIsInstalled_returnsTrue()63 public void isPackageInstalled_packageIsInstalled_returnsTrue() throws Exception { 64 String packageName = "package.name"; 65 when(mDevice.executeShellV2Command(Mockito.startsWith("pm list packages"))) 66 .thenReturn( 67 createSuccessfulCommandResultWithStdout("\npackage:" + packageName + "\n")); 68 DeviceUtils sut = createSubjectUnderTest(); 69 70 boolean res = sut.isPackageInstalled(packageName); 71 72 assertTrue(res); 73 } 74 75 @Test isPackageInstalled_packageIsNotInstalled_returnsFalse()76 public void isPackageInstalled_packageIsNotInstalled_returnsFalse() throws Exception { 77 String packageName = "package.name"; 78 when(mDevice.executeShellV2Command(Mockito.startsWith("pm list packages"))) 79 .thenReturn(createSuccessfulCommandResultWithStdout("")); 80 DeviceUtils sut = createSubjectUnderTest(); 81 82 boolean res = sut.isPackageInstalled(packageName); 83 84 assertFalse(res); 85 } 86 87 @Test isPackageInstalled_commandFailed_throws()88 public void isPackageInstalled_commandFailed_throws() throws Exception { 89 when(mDevice.executeShellV2Command(Mockito.startsWith("pm list packages"))) 90 .thenReturn(createFailedCommandResult()); 91 DeviceUtils sut = createSubjectUnderTest(); 92 93 assertThrows(DeviceUtilsException.class, () -> sut.isPackageInstalled("package.name")); 94 } 95 96 @Test launchPackage_pmDumpFailedAndPackageDoesNotExist_throws()97 public void launchPackage_pmDumpFailedAndPackageDoesNotExist_throws() throws Exception { 98 when(mDevice.executeShellV2Command(Mockito.startsWith("monkey"))) 99 .thenReturn(createFailedCommandResult()); 100 when(mDevice.executeShellV2Command(Mockito.startsWith("pm dump"))) 101 .thenReturn(createFailedCommandResult()); 102 when(mDevice.executeShellV2Command(Mockito.startsWith("pm list packages"))) 103 .thenReturn(createSuccessfulCommandResultWithStdout("no packages")); 104 DeviceUtils sut = createSubjectUnderTest(); 105 106 assertThrows(DeviceUtilsException.class, () -> sut.launchPackage("package.name")); 107 } 108 109 @Test launchPackage_pmDumpFailedAndPackageExists_throws()110 public void launchPackage_pmDumpFailedAndPackageExists_throws() throws Exception { 111 when(mDevice.executeShellV2Command(Mockito.startsWith("monkey"))) 112 .thenReturn(createFailedCommandResult()); 113 when(mDevice.executeShellV2Command(Mockito.startsWith("pm dump"))) 114 .thenReturn(createFailedCommandResult()); 115 when(mDevice.executeShellV2Command(Mockito.startsWith("pm list packages"))) 116 .thenReturn(createSuccessfulCommandResultWithStdout("package:package.name")); 117 DeviceUtils sut = createSubjectUnderTest(); 118 119 assertThrows(DeviceUtilsException.class, () -> sut.launchPackage("package.name")); 120 } 121 122 @Test launchPackage_amStartCommandFailed_throws()123 public void launchPackage_amStartCommandFailed_throws() throws Exception { 124 when(mDevice.executeShellV2Command(Mockito.startsWith("monkey"))) 125 .thenReturn(createFailedCommandResult()); 126 when(mDevice.executeShellV2Command(Mockito.startsWith("pm dump"))) 127 .thenReturn( 128 createSuccessfulCommandResultWithStdout( 129 " 87f1610" 130 + " com.google.android.gms/.app.settings.GoogleSettingsActivity" 131 + " filter 7357509\n" 132 + " Action: \"android.intent.action.MAIN\"\n" 133 + " Category: \"android.intent.category.LAUNCHER\"\n" 134 + " Category: \"android.intent.category.DEFAULT\"\n" 135 + " Category:" 136 + " \"android.intent.category.NOTIFICATION_PREFERENCES\"")); 137 when(mDevice.executeShellV2Command(Mockito.startsWith("am start"))) 138 .thenReturn(createFailedCommandResult()); 139 DeviceUtils sut = createSubjectUnderTest(); 140 141 assertThrows(DeviceUtilsException.class, () -> sut.launchPackage("com.google.android.gms")); 142 } 143 144 @Test launchPackage_amFailedToLaunchThePackage_throws()145 public void launchPackage_amFailedToLaunchThePackage_throws() throws Exception { 146 when(mDevice.executeShellV2Command(Mockito.startsWith("monkey"))) 147 .thenReturn(createFailedCommandResult()); 148 when(mDevice.executeShellV2Command(Mockito.startsWith("pm dump"))) 149 .thenReturn( 150 createSuccessfulCommandResultWithStdout( 151 " 87f1610" 152 + " com.google.android.gms/.app.settings.GoogleSettingsActivity" 153 + " filter 7357509\n" 154 + " Action: \"android.intent.action.MAIN\"\n" 155 + " Category: \"android.intent.category.LAUNCHER\"\n" 156 + " Category: \"android.intent.category.DEFAULT\"\n" 157 + " Category:" 158 + " \"android.intent.category.NOTIFICATION_PREFERENCES\"")); 159 when(mDevice.executeShellV2Command(Mockito.startsWith("am start"))) 160 .thenReturn( 161 createSuccessfulCommandResultWithStdout( 162 "Error: Activity not started, unable to resolve Intent")); 163 DeviceUtils sut = createSubjectUnderTest(); 164 165 assertThrows(DeviceUtilsException.class, () -> sut.launchPackage("com.google.android.gms")); 166 } 167 168 @Test launchPackage_monkeyFailedButAmSucceed_doesNotThrow()169 public void launchPackage_monkeyFailedButAmSucceed_doesNotThrow() throws Exception { 170 when(mDevice.executeShellV2Command(Mockito.startsWith("monkey"))) 171 .thenReturn(createFailedCommandResult()); 172 when(mDevice.executeShellV2Command(Mockito.startsWith("pm dump"))) 173 .thenReturn( 174 createSuccessfulCommandResultWithStdout( 175 " 87f1610" 176 + " com.google.android.gms/.app.settings.GoogleSettingsActivity" 177 + " filter 7357509\n" 178 + " Action: \"android.intent.action.MAIN\"\n" 179 + " Category: \"android.intent.category.LAUNCHER\"\n" 180 + " Category: \"android.intent.category.DEFAULT\"\n" 181 + " Category:" 182 + " \"android.intent.category.NOTIFICATION_PREFERENCES\"")); 183 when(mDevice.executeShellV2Command(Mockito.startsWith("am start"))) 184 .thenReturn(createSuccessfulCommandResultWithStdout("")); 185 DeviceUtils sut = createSubjectUnderTest(); 186 187 sut.launchPackage("com.google.android.gms"); 188 } 189 190 @Test launchPackage_monkeySucceed_doesNotThrow()191 public void launchPackage_monkeySucceed_doesNotThrow() throws Exception { 192 when(mDevice.executeShellV2Command(Mockito.startsWith("monkey"))) 193 .thenReturn(createSuccessfulCommandResultWithStdout("")); 194 when(mDevice.executeShellV2Command(Mockito.startsWith("pm dump"))) 195 .thenReturn(createFailedCommandResult()); 196 when(mDevice.executeShellV2Command(Mockito.startsWith("am start"))) 197 .thenReturn(createFailedCommandResult()); 198 DeviceUtils sut = createSubjectUnderTest(); 199 200 sut.launchPackage("package.name"); 201 } 202 203 @Test getLaunchActivity_oneActivityIsLauncherAndMainAndDefault_returnsIt()204 public void getLaunchActivity_oneActivityIsLauncherAndMainAndDefault_returnsIt() 205 throws Exception { 206 String pmDump = 207 " eecc562 com.google.android.gms/.bugreport.BugreportActivity filter" 208 + " ac016f3\n" 209 + " Action: \"android.intent.action.MAIN\"\n" 210 + " Category: \"android.intent.category.LAUNCHER\"\n" 211 + " 87f1610 com.google.android.gms/.app.settings.GoogleSettingsActivity" 212 + " filter 7357509\n" 213 + " Action: \"android.intent.action.MAIN\"\n" 214 + " Category: \"android.intent.category.LAUNCHER\"\n" 215 + " Category: \"android.intent.category.DEFAULT\"\n" 216 + " Category: \"android.intent.category.NOTIFICATION_PREFERENCES\"\n" 217 + " 28957f2 com.google.android.gms/.kids.SyncTailTrapperActivity filter" 218 + " 83cbcc0\n" 219 + " Action: \"android.intent.action.MAIN\"\n" 220 + " Category: \"android.intent.category.HOME\"\n" 221 + " Category: \"android.intent.category.DEFAULT\""; 222 DeviceUtils sut = createSubjectUnderTest(); 223 224 String res = sut.getLaunchActivity(pmDump); 225 226 assertThat(res).isEqualTo("com.google.android.gms/.app.settings.GoogleSettingsActivity"); 227 } 228 229 @Test getLaunchActivity_oneActivityIsLauncherAndMain_returnsIt()230 public void getLaunchActivity_oneActivityIsLauncherAndMain_returnsIt() throws Exception { 231 String pmDump = 232 " eecc562 com.google.android.gms/.bugreport.BugreportActivity filter" 233 + " ac016f3\n" 234 + " Action: \"android.intent.action.MAIN\"\n" 235 + " 87f1610 com.google.android.gms/.app.settings.GoogleSettingsActivity" 236 + " filter 7357509\n" 237 + " Action: \"android.intent.action.MAIN\"\n" 238 + " Category: \"android.intent.category.LAUNCHER\"\n" 239 + " Category: \"android.intent.category.NOTIFICATION_PREFERENCES\"\n" 240 + " 28957f2 com.google.android.gms/.kids.SyncTailTrapperActivity filter" 241 + " 83cbcc0\n" 242 + " Action: \"android.intent.action.MAIN\"\n" 243 + " Category: \"android.intent.category.HOME\"\n" 244 + " Category: \"android.intent.category.DEFAULT\"\n" 245 + " mPriority=10, mOrder=0, mHasStaticPartialTypes=false," 246 + " mHasDynamicPartialTypes=false"; 247 DeviceUtils sut = createSubjectUnderTest(); 248 249 String res = sut.getLaunchActivity(pmDump); 250 251 assertThat(res).isEqualTo("com.google.android.gms/.app.settings.GoogleSettingsActivity"); 252 } 253 254 @Test 255 public void getLaunchActivity_oneActivityIsLauncherAndOneActivityIsMain_returnsTheLauncherActivity()256 getLaunchActivity_oneActivityIsLauncherAndOneActivityIsMain_returnsTheLauncherActivity() 257 throws Exception { 258 String pmDump = 259 " eecc562 com.google.android.gms/.bugreport.BugreportActivity filter" 260 + " ac016f3\n" 261 + " Action: \"android.intent.action.MAIN\"\n" 262 + " 87f1610 com.google.android.gms/.app.settings.GoogleSettingsActivity" 263 + " filter 7357509\n" 264 + " Category: \"android.intent.category.LAUNCHER\"\n" 265 + " Category: \"android.intent.category.NOTIFICATION_PREFERENCES\"\n" 266 + " 28957f2 com.google.android.gms/.kids.SyncTailTrapperActivity filter" 267 + " 83cbcc0\n" 268 + " Action: \"android.intent.action.MAIN\"\n" 269 + " Category: \"android.intent.category.HOME\"\n" 270 + " Category: \"android.intent.category.DEFAULT\"\n" 271 + " mPriority=10, mOrder=0, mHasStaticPartialTypes=false," 272 + " mHasDynamicPartialTypes=false"; 273 DeviceUtils sut = createSubjectUnderTest(); 274 275 String res = sut.getLaunchActivity(pmDump); 276 277 assertThat(res).isEqualTo("com.google.android.gms/.app.settings.GoogleSettingsActivity"); 278 } 279 280 @Test getLaunchActivity_oneActivityIsMain_returnsIt()281 public void getLaunchActivity_oneActivityIsMain_returnsIt() throws Exception { 282 String pmDump = 283 " eecc562 com.google.android.gms/.bugreport.BugreportActivity filter" 284 + " ac016f3\n" 285 + " Action: \"android.intent.action.MAIN\"\n" 286 + " 87f1610 com.google.android.gms/.app.settings.GoogleSettingsActivity" 287 + " filter 7357509\n" 288 + " Category: \"android.intent.category.NOTIFICATION_PREFERENCES\"\n" 289 + " 28957f2 com.google.android.gms/.kids.SyncTailTrapperActivity filter" 290 + " 83cbcc0\n" 291 + " Category: \"android.intent.category.HOME\"\n" 292 + " Category: \"android.intent.category.DEFAULT\"\n" 293 + " mPriority=10, mOrder=0, mHasStaticPartialTypes=false," 294 + " mHasDynamicPartialTypes=false"; 295 DeviceUtils sut = createSubjectUnderTest(); 296 297 String res = sut.getLaunchActivity(pmDump); 298 299 assertThat(res).isEqualTo("com.google.android.gms/.bugreport.BugreportActivity"); 300 } 301 302 @Test getLaunchActivity_oneActivityIsLauncher_returnsIt()303 public void getLaunchActivity_oneActivityIsLauncher_returnsIt() throws Exception { 304 String pmDump = 305 " eecc562 com.google.android.gms/.bugreport.BugreportActivity filter" 306 + " ac016f3\n" 307 + " Category: \"android.intent.category.LAUNCHER\"\n" 308 + " 87f1610 com.google.android.gms/.app.settings.GoogleSettingsActivity" 309 + " filter 7357509\n" 310 + " Action: \"android.intent.action.MAIN\"\n" 311 + " Category: \"android.intent.category.NOTIFICATION_PREFERENCES\"\n" 312 + " 28957f2 com.google.android.gms/.kids.SyncTailTrapperActivity filter" 313 + " 83cbcc0\n" 314 + " Category: \"android.intent.category.HOME\"\n" 315 + " Category: \"android.intent.category.DEFAULT\"\n" 316 + " mPriority=10, mOrder=0, mHasStaticPartialTypes=false," 317 + " mHasDynamicPartialTypes=false"; 318 DeviceUtils sut = createSubjectUnderTest(); 319 320 String res = sut.getLaunchActivity(pmDump); 321 322 assertThat(res).isEqualTo("com.google.android.gms/.bugreport.BugreportActivity"); 323 } 324 325 @Test getLaunchActivity_noMainOrLauncherActivities_throws()326 public void getLaunchActivity_noMainOrLauncherActivities_throws() throws Exception { 327 String pmDump = 328 " eecc562 com.google.android.gms/.bugreport.BugreportActivity filter" 329 + " ac016f3\n" 330 + " Category: \"android.intent.category.HOME\"\n" 331 + " 87f1610 com.google.android.gms/.app.settings.GoogleSettingsActivity" 332 + " filter 7357509\n" 333 + " Category: \"android.intent.category.NOTIFICATION_PREFERENCES\"\n" 334 + " 28957f2 com.google.android.gms/.kids.SyncTailTrapperActivity filter" 335 + " 83cbcc0\n" 336 + " Category: \"android.intent.category.HOME\"\n" 337 + " Category: \"android.intent.category.DEFAULT\"\n" 338 + " mPriority=10, mOrder=0, mHasStaticPartialTypes=false," 339 + " mHasDynamicPartialTypes=false"; 340 DeviceUtils sut = createSubjectUnderTest(); 341 342 assertThrows(DeviceUtilsException.class, () -> sut.getLaunchActivity(pmDump)); 343 } 344 345 @Test currentTimeMillis_deviceCommandFailed_throwsException()346 public void currentTimeMillis_deviceCommandFailed_throwsException() throws Exception { 347 DeviceUtils sut = createSubjectUnderTest(); 348 when(mDevice.executeShellV2Command(Mockito.startsWith("echo"))) 349 .thenReturn(createFailedCommandResult()); 350 351 assertThrows(DeviceRuntimeException.class, () -> sut.currentTimeMillis()); 352 } 353 354 @Test currentTimeMillis_unexpectedFormat_throwsException()355 public void currentTimeMillis_unexpectedFormat_throwsException() throws Exception { 356 DeviceUtils sut = createSubjectUnderTest(); 357 when(mDevice.executeShellV2Command(Mockito.startsWith("echo"))) 358 .thenReturn(createSuccessfulCommandResultWithStdout("")); 359 360 assertThrows(DeviceRuntimeException.class, () -> sut.currentTimeMillis()); 361 } 362 363 @Test currentTimeMillis_successful_returnsTime()364 public void currentTimeMillis_successful_returnsTime() throws Exception { 365 DeviceUtils sut = createSubjectUnderTest(); 366 when(mDevice.executeShellV2Command(Mockito.startsWith("echo"))) 367 .thenReturn(createSuccessfulCommandResultWithStdout("123")); 368 369 DeviceTimestamp result = sut.currentTimeMillis(); 370 371 assertThat(result.get()).isEqualTo(Long.parseLong("123")); 372 } 373 374 @Test runWithScreenRecording_recordingDidNotStart_jobIsExecuted()375 public void runWithScreenRecording_recordingDidNotStart_jobIsExecuted() throws Exception { 376 DeviceUtils sut = createSubjectUnderTest(); 377 when(mRunUtil.runCmdInBackground(Mockito.argThat(contains("shell", "screenrecord")))) 378 .thenReturn(Mockito.mock(Process.class)); 379 when(mDevice.executeShellV2Command(Mockito.startsWith("ls"))) 380 .thenReturn(createFailedCommandResult()); 381 AtomicBoolean executed = new AtomicBoolean(false); 382 DeviceUtils.RunnableThrowingDeviceNotAvailable job = () -> executed.set(true); 383 384 sut.runWithScreenRecording(job, video -> {}); 385 386 assertThat(executed.get()).isTrue(); 387 } 388 389 @Test runWithScreenRecording_recordCommandThrowsException_jobIsExecuted()390 public void runWithScreenRecording_recordCommandThrowsException_jobIsExecuted() 391 throws Exception { 392 when(mRunUtil.runCmdInBackground(Mockito.argThat(contains("shell", "screenrecord")))) 393 .thenThrow(new IOException()); 394 DeviceUtils sut = createSubjectUnderTest(); 395 AtomicBoolean executed = new AtomicBoolean(false); 396 DeviceUtils.RunnableThrowingDeviceNotAvailable job = () -> executed.set(true); 397 398 sut.runWithScreenRecording(job, video -> {}); 399 400 assertThat(executed.get()).isTrue(); 401 } 402 403 @Test runWithScreenRecording_jobThrowsException_videoFileIsHandled()404 public void runWithScreenRecording_jobThrowsException_videoFileIsHandled() throws Exception { 405 when(mRunUtil.runCmdInBackground(Mockito.argThat(contains("shell", "screenrecord")))) 406 .thenReturn(Mockito.mock(Process.class)); 407 when(mDevice.executeShellV2Command(Mockito.startsWith("ls"))) 408 .thenReturn(createSuccessfulCommandResultWithStdout("")); 409 DeviceUtils sut = createSubjectUnderTest(); 410 DeviceUtils.RunnableThrowingDeviceNotAvailable job = 411 () -> { 412 throw new RuntimeException(); 413 }; 414 AtomicBoolean handled = new AtomicBoolean(false); 415 416 assertThrows( 417 RuntimeException.class, 418 () -> sut.runWithScreenRecording(job, video -> handled.set(true))); 419 420 assertThat(handled.get()).isTrue(); 421 } 422 423 @Test getPackageVersionName_deviceCommandFailed_returnsUnknown()424 public void getPackageVersionName_deviceCommandFailed_returnsUnknown() throws Exception { 425 DeviceUtils sut = createSubjectUnderTest(); 426 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionName"))) 427 .thenReturn(createFailedCommandResult()); 428 429 String result = sut.getPackageVersionName("any"); 430 431 assertThat(result).isEqualTo(DeviceUtils.UNKNOWN); 432 } 433 434 @Test getPackageVersionName_deviceCommandReturnsUnexpected_returnsUnknown()435 public void getPackageVersionName_deviceCommandReturnsUnexpected_returnsUnknown() 436 throws Exception { 437 DeviceUtils sut = createSubjectUnderTest(); 438 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionName"))) 439 .thenReturn( 440 createSuccessfulCommandResultWithStdout( 441 "unexpected " + DeviceUtils.VERSION_NAME_PREFIX)); 442 443 String result = sut.getPackageVersionName("any"); 444 445 assertThat(result).isEqualTo(DeviceUtils.UNKNOWN); 446 } 447 448 @Test getPackageVersionName_deviceCommandSucceed_returnsVersionName()449 public void getPackageVersionName_deviceCommandSucceed_returnsVersionName() throws Exception { 450 DeviceUtils sut = createSubjectUnderTest(); 451 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionName"))) 452 .thenReturn( 453 createSuccessfulCommandResultWithStdout( 454 " " + DeviceUtils.VERSION_NAME_PREFIX + "123")); 455 456 String result = sut.getPackageVersionName("any"); 457 458 assertThat(result).isEqualTo("123"); 459 } 460 461 @Test getPackageVersionCode_deviceCommandFailed_returnsUnknown()462 public void getPackageVersionCode_deviceCommandFailed_returnsUnknown() throws Exception { 463 DeviceUtils sut = createSubjectUnderTest(); 464 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionCode"))) 465 .thenReturn(createFailedCommandResult()); 466 467 String result = sut.getPackageVersionCode("any"); 468 469 assertThat(result).isEqualTo(DeviceUtils.UNKNOWN); 470 } 471 472 @Test getPackageVersionCode_deviceCommandReturnsUnexpected_returnsUnknown()473 public void getPackageVersionCode_deviceCommandReturnsUnexpected_returnsUnknown() 474 throws Exception { 475 DeviceUtils sut = createSubjectUnderTest(); 476 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionCode"))) 477 .thenReturn( 478 createSuccessfulCommandResultWithStdout( 479 "unexpected " + DeviceUtils.VERSION_CODE_PREFIX)); 480 481 String result = sut.getPackageVersionCode("any"); 482 483 assertThat(result).isEqualTo(DeviceUtils.UNKNOWN); 484 } 485 486 @Test getPackageVersionCode_deviceCommandSucceed_returnVersionCode()487 public void getPackageVersionCode_deviceCommandSucceed_returnVersionCode() throws Exception { 488 DeviceUtils sut = createSubjectUnderTest(); 489 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionCode"))) 490 .thenReturn( 491 createSuccessfulCommandResultWithStdout( 492 " " + DeviceUtils.VERSION_CODE_PREFIX + "123")); 493 494 String result = sut.getPackageVersionCode("any"); 495 496 assertThat(result).isEqualTo("123"); 497 } 498 499 @Test getDropboxEntries_noEntries_returnsEmptyList()500 public void getDropboxEntries_noEntries_returnsEmptyList() throws Exception { 501 DeviceUtils sut = createSubjectUnderTest(); 502 when(mRunUtil.runTimedCmd( 503 Mockito.anyLong(), 504 Mockito.eq("sh"), 505 Mockito.eq("-c"), 506 Mockito.contains("dumpsys dropbox --proto"))) 507 .thenReturn(createSuccessfulCommandResultWithStdout("")); 508 509 List<DropboxEntry> result = sut.getDropboxEntries(Set.of("")); 510 511 assertThat(result).isEmpty(); 512 } 513 514 @Test getDropboxEntries_entryExists_returnsEntry()515 public void getDropboxEntries_entryExists_returnsEntry() throws Exception { 516 Path dumpFile = Files.createTempFile(mFileSystem.getPath("/"), "dropbox", ".proto"); 517 long time = 123; 518 String data = "abc"; 519 String tag = "tag"; 520 DropBoxManagerServiceDumpProto proto = 521 DropBoxManagerServiceDumpProto.newBuilder() 522 .addEntries( 523 DropBoxManagerServiceDumpProto.Entry.newBuilder() 524 .setTimeMs(time) 525 .setData(ByteString.copyFromUtf8(data))) 526 .build(); 527 Files.write(dumpFile, proto.toByteArray()); 528 DeviceUtils sut = createSubjectUnderTestWithTempFile(dumpFile); 529 when(mRunUtil.runTimedCmd( 530 Mockito.anyLong(), 531 Mockito.eq("sh"), 532 Mockito.eq("-c"), 533 Mockito.contains("dumpsys dropbox --proto"))) 534 .thenReturn(createSuccessfulCommandResultWithStdout("")); 535 536 List<DropboxEntry> result = sut.getDropboxEntries(Set.of(tag)); 537 538 assertThat(result.get(0).getTime()).isEqualTo(time); 539 assertThat(result.get(0).getData()).isEqualTo(data); 540 assertThat(result.get(0).getTag()).isEqualTo(tag); 541 } 542 543 @Test getDropboxEntriesFromStdout_entryExists_returnsEntry()544 public void getDropboxEntriesFromStdout_entryExists_returnsEntry() throws Exception { 545 when(mRunUtil.runTimedCmd( 546 Mockito.anyLong(), 547 Mockito.eq("sh"), 548 Mockito.eq("-c"), 549 Mockito.contains("dumpsys dropbox --file"))) 550 .thenReturn(createSuccessfulCommandResultWithStdout("")); 551 when(mRunUtil.runTimedCmd( 552 Mockito.anyLong(), 553 Mockito.eq("sh"), 554 Mockito.eq("-c"), 555 Mockito.contains("dumpsys dropbox --print"))) 556 .thenReturn(createSuccessfulCommandResultWithStdout("")); 557 Path fileDumpFile = Files.createTempFile(mFileSystem.getPath("/"), "file", ".dump"); 558 Path printDumpFile = Files.createTempFile(mFileSystem.getPath("/"), "print", ".dump"); 559 String fileResult = 560 "Drop box contents: 351 entries\n" 561 + "Max entries: 1000\n" 562 + "Low priority rate limit period: 2000 ms\n" 563 + "Low priority tags: {data_app_wtf, keymaster, system_server_wtf," 564 + " system_app_strictmode, system_app_wtf, system_server_strictmode," 565 + " data_app_strictmode, netstats}\n" 566 + "\n" 567 + "2022-09-05 04:17:21 system_server_wtf (text, 1730 bytes)\n" 568 + " /data/system/dropbox/system_server_wtf@1662351441269.txt\n" 569 + "2022-09-05 04:31:06 event_data (text, 39 bytes)\n" 570 + " /data/system/dropbox/event_data@1662352266197.txt\n"; 571 String printResult = 572 "Drop box contents: 351 entries\n" 573 + "Max entries: 1000\n" 574 + "Low priority rate limit period: 2000 ms\n" 575 + "Low priority tags: {data_app_wtf, keymaster, system_server_wtf," 576 + " system_app_strictmode, system_app_wtf, system_server_strictmode," 577 + " data_app_strictmode, netstats}\n" 578 + "\n" 579 + "========================================\n" 580 + "2022-09-05 04:17:21 system_server_wtf (text, 1730 bytes)\n" 581 + "Process: system_server\n" 582 + "Subject: ActivityManager\n" 583 + "Build:" 584 + " generic/cf_x86_64_phone/vsoc_x86_64:UpsideDownCake/MASTER/8990215:userdebug/dev-keys\n" 585 + "Dropped-Count: 0\n" 586 + "\n" 587 + "android.util.Log$TerribleFailure: Sending non-protected broadcast" 588 + " com.android.bluetooth.btservice.BLUETOOTH_COUNTER_METRICS_ACTION from" 589 + " system uid 1002 pkg com.android.bluetooth\n" 590 + " at android.util.Log.wtf(Log.java:332)\n" 591 + " at android.util.Log.wtf(Log.java:326)\n" 592 + " at" 593 + " com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:13609)\n" 594 + " at" 595 + " com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:14330)\n" 596 + " at" 597 + " com.android.server.am.ActivityManagerService.broadcastIntentInPackage(ActivityManagerService.java:14530)\n" 598 + " at" 599 + " com.android.server.am.ActivityManagerService$LocalService.broadcastIntentInPackage(ActivityManagerService.java:17065)\n" 600 + " at" 601 + " com.android.server.am.PendingIntentRecord.sendInner(PendingIntentRecord.java:526)\n" 602 + " at" 603 + " com.android.server.am.PendingIntentRecord.sendWithResult(PendingIntentRecord.java:311)\n" 604 + " at" 605 + " com.android.server.am.ActivityManagerService.sendIntentSender(ActivityManagerService.java:5379)\n" 606 + " at" 607 + " android.app.PendingIntent.sendAndReturnResult(PendingIntent.java:1012)\n" 608 + " at android.app.PendingIntent.send(PendingIntent.java:983)\n" 609 + " at" 610 + " com.android.server.alarm.AlarmManagerService$DeliveryTracker.deliverLocked(AlarmManagerService.java:5500)\n" 611 + " at" 612 + " com.android.server.alarm.AlarmManagerService.deliverAlarmsLocked(AlarmManagerService.java:4400)\n" 613 + " at" 614 + " com.android.server.alarm.AlarmManagerService$AlarmThread.run(AlarmManagerService.java:4711)\n" 615 + "Caused by: java.lang.Throwable\n" 616 + " at" 617 + " com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:13610)\n" 618 + " ... 11 more\n" 619 + "\n" 620 + "========================================\n" 621 + "2022-09-05 04:31:06 event_data (text, 39 bytes)\n" 622 + "start=1662350731248\n" 623 + "end=1662352266140\n" 624 + "\n"; 625 Files.write(fileDumpFile, fileResult.getBytes()); 626 Files.write(printDumpFile, printResult.getBytes()); 627 DeviceUtils sut = createSubjectUnderTestWithTempFile(fileDumpFile, printDumpFile); 628 629 List<DropboxEntry> result = sut.getDropboxEntriesFromStdout(Set.of("system_server_wtf")); 630 631 assertThat(result.get(0).getTime()).isEqualTo(1662351441269L); 632 assertThat(result.get(0).getData()).contains("Sending non-protected broadcast"); 633 assertThat(result.get(0).getTag()).isEqualTo("system_server_wtf"); 634 assertThat(result.size()).isEqualTo(1); 635 } 636 createSubjectUnderTestWithTempFile(Path... tempFiles)637 private DeviceUtils createSubjectUnderTestWithTempFile(Path... tempFiles) { 638 when(mDevice.getSerialNumber()).thenReturn("SERIAL"); 639 FakeClock fakeClock = new FakeClock(); 640 Iterator<Path> iter = Arrays.asList(tempFiles).iterator(); 641 return new DeviceUtils( 642 mDevice, fakeClock.getSleeper(), fakeClock, () -> mRunUtil, () -> iter.next()); 643 } 644 createSubjectUnderTest()645 private DeviceUtils createSubjectUnderTest() { 646 when(mDevice.getSerialNumber()).thenReturn("SERIAL"); 647 FakeClock fakeClock = new FakeClock(); 648 return new DeviceUtils( 649 mDevice, 650 fakeClock.getSleeper(), 651 fakeClock, 652 () -> mRunUtil, 653 () -> Files.createTempFile(mFileSystem.getPath("/"), "test", ".tmp")); 654 } 655 656 private static class FakeClock implements DeviceUtils.Clock { 657 private long mCurrentTime = System.currentTimeMillis(); 658 private DeviceUtils.Sleeper mSleeper = duration -> mCurrentTime += duration; 659 getSleeper()660 private DeviceUtils.Sleeper getSleeper() { 661 return mSleeper; 662 } 663 664 @Override currentTimeMillis()665 public long currentTimeMillis() { 666 return mCurrentTime += 1; 667 } 668 } 669 contains(String... args)670 private static ArgumentMatcher<String[]> contains(String... args) { 671 return array -> Arrays.asList(array).containsAll(Arrays.asList(args)); 672 } 673 createSuccessfulCommandResultWithStdout(String stdout)674 private static CommandResult createSuccessfulCommandResultWithStdout(String stdout) { 675 CommandResult commandResult = new CommandResult(CommandStatus.SUCCESS); 676 commandResult.setExitCode(0); 677 commandResult.setStdout(stdout); 678 commandResult.setStderr(""); 679 return commandResult; 680 } 681 createFailedCommandResult()682 private static CommandResult createFailedCommandResult() { 683 CommandResult commandResult = new CommandResult(CommandStatus.FAILED); 684 commandResult.setExitCode(1); 685 commandResult.setStdout(""); 686 commandResult.setStderr("error"); 687 return commandResult; 688 } 689 } 690