1 /* 2 * Copyright (C) 2010 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 android.content.cts; 18 19 import android.accounts.Account; 20 import android.accounts.AccountManager; 21 import android.accounts.AccountManagerCallback; 22 import android.accounts.AccountManagerFuture; 23 import android.accounts.AuthenticatorException; 24 import android.accounts.OperationCanceledException; 25 import android.content.ContentResolver; 26 import android.content.Context; 27 import android.content.SyncAdapterType; 28 import android.os.Bundle; 29 import android.os.SystemClock; 30 import android.platform.test.annotations.AppModeFull; 31 import android.test.AndroidTestCase; 32 import android.util.Log; 33 34 import java.io.IOException; 35 import java.util.concurrent.CountDownLatch; 36 import java.util.concurrent.TimeUnit; 37 38 @AppModeFull(reason = "Sync manager not supported") 39 public class ContentResolverSyncTestCase extends AndroidTestCase { 40 private static final String TAG = "SyncTest"; 41 42 private static final String AUTHORITY = "android.content.cts.authority"; 43 44 private static final Account ACCOUNT = new Account(MockAccountAuthenticator.ACCOUNT_NAME, 45 MockAccountAuthenticator.ACCOUNT_TYPE); 46 47 private static final int INITIAL_SYNC_TIMEOUT_MS = 60 * 1000; 48 private static final int CANCEL_TIMEOUT_MS = 60 * 1000; 49 private static final int LATCH_TIMEOUT_MS = 5000; 50 51 private static AccountManager sAccountManager; 52 53 @Override setUp()54 public void setUp() throws Exception { 55 super.setUp(); 56 getMockSyncAdapter(); 57 sAccountManager = AccountManager.get(getContext()); 58 } 59 60 @Override tearDown()61 public void tearDown() throws Exception { 62 getMockSyncAdapter().clearData(); 63 64 // Need to clean up created account 65 removeAccount(sAccountManager, ACCOUNT, null /* callback */); 66 67 // Need to cancel any sync that was started. 68 cancelSync(null, AUTHORITY, LATCH_TIMEOUT_MS); 69 70 super.tearDown(); 71 } 72 getMockSyncAdapter()73 public static synchronized MockSyncAdapter getMockSyncAdapter() { 74 return MockSyncAdapter.getMockSyncAdapter(); 75 76 } 77 getMockAuthenticator(Context context)78 public static synchronized MockAccountAuthenticator getMockAuthenticator(Context context) { 79 return MockAccountAuthenticator.getMockAuthenticator(context); 80 } 81 addAccountExplicitly(Account account, String password, Bundle userdata)82 private void addAccountExplicitly(Account account, String password, Bundle userdata) { 83 assertTrue(sAccountManager.addAccountExplicitly(account, password, userdata)); 84 } 85 removeAccount(AccountManager am, Account account, AccountManagerCallback<Boolean> callback)86 private boolean removeAccount(AccountManager am, Account account, 87 AccountManagerCallback<Boolean> callback) throws IOException, AuthenticatorException, 88 OperationCanceledException { 89 90 AccountManagerFuture<Boolean> futureBoolean = am.removeAccount(account, 91 callback, 92 null /* handler */); 93 Boolean resultBoolean = futureBoolean.getResult(); 94 assertTrue(futureBoolean.isDone()); 95 96 return resultBoolean; 97 } 98 setNewLatch(CountDownLatch latch)99 private CountDownLatch setNewLatch(CountDownLatch latch) { 100 getMockSyncAdapter().clearData(); 101 getMockSyncAdapter().setLatch(latch); 102 return latch; 103 } 104 addAccountAndVerifyInitSync(Account account, String password, String authority, int accountIndex)105 private void addAccountAndVerifyInitSync(Account account, String password, 106 String authority, int accountIndex) { 107 108 CountDownLatch latch = setNewLatch(new CountDownLatch(1)); 109 110 addAccountExplicitly(account, password, null /* userData */); 111 112 // Wait with timeout for the callback to do its work 113 try { 114 if (!latch.await(INITIAL_SYNC_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 115 fail("should not time out waiting on latch"); 116 } 117 } catch (InterruptedException e) { 118 fail("should not throw an InterruptedException"); 119 } 120 121 assertFalse(getMockSyncAdapter().isStartSync()); 122 assertFalse(getMockSyncAdapter().isCancelSync()); 123 assertTrue(getMockSyncAdapter().isInitialized()); 124 assertEquals(account, getMockSyncAdapter().getAccounts().get(accountIndex)); 125 assertEquals(authority, getMockSyncAdapter().getAuthority()); 126 } 127 cancelSync(Account account, String authority, int latchTimeoutMillis)128 private void cancelSync(Account account, String authority, int latchTimeoutMillis) { 129 CountDownLatch latch = setNewLatch(new CountDownLatch(1)); 130 131 Bundle extras = new Bundle(); 132 extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 133 134 ContentResolver.cancelSync(account, authority); 135 136 // Wait with timeout for the callback to do its work 137 try { 138 latch.await(latchTimeoutMillis, TimeUnit.MILLISECONDS); 139 } catch (InterruptedException e) { 140 fail("should not throw an InterruptedException"); 141 } 142 // Make sure the sync manager thinks the sync finished. 143 144 final long timeout = SystemClock.uptimeMillis() + CANCEL_TIMEOUT_MS; 145 while (SystemClock.uptimeMillis() < timeout) { 146 if (!ContentResolver.isSyncActive(ACCOUNT, AUTHORITY) 147 && !ContentResolver.isSyncPending(ACCOUNT, AUTHORITY)) { 148 break; 149 } 150 Log.i(TAG, "Waiting for sync to finish..."); 151 try { 152 Thread.sleep(500); 153 } catch (InterruptedException e) { 154 } 155 } 156 } 157 requestSync(Account account, String authority, int latchTimeoutMillis)158 private void requestSync(Account account, String authority, int latchTimeoutMillis) { 159 CountDownLatch latch = setNewLatch(new CountDownLatch(1)); 160 161 Bundle extras = new Bundle(); 162 extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 163 164 ContentResolver.requestSync(account, authority, extras); 165 166 // Wait with timeout for the callback to do its work 167 try { 168 latch.await(latchTimeoutMillis, TimeUnit.MILLISECONDS); 169 } catch (InterruptedException e) { 170 fail("should not throw an InterruptedException"); 171 } 172 } 173 setIsSyncable(Account account, String authority, boolean b)174 private void setIsSyncable(Account account, String authority, boolean b) { 175 ContentResolver.setIsSyncable(account, authority, (b) ? 1 : 0); 176 } 177 178 /** 179 * Test a sync request 180 */ testRequestSync()181 public void testRequestSync() throws IOException, AuthenticatorException, 182 OperationCanceledException { 183 184 // Prevent auto sync 185 ContentResolver.setMasterSyncAutomatically(false); 186 assertEquals(false, ContentResolver.getMasterSyncAutomatically()); 187 188 addAccountAndVerifyInitSync(ACCOUNT, 189 MockAccountAuthenticator.ACCOUNT_PASSWORD, 190 AUTHORITY, 191 0); 192 193 getMockSyncAdapter().clearData(); 194 195 setIsSyncable(ACCOUNT, AUTHORITY, true); 196 cancelSync(ACCOUNT, AUTHORITY, LATCH_TIMEOUT_MS); 197 198 getMockSyncAdapter().clearData(); 199 200 requestSync(ACCOUNT, AUTHORITY, LATCH_TIMEOUT_MS); 201 202 assertTrue(getMockSyncAdapter().isStartSync()); 203 assertFalse(getMockSyncAdapter().isCancelSync()); 204 assertFalse(getMockSyncAdapter().isInitialized()); 205 assertEquals(ACCOUNT, getMockSyncAdapter().getAccounts().get(0)); 206 assertEquals(AUTHORITY, getMockSyncAdapter().getAuthority()); 207 } 208 209 /** 210 * Test a sync cancel 211 */ testCancelSync()212 public void testCancelSync() throws IOException, AuthenticatorException, 213 OperationCanceledException { 214 215 // Prevent auto sync 216 ContentResolver.setMasterSyncAutomatically(false); 217 assertEquals(false, ContentResolver.getMasterSyncAutomatically()); 218 219 addAccountAndVerifyInitSync(ACCOUNT, 220 MockAccountAuthenticator.ACCOUNT_PASSWORD, 221 AUTHORITY, 222 0); 223 224 getMockSyncAdapter().clearData(); 225 226 setIsSyncable(ACCOUNT, AUTHORITY, true); 227 requestSync(ACCOUNT, AUTHORITY, LATCH_TIMEOUT_MS); 228 229 getMockSyncAdapter().clearData(); 230 231 cancelSync(ACCOUNT, AUTHORITY, LATCH_TIMEOUT_MS); 232 233 assertFalse(getMockSyncAdapter().isStartSync()); 234 assertTrue(getMockSyncAdapter().isCancelSync()); 235 assertFalse(getMockSyncAdapter().isInitialized()); 236 237 assertFalse(ContentResolver.isSyncActive(ACCOUNT, AUTHORITY)); 238 assertFalse(ContentResolver.isSyncPending(ACCOUNT, AUTHORITY)); 239 } 240 241 /** 242 * Test if we can set and get the MasterSyncAutomatically switch 243 */ testGetAndSetMasterSyncAutomatically()244 public void testGetAndSetMasterSyncAutomatically() throws Exception { 245 ContentResolver.setMasterSyncAutomatically(true); 246 assertEquals(true, ContentResolver.getMasterSyncAutomatically()); 247 248 ContentResolver.setMasterSyncAutomatically(false); 249 assertEquals(false, ContentResolver.getMasterSyncAutomatically()); 250 Thread.sleep(3000); 251 } 252 253 /** 254 * Test if we can set and get the SyncAutomatically switch for an account 255 */ testGetAndSetSyncAutomatically()256 public void testGetAndSetSyncAutomatically() { 257 try { 258 Thread.sleep(5000); 259 } catch (InterruptedException e) { 260 } 261 // Prevent auto sync 262 ContentResolver.setMasterSyncAutomatically(false); 263 assertEquals(false, ContentResolver.getMasterSyncAutomatically()); 264 265 ContentResolver.setSyncAutomatically(ACCOUNT, AUTHORITY, false); 266 assertEquals(false, ContentResolver.getSyncAutomatically(ACCOUNT, AUTHORITY)); 267 268 ContentResolver.setSyncAutomatically(ACCOUNT, AUTHORITY, true); 269 assertEquals(true, ContentResolver.getSyncAutomatically(ACCOUNT, AUTHORITY)); 270 } 271 272 /** 273 * Test if we can set and get the IsSyncable switch for an account 274 */ testGetAndSetIsSyncable()275 public void testGetAndSetIsSyncable() { 276 // Prevent auto sync 277 ContentResolver.setMasterSyncAutomatically(false); 278 assertEquals(false, ContentResolver.getMasterSyncAutomatically()); 279 280 addAccountExplicitly(ACCOUNT, MockAccountAuthenticator.ACCOUNT_PASSWORD, null /* userData */); 281 282 ContentResolver.setIsSyncable(ACCOUNT, AUTHORITY, 2); 283 assertTrue(ContentResolver.getIsSyncable(ACCOUNT, AUTHORITY) > 0); 284 285 ContentResolver.setIsSyncable(ACCOUNT, AUTHORITY, 1); 286 assertTrue(ContentResolver.getIsSyncable(ACCOUNT, AUTHORITY) > 0); 287 288 ContentResolver.setIsSyncable(ACCOUNT, AUTHORITY, 0); 289 assertEquals(0, ContentResolver.getIsSyncable(ACCOUNT, AUTHORITY)); 290 291 ContentResolver.setIsSyncable(ACCOUNT, AUTHORITY, -1); 292 assertTrue(ContentResolver.getIsSyncable(ACCOUNT, AUTHORITY) < 0); 293 294 ContentResolver.setIsSyncable(ACCOUNT, AUTHORITY, -2); 295 assertTrue(ContentResolver.getIsSyncable(ACCOUNT, AUTHORITY) < 0); 296 } 297 298 /** 299 * Test if we can get the sync adapter types 300 */ 301 public void testGetSyncAdapterTypes() { 302 SyncAdapterType[] types = ContentResolver.getSyncAdapterTypes(); 303 assertNotNull(types); 304 int length = types.length; 305 assertTrue(length > 0); 306 boolean found = false; 307 for (int n=0; n < length; n++) { 308 SyncAdapterType type = types[n]; 309 if (MockAccountAuthenticator.ACCOUNT_TYPE.equals(type.accountType) && 310 AUTHORITY.equals(type.authority)) { 311 found = true; 312 break; 313 } 314 } 315 assertTrue(found); 316 } 317 318 /** 319 * Test if a badly formed sync request is throwing exceptions 320 */ 321 public void testStartSyncFailure() { 322 try { 323 ContentResolver.requestSync(null, null, null); 324 fail("did not throw IllegalArgumentException when extras is null."); 325 } catch (IllegalArgumentException e) { 326 //expected. 327 } 328 } 329 330 /** 331 * Test validate sync extra bundle 332 */ 333 public void testValidateSyncExtrasBundle() { 334 Bundle extras = new Bundle(); 335 extras.putInt("Integer", 20); 336 extras.putLong("Long", 10l); 337 extras.putBoolean("Boolean", true); 338 extras.putFloat("Float", 5.5f); 339 extras.putDouble("Double", 2.5); 340 extras.putString("String", MockAccountAuthenticator.ACCOUNT_NAME); 341 extras.putCharSequence("CharSequence", null); 342 343 ContentResolver.validateSyncExtrasBundle(extras); 344 345 extras.putChar("Char", 'a'); // type Char is invalid 346 try { 347 ContentResolver.validateSyncExtrasBundle(extras); 348 fail("did not throw IllegalArgumentException when extras is invalide."); 349 } catch (IllegalArgumentException e) { 350 //expected. 351 } 352 } 353 354 /** 355 * Test to verify that a SyncAdapter is called on all the accounts accounts 356 */ 357 public void testCallMultipleAccounts() { 358 // Prevent auto sync 359 ContentResolver.setMasterSyncAutomatically(false); 360 assertEquals(false, ContentResolver.getMasterSyncAutomatically()); 361 362 addAccountAndVerifyInitSync(ACCOUNT, 363 MockAccountAuthenticator.ACCOUNT_PASSWORD, 364 AUTHORITY, 365 0); 366 367 getMockSyncAdapter().clearData(); 368 369 setIsSyncable(ACCOUNT, AUTHORITY, true); 370 cancelSync(ACCOUNT, AUTHORITY, LATCH_TIMEOUT_MS); 371 372 getMockSyncAdapter().clearData(); 373 374 requestSync(null /* all accounts */, AUTHORITY, LATCH_TIMEOUT_MS); 375 376 assertTrue(getMockSyncAdapter().isStartSync()); 377 assertFalse(getMockSyncAdapter().isCancelSync()); 378 assertFalse(getMockSyncAdapter().isInitialized()); 379 assertEquals(ACCOUNT, getMockSyncAdapter().getAccounts().get(0)); 380 assertEquals(AUTHORITY, getMockSyncAdapter().getAuthority()); 381 382 } 383 } 384