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