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.content;
18 
19 import static android.content.pm.UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT;
20 import static android.content.pm.UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT;
21 import static android.content.pm.UserProperties.SHOW_IN_SETTINGS_WITH_PARENT;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.Mockito.doNothing;
27 import static org.mockito.Mockito.doReturn;
28 import static org.mockito.Mockito.spy;
29 import static org.mockito.Mockito.when;
30 
31 import android.accounts.AccountManagerInternal;
32 import android.content.ContentResolver;
33 import android.content.Context;
34 import android.content.pm.UserInfo;
35 import android.content.pm.UserProperties;
36 import android.os.Bundle;
37 import android.os.UserManager;
38 import android.provider.ContactsContract;
39 import android.test.suitebuilder.annotation.SmallTest;
40 
41 import androidx.test.core.app.ApplicationProvider;
42 
43 import junit.framework.TestCase;
44 
45 import org.jetbrains.annotations.NotNull;
46 import org.junit.Before;
47 import org.mockito.Mock;
48 import org.mockito.MockitoAnnotations;
49 
50 /**
51  * Tests for SyncManager.
52  *
53  * bit FrameworksServicesTests:com.android.server.content.SyncManagerTest
54  */
55 @SmallTest
56 public class SyncManagerTest extends TestCase {
57 
58     final String KEY_1 = "key_1";
59     final String KEY_2 = "key_2";
60 
61     private SyncManager mSyncManager;
62     private Context mContext;
63 
64     @Mock
65     private UserManager mUserManager;
66     @Mock
67     private AccountManagerInternal mAccountManagerInternal;
68 
69     private class SyncManagerWithMockedServices extends SyncManager {
70 
71         @Override
getAccountManagerInternal()72         protected AccountManagerInternal getAccountManagerInternal() {
73             return mAccountManagerInternal;
74         }
75 
SyncManagerWithMockedServices(Context context, boolean factoryTest)76         private SyncManagerWithMockedServices(Context context, boolean factoryTest) {
77             super(context, factoryTest);
78         }
79     }
80 
81     @Before
setUp()82     public void setUp() {
83         MockitoAnnotations.initMocks(this);
84         mContext = spy(ApplicationProvider.getApplicationContext());
85         when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
86         doNothing().when(mAccountManagerInternal).addOnAppPermissionChangeListener(any());
87         mSyncManager = spy(new SyncManagerWithMockedServices(mContext, true));
88     }
89 
testSyncExtrasEquals_WithNull()90     public void testSyncExtrasEquals_WithNull() throws Exception {
91         Bundle b1 = new Bundle();
92         Bundle b2 = new Bundle();
93 
94         b1.putString(KEY_1, null);
95         b2.putString(KEY_1, null);
96 
97         assertTrue("Null extra not properly compared between bundles.",
98                 SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
99     }
100 
testSyncExtrasEqualsBigger_WithNull()101     public void testSyncExtrasEqualsBigger_WithNull() throws Exception {
102         Bundle b1 = new Bundle();
103         Bundle b2 = new Bundle();
104 
105         b1.putString(KEY_1, null);
106         b2.putString(KEY_1, null);
107 
108         b1.putString(KEY_2, "bla");
109         b2.putString(KEY_2, "bla");
110 
111         assertTrue("Extras not properly compared between bundles.",
112                 SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
113     }
114 
testSyncExtrasEqualsFails_WithNull()115     public void testSyncExtrasEqualsFails_WithNull() throws Exception {
116         Bundle b1 = new Bundle();
117         b1.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
118         b1.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
119 
120         Bundle b2 = new Bundle();
121         b2.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
122         b2.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
123         b2.putString(null, "Hello NPE!");
124         b2.putString("a", "b");
125         b2.putString("c", "d");
126         b2.putString("e", "f");
127 
128         assertFalse("Extras not properly compared between bundles.",
129                 SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
130     }
131 
testSyncExtrasEqualsFails_differentValues()132     public void testSyncExtrasEqualsFails_differentValues() throws Exception {
133         Bundle b1 = new Bundle();
134         Bundle b2 = new Bundle();
135 
136         b1.putString(KEY_1, null);
137         b2.putString(KEY_1, null);
138 
139         b1.putString(KEY_2, "bla");
140         b2.putString(KEY_2, "ble");  // different key
141 
142         assertFalse("Extras considered equal when they are different.",
143                 SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
144     }
145 
testSyncExtrasEqualsFails_differentNulls()146     public void testSyncExtrasEqualsFails_differentNulls() throws Exception {
147         Bundle b1 = new Bundle();
148         Bundle b2 = new Bundle();
149 
150         b1.putString(KEY_1, null);
151         b2.putString(KEY_1, "bla");  // different key
152 
153         b1.putString(KEY_2, "ble");
154         b2.putString(KEY_2, "ble");
155 
156         assertFalse("Extras considered equal when they are different.",
157                 SyncManager.syncExtrasEquals(b1, b2, false /* don't care about system extras */));
158     }
159 
testFormatDurationHMS()160     public void testFormatDurationHMS() {
161         checkFormatDurationHMS("0s", 0, 0, 0, 0);
162         checkFormatDurationHMS("1s", 0, 0, 0, 1);
163         checkFormatDurationHMS("9s", 0, 0, 0, 9);
164         checkFormatDurationHMS("10s", 0, 0, 0, 10);
165         checkFormatDurationHMS("59s", 0, 0, 0, 59);
166         checkFormatDurationHMS("1m00s", 0, 0, 1, 0);
167         checkFormatDurationHMS("1m01s", 0, 0, 1, 1);
168         checkFormatDurationHMS("1m09s", 0, 0, 1, 9);
169         checkFormatDurationHMS("1m10s", 0, 0, 1, 10);
170         checkFormatDurationHMS("1m59s", 0, 0, 1, 59);
171         checkFormatDurationHMS("1h00m00s", 0, 1, 0, 0);
172         checkFormatDurationHMS("1h00m01s", 0, 1, 0, 1);
173         checkFormatDurationHMS("1h01m01s", 0, 1, 1, 1);
174         checkFormatDurationHMS("1h09m10s", 0, 1, 9, 10);
175         checkFormatDurationHMS("1h10m59s", 0, 1, 10, 59);
176         checkFormatDurationHMS("1h59m00s", 0, 1, 59, 0);
177 
178         checkFormatDurationHMS("1d00h00m00s", 1, 0, 0, 0);
179         checkFormatDurationHMS("1d00h00m00s", 1, 0, 0, 0);
180         checkFormatDurationHMS("1d01h00m00s", 1, 1, 0, 0);
181         checkFormatDurationHMS("1d09h00m00s", 1, 9, 0, 0);
182         checkFormatDurationHMS("1d10h00m00s", 1, 10, 0, 0);
183         checkFormatDurationHMS("1d23h00m00s", 1, 23, 0, 0);
184         checkFormatDurationHMS("123d01h00m00s", 123, 1, 0, 0);
185 
186         final StringBuilder sb = new StringBuilder();
187         assertEquals("-1m01s", SyncManager.formatDurationHMS(sb, -61000L).toString());
188     }
189 
checkFormatDurationHMS(String expected, int d, int h, int m, int s)190     private void checkFormatDurationHMS(String expected,
191             int d, int h, int m, int s) {
192         final long time = (d * 24 * 3600) + (h * 3600) + (m * 60) + s;
193 
194         final StringBuilder sb = new StringBuilder();
195         assertEquals(expected, SyncManager.formatDurationHMS(sb, time * 1000).toString());
196     }
197 
createUserInfo(String name, int id, int groupId, int flags)198     private UserInfo createUserInfo(String name, int id, int groupId, int flags) {
199         final UserInfo ui = new UserInfo(id, name, flags | UserInfo.FLAG_INITIALIZED);
200         ui.profileGroupId = groupId;
201         return ui;
202     }
203 
204     @NotNull
getCloneUserProperties()205     private UserProperties getCloneUserProperties() {
206         return new UserProperties.Builder()
207                 .setStartWithParent(true)
208                 .setShowInLauncher(SHOW_IN_LAUNCHER_WITH_PARENT)
209                 .setShowInSettings(SHOW_IN_SETTINGS_WITH_PARENT)
210                 .setUseParentsContacts(true)
211                 .setInheritDevicePolicy(INHERIT_DEVICE_POLICY_FROM_PARENT)
212                 .build();
213     }
214 
mockUserProperties(UserInfo primaryUserInfo, UserInfo cloneUserInfo)215     private void mockUserProperties(UserInfo primaryUserInfo, UserInfo cloneUserInfo) {
216         UserProperties cloneUserProperties = getCloneUserProperties();
217         when(mUserManager.getUserProperties(cloneUserInfo.getUserHandle()))
218                 .thenReturn(cloneUserProperties);
219         // Set default user properties for primary user
220         when(mUserManager.getUserProperties(primaryUserInfo.getUserHandle()))
221                 .thenReturn(new UserProperties.Builder().build());
222     }
223 
testShouldDisableSync()224     public void testShouldDisableSync() {
225         doReturn(true).when(mSyncManager).isContactSharingAllowedForCloneProfile();
226         UserInfo primaryUserInfo = createUserInfo("primary", 0 /* id */, 0 /* groupId */,
227                 UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN);
228         UserInfo cloneUserInfo = createUserInfo("clone", 10 /* id */, 0 /* groupId */,
229                 UserInfo.FLAG_PROFILE);
230 
231         mockUserProperties(primaryUserInfo, cloneUserInfo);
232 
233         // Clone user accounts must have contact syncs disabled
234         assertThat(mSyncManager.shouldDisableSyncForUser(cloneUserInfo,
235                 ContactsContract.AUTHORITY)).isTrue();
236         assertThat(mSyncManager.shouldDisableSyncForUser(primaryUserInfo,
237                 ContactsContract.AUTHORITY)).isFalse();
238     }
239 }
240