blob: d09d0c8d9e5cde21274cd6f481cb49395a82f8cf [file] [log] [blame]
Neil Fuller68f66662017-03-16 18:32:21 +00001/*
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
17package com.android.server.timezone;
18
Neil Fullera6a71d02017-06-13 15:12:17 +010019import com.android.timezone.distro.DistroVersion;
20import com.android.timezone.distro.StagedDistroOperation;
Neil Fuller9c90dc02017-06-22 14:10:29 +010021import com.android.timezone.distro.TimeZoneDistro;
Neil Fuller5ca8b5b2017-06-29 12:39:49 +010022import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
Neil Fullera6a71d02017-06-13 15:12:17 +010023
Neil Fuller68f66662017-03-16 18:32:21 +000024import org.junit.Before;
25import org.junit.Test;
26
27import android.app.timezone.Callback;
28import android.app.timezone.DistroRulesVersion;
29import android.app.timezone.ICallback;
30import android.app.timezone.RulesManager;
31import android.app.timezone.RulesState;
32import android.os.ParcelFileDescriptor;
33
Neil Fuller54525bf2017-06-22 14:10:29 +010034import java.io.File;
Neil Fuller87b11282017-06-23 16:43:45 +010035import java.io.FileDescriptor;
Neil Fuller54525bf2017-06-22 14:10:29 +010036import java.io.FileOutputStream;
Neil Fuller68f66662017-03-16 18:32:21 +000037import java.io.IOException;
Neil Fuller87b11282017-06-23 16:43:45 +010038import java.io.PrintWriter;
Neil Fuller68f66662017-03-16 18:32:21 +000039import java.util.concurrent.Executor;
40import javax.annotation.Nullable;
Neil Fuller68f66662017-03-16 18:32:21 +000041
Neil Fuller87b11282017-06-23 16:43:45 +010042import libcore.io.IoUtils;
43
Neil Fuller68f66662017-03-16 18:32:21 +000044import static com.android.server.timezone.RulesManagerService.REQUIRED_UPDATER_PERMISSION;
45import static org.junit.Assert.assertEquals;
46import static org.junit.Assert.assertFalse;
47import static org.junit.Assert.assertNotNull;
48import static org.junit.Assert.assertNull;
49import static org.junit.Assert.assertTrue;
50import static org.junit.Assert.fail;
Neil Fuller9c90dc02017-06-22 14:10:29 +010051import static org.mockito.ArgumentMatchers.any;
Neil Fuller68f66662017-03-16 18:32:21 +000052import static org.mockito.Mockito.doNothing;
53import static org.mockito.Mockito.doReturn;
54import static org.mockito.Mockito.doThrow;
55import static org.mockito.Mockito.mock;
56import static org.mockito.Mockito.reset;
57import static org.mockito.Mockito.verify;
58import static org.mockito.Mockito.verifyNoMoreInteractions;
Neil Fuller87b11282017-06-23 16:43:45 +010059import static org.mockito.Mockito.verifyZeroInteractions;
Neil Fuller68f66662017-03-16 18:32:21 +000060import static org.mockito.Mockito.when;
61
62/**
63 * White box interaction / unit testing of the {@link RulesManagerService}.
64 */
65public class RulesManagerServiceTest {
66
67 private RulesManagerService mRulesManagerService;
68
69 private FakeExecutor mFakeExecutor;
70 private PermissionHelper mMockPermissionHelper;
Neil Fuller68f66662017-03-16 18:32:21 +000071 private PackageTracker mMockPackageTracker;
72 private TimeZoneDistroInstaller mMockTimeZoneDistroInstaller;
73
74 @Before
75 public void setUp() {
76 mFakeExecutor = new FakeExecutor();
77
Neil Fuller68f66662017-03-16 18:32:21 +000078 mMockPackageTracker = mock(PackageTracker.class);
79 mMockPermissionHelper = mock(PermissionHelper.class);
80 mMockTimeZoneDistroInstaller = mock(TimeZoneDistroInstaller.class);
81
82 mRulesManagerService = new RulesManagerService(
83 mMockPermissionHelper,
84 mFakeExecutor,
Neil Fuller68f66662017-03-16 18:32:21 +000085 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
Neil Fuller54525bf2017-06-22 14:10:29 +0100280 ParcelFileDescriptor parcelFileDescriptor =
281 createParcelFileDescriptor(createArbitraryBytes(1000));
Neil Fuller68f66662017-03-16 18:32:21 +0000282
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
Neil Fuller9c90dc02017-06-22 14:10:29 +0100290 // Request the rules state while the async operation is "happening".
291 RulesState actualRulesState = mRulesManagerService.getRulesState();
Neil Fuller68f66662017-03-16 18:32:21 +0000292 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 */);
Neil Fuller9c90dc02017-06-22 14:10:29 +0100297 assertEquals(expectedRuleState, actualRulesState);
Neil Fuller68f66662017-03-16 18:32:21 +0000298 }
299
300 @Test
301 public void requestInstall_operationInProgress() throws Exception {
302 configureCallerHasPermission();
303
Neil Fuller54525bf2017-06-22 14:10:29 +0100304 ParcelFileDescriptor parcelFileDescriptor1 =
305 createParcelFileDescriptor(createArbitraryBytes(1000));
Neil Fuller68f66662017-03-16 18:32:21 +0000306
307 byte[] tokenBytes = createArbitraryTokenBytes();
308 ICallback callback = new StubbedCallback();
309
310 // First request should succeed.
311 assertEquals(RulesManager.SUCCESS,
Neil Fuller54525bf2017-06-22 14:10:29 +0100312 mRulesManagerService.requestInstall(parcelFileDescriptor1, tokenBytes, callback));
Neil Fuller68f66662017-03-16 18:32:21 +0000313
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.
Neil Fuller54525bf2017-06-22 14:10:29 +0100319 ParcelFileDescriptor parcelFileDescriptor2 =
320 createParcelFileDescriptor(createArbitraryBytes(1000));
Neil Fuller68f66662017-03-16 18:32:21 +0000321 assertEquals(RulesManager.ERROR_OPERATION_IN_PROGRESS,
Neil Fuller54525bf2017-06-22 14:10:29 +0100322 mRulesManagerService.requestInstall(parcelFileDescriptor2, tokenBytes, callback));
323
324 assertClosed(parcelFileDescriptor2);
Neil Fuller68f66662017-03-16 18:32:21 +0000325
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
Neil Fuller54525bf2017-06-22 14:10:29 +0100336 ParcelFileDescriptor parcelFileDescriptor =
337 createParcelFileDescriptor(createArbitraryBytes(1000));
Neil Fuller68f66662017-03-16 18:32:21 +0000338
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
Neil Fuller54525bf2017-06-22 14:10:29 +0100348 assertClosed(parcelFileDescriptor);
349
Neil Fuller68f66662017-03-16 18:32:21 +0000350 // 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
Neil Fuller54525bf2017-06-22 14:10:29 +0100379 ParcelFileDescriptor parcelFileDescriptor =
380 createParcelFileDescriptor(createArbitraryBytes(1000));
Neil Fuller68f66662017-03-16 18:32:21 +0000381 byte[] tokenBytes = createArbitraryTokenBytes();
382 ICallback callback = null;
383
384 try {
385 mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback);
386 fail();
387 } catch (NullPointerException expected) {}
388
Neil Fuller54525bf2017-06-22 14:10:29 +0100389 assertClosed(parcelFileDescriptor);
390
Neil Fuller68f66662017-03-16 18:32:21 +0000391 // 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
Neil Fuller54525bf2017-06-22 14:10:29 +0100401 ParcelFileDescriptor parcelFileDescriptor =
402 createParcelFileDescriptor(createArbitraryBytes(1000));
Neil Fuller68f66662017-03-16 18:32:21 +0000403
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.
Neil Fuller9c90dc02017-06-22 14:10:29 +0100419 configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_SUCCESS);
Neil Fuller68f66662017-03-16 18:32:21 +0000420
421 // Simulate the async execution.
422 mFakeExecutor.simulateAsyncExecutionOfLastCommand();
423
Neil Fuller54525bf2017-06-22 14:10:29 +0100424 assertClosed(parcelFileDescriptor);
425
Neil Fuller68f66662017-03-16 18:32:21 +0000426 // Verify the expected calls were made to other components.
Neil Fuller9c90dc02017-06-22 14:10:29 +0100427 verifyStageInstallCalled();
Neil Fuller68f66662017-03-16 18:32:21 +0000428 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
Neil Fuller54525bf2017-06-22 14:10:29 +0100438 ParcelFileDescriptor parcelFileDescriptor =
439 createParcelFileDescriptor(createArbitraryBytes(1000));
Neil Fuller68f66662017-03-16 18:32:21 +0000440
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.
Neil Fuller9c90dc02017-06-22 14:10:29 +0100453 configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_SUCCESS);
Neil Fuller68f66662017-03-16 18:32:21 +0000454
455 // Simulate the async execution.
456 mFakeExecutor.simulateAsyncExecutionOfLastCommand();
457
Neil Fuller54525bf2017-06-22 14:10:29 +0100458 assertClosed(parcelFileDescriptor);
459
Neil Fuller68f66662017-03-16 18:32:21 +0000460 // Verify the expected calls were made to other components.
Neil Fuller9c90dc02017-06-22 14:10:29 +0100461 verifyStageInstallCalled();
Neil Fuller68f66662017-03-16 18:32:21 +0000462 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
Neil Fuller54525bf2017-06-22 14:10:29 +0100472 ParcelFileDescriptor parcelFileDescriptor =
473 createParcelFileDescriptor(createArbitraryBytes(1000));
Neil Fuller68f66662017-03-16 18:32:21 +0000474
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.
Neil Fuller9c90dc02017-06-22 14:10:29 +0100489 configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR);
Neil Fuller68f66662017-03-16 18:32:21 +0000490
491 // Simulate the async execution.
492 mFakeExecutor.simulateAsyncExecutionOfLastCommand();
493
Neil Fuller54525bf2017-06-22 14:10:29 +0100494 assertClosed(parcelFileDescriptor);
495
Neil Fuller68f66662017-03-16 18:32:21 +0000496 // Verify the expected calls were made to other components.
Neil Fuller9c90dc02017-06-22 14:10:29 +0100497 verifyStageInstallCalled();
Neil Fuller68f66662017-03-16 18:32:21 +0000498
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
Neil Fuller68f66662017-03-16 18:32:21 +0000508 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.
Neil Fuller8e27c922017-09-14 09:34:56 +0100588 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);
Neil Fuller68f66662017-03-16 18:32:21 +0000621
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.
Neil Fuller8e27c922017-09-14 09:34:56 +0100648 configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_SUCCESS);
Neil Fuller68f66662017-03-16 18:32:21 +0000649
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.
Neil Fuller8e27c922017-09-14 09:34:56 +0100679 configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_FAIL);
Neil Fuller68f66662017-03-16 18:32:21 +0000680
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
Neil Fuller87b11282017-06-23 16:43:45 +0100764 @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
Neil Fuller68f66662017-03-16 18:32:21 +0000855 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
Neil Fuller9c90dc02017-06-22 14:10:29 +0100878 private void configureStageInstallExpectation(int resultCode)
Neil Fuller68f66662017-03-16 18:32:21 +0000879 throws Exception {
Neil Fuller9c90dc02017-06-22 14:10:29 +0100880 when(mMockTimeZoneDistroInstaller.stageInstallWithErrorCode(any(TimeZoneDistro.class)))
Neil Fuller68f66662017-03-16 18:32:21 +0000881 .thenReturn(resultCode);
882 }
883
Neil Fuller8e27c922017-09-14 09:34:56 +0100884 private void configureStageUninstallExpectation(int resultCode) throws Exception {
885 doReturn(resultCode).when(mMockTimeZoneDistroInstaller).stageUninstall();
Neil Fuller68f66662017-03-16 18:32:21 +0000886 }
887
Neil Fuller9c90dc02017-06-22 14:10:29 +0100888 private void verifyStageInstallCalled() throws Exception {
889 verify(mMockTimeZoneDistroInstaller).stageInstallWithErrorCode(any(TimeZoneDistro.class));
Neil Fuller68f66662017-03-16 18:32:21 +0000890 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
Neil Fuller68f66662017-03-16 18:32:21 +0000921 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
Neil Fuller54525bf2017-06-22 14:10:29 +0100960 private static void assertClosed(ParcelFileDescriptor parcelFileDescriptor) {
961 assertFalse(parcelFileDescriptor.getFileDescriptor().valid());
962 }
963
Neil Fuller68f66662017-03-16 18:32:21 +0000964 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 }
Neil Fuller54525bf2017-06-22 14:10:29 +01001020
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 }
Neil Fuller68f66662017-03-16 18:32:21 +00001033}