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