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.res.Resources;
     26 import android.os.Bundle;
     27 import android.test.AndroidTestCase;
     28 import android.test.RenamingDelegatingContext;
     29 import android.test.mock.MockContentResolver;
     30 import android.test.mock.MockContext;
     31 import android.test.suitebuilder.annotation.LargeTest;
     32 import android.test.suitebuilder.annotation.MediumTest;
     33 import android.test.suitebuilder.annotation.SmallTest;
     34 
     35 import com.android.internal.os.AtomicFile;
     36 
     37 import java.io.File;
     38 import java.io.FileOutputStream;
     39 
     40 /**
     41  * Test for SyncStorageEngine.
     42  *
     43  * bit FrameworksServicesTests:com.android.server.content.SyncStorageEngineTest
     44  *
     45  * TODO Broken.  Fix it.  b/62485315
     46  */
     47 public class SyncStorageEngineTest extends AndroidTestCase {
     48 
     49     protected Account account1;
     50     protected Account account2;
     51     protected ComponentName syncService1;
     52     protected String authority1 = "testprovider";
     53     protected Bundle defaultBundle;
     54     protected final int DEFAULT_USER = 0;
     55 
     56     /* Some default poll frequencies. */
     57     final long dayPoll = (60 * 60 * 24);
     58     final long dayFuzz = 60;
     59     final long thousandSecs = 1000;
     60     final long thousandSecsFuzz = 100;
     61 
     62     MockContentResolver mockResolver;
     63     SyncStorageEngine engine;
     64 
     65     private File getSyncDir() {
     66         return new File(new File(getContext().getFilesDir(), "system"), "sync");
     67     }
     68 
     69     @Override
     70     public void setUp() {
     71         account1 = new Account("a (at) example.com", "example.type");
     72         account2 = new Account("b (at) example.com", "example.type");
     73         syncService1 = new ComponentName("com.example", "SyncService");
     74         // Default bundle.
     75         defaultBundle = new Bundle();
     76         defaultBundle.putInt("int_key", 0);
     77         defaultBundle.putString("string_key", "hello");
     78         // Set up storage engine.
     79         mockResolver = new MockContentResolver();
     80         engine = SyncStorageEngine.newTestInstance(
     81                 new TestContext(mockResolver, getContext()));
     82     }
     83 
     84     /**
     85      * Test that we handle the case of a history row being old enough to purge before the
     86      * corresponding sync is finished. This can happen if the clock changes while we are syncing.
     87      *
     88      */
     89     // TODO: this test causes AidlTest to fail. Omit for now
     90     // @SmallTest
     91     public void testPurgeActiveSync() throws Exception {
     92         final Account account = new Account("a (at) example.com", "example.type");
     93         final String authority = "testprovider";
     94 
     95         MockContentResolver mockResolver = new MockContentResolver();
     96 
     97         SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
     98                 new TestContext(mockResolver, getContext()));
     99         long time0 = 1000;
    100         SyncOperation op = new SyncOperation(account, 0, 0, "foo",
    101                 SyncOperation.REASON_PERIODIC,
    102                 SyncStorageEngine.SOURCE_LOCAL,
    103                 authority,
    104                 Bundle.EMPTY, true);
    105         long historyId = engine.insertStartSyncEvent(op, time0);
    106         long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
    107         engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
    108     }
    109 
    110     @LargeTest
    111     public void testAuthorityPersistence() throws Exception {
    112         final Account account1 = new Account("a (at) example.com", "example.type");
    113         final Account account2 = new Account("b (at) example.com", "example.type.2");
    114         final String authority1 = "testprovider1";
    115         final String authority2 = "testprovider2";
    116 
    117         engine.setMasterSyncAutomatically(false, 0);
    118 
    119         engine.setIsSyncable(account1, 0, authority1, 1);
    120         engine.setSyncAutomatically(account1, 0, authority1, true);
    121 
    122         engine.setIsSyncable(account2, 0, authority1, 1);
    123         engine.setSyncAutomatically(account2, 0, authority1, true);
    124 
    125         engine.setIsSyncable(account1, 0, authority2, 1);
    126         engine.setSyncAutomatically(account1, 0, authority2, false);
    127 
    128         engine.setIsSyncable(account2, 0, authority2, 0);
    129         engine.setSyncAutomatically(account2, 0, authority2, true);
    130 
    131         engine.writeAllState();
    132         engine.clearAndReadState();
    133 
    134         assertEquals(true, engine.getSyncAutomatically(account1, 0, authority1));
    135         assertEquals(true, engine.getSyncAutomatically(account2, 0, authority1));
    136         assertEquals(false, engine.getSyncAutomatically(account1, 0, authority2));
    137         assertEquals(true, engine.getSyncAutomatically(account2, 0, authority2));
    138 
    139         assertEquals(1, engine.getIsSyncable(account1, 0, authority1));
    140         assertEquals(1, engine.getIsSyncable(account2, 0, authority1));
    141         assertEquals(1, engine.getIsSyncable(account1, 0, authority2));
    142         assertEquals(0, engine.getIsSyncable(account2, 0, authority2));
    143     }
    144 
    145     @MediumTest
    146     public void testListenForTicklesParsing() throws Exception {
    147         byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
    148                 + "<accounts>\n"
    149                 + "<listenForTickles user=\"0\" enabled=\"false\" />"
    150                 + "<listenForTickles user=\"1\" enabled=\"true\" />"
    151                 + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
    152                 + "<authority id=\"1\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
    153                 + "</accounts>\n").getBytes();
    154 
    155         MockContentResolver mockResolver = new MockContentResolver();
    156         final TestContext testContext = new TestContext(mockResolver, getContext());
    157 
    158         File syncDir = getSyncDir();
    159         syncDir.mkdirs();
    160         AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
    161         FileOutputStream fos = accountInfoFile.startWrite();
    162         fos.write(accountsFileData);
    163         accountInfoFile.finishWrite(fos);
    164 
    165         SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
    166 
    167         assertEquals(false, engine.getMasterSyncAutomatically(0));
    168         assertEquals(true, engine.getMasterSyncAutomatically(1));
    169         assertEquals(true, engine.getMasterSyncAutomatically(2));
    170 
    171     }
    172 
    173     @MediumTest
    174     public void testAuthorityRenaming() throws Exception {
    175         final Account account1 = new Account("acc1", "type1");
    176         final Account account2 = new Account("acc2", "type2");
    177         final String authorityContacts = "contacts";
    178         final String authorityCalendar = "calendar";
    179         final String authorityOther = "other";
    180         final String authorityContactsNew = "com.android.contacts";
    181         final String authorityCalendarNew = "com.android.calendar";
    182 
    183         MockContentResolver mockResolver = new MockContentResolver();
    184 
    185         final TestContext testContext = new TestContext(mockResolver, getContext());
    186 
    187         byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
    188                 + "<accounts>\n"
    189                 + "<authority id=\"0\" account=\"acc1\" type=\"type1\" authority=\"contacts\" />\n"
    190                 + "<authority id=\"1\" account=\"acc1\" type=\"type1\" authority=\"calendar\" />\n"
    191                 + "<authority id=\"2\" account=\"acc1\" type=\"type1\" authority=\"other\" />\n"
    192                 + "<authority id=\"3\" account=\"acc2\" type=\"type2\" authority=\"contacts\" />\n"
    193                 + "<authority id=\"4\" account=\"acc2\" type=\"type2\" authority=\"calendar\" />\n"
    194                 + "<authority id=\"5\" account=\"acc2\" type=\"type2\" authority=\"other\" />\n"
    195                 + "<authority id=\"6\" account=\"acc2\" type=\"type2\" enabled=\"false\""
    196                 + " authority=\"com.android.calendar\" />\n"
    197                 + "<authority id=\"7\" account=\"acc2\" type=\"type2\" enabled=\"false\""
    198                 + " authority=\"com.android.contacts\" />\n"
    199                 + "</accounts>\n").getBytes();
    200 
    201         File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
    202         syncDir.mkdirs();
    203         AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
    204         FileOutputStream fos = accountInfoFile.startWrite();
    205         fos.write(accountsFileData);
    206         accountInfoFile.finishWrite(fos);
    207 
    208         SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
    209 
    210         assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityContacts));
    211         assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityCalendar));
    212         assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityOther));
    213         assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityContactsNew));
    214         assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityCalendarNew));
    215 
    216         assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContacts));
    217         assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendar));
    218         assertEquals(true, engine.getSyncAutomatically(account2, 0, authorityOther));
    219         assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContactsNew));
    220         assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendarNew));
    221     }
    222 
    223     @SmallTest
    224     public void testSyncableMigration() throws Exception {
    225         final Account account = new Account("acc", "type");
    226 
    227         MockContentResolver mockResolver = new MockContentResolver();
    228 
    229         final TestContext testContext = new TestContext(mockResolver, getContext());
    230 
    231         byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
    232                 + "<accounts>\n"
    233                 + "<authority id=\"0\" account=\"acc\" authority=\"other1\" />\n"
    234                 + "<authority id=\"1\" account=\"acc\" type=\"type\" authority=\"other2\" />\n"
    235                 + "<authority id=\"2\" account=\"acc\" type=\"type\" syncable=\"false\""
    236                 + " authority=\"other3\" />\n"
    237                 + "<authority id=\"3\" account=\"acc\" type=\"type\" syncable=\"true\""
    238                 + " authority=\"other4\" />\n"
    239                 + "</accounts>\n").getBytes();
    240 
    241         File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
    242         syncDir.mkdirs();
    243         AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
    244         FileOutputStream fos = accountInfoFile.startWrite();
    245         fos.write(accountsFileData);
    246         accountInfoFile.finishWrite(fos);
    247 
    248         SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
    249 
    250         assertEquals(-1, engine.getIsSyncable(account, 0, "other1"));
    251         assertEquals(1, engine.getIsSyncable(account, 0, "other2"));
    252         assertEquals(0, engine.getIsSyncable(account, 0, "other3"));
    253         assertEquals(1, engine.getIsSyncable(account, 0, "other4"));
    254     }
    255 
    256     /**
    257      * Verify that the API cannot cause a run-time reboot by passing in the empty string as an
    258      * authority. The problem here is that
    259      * {@link SyncStorageEngine#getOrCreateAuthorityLocked(account, provider)} would register
    260      * an empty authority which causes a RTE in {@link SyncManager#scheduleReadyPeriodicSyncs()}.
    261      * This is not strictly a SSE test, but it does depend on the SSE data structures.
    262      */
    263     @SmallTest
    264     public void testExpectedIllegalArguments() throws Exception {
    265         try {
    266             ContentResolver.setSyncAutomatically(account1, "", true);
    267             fail("empty provider string should throw IllegalArgumentException");
    268         } catch (IllegalArgumentException expected) {}
    269 
    270         try {
    271             ContentResolver.addPeriodicSync(account1, "", Bundle.EMPTY, 84000L);
    272             fail("empty provider string should throw IllegalArgumentException");
    273         } catch (IllegalArgumentException expected) {}
    274 
    275         try {
    276             ContentResolver.removePeriodicSync(account1, "", Bundle.EMPTY);
    277             fail("empty provider string should throw IllegalArgumentException");
    278         } catch (IllegalArgumentException expected) {}
    279 
    280         try {
    281             ContentResolver.cancelSync(account1, "");
    282             fail("empty provider string should throw IllegalArgumentException");
    283         } catch (IllegalArgumentException expected) {}
    284 
    285         try {
    286             ContentResolver.setIsSyncable(account1, "", 0);
    287             fail("empty provider string should throw IllegalArgumentException");
    288         } catch (IllegalArgumentException expected) {}
    289 
    290         try {
    291             ContentResolver.cancelSync(account1, "");
    292             fail("empty provider string should throw IllegalArgumentException");
    293         } catch (IllegalArgumentException expected) {}
    294 
    295         try {
    296             ContentResolver.requestSync(account1, "", Bundle.EMPTY);
    297             fail("empty provider string should throw IllegalArgumentException");
    298         } catch (IllegalArgumentException expected) {}
    299 
    300         try {
    301             ContentResolver.getSyncStatus(account1, "");
    302             fail("empty provider string should throw IllegalArgumentException");
    303         } catch (IllegalArgumentException expected) {}
    304 
    305         // Make sure we aren't blocking null account/provider for those functions that use it
    306         // to specify ALL accounts/providers.
    307         ContentResolver.requestSync(null, null, Bundle.EMPTY);
    308         ContentResolver.cancelSync(null, null);
    309     }
    310 }
    311 
    312 class TestContext extends ContextWrapper {
    313 
    314     ContentResolver mResolver;
    315 
    316     private final Context mRealContext;
    317 
    318     public TestContext(ContentResolver resolver, Context realContext) {
    319         super(new RenamingDelegatingContext(new MockContext(), realContext, "test."));
    320         mRealContext = realContext;
    321         mResolver = resolver;
    322     }
    323 
    324     @Override
    325     public Resources getResources() {
    326         return mRealContext.getResources();
    327     }
    328 
    329     @Override
    330     public File getFilesDir() {
    331         return mRealContext.getFilesDir();
    332     }
    333 
    334     @Override
    335     public void enforceCallingOrSelfPermission(String permission, String message) {
    336     }
    337 
    338     @Override
    339     public void sendBroadcast(Intent intent) {
    340     }
    341 
    342     @Override
    343     public ContentResolver getContentResolver() {
    344         return mResolver;
    345     }
    346 }
    347