1 /* 2 * Copyright (C) 2007 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 android.accounts.Account; 20 import android.content.ComponentName; 21 import android.content.ContentResolver; 22 import android.content.Context; 23 import android.content.ContextWrapper; 24 import android.content.Intent; 25 import android.content.PeriodicSync; 26 import android.content.res.Resources; 27 import android.os.Bundle; 28 import android.test.AndroidTestCase; 29 import android.test.RenamingDelegatingContext; 30 import android.test.mock.MockContentResolver; 31 import android.test.mock.MockContext; 32 import android.test.suitebuilder.annotation.LargeTest; 33 import android.test.suitebuilder.annotation.MediumTest; 34 import android.test.suitebuilder.annotation.SmallTest; 35 36 import com.android.server.content.SyncStorageEngine.EndPoint; 37 38 import com.android.internal.os.AtomicFile; 39 40 import java.io.File; 41 import java.io.FileOutputStream; 42 import java.util.List; 43 44 import com.android.server.content.SyncStorageEngine.EndPoint; 45 46 public class SyncStorageEngineTest extends AndroidTestCase { 47 48 protected Account account1; 49 protected Account account2; 50 protected ComponentName syncService1; 51 protected String authority1 = "testprovider"; 52 protected Bundle defaultBundle; 53 protected final int DEFAULT_USER = 0; 54 55 /* Some default poll frequencies. */ 56 final long dayPoll = (60 * 60 * 24); 57 final long dayFuzz = 60; 58 final long thousandSecs = 1000; 59 final long thousandSecsFuzz = 100; 60 61 MockContentResolver mockResolver; 62 SyncStorageEngine engine; 63 getSyncDir()64 private File getSyncDir() { 65 return new File(new File(getContext().getFilesDir(), "system"), "sync"); 66 } 67 68 @Override setUp()69 public void setUp() { 70 account1 = new Account("a@example.com", "example.type"); 71 account2 = new Account("b@example.com", "example.type"); 72 syncService1 = new ComponentName("com.example", "SyncService"); 73 // Default bundle. 74 defaultBundle = new Bundle(); 75 defaultBundle.putInt("int_key", 0); 76 defaultBundle.putString("string_key", "hello"); 77 // Set up storage engine. 78 mockResolver = new MockContentResolver(); 79 engine = SyncStorageEngine.newTestInstance( 80 new TestContext(mockResolver, getContext())); 81 } 82 83 /** 84 * Test that we handle the case of a history row being old enough to purge before the 85 * corresponding sync is finished. This can happen if the clock changes while we are syncing. 86 * 87 */ 88 // TODO: this test causes AidlTest to fail. Omit for now 89 // @SmallTest testPurgeActiveSync()90 public void testPurgeActiveSync() throws Exception { 91 final Account account = new Account("a@example.com", "example.type"); 92 final String authority = "testprovider"; 93 94 MockContentResolver mockResolver = new MockContentResolver(); 95 96 SyncStorageEngine engine = SyncStorageEngine.newTestInstance( 97 new TestContext(mockResolver, getContext())); 98 long time0 = 1000; 99 SyncOperation op = new SyncOperation(account, 0, 100 SyncOperation.REASON_PERIODIC, 101 SyncStorageEngine.SOURCE_LOCAL, 102 authority, 103 Bundle.EMPTY, time0, 0 /* flex*/, 0, 0, true); 104 long historyId = engine.insertStartSyncEvent(op, time0); 105 long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2; 106 engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0); 107 } 108 109 /** 110 * Test persistence of pending operations. 111 */ 112 @MediumTest testAppendPending()113 public void testAppendPending() throws Exception { 114 SyncOperation sop = new SyncOperation(account1, 115 DEFAULT_USER, 116 SyncOperation.REASON_PERIODIC, 117 SyncStorageEngine.SOURCE_LOCAL, authority1, Bundle.EMPTY, 118 0 /* runtime */, 0 /* flex */, 0 /* backoff */, 0 /* delayuntil */, 119 true /* expedited */); 120 engine.insertIntoPending(sop); 121 122 // Force engine to read from disk. 123 engine.clearAndReadState(); 124 125 assertTrue(engine.getPendingOperationCount() == 1); 126 List<SyncStorageEngine.PendingOperation> pops = engine.getPendingOperations(); 127 SyncStorageEngine.PendingOperation popRetrieved = pops.get(0); 128 assertEquals(sop.target.account, popRetrieved.target.account); 129 assertEquals(sop.target.provider, popRetrieved.target.provider); 130 assertEquals(sop.target.service, popRetrieved.target.service); 131 assertEquals(sop.target.userId, popRetrieved.target.userId); 132 assertEquals(sop.reason, popRetrieved.reason); 133 assertEquals(sop.syncSource, popRetrieved.syncSource); 134 assertEquals(sop.isExpedited(), popRetrieved.expedited); 135 assert(android.content.PeriodicSync.syncExtrasEquals(sop.extras, popRetrieved.extras)); 136 } 137 138 /** 139 * Verify {@link com.android.server.content.SyncStorageEngine#writePendingOperationsLocked()} 140 */ testWritePendingOperationsLocked()141 public void testWritePendingOperationsLocked() throws Exception { 142 SyncOperation sop = new SyncOperation(account1, 143 DEFAULT_USER, 144 SyncOperation.REASON_IS_SYNCABLE, 145 SyncStorageEngine.SOURCE_LOCAL, authority1, Bundle.EMPTY, 146 1000L /* runtime */, 57L /* flex */, 0 /* backoff */, 0 /* delayuntil */, 147 true /* expedited */); 148 SyncOperation sop1 = new SyncOperation(account2, 149 DEFAULT_USER, 150 SyncOperation.REASON_PERIODIC, 151 SyncStorageEngine.SOURCE_LOCAL, authority1, defaultBundle, 152 0 /* runtime */, 0 /* flex */, 20L /* backoff */, 100L /* delayuntil */, 153 false /* expedited */); 154 SyncOperation deleted = new SyncOperation(account2, 155 DEFAULT_USER, 156 SyncOperation.REASON_SYNC_AUTO, 157 SyncStorageEngine.SOURCE_LOCAL, authority1, Bundle.EMPTY, 158 0 /* runtime */, 0 /* flex */, 20L /* backoff */, 100L /* delayuntil */, 159 false /* expedited */); 160 engine.insertIntoPending(sop); 161 engine.insertIntoPending(sop1); 162 engine.insertIntoPending(deleted); 163 164 SyncStorageEngine.PendingOperation popDeleted = engine.getPendingOperations().get(2); 165 // Free verifying, going to delete it anyway. 166 assertEquals(deleted.target.account, popDeleted.target.account); 167 assertEquals(deleted.target.provider, popDeleted.target.provider); 168 assertEquals(deleted.target.service, popDeleted.target.service); 169 assertEquals(deleted.target.userId, popDeleted.target.userId); 170 assertEquals(deleted.reason, popDeleted.reason); 171 assertEquals(deleted.syncSource, popDeleted.syncSource); 172 assertEquals(deleted.isExpedited(), popDeleted.expedited); 173 assert(android.content.PeriodicSync.syncExtrasEquals(deleted.extras, popDeleted.extras)); 174 // Delete one to force write-all 175 engine.deleteFromPending(popDeleted); 176 assertEquals("Delete of pending op failed.", 2, engine.getPendingOperationCount()); 177 // If there's dirty pending data (which there is because we deleted a pending op) this 178 // re-writes the entire file. 179 engine.writeAllState(); 180 181 engine.clearAndReadState(); 182 183 // Validate state read back out. 184 assertEquals("Delete of pending op failed.", 2, engine.getPendingOperationCount()); 185 186 List<SyncStorageEngine.PendingOperation> pops = engine.getPendingOperations(); 187 188 SyncStorageEngine.PendingOperation popRetrieved = pops.get(0); 189 assertEquals(sop.target.account, popRetrieved.target.account); 190 assertEquals(sop.target.provider, popRetrieved.target.provider); 191 assertEquals(sop.target.service, popRetrieved.target.service); 192 assertEquals(sop.target.userId, popRetrieved.target.userId); 193 assertEquals(sop.reason, popRetrieved.reason); 194 assertEquals(sop.syncSource, popRetrieved.syncSource); 195 assertEquals(sop.isExpedited(), popRetrieved.expedited); 196 assert(android.content.PeriodicSync.syncExtrasEquals(sop.extras, popRetrieved.extras)); 197 198 popRetrieved = pops.get(1); 199 assertEquals(sop1.target.account, popRetrieved.target.account); 200 assertEquals(sop1.target.provider, popRetrieved.target.provider); 201 assertEquals(sop1.target.service, popRetrieved.target.service); 202 assertEquals(sop1.target.userId, popRetrieved.target.userId); 203 assertEquals(sop1.reason, popRetrieved.reason); 204 assertEquals(sop1.syncSource, popRetrieved.syncSource); 205 assertEquals(sop1.isExpedited(), popRetrieved.expedited); 206 assert(android.content.PeriodicSync.syncExtrasEquals(sop1.extras, popRetrieved.extras)); 207 } 208 209 /** 210 * Test that we can create, remove and retrieve periodic syncs. Backwards compatibility - 211 * periodic syncs with no flex time are no longer used. 212 */ 213 @MediumTest testPeriodics()214 public void testPeriodics() throws Exception { 215 final Account account1 = new Account("a@example.com", "example.type"); 216 final Account account2 = new Account("b@example.com", "example.type.2"); 217 final String authority = "testprovider"; 218 final Bundle extras1 = new Bundle(); 219 extras1.putString("a", "1"); 220 final Bundle extras2 = new Bundle(); 221 extras2.putString("a", "2"); 222 final int period1 = 200; 223 final int period2 = 1000; 224 225 PeriodicSync sync1 = new PeriodicSync(account1, authority, extras1, period1); 226 EndPoint end1 = new EndPoint(account1, authority, 0); 227 228 PeriodicSync sync2 = new PeriodicSync(account1, authority, extras2, period1); 229 PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2); 230 PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2); 231 232 233 234 removePeriodicSyncs(engine, account1, 0, authority); 235 removePeriodicSyncs(engine, account2, 0, authority); 236 removePeriodicSyncs(engine, account1, 1, authority); 237 238 // this should add two distinct periodic syncs for account1 and one for account2 239 engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 0), period1, 0, extras1); 240 engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 0), period1, 0, extras2); 241 engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 0), period2, 0, extras2); 242 engine.updateOrAddPeriodicSync(new EndPoint(account2, authority, 0), period2, 0, extras2); 243 // add a second user 244 engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 1), period1, 0, extras2); 245 246 List<PeriodicSync> syncs = engine.getPeriodicSyncs(new EndPoint(account1, authority, 0)); 247 248 assertEquals(2, syncs.size()); 249 250 assertEquals(sync1, syncs.get(0)); 251 assertEquals(sync3, syncs.get(1)); 252 253 engine.removePeriodicSync(new EndPoint(account1, authority, 0), extras1); 254 255 syncs = engine.getPeriodicSyncs(new EndPoint(account1, authority, 0)); 256 assertEquals(1, syncs.size()); 257 assertEquals(sync3, syncs.get(0)); 258 259 syncs = engine.getPeriodicSyncs(new EndPoint(account2, authority, 0)); 260 assertEquals(1, syncs.size()); 261 assertEquals(sync4, syncs.get(0)); 262 263 syncs = engine.getPeriodicSyncs(new EndPoint(sync2.account, sync2.authority, 1)); 264 assertEquals(1, syncs.size()); 265 assertEquals(sync2, syncs.get(0)); 266 } 267 268 /** 269 * Test that we can create, remove and retrieve periodic syncs with a provided flex time. 270 */ 271 @MediumTest testPeriodicsV2()272 public void testPeriodicsV2() throws Exception { 273 final Account account1 = new Account("a@example.com", "example.type"); 274 final Account account2 = new Account("b@example.com", "example.type.2"); 275 final String authority = "testprovider"; 276 final Bundle extras1 = new Bundle(); 277 extras1.putString("a", "1"); 278 final Bundle extras2 = new Bundle(); 279 extras2.putString("a", "2"); 280 final int period1 = 200; 281 final int period2 = 1000; 282 final int flex1 = 10; 283 final int flex2 = 100; 284 EndPoint point1 = new EndPoint(account1, authority, 0); 285 EndPoint point2 = new EndPoint(account2, authority, 0); 286 EndPoint point1User2 = new EndPoint(account1, authority, 1); 287 288 PeriodicSync sync1 = new PeriodicSync(account1, authority, extras1, period1, flex1); 289 PeriodicSync sync2 = new PeriodicSync(account1, authority, extras2, period1, flex1); 290 PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2, flex2); 291 PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2, flex2); 292 293 EndPoint target1 = new EndPoint(account1, authority, 0); 294 EndPoint target2 = new EndPoint(account2, authority, 0); 295 EndPoint target1UserB = new EndPoint(account1, authority, 1); 296 297 MockContentResolver mockResolver = new MockContentResolver(); 298 299 SyncStorageEngine engine = SyncStorageEngine.newTestInstance( 300 new TestContext(mockResolver, getContext())); 301 302 removePeriodicSyncs(engine, account1, 0, authority); 303 removePeriodicSyncs(engine, account2, 0, authority); 304 removePeriodicSyncs(engine, account1, 1, authority); 305 306 // This should add two distinct periodic syncs for account1 and one for account2 307 engine.updateOrAddPeriodicSync(target1, period1, flex1, extras1); 308 engine.updateOrAddPeriodicSync(target1, period1, flex1, extras2); 309 // Edit existing sync and update the period and flex. 310 engine.updateOrAddPeriodicSync(target1, period2, flex2, extras2); 311 engine.updateOrAddPeriodicSync(target2, period2, flex2, extras2); 312 // add a target for a second user. 313 engine.updateOrAddPeriodicSync(target1UserB, period1, flex1, extras2); 314 315 List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1); 316 317 assertEquals(2, syncs.size()); 318 319 assertEquals(sync1, syncs.get(0)); 320 assertEquals(sync3, syncs.get(1)); 321 322 engine.removePeriodicSync(target1, extras1); 323 324 syncs = engine.getPeriodicSyncs(target1); 325 assertEquals(1, syncs.size()); 326 assertEquals(sync3, syncs.get(0)); 327 328 syncs = engine.getPeriodicSyncs(target2); 329 assertEquals(1, syncs.size()); 330 assertEquals(sync4, syncs.get(0)); 331 332 syncs = engine.getPeriodicSyncs(target1UserB); 333 assertEquals(1, syncs.size()); 334 assertEquals(sync2, syncs.get(0)); 335 } 336 removePeriodicSyncs(SyncStorageEngine engine, Account account, int userId, String authority)337 private void removePeriodicSyncs(SyncStorageEngine engine, Account account, int userId, String authority) { 338 EndPoint target = new EndPoint(account, authority, userId); 339 engine.setIsSyncable(account, userId, authority, engine.getIsSyncable(account, userId, authority)); 340 List<PeriodicSync> syncs = engine.getPeriodicSyncs(target); 341 for (PeriodicSync sync : syncs) { 342 engine.removePeriodicSync(target, sync.extras); 343 } 344 } 345 346 @LargeTest testAuthorityPersistence()347 public void testAuthorityPersistence() throws Exception { 348 final Account account1 = new Account("a@example.com", "example.type"); 349 final Account account2 = new Account("b@example.com", "example.type.2"); 350 final String authority1 = "testprovider1"; 351 final String authority2 = "testprovider2"; 352 final Bundle extras1 = new Bundle(); 353 extras1.putString("a", "1"); 354 final Bundle extras2 = new Bundle(); 355 extras2.putString("a", "2"); 356 extras2.putLong("b", 2); 357 extras2.putInt("c", 1); 358 extras2.putBoolean("d", true); 359 extras2.putDouble("e", 1.2); 360 extras2.putFloat("f", 4.5f); 361 extras2.putParcelable("g", account1); 362 final int period1 = 200; 363 final int period2 = 1000; 364 final int flex1 = 10; 365 final int flex2 = 100; 366 367 EndPoint point1 = new EndPoint(account1, authority1, 0); 368 EndPoint point2 = new EndPoint(account1, authority2, 0); 369 EndPoint point3 = new EndPoint(account2, authority1, 0); 370 371 PeriodicSync sync1 = new PeriodicSync(account1, authority1, extras1, period1, flex1); 372 PeriodicSync sync2 = new PeriodicSync(account1, authority1, extras2, period1, flex1); 373 PeriodicSync sync3 = new PeriodicSync(account1, authority2, extras1, period1, flex1); 374 PeriodicSync sync4 = new PeriodicSync(account1, authority2, extras2, period2, flex2); 375 PeriodicSync sync5 = new PeriodicSync(account2, authority1, extras1, period1, flex1); 376 377 EndPoint target1 = new EndPoint(account1, authority1, 0); 378 EndPoint target2 = new EndPoint(account1, authority2, 0); 379 EndPoint target3 = new EndPoint(account2, authority1, 0); 380 381 removePeriodicSyncs(engine, account1, 0, authority1); 382 removePeriodicSyncs(engine, account2, 0, authority1); 383 removePeriodicSyncs(engine, account1, 0, authority2); 384 removePeriodicSyncs(engine, account2, 0, authority2); 385 386 engine.setMasterSyncAutomatically(false, 0); 387 388 engine.setIsSyncable(account1, 0, authority1, 1); 389 engine.setSyncAutomatically(account1, 0, authority1, true); 390 391 engine.setIsSyncable(account2, 0, authority1, 1); 392 engine.setSyncAutomatically(account2, 0, authority1, true); 393 394 engine.setIsSyncable(account1, 0, authority2, 1); 395 engine.setSyncAutomatically(account1, 0, authority2, false); 396 397 engine.setIsSyncable(account2, 0, authority2, 0); 398 engine.setSyncAutomatically(account2, 0, authority2, true); 399 400 engine.updateOrAddPeriodicSync(target1, period1, flex1, extras1); 401 engine.updateOrAddPeriodicSync(target1, period1, flex1, extras2); 402 engine.updateOrAddPeriodicSync(target2, period1, flex1, extras1); 403 engine.updateOrAddPeriodicSync(target2, period2, flex2, extras2); 404 engine.updateOrAddPeriodicSync(target3, period1, flex1, extras1); 405 406 engine.writeAllState(); 407 engine.clearAndReadState(); 408 409 List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1); 410 assertEquals(2, syncs.size()); 411 assertEquals(sync1, syncs.get(0)); 412 assertEquals(sync2, syncs.get(1)); 413 414 syncs = engine.getPeriodicSyncs(target2); 415 assertEquals(2, syncs.size()); 416 assertEquals(sync3, syncs.get(0)); 417 assertEquals(sync4, syncs.get(1)); 418 419 syncs = engine.getPeriodicSyncs(target3); 420 assertEquals(1, syncs.size()); 421 assertEquals(sync5, syncs.get(0)); 422 423 assertEquals(true, engine.getSyncAutomatically(account1, 0, authority1)); 424 assertEquals(true, engine.getSyncAutomatically(account2, 0, authority1)); 425 assertEquals(false, engine.getSyncAutomatically(account1, 0, authority2)); 426 assertEquals(true, engine.getSyncAutomatically(account2, 0, authority2)); 427 428 assertEquals(1, engine.getIsSyncable(account1, 0, authority1)); 429 assertEquals(1, engine.getIsSyncable(account2, 0, authority1)); 430 assertEquals(1, engine.getIsSyncable(account1, 0, authority2)); 431 assertEquals(0, engine.getIsSyncable(account2, 0, authority2)); 432 } 433 434 @SmallTest testComponentParsing()435 public void testComponentParsing() throws Exception { 436 437 byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 438 + "<accounts version=\"2\" >\n" 439 + "<authority id=\"0\" user=\"0\" package=\"" + syncService1.getPackageName() + "\"" 440 + " class=\"" + syncService1.getClassName() + "\" syncable=\"true\">" 441 + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>" 442 + "\n</authority>" 443 + "</accounts>").getBytes(); 444 445 File syncDir = getSyncDir(); 446 syncDir.mkdirs(); 447 AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 448 FileOutputStream fos = accountInfoFile.startWrite(); 449 fos.write(accountsFileData); 450 accountInfoFile.finishWrite(fos); 451 452 engine.clearAndReadState(); 453 454 SyncStorageEngine.AuthorityInfo aInfo = engine.getAuthority(0); 455 assertNotNull(aInfo); 456 457 // Test service component read 458 List<PeriodicSync> syncs = engine.getPeriodicSyncs( 459 new SyncStorageEngine.EndPoint(syncService1, 0)); 460 assertEquals(1, syncs.size()); 461 assertEquals(true, engine.getIsTargetServiceActive(syncService1, 0)); 462 } 463 464 @SmallTest testComponentSettings()465 public void testComponentSettings() throws Exception { 466 EndPoint target1 = new EndPoint(syncService1, 0); 467 engine.updateOrAddPeriodicSync(target1, dayPoll, dayFuzz, Bundle.EMPTY); 468 469 engine.setIsTargetServiceActive(target1.service, 0, true); 470 boolean active = engine.getIsTargetServiceActive(target1.service, 0); 471 assert(active); 472 473 engine.setIsTargetServiceActive(target1.service, 1, false); 474 active = engine.getIsTargetServiceActive(target1.service, 1); 475 assert(!active); 476 } 477 478 @MediumTest 479 /** 480 * V2 introduces flex time as well as service components. 481 * @throws Exception 482 */ testAuthorityParsingV2()483 public void testAuthorityParsingV2() throws Exception { 484 final Account account = new Account("account1", "type1"); 485 final String authority1 = "auth1"; 486 final String authority2 = "auth2"; 487 final String authority3 = "auth3"; 488 489 EndPoint target1 = new EndPoint(account, authority1, 0); 490 EndPoint target2 = new EndPoint(account, authority2, 0); 491 EndPoint target3 = new EndPoint(account, authority3, 0); 492 EndPoint target4 = new EndPoint(account, authority3, 1); 493 494 PeriodicSync sync1 = new PeriodicSync(account, authority1, Bundle.EMPTY, dayPoll, dayFuzz); 495 PeriodicSync sync2 = new PeriodicSync(account, authority2, Bundle.EMPTY, dayPoll, dayFuzz); 496 PeriodicSync sync3 = new PeriodicSync(account, authority3, Bundle.EMPTY, dayPoll, dayFuzz); 497 PeriodicSync sync1s = new PeriodicSync(account, authority1, Bundle.EMPTY, thousandSecs, 498 thousandSecsFuzz); 499 PeriodicSync sync2s = new PeriodicSync(account, authority2, Bundle.EMPTY, thousandSecs, 500 thousandSecsFuzz); 501 PeriodicSync sync3s = new PeriodicSync(account, authority3, Bundle.EMPTY, thousandSecs, 502 thousandSecsFuzz); 503 504 byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 505 + "<accounts version=\"2\" >\n" 506 + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" >" 507 + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>" 508 + "\n</authority>" 509 + "<authority id=\"1\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth2\" >" 510 + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>" 511 + "\n</authority>" 512 // No user defaults to user 0 - all users. 513 + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" >" 514 + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>" 515 + "\n</authority>" 516 + "<authority id=\"3\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth3\" >" 517 + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>" 518 + "\n</authority>" 519 + "</accounts>").getBytes(); 520 521 File syncDir = getSyncDir(); 522 syncDir.mkdirs(); 523 AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 524 FileOutputStream fos = accountInfoFile.startWrite(); 525 fos.write(accountsFileData); 526 accountInfoFile.finishWrite(fos); 527 528 engine.clearAndReadState(); 529 530 List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1); 531 assertEquals("Got incorrect # of syncs", 1, syncs.size()); 532 assertEquals(sync1, syncs.get(0)); 533 534 syncs = engine.getPeriodicSyncs(target2); 535 assertEquals(1, syncs.size()); 536 assertEquals(sync2, syncs.get(0)); 537 538 syncs = engine.getPeriodicSyncs(target3); 539 assertEquals(1, syncs.size()); 540 assertEquals(sync3, syncs.get(0)); 541 542 syncs = engine.getPeriodicSyncs(target4); 543 544 assertEquals(1, syncs.size()); 545 assertEquals(sync3, syncs.get(0)); 546 547 // Test empty periodic data. 548 accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 549 + "<accounts version=\"2\">\n" 550 + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n" 551 + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n" 552 + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n" 553 + "</accounts>\n").getBytes(); 554 555 accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 556 fos = accountInfoFile.startWrite(); 557 fos.write(accountsFileData); 558 accountInfoFile.finishWrite(fos); 559 560 engine.clearAndReadState(); 561 562 syncs = engine.getPeriodicSyncs(target1); 563 assertEquals(0, syncs.size()); 564 565 syncs = engine.getPeriodicSyncs(target2); 566 assertEquals(0, syncs.size()); 567 568 syncs = engine.getPeriodicSyncs(target3); 569 assertEquals(0, syncs.size()); 570 571 accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 572 + "<accounts version=\"2\">\n" 573 + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\">\n" 574 + "<periodicSync period=\"1000\" />\n" 575 + "</authority>" 576 + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\">\n" 577 + "<periodicSync period=\"1000\" />\n" 578 + "</authority>" 579 + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\">\n" 580 + "<periodicSync period=\"1000\" />\n" 581 + "</authority>" 582 + "</accounts>\n").getBytes(); 583 584 accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 585 fos = accountInfoFile.startWrite(); 586 fos.write(accountsFileData); 587 accountInfoFile.finishWrite(fos); 588 589 engine.clearAndReadState(); 590 591 syncs = engine.getPeriodicSyncs(target1); 592 assertEquals(1, syncs.size()); 593 assertEquals(sync1s, syncs.get(0)); 594 595 syncs = engine.getPeriodicSyncs(target2); 596 assertEquals(1, syncs.size()); 597 assertEquals(sync2s, syncs.get(0)); 598 599 syncs = engine.getPeriodicSyncs(target3); 600 assertEquals(1, syncs.size()); 601 assertEquals(sync3s, syncs.get(0)); 602 } 603 604 @MediumTest testAuthorityParsing()605 public void testAuthorityParsing() throws Exception { 606 final Account account = new Account("account1", "type1"); 607 final String authority1 = "auth1"; 608 final String authority2 = "auth2"; 609 final String authority3 = "auth3"; 610 final Bundle extras = new Bundle(); 611 612 EndPoint target1 = new EndPoint(account, authority1, 0); 613 EndPoint target2 = new EndPoint(account, authority2, 0); 614 EndPoint target3 = new EndPoint(account, authority3, 0); 615 EndPoint target4 = new EndPoint(account, authority3, 1); 616 617 PeriodicSync sync1 = new PeriodicSync(account, authority1, extras, (long) (60 * 60 * 24)); 618 PeriodicSync sync2 = new PeriodicSync(account, authority2, extras, (long) (60 * 60 * 24)); 619 PeriodicSync sync3 = new PeriodicSync(account, authority3, extras, (long) (60 * 60 * 24)); 620 PeriodicSync sync1s = new PeriodicSync(account, authority1, extras, 1000); 621 PeriodicSync sync2s = new PeriodicSync(account, authority2, extras, 1000); 622 PeriodicSync sync3s = new PeriodicSync(account, authority3, extras, 1000); 623 624 MockContentResolver mockResolver = new MockContentResolver(); 625 626 final TestContext testContext = new TestContext(mockResolver, getContext()); 627 628 byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 629 + "<accounts>\n" 630 + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n" 631 + "<authority id=\"1\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n" 632 + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n" 633 + "<authority id=\"3\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n" 634 + "</accounts>\n").getBytes(); 635 636 File syncDir = getSyncDir(); 637 syncDir.mkdirs(); 638 AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 639 FileOutputStream fos = accountInfoFile.startWrite(); 640 fos.write(accountsFileData); 641 accountInfoFile.finishWrite(fos); 642 643 SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); 644 645 List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1); 646 assertEquals(1, syncs.size()); 647 assertEquals("expected sync1: " + sync1.toString() + " == sync 2" + syncs.get(0).toString(), sync1, syncs.get(0)); 648 649 syncs = engine.getPeriodicSyncs(target2); 650 assertEquals(1, syncs.size()); 651 assertEquals(sync2, syncs.get(0)); 652 653 syncs = engine.getPeriodicSyncs(target3); 654 assertEquals(1, syncs.size()); 655 assertEquals(sync3, syncs.get(0)); 656 syncs = engine.getPeriodicSyncs(target4); 657 658 659 assertEquals(1, syncs.size()); 660 assertEquals(sync3, syncs.get(0)); 661 662 accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 663 + "<accounts version=\"2\">\n" 664 + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n" 665 + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n" 666 + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n" 667 + "</accounts>\n").getBytes(); 668 669 accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 670 fos = accountInfoFile.startWrite(); 671 fos.write(accountsFileData); 672 accountInfoFile.finishWrite(fos); 673 674 engine.clearAndReadState(); 675 676 syncs = engine.getPeriodicSyncs(target1); 677 assertEquals(0, syncs.size()); 678 679 syncs = engine.getPeriodicSyncs(target2); 680 assertEquals(0, syncs.size()); 681 682 syncs = engine.getPeriodicSyncs(target3); 683 assertEquals(0, syncs.size()); 684 685 accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 686 + "<accounts version=\"2\">\n" 687 + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\">\n" 688 + "<periodicSync period=\"1000\" />\n" 689 + "</authority>" 690 + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\">\n" 691 + "<periodicSync period=\"1000\" />\n" 692 + "</authority>" 693 + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\">\n" 694 + "<periodicSync period=\"1000\" />\n" 695 + "</authority>" 696 + "</accounts>\n").getBytes(); 697 698 accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 699 fos = accountInfoFile.startWrite(); 700 fos.write(accountsFileData); 701 accountInfoFile.finishWrite(fos); 702 703 engine.clearAndReadState(); 704 705 syncs = engine.getPeriodicSyncs(target1); 706 assertEquals(1, syncs.size()); 707 assertEquals(sync1s, syncs.get(0)); 708 709 syncs = engine.getPeriodicSyncs(target2); 710 assertEquals(1, syncs.size()); 711 assertEquals(sync2s, syncs.get(0)); 712 713 syncs = engine.getPeriodicSyncs(target3); 714 assertEquals(1, syncs.size()); 715 assertEquals(sync3s, syncs.get(0)); 716 } 717 718 @MediumTest testListenForTicklesParsing()719 public void testListenForTicklesParsing() throws Exception { 720 byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 721 + "<accounts>\n" 722 + "<listenForTickles user=\"0\" enabled=\"false\" />" 723 + "<listenForTickles user=\"1\" enabled=\"true\" />" 724 + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n" 725 + "<authority id=\"1\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n" 726 + "</accounts>\n").getBytes(); 727 728 MockContentResolver mockResolver = new MockContentResolver(); 729 final TestContext testContext = new TestContext(mockResolver, getContext()); 730 731 File syncDir = getSyncDir(); 732 syncDir.mkdirs(); 733 AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 734 FileOutputStream fos = accountInfoFile.startWrite(); 735 fos.write(accountsFileData); 736 accountInfoFile.finishWrite(fos); 737 738 SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); 739 740 assertEquals(false, engine.getMasterSyncAutomatically(0)); 741 assertEquals(true, engine.getMasterSyncAutomatically(1)); 742 assertEquals(true, engine.getMasterSyncAutomatically(2)); 743 744 } 745 746 @MediumTest testAuthorityRenaming()747 public void testAuthorityRenaming() throws Exception { 748 final Account account1 = new Account("acc1", "type1"); 749 final Account account2 = new Account("acc2", "type2"); 750 final String authorityContacts = "contacts"; 751 final String authorityCalendar = "calendar"; 752 final String authorityOther = "other"; 753 final String authorityContactsNew = "com.android.contacts"; 754 final String authorityCalendarNew = "com.android.calendar"; 755 756 MockContentResolver mockResolver = new MockContentResolver(); 757 758 final TestContext testContext = new TestContext(mockResolver, getContext()); 759 760 byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 761 + "<accounts>\n" 762 + "<authority id=\"0\" account=\"acc1\" type=\"type1\" authority=\"contacts\" />\n" 763 + "<authority id=\"1\" account=\"acc1\" type=\"type1\" authority=\"calendar\" />\n" 764 + "<authority id=\"2\" account=\"acc1\" type=\"type1\" authority=\"other\" />\n" 765 + "<authority id=\"3\" account=\"acc2\" type=\"type2\" authority=\"contacts\" />\n" 766 + "<authority id=\"4\" account=\"acc2\" type=\"type2\" authority=\"calendar\" />\n" 767 + "<authority id=\"5\" account=\"acc2\" type=\"type2\" authority=\"other\" />\n" 768 + "<authority id=\"6\" account=\"acc2\" type=\"type2\" enabled=\"false\"" 769 + " authority=\"com.android.calendar\" />\n" 770 + "<authority id=\"7\" account=\"acc2\" type=\"type2\" enabled=\"false\"" 771 + " authority=\"com.android.contacts\" />\n" 772 + "</accounts>\n").getBytes(); 773 774 File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync"); 775 syncDir.mkdirs(); 776 AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 777 FileOutputStream fos = accountInfoFile.startWrite(); 778 fos.write(accountsFileData); 779 accountInfoFile.finishWrite(fos); 780 781 SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); 782 783 assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityContacts)); 784 assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityCalendar)); 785 assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityOther)); 786 assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityContactsNew)); 787 assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityCalendarNew)); 788 789 assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContacts)); 790 assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendar)); 791 assertEquals(true, engine.getSyncAutomatically(account2, 0, authorityOther)); 792 assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContactsNew)); 793 assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendarNew)); 794 } 795 796 @SmallTest testSyncableMigration()797 public void testSyncableMigration() throws Exception { 798 final Account account = new Account("acc", "type"); 799 800 MockContentResolver mockResolver = new MockContentResolver(); 801 802 final TestContext testContext = new TestContext(mockResolver, getContext()); 803 804 byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 805 + "<accounts>\n" 806 + "<authority id=\"0\" account=\"acc\" authority=\"other1\" />\n" 807 + "<authority id=\"1\" account=\"acc\" type=\"type\" authority=\"other2\" />\n" 808 + "<authority id=\"2\" account=\"acc\" type=\"type\" syncable=\"false\"" 809 + " authority=\"other3\" />\n" 810 + "<authority id=\"3\" account=\"acc\" type=\"type\" syncable=\"true\"" 811 + " authority=\"other4\" />\n" 812 + "</accounts>\n").getBytes(); 813 814 File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync"); 815 syncDir.mkdirs(); 816 AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 817 FileOutputStream fos = accountInfoFile.startWrite(); 818 fos.write(accountsFileData); 819 accountInfoFile.finishWrite(fos); 820 821 SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); 822 823 assertEquals(-1, engine.getIsSyncable(account, 0, "other1")); 824 assertEquals(1, engine.getIsSyncable(account, 0, "other2")); 825 assertEquals(0, engine.getIsSyncable(account, 0, "other3")); 826 assertEquals(1, engine.getIsSyncable(account, 0, "other4")); 827 } 828 829 /** 830 * Verify that the API cannot cause a run-time reboot by passing in the empty string as an 831 * authority. The problem here is that 832 * {@link SyncStorageEngine#getOrCreateAuthorityLocked(account, provider)} would register 833 * an empty authority which causes a RTE in {@link SyncManager#scheduleReadyPeriodicSyncs()}. 834 * This is not strictly a SSE test, but it does depend on the SSE data structures. 835 */ 836 @SmallTest testExpectedIllegalArguments()837 public void testExpectedIllegalArguments() throws Exception { 838 try { 839 ContentResolver.setSyncAutomatically(account1, "", true); 840 fail("empty provider string should throw IllegalArgumentException"); 841 } catch (IllegalArgumentException expected) {} 842 843 try { 844 ContentResolver.addPeriodicSync(account1, "", Bundle.EMPTY, 84000L); 845 fail("empty provider string should throw IllegalArgumentException"); 846 } catch (IllegalArgumentException expected) {} 847 848 try { 849 ContentResolver.removePeriodicSync(account1, "", Bundle.EMPTY); 850 fail("empty provider string should throw IllegalArgumentException"); 851 } catch (IllegalArgumentException expected) {} 852 853 try { 854 ContentResolver.cancelSync(account1, ""); 855 fail("empty provider string should throw IllegalArgumentException"); 856 } catch (IllegalArgumentException expected) {} 857 858 try { 859 ContentResolver.setIsSyncable(account1, "", 0); 860 fail("empty provider string should throw IllegalArgumentException"); 861 } catch (IllegalArgumentException expected) {} 862 863 try { 864 ContentResolver.cancelSync(account1, ""); 865 fail("empty provider string should throw IllegalArgumentException"); 866 } catch (IllegalArgumentException expected) {} 867 868 try { 869 ContentResolver.requestSync(account1, "", Bundle.EMPTY); 870 fail("empty provider string should throw IllegalArgumentException"); 871 } catch (IllegalArgumentException expected) {} 872 873 try { 874 ContentResolver.getSyncStatus(account1, ""); 875 fail("empty provider string should throw IllegalArgumentException"); 876 } catch (IllegalArgumentException expected) {} 877 878 // Make sure we aren't blocking null account/provider for those functions that use it 879 // to specify ALL accounts/providers. 880 ContentResolver.requestSync(null, null, Bundle.EMPTY); 881 ContentResolver.cancelSync(null, null); 882 } 883 } 884 885 class TestContext extends ContextWrapper { 886 887 ContentResolver mResolver; 888 889 private final Context mRealContext; 890 TestContext(ContentResolver resolver, Context realContext)891 public TestContext(ContentResolver resolver, Context realContext) { 892 super(new RenamingDelegatingContext(new MockContext(), realContext, "test.")); 893 mRealContext = realContext; 894 mResolver = resolver; 895 } 896 897 @Override getResources()898 public Resources getResources() { 899 return mRealContext.getResources(); 900 } 901 902 @Override getFilesDir()903 public File getFilesDir() { 904 return mRealContext.getFilesDir(); 905 } 906 907 @Override enforceCallingOrSelfPermission(String permission, String message)908 public void enforceCallingOrSelfPermission(String permission, String message) { 909 } 910 911 @Override sendBroadcast(Intent intent)912 public void sendBroadcast(Intent intent) { 913 } 914 915 @Override getContentResolver()916 public ContentResolver getContentResolver() { 917 return mResolver; 918 } 919 } 920