blob: f9ebd28418cd0ddc4511460bc497a6ee9ddb3152 [file] [log] [blame]
Bernardo Rufinofa518532018-01-02 16:01:53 +00001/*
2 * Copyright (C) 2018 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.backup;
18
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000019import static com.android.server.backup.testing.TransportTestUtils.TRANSPORT_NAMES;
20
Bernardo Rufinofa518532018-01-02 16:01:53 +000021import static com.google.common.truth.Truth.assertThat;
22
23import static org.mockito.ArgumentMatchers.any;
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000024import static org.mockito.ArgumentMatchers.anyInt;
Bernardo Rufinofa518532018-01-02 16:01:53 +000025import static org.mockito.ArgumentMatchers.eq;
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000026import static org.mockito.Mockito.mock;
Bernardo Rufinofa518532018-01-02 16:01:53 +000027import static org.mockito.Mockito.verify;
28import static org.mockito.Mockito.when;
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000029import static org.robolectric.Shadows.shadowOf;
Bernardo Rufinofa518532018-01-02 16:01:53 +000030import static org.testng.Assert.expectThrows;
31
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000032import android.app.backup.BackupManager;
33import android.app.backup.ISelectBackupTransportCallback;
34import android.content.ComponentName;
35import android.content.Context;
Bernardo Rufinofa518532018-01-02 16:01:53 +000036import android.content.ContextWrapper;
37import android.os.HandlerThread;
38import android.platform.test.annotations.Presubmit;
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000039import android.provider.Settings;
Bernardo Rufinofa518532018-01-02 16:01:53 +000040
41import com.android.server.backup.testing.ShadowAppBackupUtils;
42import com.android.server.backup.testing.TransportTestUtils;
43import com.android.server.backup.testing.TransportTestUtils.TransportData;
44import com.android.server.backup.transport.TransportNotRegisteredException;
45import com.android.server.testing.FrameworkRobolectricTestRunner;
46import com.android.server.testing.SystemLoaderClasses;
47
48import org.junit.After;
49import org.junit.Before;
50import org.junit.Test;
51import org.junit.runner.RunWith;
52import org.mockito.Mock;
53import org.mockito.MockitoAnnotations;
54import org.robolectric.RuntimeEnvironment;
Bernardo Rufinofa518532018-01-02 16:01:53 +000055import org.robolectric.annotation.Config;
56import org.robolectric.shadows.ShadowContextWrapper;
57import org.robolectric.shadows.ShadowLog;
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000058import org.robolectric.shadows.ShadowLooper;
59import org.robolectric.shadows.ShadowSettings;
Bernardo Rufinofa518532018-01-02 16:01:53 +000060
61import java.io.File;
62import java.util.HashMap;
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000063import java.util.List;
Bernardo Rufinofa518532018-01-02 16:01:53 +000064import java.util.Map;
65
66@RunWith(FrameworkRobolectricTestRunner.class)
67@Config(
68 manifest = Config.NONE,
69 sdk = 26,
70 shadows = {ShadowAppBackupUtils.class}
71)
72@SystemLoaderClasses({RefactoredBackupManagerService.class, TransportManager.class})
73@Presubmit
74public class BackupManagerServiceRoboTest {
75 private static final String TAG = "BMSTest";
76 private static final String TRANSPORT_NAME =
77 "com.google.android.gms/.backup.BackupTransportService";
78
79 @Mock private TransportManager mTransportManager;
80 private HandlerThread mBackupThread;
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000081 private ShadowLooper mShadowBackupLooper;
Bernardo Rufinofa518532018-01-02 16:01:53 +000082 private File mBaseStateDir;
83 private File mDataDir;
84 private RefactoredBackupManagerService mBackupManagerService;
85 private ShadowContextWrapper mShadowContext;
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000086 private Context mContext;
Bernardo Rufinofa518532018-01-02 16:01:53 +000087
88 @Before
89 public void setUp() throws Exception {
90 MockitoAnnotations.initMocks(this);
91
92 mBackupThread = new HandlerThread("backup-test");
93 mBackupThread.setUncaughtExceptionHandler(
94 (t, e) -> ShadowLog.e(TAG, "Uncaught exception in test thread " + t.getName(), e));
95 mBackupThread.start();
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000096 mShadowBackupLooper = shadowOf(mBackupThread.getLooper());
Bernardo Rufinofa518532018-01-02 16:01:53 +000097
98 ContextWrapper context = RuntimeEnvironment.application;
Bernardo Rufino5a484dc2018-01-02 15:53:44 +000099 mContext = context;
100 mShadowContext = shadowOf(context);
Bernardo Rufinofa518532018-01-02 16:01:53 +0000101
Bernardo Rufino5a484dc2018-01-02 15:53:44 +0000102 File cacheDir = mContext.getCacheDir();
Bernardo Rufinofa518532018-01-02 16:01:53 +0000103 mBaseStateDir = new File(cacheDir, "base_state_dir");
104 mDataDir = new File(cacheDir, "data_dir");
105
106 mBackupManagerService =
107 new RefactoredBackupManagerService(
Bernardo Rufino5a484dc2018-01-02 15:53:44 +0000108 mContext,
109 new Trampoline(mContext),
Bernardo Rufinofa518532018-01-02 16:01:53 +0000110 mBackupThread,
111 mBaseStateDir,
112 mDataDir,
113 mTransportManager);
114 }
115
116 @After
117 public void tearDown() throws Exception {
118 mBackupThread.quit();
119 ShadowAppBackupUtils.reset();
120 }
121
Bernardo Rufino5a484dc2018-01-02 15:53:44 +0000122 /* Tests for destination string */
123
Bernardo Rufinofa518532018-01-02 16:01:53 +0000124 @Test
125 public void testDestinationString() throws Exception {
126 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
127 when(mTransportManager.getTransportCurrentDestinationString(eq(TRANSPORT_NAME)))
128 .thenReturn("destinationString");
129
130 String destination = mBackupManagerService.getDestinationString(TRANSPORT_NAME);
131
132 assertThat(destination).isEqualTo("destinationString");
133 }
134
135 @Test
136 public void testDestinationString_whenTransportNotRegistered() throws Exception {
137 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
138 when(mTransportManager.getTransportCurrentDestinationString(eq(TRANSPORT_NAME)))
139 .thenThrow(TransportNotRegisteredException.class);
140
141 String destination = mBackupManagerService.getDestinationString(TRANSPORT_NAME);
142
143 assertThat(destination).isNull();
144 }
145
146 @Test
147 public void testDestinationString_withoutPermission() throws Exception {
148 mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
149 when(mTransportManager.getTransportCurrentDestinationString(eq(TRANSPORT_NAME)))
150 .thenThrow(TransportNotRegisteredException.class);
151
152 expectThrows(
153 SecurityException.class,
154 () -> mBackupManagerService.getDestinationString(TRANSPORT_NAME));
155 }
156
Bernardo Rufino5a484dc2018-01-02 15:53:44 +0000157 /* Tests for app eligibility */
158
Bernardo Rufinofa518532018-01-02 16:01:53 +0000159 @Test
160 public void testIsAppEligibleForBackup_whenAppEligible() throws Exception {
161 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
162 TransportData transport =
163 TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
164 ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> true;
165
166 boolean result = mBackupManagerService.isAppEligibleForBackup("app.package");
167
168 assertThat(result).isTrue();
169 verify(mTransportManager)
170 .disposeOfTransportClient(eq(transport.transportClientMock), any());
171 }
172
173 @Test
174 public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception {
175 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
176 TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
177 ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false;
178
179 boolean result = mBackupManagerService.isAppEligibleForBackup("app.package");
180
181 assertThat(result).isFalse();
182 }
183
184 @Test
185 public void testIsAppEligibleForBackup_withoutPermission() throws Exception {
186 mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
187 TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
188
189 expectThrows(
190 SecurityException.class,
191 () -> mBackupManagerService.isAppEligibleForBackup("app.package"));
192 }
193
194 @Test
195 public void testFilterAppsEligibleForBackup() throws Exception {
196 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
197 TransportData transport =
198 TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
199 Map<String, Boolean> packagesMap = new HashMap<>();
200 packagesMap.put("package.a", true);
201 packagesMap.put("package.b", false);
202 ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = packagesMap::get;
203 String[] packages = packagesMap.keySet().toArray(new String[packagesMap.size()]);
204
205 String[] filtered = mBackupManagerService.filterAppsEligibleForBackup(packages);
206
207 assertThat(filtered).asList().containsExactly("package.a");
208 verify(mTransportManager)
209 .disposeOfTransportClient(eq(transport.transportClientMock), any());
210 }
211
212 @Test
213 public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception {
214 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
215 ShadowAppBackupUtils.sAppIsRunningAndEligibleForBackupWithTransport = p -> false;
216
217 String[] filtered =
218 mBackupManagerService.filterAppsEligibleForBackup(
219 new String[] {"package.a", "package.b"});
220
221 assertThat(filtered).isEmpty();
222 }
223
224 @Test
225 public void testFilterAppsEligibleForBackup_withoutPermission() throws Exception {
226 mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
227 TransportTestUtils.setUpCurrentTransport(mTransportManager, TRANSPORT_NAME);
228
229 expectThrows(
230 SecurityException.class,
231 () ->
232 mBackupManagerService.filterAppsEligibleForBackup(
233 new String[] {"package.a", "package.b"}));
234 }
Bernardo Rufino5a484dc2018-01-02 15:53:44 +0000235
236 /* Tests for select transport */
237
238 private TransportData mNewTransport;
239 private TransportData mOldTransport;
240 private ComponentName mNewTransportComponent;
241 private ISelectBackupTransportCallback mCallback;
242
243 private void setUpForSelectTransport() throws Exception {
244 List<TransportData> transports =
245 TransportTestUtils.setUpTransports(mTransportManager, TRANSPORT_NAMES);
246 mNewTransport = transports.get(0);
247 mNewTransportComponent = mNewTransport.transportClientMock.getTransportComponent();
248 mOldTransport = transports.get(1);
249 when(mTransportManager.selectTransport(eq(mNewTransport.transportName)))
250 .thenReturn(mOldTransport.transportName);
251 }
252
253 @Test
254 public void testSelectBackupTransport() throws Exception {
255 setUpForSelectTransport();
256 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
257
258 String oldTransport =
259 mBackupManagerService.selectBackupTransport(mNewTransport.transportName);
260
261 assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
262 assertThat(oldTransport).isEqualTo(mOldTransport.transportName);
263 }
264
265 @Test
266 public void testSelectBackupTransport_withoutPermission() throws Exception {
267 setUpForSelectTransport();
268 mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
269
270 expectThrows(
271 SecurityException.class,
272 () -> mBackupManagerService.selectBackupTransport(mNewTransport.transportName));
273 }
274
275 @Test
276 public void testSelectBackupTransportAsync() throws Exception {
277 setUpForSelectTransport();
278 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
279 when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
280 .thenReturn(BackupManager.SUCCESS);
281 ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
282
283 mBackupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
284
285 mShadowBackupLooper.runToEndOfTasks();
286 assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName);
287 verify(callback).onSuccess(eq(mNewTransport.transportName));
288 }
289
290 @Test
291 public void testSelectBackupTransportAsync_whenRegistrationFails() throws Exception {
292 setUpForSelectTransport();
293 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
294 when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
295 .thenReturn(BackupManager.ERROR_TRANSPORT_UNAVAILABLE);
296 ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
297
298 mBackupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
299
300 mShadowBackupLooper.runToEndOfTasks();
301 assertThat(getSettingsTransport()).isNotEqualTo(mNewTransport.transportName);
302 verify(callback).onFailure(anyInt());
303 }
304
305 @Test
306 public void testSelectBackupTransportAsync_whenTransportGetsUnregistered() throws Exception {
307 TransportTestUtils.setUpTransports(
308 mTransportManager, new TransportData(TRANSPORT_NAME, null, null));
309 ComponentName newTransportComponent =
310 TransportTestUtils.transportComponentName(TRANSPORT_NAME);
311 mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
312 when(mTransportManager.registerAndSelectTransport(eq(newTransportComponent)))
313 .thenReturn(BackupManager.SUCCESS);
314 ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
315
316 mBackupManagerService.selectBackupTransportAsync(newTransportComponent, callback);
317
318 mShadowBackupLooper.runToEndOfTasks();
319 assertThat(getSettingsTransport()).isNotEqualTo(TRANSPORT_NAME);
320 verify(callback).onFailure(anyInt());
321 }
322
323 @Test
324 public void testSelectBackupTransportAsync_withoutPermission() throws Exception {
325 setUpForSelectTransport();
326 mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
327 ComponentName newTransportComponent =
328 mNewTransport.transportClientMock.getTransportComponent();
329
330 expectThrows(
331 SecurityException.class,
332 () ->
333 mBackupManagerService.selectBackupTransportAsync(
334 newTransportComponent, mock(ISelectBackupTransportCallback.class)));
335 }
336
337 private String getSettingsTransport() {
338 return ShadowSettings.ShadowSecure.getString(
339 mContext.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
340 }
Bernardo Rufinofa518532018-01-02 16:01:53 +0000341}