1 /* 2 * Copyright (C) 2017 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.server.timezone; 18 19 import com.android.timezone.distro.DistroVersion; 20 import com.android.timezone.distro.StagedDistroOperation; 21 import com.android.timezone.distro.TimeZoneDistro; 22 import com.android.timezone.distro.installer.TimeZoneDistroInstaller; 23 24 import org.junit.Before; 25 import org.junit.Test; 26 27 import android.app.timezone.Callback; 28 import android.app.timezone.DistroRulesVersion; 29 import android.app.timezone.ICallback; 30 import android.app.timezone.RulesManager; 31 import android.app.timezone.RulesState; 32 import android.os.ParcelFileDescriptor; 33 34 import java.io.File; 35 import java.io.FileDescriptor; 36 import java.io.FileOutputStream; 37 import java.io.IOException; 38 import java.io.PrintWriter; 39 import java.util.concurrent.Executor; 40 import javax.annotation.Nullable; 41 42 import libcore.io.IoUtils; 43 44 import static com.android.server.timezone.RulesManagerService.REQUIRED_UPDATER_PERMISSION; 45 import static org.junit.Assert.assertEquals; 46 import static org.junit.Assert.assertFalse; 47 import static org.junit.Assert.assertNotNull; 48 import static org.junit.Assert.assertNull; 49 import static org.junit.Assert.assertTrue; 50 import static org.junit.Assert.fail; 51 import static org.mockito.ArgumentMatchers.any; 52 import static org.mockito.Mockito.doNothing; 53 import static org.mockito.Mockito.doReturn; 54 import static org.mockito.Mockito.doThrow; 55 import static org.mockito.Mockito.mock; 56 import static org.mockito.Mockito.reset; 57 import static org.mockito.Mockito.verify; 58 import static org.mockito.Mockito.verifyNoMoreInteractions; 59 import static org.mockito.Mockito.verifyZeroInteractions; 60 import static org.mockito.Mockito.when; 61 62 /** 63 * White box interaction / unit testing of the {@link RulesManagerService}. 64 */ 65 public class RulesManagerServiceTest { 66 67 private RulesManagerService mRulesManagerService; 68 69 private FakeExecutor mFakeExecutor; 70 private PermissionHelper mMockPermissionHelper; 71 private PackageTracker mMockPackageTracker; 72 private TimeZoneDistroInstaller mMockTimeZoneDistroInstaller; 73 74 @Before 75 public void setUp() { 76 mFakeExecutor = new FakeExecutor(); 77 78 mMockPackageTracker = mock(PackageTracker.class); 79 mMockPermissionHelper = mock(PermissionHelper.class); 80 mMockTimeZoneDistroInstaller = mock(TimeZoneDistroInstaller.class); 81 82 mRulesManagerService = new RulesManagerService( 83 mMockPermissionHelper, 84 mFakeExecutor, 85 mMockPackageTracker, 86 mMockTimeZoneDistroInstaller); 87 } 88 89 @Test(expected = SecurityException.class) 90 public void getRulesState_noCallerPermission() throws Exception { 91 configureCallerDoesNotHavePermission(); 92 mRulesManagerService.getRulesState(); 93 } 94 95 @Test(expected = SecurityException.class) 96 public void requestInstall_noCallerPermission() throws Exception { 97 configureCallerDoesNotHavePermission(); 98 mRulesManagerService.requestInstall(null, null, null); 99 } 100 101 @Test(expected = SecurityException.class) 102 public void requestUninstall_noCallerPermission() throws Exception { 103 configureCallerDoesNotHavePermission(); 104 mRulesManagerService.requestUninstall(null, null); 105 } 106 107 @Test(expected = SecurityException.class) 108 public void requestNothing_noCallerPermission() throws Exception { 109 configureCallerDoesNotHavePermission(); 110 mRulesManagerService.requestNothing(null, true); 111 } 112 113 @Test 114 public void getRulesState_systemRulesError() throws Exception { 115 configureDeviceCannotReadSystemRulesVersion(); 116 117 assertNull(mRulesManagerService.getRulesState()); 118 } 119 120 @Test 121 public void getRulesState_stagedInstall() throws Exception { 122 configureCallerHasPermission(); 123 124 configureDeviceSystemRulesVersion("2016a"); 125 126 DistroVersion stagedDistroVersion = new DistroVersion( 127 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, 128 DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1, 129 "2016c", 130 3); 131 configureStagedInstall(stagedDistroVersion); 132 133 DistroVersion installedDistroVersion = new DistroVersion( 134 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, 135 DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1, 136 "2016b", 137 4); 138 configureInstalledDistroVersion(installedDistroVersion); 139 140 DistroRulesVersion stagedDistroRulesVersion = new DistroRulesVersion( 141 stagedDistroVersion.rulesVersion, stagedDistroVersion.revision); 142 DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion( 143 installedDistroVersion.rulesVersion, installedDistroVersion.revision); 144 RulesState expectedRuleState = new RulesState( 145 "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED, 146 false /* operationInProgress */, 147 RulesState.STAGED_OPERATION_INSTALL, stagedDistroRulesVersion, 148 RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion); 149 assertEquals(expectedRuleState, mRulesManagerService.getRulesState()); 150 } 151 152 @Test 153 public void getRulesState_nothingStaged() throws Exception { 154 configureCallerHasPermission(); 155 156 configureDeviceSystemRulesVersion("2016a"); 157 158 configureNoStagedOperation(); 159 160 DistroVersion installedDistroVersion = new DistroVersion( 161 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, 162 DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1, 163 "2016b", 164 4); 165 configureInstalledDistroVersion(installedDistroVersion); 166 167 DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion( 168 installedDistroVersion.rulesVersion, installedDistroVersion.revision); 169 RulesState expectedRuleState = new RulesState( 170 "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED, 171 false /* operationInProgress */, 172 RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */, 173 RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion); 174 assertEquals(expectedRuleState, mRulesManagerService.getRulesState()); 175 } 176 177 @Test 178 public void getRulesState_uninstallStaged() throws Exception { 179 configureCallerHasPermission(); 180 181 configureDeviceSystemRulesVersion("2016a"); 182 183 configureStagedUninstall(); 184 185 DistroVersion installedDistroVersion = new DistroVersion( 186 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, 187 DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1, 188 "2016b", 189 4); 190 configureInstalledDistroVersion(installedDistroVersion); 191 192 DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion( 193 installedDistroVersion.rulesVersion, installedDistroVersion.revision); 194 RulesState expectedRuleState = new RulesState( 195 "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED, 196 false /* operationInProgress */, 197 RulesState.STAGED_OPERATION_UNINSTALL, null /* stagedDistroRulesVersion */, 198 RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion); 199 assertEquals(expectedRuleState, mRulesManagerService.getRulesState()); 200 } 201 202 @Test 203 public void getRulesState_installedRulesError() throws Exception { 204 configureCallerHasPermission(); 205 206 String systemRulesVersion = "2016a"; 207 configureDeviceSystemRulesVersion(systemRulesVersion); 208 209 configureStagedUninstall(); 210 configureDeviceCannotReadInstalledDistroVersion(); 211 212 RulesState expectedRuleState = new RulesState( 213 "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED, 214 false /* operationInProgress */, 215 RulesState.STAGED_OPERATION_UNINSTALL, null /* stagedDistroRulesVersion */, 216 RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */); 217 assertEquals(expectedRuleState, mRulesManagerService.getRulesState()); 218 } 219 220 @Test 221 public void getRulesState_stagedRulesError() throws Exception { 222 configureCallerHasPermission(); 223 224 String systemRulesVersion = "2016a"; 225 configureDeviceSystemRulesVersion(systemRulesVersion); 226 227 configureDeviceCannotReadStagedDistroOperation(); 228 229 DistroVersion installedDistroVersion = new DistroVersion( 230 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, 231 DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1, 232 "2016b", 233 4); 234 configureInstalledDistroVersion(installedDistroVersion); 235 236 DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion( 237 installedDistroVersion.rulesVersion, installedDistroVersion.revision); 238 RulesState expectedRuleState = new RulesState( 239 "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED, 240 false /* operationInProgress */, 241 RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */, 242 RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion); 243 assertEquals(expectedRuleState, mRulesManagerService.getRulesState()); 244 } 245 246 @Test 247 public void getRulesState_noInstalledRules() throws Exception { 248 configureCallerHasPermission(); 249 250 String systemRulesVersion = "2016a"; 251 configureDeviceSystemRulesVersion(systemRulesVersion); 252 configureNoStagedOperation(); 253 configureInstalledDistroVersion(null); 254 255 RulesState expectedRuleState = new RulesState( 256 systemRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED, 257 false /* operationInProgress */, 258 RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */, 259 RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */); 260 assertEquals(expectedRuleState, mRulesManagerService.getRulesState()); 261 } 262 263 @Test 264 public void getRulesState_operationInProgress() throws Exception { 265 configureCallerHasPermission(); 266 267 String systemRulesVersion = "2016a"; 268 String installedRulesVersion = "2016b"; 269 int revision = 3; 270 271 configureDeviceSystemRulesVersion(systemRulesVersion); 272 273 DistroVersion installedDistroVersion = new DistroVersion( 274 DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, 275 DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1, 276 installedRulesVersion, 277 revision); 278 configureInstalledDistroVersion(installedDistroVersion); 279 280 ParcelFileDescriptor parcelFileDescriptor = 281 createParcelFileDescriptor(createArbitraryBytes(1000)); 282 283 // Start an async operation so there is one in progress. The mFakeExecutor won't actually 284 // execute it. 285 byte[] tokenBytes = createArbitraryTokenBytes(); 286 ICallback callback = new StubbedCallback(); 287 288 mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback); 289 290 // Request the rules state while the async operation is "happening". 291 RulesState actualRulesState = mRulesManagerService.getRulesState(); 292 RulesState expectedRuleState = new RulesState( 293 systemRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED, 294 true /* operationInProgress */, 295 RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */, 296 RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */); 297 assertEquals(expectedRuleState, actualRulesState); 298 } 299 300 @Test 301 public void requestInstall_operationInProgress() throws Exception { 302 configureCallerHasPermission(); 303 304 ParcelFileDescriptor parcelFileDescriptor1 = 305 createParcelFileDescriptor(createArbitraryBytes(1000)); 306 307 byte[] tokenBytes = createArbitraryTokenBytes(); 308 ICallback callback = new StubbedCallback(); 309 310 // First request should succeed. 311 assertEquals(RulesManager.SUCCESS, 312 mRulesManagerService.requestInstall(parcelFileDescriptor1, tokenBytes, callback)); 313 314 // Something async should be enqueued. Clear it but do not execute it so we can detect the 315 // second request does nothing. 316 mFakeExecutor.getAndResetLastCommand(); 317 318 // Second request should fail. 319 ParcelFileDescriptor parcelFileDescriptor2 = 320 createParcelFileDescriptor(createArbitraryBytes(1000)); 321 assertEquals(RulesManager.ERROR_OPERATION_IN_PROGRESS, 322 mRulesManagerService.requestInstall(parcelFileDescriptor2, tokenBytes, callback)); 323 324 assertClosed(parcelFileDescriptor2); 325 326 // Assert nothing async was enqueued. 327 mFakeExecutor.assertNothingQueued(); 328 verifyNoInstallerCallsMade(); 329 verifyNoPackageTrackerCallsMade(); 330 } 331 332 @Test 333 public void requestInstall_badToken() throws Exception { 334 configureCallerHasPermission(); 335 336 ParcelFileDescriptor parcelFileDescriptor = 337 createParcelFileDescriptor(createArbitraryBytes(1000)); 338 339 byte[] badTokenBytes = new byte[2]; 340 ICallback callback = new StubbedCallback(); 341 342 try { 343 mRulesManagerService.requestInstall(parcelFileDescriptor, badTokenBytes, callback); 344 fail(); 345 } catch (IllegalArgumentException expected) { 346 } 347 348 assertClosed(parcelFileDescriptor); 349 350 // Assert nothing async was enqueued. 351 mFakeExecutor.assertNothingQueued(); 352 verifyNoInstallerCallsMade(); 353 verifyNoPackageTrackerCallsMade(); 354 } 355 356 @Test 357 public void requestInstall_nullParcelFileDescriptor() throws Exception { 358 configureCallerHasPermission(); 359 360 ParcelFileDescriptor parcelFileDescriptor = null; 361 byte[] tokenBytes = createArbitraryTokenBytes(); 362 ICallback callback = new StubbedCallback(); 363 364 try { 365 mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback); 366 fail(); 367 } catch (NullPointerException expected) {} 368 369 // Assert nothing async was enqueued. 370 mFakeExecutor.assertNothingQueued(); 371 verifyNoInstallerCallsMade(); 372 verifyNoPackageTrackerCallsMade(); 373 } 374 375 @Test 376 public void requestInstall_nullCallback() throws Exception { 377 configureCallerHasPermission(); 378 379 ParcelFileDescriptor parcelFileDescriptor = 380 createParcelFileDescriptor(createArbitraryBytes(1000)); 381 byte[] tokenBytes = createArbitraryTokenBytes(); 382 ICallback callback = null; 383 384 try { 385 mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback); 386 fail(); 387 } catch (NullPointerException expected) {} 388 389 assertClosed(parcelFileDescriptor); 390 391 // Assert nothing async was enqueued. 392 mFakeExecutor.assertNothingQueued(); 393 verifyNoInstallerCallsMade(); 394 verifyNoPackageTrackerCallsMade(); 395 } 396 397 @Test 398 public void requestInstall_asyncSuccess() throws Exception { 399 configureCallerHasPermission(); 400 401 ParcelFileDescriptor parcelFileDescriptor = 402 createParcelFileDescriptor(createArbitraryBytes(1000)); 403 404 CheckToken token = createArbitraryToken(); 405 byte[] tokenBytes = token.toByteArray(); 406 407 TestCallback callback = new TestCallback(); 408 409 // Request the install. 410 assertEquals(RulesManager.SUCCESS, 411 mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback)); 412 413 // Assert nothing has happened yet. 414 callback.assertNoResultReceived(); 415 verifyNoInstallerCallsMade(); 416 verifyNoPackageTrackerCallsMade(); 417 418 // Set up the installer. 419 configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_SUCCESS); 420 421 // Simulate the async execution. 422 mFakeExecutor.simulateAsyncExecutionOfLastCommand(); 423 424 assertClosed(parcelFileDescriptor); 425 426 // Verify the expected calls were made to other components. 427 verifyStageInstallCalled(); 428 verifyPackageTrackerCalled(token, true /* success */); 429 430 // Check the callback was called. 431 callback.assertResultReceived(Callback.SUCCESS); 432 } 433 434 @Test 435 public void requestInstall_nullTokenBytes() throws Exception { 436 configureCallerHasPermission(); 437 438 ParcelFileDescriptor parcelFileDescriptor = 439 createParcelFileDescriptor(createArbitraryBytes(1000)); 440 441 TestCallback callback = new TestCallback(); 442 443 // Request the install. 444 assertEquals(RulesManager.SUCCESS, 445 mRulesManagerService.requestInstall( 446 parcelFileDescriptor, null /* tokenBytes */, callback)); 447 448 // Assert nothing has happened yet. 449 verifyNoInstallerCallsMade(); 450 callback.assertNoResultReceived(); 451 452 // Set up the installer. 453 configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_SUCCESS); 454 455 // Simulate the async execution. 456 mFakeExecutor.simulateAsyncExecutionOfLastCommand(); 457 458 assertClosed(parcelFileDescriptor); 459 460 // Verify the expected calls were made to other components. 461 verifyStageInstallCalled(); 462 verifyPackageTrackerCalled(null /* expectedToken */, true /* success */); 463 464 // Check the callback was received. 465 callback.assertResultReceived(Callback.SUCCESS); 466 } 467 468 @Test 469 public void requestInstall_asyncInstallFail() throws Exception { 470 configureCallerHasPermission(); 471 472 ParcelFileDescriptor parcelFileDescriptor = 473 createParcelFileDescriptor(createArbitraryBytes(1000)); 474 475 CheckToken token = createArbitraryToken(); 476 byte[] tokenBytes = token.toByteArray(); 477 478 TestCallback callback = new TestCallback(); 479 480 // Request the install. 481 assertEquals(RulesManager.SUCCESS, 482 mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback)); 483 484 // Assert nothing has happened yet. 485 verifyNoInstallerCallsMade(); 486 callback.assertNoResultReceived(); 487 488 // Set up the installer. 489 configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR); 490 491 // Simulate the async execution. 492 mFakeExecutor.simulateAsyncExecutionOfLastCommand(); 493 494 assertClosed(parcelFileDescriptor); 495 496 // Verify the expected calls were made to other components. 497 verifyStageInstallCalled(); 498 499 // Validation failure is treated like a successful check: repeating it won't improve things. 500 boolean expectedSuccess = true; 501 verifyPackageTrackerCalled(token, expectedSuccess); 502 503 // Check the callback was received. 504 callback.assertResultReceived(Callback.ERROR_INSTALL_VALIDATION_ERROR); 505 } 506 507 @Test 508 public void requestUninstall_operationInProgress() throws Exception { 509 configureCallerHasPermission(); 510 511 byte[] tokenBytes = createArbitraryTokenBytes(); 512 ICallback callback = new StubbedCallback(); 513 514 // First request should succeed. 515 assertEquals(RulesManager.SUCCESS, 516 mRulesManagerService.requestUninstall(tokenBytes, callback)); 517 518 // Something async should be enqueued. Clear it but do not execute it so we can detect the 519 // second request does nothing. 520 mFakeExecutor.getAndResetLastCommand(); 521 522 // Second request should fail. 523 assertEquals(RulesManager.ERROR_OPERATION_IN_PROGRESS, 524 mRulesManagerService.requestUninstall(tokenBytes, callback)); 525 526 // Assert nothing async was enqueued. 527 mFakeExecutor.assertNothingQueued(); 528 verifyNoInstallerCallsMade(); 529 verifyNoPackageTrackerCallsMade(); 530 } 531 532 @Test 533 public void requestUninstall_badToken() throws Exception { 534 configureCallerHasPermission(); 535 536 byte[] badTokenBytes = new byte[2]; 537 ICallback callback = new StubbedCallback(); 538 539 try { 540 mRulesManagerService.requestUninstall(badTokenBytes, callback); 541 fail(); 542 } catch (IllegalArgumentException expected) { 543 } 544 545 // Assert nothing async was enqueued. 546 mFakeExecutor.assertNothingQueued(); 547 verifyNoInstallerCallsMade(); 548 verifyNoPackageTrackerCallsMade(); 549 } 550 551 @Test 552 public void requestUninstall_nullCallback() throws Exception { 553 configureCallerHasPermission(); 554 555 byte[] tokenBytes = createArbitraryTokenBytes(); 556 ICallback callback = null; 557 558 try { 559 mRulesManagerService.requestUninstall(tokenBytes, callback); 560 fail(); 561 } catch (NullPointerException expected) {} 562 563 // Assert nothing async was enqueued. 564 mFakeExecutor.assertNothingQueued(); 565 verifyNoInstallerCallsMade(); 566 verifyNoPackageTrackerCallsMade(); 567 } 568 569 @Test 570 public void requestUninstall_asyncSuccess() throws Exception { 571 configureCallerHasPermission(); 572 573 CheckToken token = createArbitraryToken(); 574 byte[] tokenBytes = token.toByteArray(); 575 576 TestCallback callback = new TestCallback(); 577 578 // Request the uninstall. 579 assertEquals(RulesManager.SUCCESS, 580 mRulesManagerService.requestUninstall(tokenBytes, callback)); 581 582 // Assert nothing has happened yet. 583 callback.assertNoResultReceived(); 584 verifyNoInstallerCallsMade(); 585 verifyNoPackageTrackerCallsMade(); 586 587 // Set up the installer. 588 configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_SUCCESS); 589 590 // Simulate the async execution. 591 mFakeExecutor.simulateAsyncExecutionOfLastCommand(); 592 593 // Verify the expected calls were made to other components. 594 verifyStageUninstallCalled(); 595 verifyPackageTrackerCalled(token, true /* success */); 596 597 // Check the callback was called. 598 callback.assertResultReceived(Callback.SUCCESS); 599 } 600 601 @Test 602 public void requestUninstall_asyncNothingInstalled() throws Exception { 603 configureCallerHasPermission(); 604 605 CheckToken token = createArbitraryToken(); 606 byte[] tokenBytes = token.toByteArray(); 607 608 TestCallback callback = new TestCallback(); 609 610 // Request the uninstall. 611 assertEquals(RulesManager.SUCCESS, 612 mRulesManagerService.requestUninstall(tokenBytes, callback)); 613 614 // Assert nothing has happened yet. 615 callback.assertNoResultReceived(); 616 verifyNoInstallerCallsMade(); 617 verifyNoPackageTrackerCallsMade(); 618 619 // Set up the installer. 620 configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_NOTHING_INSTALLED); 621 622 // Simulate the async execution. 623 mFakeExecutor.simulateAsyncExecutionOfLastCommand(); 624 625 // Verify the expected calls were made to other components. 626 verifyStageUninstallCalled(); 627 verifyPackageTrackerCalled(token, true /* success */); 628 629 // Check the callback was called. 630 callback.assertResultReceived(Callback.SUCCESS); 631 } 632 633 @Test 634 public void requestUninstall_nullTokenBytes() throws Exception { 635 configureCallerHasPermission(); 636 637 TestCallback callback = new TestCallback(); 638 639 // Request the uninstall. 640 assertEquals(RulesManager.SUCCESS, 641 mRulesManagerService.requestUninstall(null /* tokenBytes */, callback)); 642 643 // Assert nothing has happened yet. 644 verifyNoInstallerCallsMade(); 645 callback.assertNoResultReceived(); 646 647 // Set up the installer. 648 configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_SUCCESS); 649 650 // Simulate the async execution. 651 mFakeExecutor.simulateAsyncExecutionOfLastCommand(); 652 653 // Verify the expected calls were made to other components. 654 verifyStageUninstallCalled(); 655 verifyPackageTrackerCalled(null /* expectedToken */, true /* success */); 656 657 // Check the callback was received. 658 callback.assertResultReceived(Callback.SUCCESS); 659 } 660 661 @Test 662 public void requestUninstall_asyncUninstallFail() throws Exception { 663 configureCallerHasPermission(); 664 665 CheckToken token = createArbitraryToken(); 666 byte[] tokenBytes = token.toByteArray(); 667 668 TestCallback callback = new TestCallback(); 669 670 // Request the uninstall. 671 assertEquals(RulesManager.SUCCESS, 672 mRulesManagerService.requestUninstall(tokenBytes, callback)); 673 674 // Assert nothing has happened yet. 675 verifyNoInstallerCallsMade(); 676 callback.assertNoResultReceived(); 677 678 // Set up the installer. 679 configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_FAIL); 680 681 // Simulate the async execution. 682 mFakeExecutor.simulateAsyncExecutionOfLastCommand(); 683 684 // Verify the expected calls were made to other components. 685 verifyStageUninstallCalled(); 686 verifyPackageTrackerCalled(token, false /* success */); 687 688 // Check the callback was received. 689 callback.assertResultReceived(Callback.ERROR_UNKNOWN_FAILURE); 690 } 691 692 @Test 693 public void requestNothing_operationInProgressOk() throws Exception { 694 configureCallerHasPermission(); 695 696 // Set up a parallel operation. 697 assertEquals(RulesManager.SUCCESS, 698 mRulesManagerService.requestUninstall(null, new StubbedCallback())); 699 // Something async should be enqueued. Clear it but do not execute it to simulate it still 700 // being in progress. 701 mFakeExecutor.getAndResetLastCommand(); 702 703 CheckToken token = createArbitraryToken(); 704 byte[] tokenBytes = token.toByteArray(); 705 706 // Make the call. 707 mRulesManagerService.requestNothing(tokenBytes, true /* success */); 708 709 // Assert nothing async was enqueued. 710 mFakeExecutor.assertNothingQueued(); 711 712 // Verify the expected calls were made to other components. 713 verifyPackageTrackerCalled(token, true /* success */); 714 verifyNoInstallerCallsMade(); 715 } 716 717 @Test 718 public void requestNothing_badToken() throws Exception { 719 configureCallerHasPermission(); 720 721 byte[] badTokenBytes = new byte[2]; 722 723 try { 724 mRulesManagerService.requestNothing(badTokenBytes, true /* success */); 725 fail(); 726 } catch (IllegalArgumentException expected) { 727 } 728 729 // Assert nothing async was enqueued. 730 mFakeExecutor.assertNothingQueued(); 731 732 // Assert no other calls were made. 733 verifyNoInstallerCallsMade(); 734 verifyNoPackageTrackerCallsMade(); 735 } 736 737 @Test 738 public void requestNothing() throws Exception { 739 configureCallerHasPermission(); 740 741 CheckToken token = createArbitraryToken(); 742 byte[] tokenBytes = token.toByteArray(); 743 744 // Make the call. 745 mRulesManagerService.requestNothing(tokenBytes, false /* success */); 746 747 // Assert everything required was done. 748 verifyNoInstallerCallsMade(); 749 verifyPackageTrackerCalled(token, false /* success */); 750 } 751 752 @Test 753 public void requestNothing_nullTokenBytes() throws Exception { 754 configureCallerHasPermission(); 755 756 // Make the call. 757 mRulesManagerService.requestNothing(null /* tokenBytes */, true /* success */); 758 759 // Assert everything required was done. 760 verifyNoInstallerCallsMade(); 761 verifyPackageTrackerCalled(null /* token */, true /* success */); 762 } 763 764 @Test 765 public void dump_noPermission() throws Exception { 766 when(mMockPermissionHelper.checkDumpPermission(any(String.class), any(PrintWriter.class))) 767 .thenReturn(false); 768 769 doDumpCallAndCapture(mRulesManagerService, null); 770 verifyZeroInteractions(mMockPackageTracker, mMockTimeZoneDistroInstaller); 771 } 772 773 @Test 774 public void dump_emptyArgs() throws Exception { 775 doSuccessfulDumpCall(mRulesManagerService, new String[0]); 776 777 // Verify the package tracker was consulted. 778 verify(mMockPackageTracker).dump(any(PrintWriter.class)); 779 } 780 781 @Test 782 public void dump_nullArgs() throws Exception { 783 doSuccessfulDumpCall(mRulesManagerService, null); 784 // Verify the package tracker was consulted. 785 verify(mMockPackageTracker).dump(any(PrintWriter.class)); 786 } 787 788 @Test 789 public void dump_unknownArgs() throws Exception { 790 String dumpedTextUnknownArgs = doSuccessfulDumpCall( 791 mRulesManagerService, new String[] { "foo", "bar"}); 792 793 // Verify the package tracker was consulted. 794 verify(mMockPackageTracker).dump(any(PrintWriter.class)); 795 796 String dumpedTextZeroArgs = doSuccessfulDumpCall(mRulesManagerService, null); 797 assertEquals(dumpedTextZeroArgs, dumpedTextUnknownArgs); 798 } 799 800 @Test 801 public void dump_formatState() throws Exception { 802 // Just expect these to not throw exceptions, not return nothing, and not interact with the 803 // package tracker. 804 doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("p")); 805 doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("s")); 806 doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("c")); 807 doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("i")); 808 doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("o")); 809 doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("t")); 810 doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("a")); 811 doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("z" /* Unknown */)); 812 doSuccessfulDumpCall(mRulesManagerService, dumpFormatArgs("piscotz")); 813 814 verifyZeroInteractions(mMockPackageTracker); 815 } 816 817 private static String[] dumpFormatArgs(String argsString) { 818 return new String[] { "-format_state", argsString}; 819 } 820 821 private String doSuccessfulDumpCall(RulesManagerService rulesManagerService, String[] args) 822 throws Exception { 823 when(mMockPermissionHelper.checkDumpPermission(any(String.class), any(PrintWriter.class))) 824 .thenReturn(true); 825 826 // Set up the mocks to return (arbitrary) information about the current device state. 827 when(mMockTimeZoneDistroInstaller.getSystemRulesVersion()).thenReturn("2017a"); 828 when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion()).thenReturn( 829 new DistroVersion(2, 3, "2017b", 4)); 830 when(mMockTimeZoneDistroInstaller.getStagedDistroOperation()).thenReturn( 831 StagedDistroOperation.install(new DistroVersion(5, 6, "2017c", 7))); 832 833 // Do the dump call. 834 String dumpedOutput = doDumpCallAndCapture(rulesManagerService, args); 835 836 assertFalse(dumpedOutput.isEmpty()); 837 838 return dumpedOutput; 839 } 840 841 private static String doDumpCallAndCapture( 842 RulesManagerService rulesManagerService, String[] args) throws IOException { 843 File file = File.createTempFile("dump", null); 844 try { 845 try (FileOutputStream fos = new FileOutputStream(file)) { 846 FileDescriptor fd = fos.getFD(); 847 rulesManagerService.dump(fd, args); 848 } 849 return IoUtils.readFileAsString(file.getAbsolutePath()); 850 } finally { 851 file.delete(); 852 } 853 } 854 855 private void verifyNoPackageTrackerCallsMade() { 856 verifyNoMoreInteractions(mMockPackageTracker); 857 reset(mMockPackageTracker); 858 } 859 860 private void verifyPackageTrackerCalled( 861 CheckToken expectedCheckToken, boolean expectedSuccess) { 862 verify(mMockPackageTracker).recordCheckResult(expectedCheckToken, expectedSuccess); 863 reset(mMockPackageTracker); 864 } 865 866 private void configureCallerHasPermission() throws Exception { 867 doNothing() 868 .when(mMockPermissionHelper) 869 .enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION); 870 } 871 872 private void configureCallerDoesNotHavePermission() { 873 doThrow(new SecurityException("Simulated permission failure")) 874 .when(mMockPermissionHelper) 875 .enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION); 876 } 877 878 private void configureStageInstallExpectation(int resultCode) 879 throws Exception { 880 when(mMockTimeZoneDistroInstaller.stageInstallWithErrorCode(any(TimeZoneDistro.class))) 881 .thenReturn(resultCode); 882 } 883 884 private void configureStageUninstallExpectation(int resultCode) throws Exception { 885 doReturn(resultCode).when(mMockTimeZoneDistroInstaller).stageUninstall(); 886 } 887 888 private void verifyStageInstallCalled() throws Exception { 889 verify(mMockTimeZoneDistroInstaller).stageInstallWithErrorCode(any(TimeZoneDistro.class)); 890 verifyNoMoreInteractions(mMockTimeZoneDistroInstaller); 891 reset(mMockTimeZoneDistroInstaller); 892 } 893 894 private void verifyStageUninstallCalled() throws Exception { 895 verify(mMockTimeZoneDistroInstaller).stageUninstall(); 896 verifyNoMoreInteractions(mMockTimeZoneDistroInstaller); 897 reset(mMockTimeZoneDistroInstaller); 898 } 899 900 private void verifyNoInstallerCallsMade() { 901 verifyNoMoreInteractions(mMockTimeZoneDistroInstaller); 902 reset(mMockTimeZoneDistroInstaller); 903 } 904 905 private static byte[] createArbitraryBytes(int length) { 906 byte[] bytes = new byte[length]; 907 for (int i = 0; i < length; i++) { 908 bytes[i] = (byte) i; 909 } 910 return bytes; 911 } 912 913 private byte[] createArbitraryTokenBytes() { 914 return createArbitraryToken().toByteArray(); 915 } 916 917 private CheckToken createArbitraryToken() { 918 return new CheckToken(1, new PackageVersions(1, 1)); 919 } 920 921 private void configureDeviceSystemRulesVersion(String systemRulesVersion) throws Exception { 922 when(mMockTimeZoneDistroInstaller.getSystemRulesVersion()).thenReturn(systemRulesVersion); 923 } 924 925 private void configureInstalledDistroVersion(@Nullable DistroVersion installedDistroVersion) 926 throws Exception { 927 when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion()) 928 .thenReturn(installedDistroVersion); 929 } 930 931 private void configureStagedInstall(DistroVersion stagedDistroVersion) throws Exception { 932 when(mMockTimeZoneDistroInstaller.getStagedDistroOperation()) 933 .thenReturn(StagedDistroOperation.install(stagedDistroVersion)); 934 } 935 936 private void configureStagedUninstall() throws Exception { 937 when(mMockTimeZoneDistroInstaller.getStagedDistroOperation()) 938 .thenReturn(StagedDistroOperation.uninstall()); 939 } 940 941 private void configureNoStagedOperation() throws Exception { 942 when(mMockTimeZoneDistroInstaller.getStagedDistroOperation()).thenReturn(null); 943 } 944 945 private void configureDeviceCannotReadStagedDistroOperation() throws Exception { 946 when(mMockTimeZoneDistroInstaller.getStagedDistroOperation()) 947 .thenThrow(new IOException("Simulated failure")); 948 } 949 950 private void configureDeviceCannotReadSystemRulesVersion() throws Exception { 951 when(mMockTimeZoneDistroInstaller.getSystemRulesVersion()) 952 .thenThrow(new IOException("Simulated failure")); 953 } 954 955 private void configureDeviceCannotReadInstalledDistroVersion() throws Exception { 956 when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion()) 957 .thenThrow(new IOException("Simulated failure")); 958 } 959 960 private static void assertClosed(ParcelFileDescriptor parcelFileDescriptor) { 961 assertFalse(parcelFileDescriptor.getFileDescriptor().valid()); 962 } 963 964 private static class FakeExecutor implements Executor { 965 966 private Runnable mLastCommand; 967 968 @Override 969 public void execute(Runnable command) { 970 assertNull(mLastCommand); 971 assertNotNull(command); 972 mLastCommand = command; 973 } 974 975 public Runnable getAndResetLastCommand() { 976 assertNotNull(mLastCommand); 977 Runnable toReturn = mLastCommand; 978 mLastCommand = null; 979 return toReturn; 980 } 981 982 public void simulateAsyncExecutionOfLastCommand() { 983 Runnable toRun = getAndResetLastCommand(); 984 toRun.run(); 985 } 986 987 public void assertNothingQueued() { 988 assertNull(mLastCommand); 989 } 990 } 991 992 private static class TestCallback extends ICallback.Stub { 993 994 private boolean mOnFinishedCalled; 995 private int mLastError; 996 997 @Override 998 public void onFinished(int error) { 999 assertFalse(mOnFinishedCalled); 1000 mOnFinishedCalled = true; 1001 mLastError = error; 1002 } 1003 1004 public void assertResultReceived(int expectedResult) { 1005 assertTrue(mOnFinishedCalled); 1006 assertEquals(expectedResult, mLastError); 1007 } 1008 1009 public void assertNoResultReceived() { 1010 assertFalse(mOnFinishedCalled); 1011 } 1012 } 1013 1014 private static class StubbedCallback extends ICallback.Stub { 1015 @Override 1016 public void onFinished(int error) { 1017 fail("Unexpected call"); 1018 } 1019 } 1020 1021 private static ParcelFileDescriptor createParcelFileDescriptor(byte[] bytes) 1022 throws IOException { 1023 File file = File.createTempFile("pfd", null); 1024 try (FileOutputStream fos = new FileOutputStream(file)) { 1025 fos.write(bytes); 1026 } 1027 ParcelFileDescriptor pfd = 1028 ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); 1029 // This should now be safe to delete. The ParcelFileDescriptor has an open fd. 1030 file.delete(); 1031 return pfd; 1032 } 1033 } 1034