Home | History | Annotate | Download | only in content
      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 
     64     private File getSyncDir() {
     65         return new File(new File(getContext().getFilesDir(), "system"), "sync");
     66     }
     67 
     68     @Override
     69     public void setUp() {
     70         account1 = new Account("a (at) example.com", "example.type");
     71         account2 = new Account("b (at) 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
     90     public void testPurgeActiveSync() throws Exception {
     91         final Account account = new Account("a (at) 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
    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      */
    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
    214     public void testPeriodics() throws Exception {
    215         final Account account1 = new Account("a (at) example.com", "example.type");
    216         final Account account2 = new Account("b (at) 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
    272     public void testPeriodicsV2() throws Exception {
    273         final Account account1 = new Account("a (at) example.com", "example.type");
    274         final Account account2 = new Account("b (at) 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 
    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
    347     public void testAuthorityPersistence() throws Exception {
    348         final Account account1 = new Account("a (at) example.com", "example.type");
    349         final Account account2 = new Account("b (at) 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
    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
    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      */
    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
    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
    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
    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
    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
    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 
    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
    898     public Resources getResources() {
    899         return mRealContext.getResources();
    900     }
    901 
    902     @Override
    903     public File getFilesDir() {
    904         return mRealContext.getFilesDir();
    905     }
    906 
    907     @Override
    908     public void enforceCallingOrSelfPermission(String permission, String message) {
    909     }
    910 
    911     @Override
    912     public void sendBroadcast(Intent intent) {
    913     }
    914 
    915     @Override
    916     public ContentResolver getContentResolver() {
    917         return mResolver;
    918     }
    919 }
    920