SyncStorageEngineTest.java revision 56dbf8f23677d28615e61ef2fbb0e738cca02528
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        assert(engine.getPendingOperationCount() == 1);
124        List<SyncStorageEngine.PendingOperation> pops = engine.getPendingOperations();
125        SyncStorageEngine.PendingOperation popRetrieved = pops.get(0);
126        assertEquals(sop.target.account, popRetrieved.authority.account);
127        assertEquals(sop.target.provider, popRetrieved.authority.provider);
128        assertEquals(sop.target.service, popRetrieved.authority.service);
129        assertEquals(sop.target.userId, popRetrieved.authority.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        // Sync Service component.
364        PeriodicSync sync1 = new PeriodicSync(syncService1, Bundle.EMPTY, dayPoll, dayFuzz);
365
366        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
367                + "<accounts version=\"2\" >\n"
368                + "<authority id=\"0\" user=\"0\" package=\"" + syncService1.getPackageName() + "\""
369                + " class=\"" + syncService1.getClassName() + "\" syncable=\"true\">"
370                + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
371                + "\n</authority>"
372                + "</accounts>").getBytes();
373
374        File syncDir = getSyncDir();
375        syncDir.mkdirs();
376        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
377        FileOutputStream fos = accountInfoFile.startWrite();
378        fos.write(accountsFileData);
379        accountInfoFile.finishWrite(fos);
380
381        engine.clearAndReadState();
382
383        // Test service component read
384        List<PeriodicSync> syncs = engine.getPeriodicSyncs(
385                new SyncStorageEngine.EndPoint(syncService1, 0));
386        assertEquals(1, syncs.size());
387        assertEquals(1, engine.getIsTargetServiceActive(syncService1, 0));
388    }
389
390    @MediumTest
391    /**
392     * V2 introduces flex time as well as service components.
393     * @throws Exception
394     */
395    public void testAuthorityParsingV2() throws Exception {
396        final Account account = new Account("account1", "type1");
397        final String authority1 = "auth1";
398        final String authority2 = "auth2";
399        final String authority3 = "auth3";
400
401        EndPoint target1 = new EndPoint(account, authority1, 0);
402        EndPoint target2 = new EndPoint(account, authority2, 0);
403        EndPoint target3 = new EndPoint(account, authority3, 0);
404        EndPoint target4 = new EndPoint(account, authority3, 1);
405
406        PeriodicSync sync1 = new PeriodicSync(account, authority1, Bundle.EMPTY, dayPoll, dayFuzz);
407        PeriodicSync sync2 = new PeriodicSync(account, authority2, Bundle.EMPTY, dayPoll, dayFuzz);
408        PeriodicSync sync3 = new PeriodicSync(account, authority3, Bundle.EMPTY, dayPoll, dayFuzz);
409        PeriodicSync sync1s = new PeriodicSync(account, authority1, Bundle.EMPTY, thousandSecs,
410                thousandSecsFuzz);
411        PeriodicSync sync2s = new PeriodicSync(account, authority2, Bundle.EMPTY, thousandSecs,
412                thousandSecsFuzz);
413        PeriodicSync sync3s = new PeriodicSync(account, authority3, Bundle.EMPTY, thousandSecs,
414                thousandSecsFuzz);
415
416        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
417                + "<accounts version=\"2\" >\n"
418                + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" >"
419                + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
420                + "\n</authority>"
421                + "<authority id=\"1\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth2\" >"
422                + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
423                + "\n</authority>"
424                // No user defaults to user 0 - all users.
425                + "<authority id=\"2\"            account=\"account1\" type=\"type1\" authority=\"auth3\" >"
426                + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
427                + "\n</authority>"
428                + "<authority id=\"3\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth3\" >"
429                + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
430                + "\n</authority>"
431                + "</accounts>").getBytes();
432
433        File syncDir = getSyncDir();
434        syncDir.mkdirs();
435        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
436        FileOutputStream fos = accountInfoFile.startWrite();
437        fos.write(accountsFileData);
438        accountInfoFile.finishWrite(fos);
439
440        engine.clearAndReadState();
441
442        List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
443        assertEquals("Got incorrect # of syncs", 1, syncs.size());
444        assertEquals(sync1, syncs.get(0));
445
446        syncs = engine.getPeriodicSyncs(target2);
447        assertEquals(1, syncs.size());
448        assertEquals(sync2, syncs.get(0));
449
450        syncs = engine.getPeriodicSyncs(target3);
451        assertEquals(1, syncs.size());
452        assertEquals(sync3, syncs.get(0));
453
454        syncs = engine.getPeriodicSyncs(target4);
455
456        assertEquals(1, syncs.size());
457        assertEquals(sync3, syncs.get(0));
458
459        // Test empty periodic data.
460        accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
461                + "<accounts version=\"2\">\n"
462                + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
463                + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n"
464                + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n"
465                + "</accounts>\n").getBytes();
466
467        accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
468        fos = accountInfoFile.startWrite();
469        fos.write(accountsFileData);
470        accountInfoFile.finishWrite(fos);
471
472        engine.clearAndReadState();
473
474        syncs = engine.getPeriodicSyncs(target1);
475        assertEquals(0, syncs.size());
476
477        syncs = engine.getPeriodicSyncs(target2);
478        assertEquals(0, syncs.size());
479
480        syncs = engine.getPeriodicSyncs(target3);
481        assertEquals(0, syncs.size());
482
483        accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
484                + "<accounts version=\"2\">\n"
485                + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\">\n"
486                + "<periodicSync period=\"1000\" />\n"
487                + "</authority>"
488                + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\">\n"
489                + "<periodicSync period=\"1000\" />\n"
490                + "</authority>"
491                + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\">\n"
492                + "<periodicSync period=\"1000\" />\n"
493                + "</authority>"
494                + "</accounts>\n").getBytes();
495
496        accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
497        fos = accountInfoFile.startWrite();
498        fos.write(accountsFileData);
499        accountInfoFile.finishWrite(fos);
500
501        engine.clearAndReadState();
502
503        syncs = engine.getPeriodicSyncs(target1);
504        assertEquals(1, syncs.size());
505        assertEquals(sync1s, syncs.get(0));
506
507        syncs = engine.getPeriodicSyncs(target2);
508        assertEquals(1, syncs.size());
509        assertEquals(sync2s, syncs.get(0));
510
511        syncs = engine.getPeriodicSyncs(target3);
512        assertEquals(1, syncs.size());
513        assertEquals(sync3s, syncs.get(0));
514    }
515
516    @MediumTest
517    public void testAuthorityParsing() throws Exception {
518        final Account account = new Account("account1", "type1");
519        final String authority1 = "auth1";
520        final String authority2 = "auth2";
521        final String authority3 = "auth3";
522        final Bundle extras = new Bundle();
523
524        EndPoint target1 = new EndPoint(account, authority1, 0);
525        EndPoint target2 = new EndPoint(account, authority2, 0);
526        EndPoint target3 = new EndPoint(account, authority3, 0);
527        EndPoint target4 = new EndPoint(account, authority3, 1);
528
529        PeriodicSync sync1 = new PeriodicSync(account, authority1, extras, (long) (60 * 60 * 24));
530        PeriodicSync sync2 = new PeriodicSync(account, authority2, extras, (long) (60 * 60 * 24));
531        PeriodicSync sync3 = new PeriodicSync(account, authority3, extras, (long) (60 * 60 * 24));
532        PeriodicSync sync1s = new PeriodicSync(account, authority1, extras, 1000);
533        PeriodicSync sync2s = new PeriodicSync(account, authority2, extras, 1000);
534        PeriodicSync sync3s = new PeriodicSync(account, authority3, extras, 1000);
535
536        MockContentResolver mockResolver = new MockContentResolver();
537
538        final TestContext testContext = new TestContext(mockResolver, getContext());
539
540        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
541                + "<accounts>\n"
542                + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
543                + "<authority id=\"1\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n"
544                + "<authority id=\"2\"            account=\"account1\" type=\"type1\" authority=\"auth3\" />\n"
545                + "<authority id=\"3\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n"
546                + "</accounts>\n").getBytes();
547
548        File syncDir = getSyncDir();
549        syncDir.mkdirs();
550        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
551        FileOutputStream fos = accountInfoFile.startWrite();
552        fos.write(accountsFileData);
553        accountInfoFile.finishWrite(fos);
554
555        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
556
557        List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
558        assertEquals(1, syncs.size());
559        assertEquals("expected sync1: " + sync1.toString() + " == sync 2" + syncs.get(0).toString(), sync1, syncs.get(0));
560
561        syncs = engine.getPeriodicSyncs(target2);
562        assertEquals(1, syncs.size());
563        assertEquals(sync2, syncs.get(0));
564
565        syncs = engine.getPeriodicSyncs(target3);
566        assertEquals(1, syncs.size());
567        assertEquals(sync3, syncs.get(0));
568        syncs = engine.getPeriodicSyncs(target4);
569
570
571        assertEquals(1, syncs.size());
572        assertEquals(sync3, syncs.get(0));
573
574        accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
575                + "<accounts version=\"2\">\n"
576                + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
577                + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n"
578                + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n"
579                + "</accounts>\n").getBytes();
580
581        accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
582        fos = accountInfoFile.startWrite();
583        fos.write(accountsFileData);
584        accountInfoFile.finishWrite(fos);
585
586        engine.clearAndReadState();
587
588        syncs = engine.getPeriodicSyncs(target1);
589        assertEquals(0, syncs.size());
590
591        syncs = engine.getPeriodicSyncs(target2);
592        assertEquals(0, syncs.size());
593
594        syncs = engine.getPeriodicSyncs(target3);
595        assertEquals(0, syncs.size());
596
597        accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
598                + "<accounts version=\"2\">\n"
599                + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\">\n"
600                + "<periodicSync period=\"1000\" />\n"
601                + "</authority>"
602                + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\">\n"
603                + "<periodicSync period=\"1000\" />\n"
604                + "</authority>"
605                + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\">\n"
606                + "<periodicSync period=\"1000\" />\n"
607                + "</authority>"
608                + "</accounts>\n").getBytes();
609
610        accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
611        fos = accountInfoFile.startWrite();
612        fos.write(accountsFileData);
613        accountInfoFile.finishWrite(fos);
614
615        engine.clearAndReadState();
616
617        syncs = engine.getPeriodicSyncs(target1);
618        assertEquals(1, syncs.size());
619        assertEquals(sync1s, syncs.get(0));
620
621        syncs = engine.getPeriodicSyncs(target2);
622        assertEquals(1, syncs.size());
623        assertEquals(sync2s, syncs.get(0));
624
625        syncs = engine.getPeriodicSyncs(target3);
626        assertEquals(1, syncs.size());
627        assertEquals(sync3s, syncs.get(0));
628    }
629
630    @MediumTest
631    public void testListenForTicklesParsing() throws Exception {
632        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
633                + "<accounts>\n"
634                + "<listenForTickles user=\"0\" enabled=\"false\" />"
635                + "<listenForTickles user=\"1\" enabled=\"true\" />"
636                + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
637                + "<authority id=\"1\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
638                + "</accounts>\n").getBytes();
639
640        MockContentResolver mockResolver = new MockContentResolver();
641        final TestContext testContext = new TestContext(mockResolver, getContext());
642
643        File syncDir = getSyncDir();
644        syncDir.mkdirs();
645        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
646        FileOutputStream fos = accountInfoFile.startWrite();
647        fos.write(accountsFileData);
648        accountInfoFile.finishWrite(fos);
649
650        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
651
652        assertEquals(false, engine.getMasterSyncAutomatically(0));
653        assertEquals(true, engine.getMasterSyncAutomatically(1));
654        assertEquals(true, engine.getMasterSyncAutomatically(2));
655
656    }
657
658    @MediumTest
659    public void testAuthorityRenaming() throws Exception {
660        final Account account1 = new Account("acc1", "type1");
661        final Account account2 = new Account("acc2", "type2");
662        final String authorityContacts = "contacts";
663        final String authorityCalendar = "calendar";
664        final String authorityOther = "other";
665        final String authorityContactsNew = "com.android.contacts";
666        final String authorityCalendarNew = "com.android.calendar";
667
668        MockContentResolver mockResolver = new MockContentResolver();
669
670        final TestContext testContext = new TestContext(mockResolver, getContext());
671
672        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
673                + "<accounts>\n"
674                + "<authority id=\"0\" account=\"acc1\" type=\"type1\" authority=\"contacts\" />\n"
675                + "<authority id=\"1\" account=\"acc1\" type=\"type1\" authority=\"calendar\" />\n"
676                + "<authority id=\"2\" account=\"acc1\" type=\"type1\" authority=\"other\" />\n"
677                + "<authority id=\"3\" account=\"acc2\" type=\"type2\" authority=\"contacts\" />\n"
678                + "<authority id=\"4\" account=\"acc2\" type=\"type2\" authority=\"calendar\" />\n"
679                + "<authority id=\"5\" account=\"acc2\" type=\"type2\" authority=\"other\" />\n"
680                + "<authority id=\"6\" account=\"acc2\" type=\"type2\" enabled=\"false\""
681                + " authority=\"com.android.calendar\" />\n"
682                + "<authority id=\"7\" account=\"acc2\" type=\"type2\" enabled=\"false\""
683                + " authority=\"com.android.contacts\" />\n"
684                + "</accounts>\n").getBytes();
685
686        File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
687        syncDir.mkdirs();
688        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
689        FileOutputStream fos = accountInfoFile.startWrite();
690        fos.write(accountsFileData);
691        accountInfoFile.finishWrite(fos);
692
693        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
694
695        assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityContacts));
696        assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityCalendar));
697        assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityOther));
698        assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityContactsNew));
699        assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityCalendarNew));
700
701        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContacts));
702        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendar));
703        assertEquals(true, engine.getSyncAutomatically(account2, 0, authorityOther));
704        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContactsNew));
705        assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendarNew));
706    }
707
708    @SmallTest
709    public void testSyncableMigration() throws Exception {
710        final Account account = new Account("acc", "type");
711
712        MockContentResolver mockResolver = new MockContentResolver();
713
714        final TestContext testContext = new TestContext(mockResolver, getContext());
715
716        byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
717                + "<accounts>\n"
718                + "<authority id=\"0\" account=\"acc\" authority=\"other1\" />\n"
719                + "<authority id=\"1\" account=\"acc\" type=\"type\" authority=\"other2\" />\n"
720                + "<authority id=\"2\" account=\"acc\" type=\"type\" syncable=\"false\""
721                + " authority=\"other3\" />\n"
722                + "<authority id=\"3\" account=\"acc\" type=\"type\" syncable=\"true\""
723                + " authority=\"other4\" />\n"
724                + "</accounts>\n").getBytes();
725
726        File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
727        syncDir.mkdirs();
728        AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
729        FileOutputStream fos = accountInfoFile.startWrite();
730        fos.write(accountsFileData);
731        accountInfoFile.finishWrite(fos);
732
733        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
734
735        assertEquals(-1, engine.getIsSyncable(account, 0, "other1"));
736        assertEquals(1, engine.getIsSyncable(account, 0, "other2"));
737        assertEquals(0, engine.getIsSyncable(account, 0, "other3"));
738        assertEquals(1, engine.getIsSyncable(account, 0, "other4"));
739    }
740}
741
742class TestContext extends ContextWrapper {
743
744    ContentResolver mResolver;
745
746    private final Context mRealContext;
747
748    public TestContext(ContentResolver resolver, Context realContext) {
749        super(new RenamingDelegatingContext(new MockContext(), realContext, "test."));
750        mRealContext = realContext;
751        mResolver = resolver;
752    }
753
754    @Override
755    public Resources getResources() {
756        return mRealContext.getResources();
757    }
758
759    @Override
760    public File getFilesDir() {
761        return mRealContext.getFilesDir();
762    }
763
764    @Override
765    public void enforceCallingOrSelfPermission(String permission, String message) {
766    }
767
768    @Override
769    public void sendBroadcast(Intent intent) {
770    }
771
772    @Override
773    public ContentResolver getContentResolver() {
774        return mResolver;
775    }
776}
777