• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.providers.contacts;
18 
19 import android.content.ContentProviderOperation;
20 import android.content.ContentUris;
21 import android.content.ContentValues;
22 import android.database.Cursor;
23 import android.net.Uri;
24 import android.provider.ContactsContract.MetadataSync;
25 import android.provider.ContactsContract.MetadataSyncState;
26 import android.provider.ContactsContract.RawContacts;
27 import android.test.MoreAsserts;
28 import android.test.suitebuilder.annotation.MediumTest;
29 import com.android.providers.contacts.ContactsDatabaseHelper.MetadataSyncColumns;
30 import com.android.providers.contacts.testutil.RawContactUtil;
31 import com.google.android.collect.Lists;
32 
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.HashSet;
36 import java.util.Set;
37 
38 /**
39  * Unit tests for {@link com.android.providers.contacts.ContactMetadataProvider}.
40  * <p/>
41  * Run the test like this:
42  * <code>
43  * adb shell am instrument -e class com.android.providers.contacts.ContactMetadataProviderTest -w \
44  * com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
45  * </code>
46  */
47 @MediumTest
48 public class ContactMetadataProviderTest extends BaseContactsProvider2Test {
49     private static String TEST_ACCOUNT_TYPE1 = "test_account_type1";
50     private static String TEST_ACCOUNT_NAME1 = "test_account_name1";
51     private static String TEST_DATA_SET1 = "plus";
52     private static String TEST_BACKUP_ID1 = "1001";
53     private static String TEST_DATA1 = "{\n" +
54             "  \"unique_contact_id\": {\n" +
55             "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
56             "    \"custom_account_type\": " + TEST_ACCOUNT_TYPE1 + ",\n" +
57             "    \"account_name\": " + TEST_ACCOUNT_NAME1 + ",\n" +
58             "    \"contact_id\": " + TEST_BACKUP_ID1 + ",\n" +
59             "    \"data_set\": \"GOOGLE_PLUS\"\n" +
60             "  },\n" +
61             "  \"contact_prefs\": {\n" +
62             "    \"send_to_voicemail\": true,\n" +
63             "    \"starred\": true,\n" +
64             "    \"pinned\": 2\n" +
65             "  }\n" +
66             "  }";
67     private static byte[] TEST_SYNC_STATE1 = "sync state1".getBytes();
68     private static String TEST_ACCOUNT_TYPE2 = "test_account_type2";
69     private static String TEST_ACCOUNT_NAME2 = "test_account_name2";
70     private static String TEST_DATA_SET2 = null;
71     private static String TEST_BACKUP_ID2 = "1002";
72     private static String TEST_DATA2 =  "{\n" +
73             "  \"unique_contact_id\": {\n" +
74             "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
75             "    \"custom_account_type\": " + TEST_ACCOUNT_TYPE2 + ",\n" +
76             "    \"account_name\": " + TEST_ACCOUNT_NAME2 + ",\n" +
77             "    \"contact_id\": " + TEST_BACKUP_ID2 + ",\n" +
78             "    \"data_set\": \"GOOGLE_PLUS\"\n" +
79             "  },\n" +
80             "  \"contact_prefs\": {\n" +
81             "    \"send_to_voicemail\": true,\n" +
82             "    \"starred\": true,\n" +
83             "    \"pinned\": 2\n" +
84             "  }\n" +
85             "  }";
86     private static byte[] TEST_SYNC_STATE2 = "sync state2".getBytes();
87     private static String SELECTION_BY_TEST_ACCOUNT1 = MetadataSync.ACCOUNT_NAME + "='" +
88             TEST_ACCOUNT_NAME1 + "' AND " + MetadataSync.ACCOUNT_TYPE + "='" + TEST_ACCOUNT_TYPE1 +
89             "' AND " + MetadataSync.DATA_SET + "='" + TEST_DATA_SET1 + "'";
90 
91     private static String SELECTION_BY_TEST_ACCOUNT2 = MetadataSync.ACCOUNT_NAME + "='" +
92             TEST_ACCOUNT_NAME2 + "' AND " + MetadataSync.ACCOUNT_TYPE + "='" + TEST_ACCOUNT_TYPE2 +
93             "' AND " + MetadataSync.DATA_SET + "='" + TEST_DATA_SET2 + "'";
94 
95     private ContactMetadataProvider mContactMetadataProvider;
96     private ContentValues defaultValues;
97 
98     @Override
setUp()99     protected void setUp() throws Exception {
100         super.setUp();
101         mContactMetadataProvider = addProvider(
102                 ContactMetadataProviderTestable.class, MetadataSync.METADATA_AUTHORITY);
103         // Reset the dbHelper to be the one ContactsProvider2 is using. Before this, two providers
104         // are using different dbHelpers.
105         mContactMetadataProvider.setDatabaseHelper(((SynchronousContactsProvider2)
106                 mActor.provider).getDatabaseHelper());
107         setupData();
108     }
109 
testInsertWithInvalidUri()110     public void testInsertWithInvalidUri() {
111         try {
112             mResolver.insert(Uri.withAppendedPath(MetadataSync.METADATA_AUTHORITY_URI,
113                     "metadata"), getDefaultValues());
114             fail("the insert was expected to fail, but it succeeded");
115         } catch (IllegalArgumentException e) {
116             // this was expected
117         }
118     }
119 
testUpdateWithInvalidUri()120     public void testUpdateWithInvalidUri() {
121         try {
122             mResolver.update(Uri.withAppendedPath(MetadataSync.METADATA_AUTHORITY_URI,
123                     "metadata"), getDefaultValues(), null, null);
124             fail("the update was expected to fail, but it succeeded");
125         } catch (IllegalArgumentException e) {
126             // this was expected
127         }
128     }
129 
testGetMetadataByAccount()130     public void testGetMetadataByAccount() {
131         Cursor c = mResolver.query(MetadataSync.CONTENT_URI, null, SELECTION_BY_TEST_ACCOUNT1,
132                 null, null);
133         assertEquals(1, c.getCount());
134 
135         ContentValues expectedValues = defaultValues;
136         expectedValues.remove(MetadataSyncColumns.ACCOUNT_ID);
137         c.moveToFirst();
138         assertCursorValues(c, expectedValues);
139         c.close();
140     }
141 
testFailOnInsertMetadataForSameAccountIdAndBackupId()142     public void testFailOnInsertMetadataForSameAccountIdAndBackupId() {
143         // Insert a new metadata with same account and backupId as defaultValues should fail.
144         String newData = "{\n" +
145                 "  \"unique_contact_id\": {\n" +
146                 "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
147                 "    \"custom_account_type\": " + TEST_ACCOUNT_TYPE1 + ",\n" +
148                 "    \"account_name\": " + TEST_ACCOUNT_NAME1 + ",\n" +
149                 "    \"contact_id\": " + TEST_BACKUP_ID1 + ",\n" +
150                 "    \"data_set\": \"GOOGLE_PLUS\"\n" +
151                 "  },\n" +
152                 "  \"contact_prefs\": {\n" +
153                 "    \"send_to_voicemail\": false,\n" +
154                 "    \"starred\": false,\n" +
155                 "    \"pinned\": 1\n" +
156                 "  }\n" +
157                 "  }";
158 
159         ContentValues  newValues =  new ContentValues();
160         newValues.put(MetadataSync.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
161         newValues.put(MetadataSync.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
162         newValues.put(MetadataSync.DATA_SET, TEST_DATA_SET1);
163         newValues.put(MetadataSync.RAW_CONTACT_BACKUP_ID, TEST_BACKUP_ID1);
164         newValues.put(MetadataSync.DATA, newData);
165         newValues.put(MetadataSync.DELETED, 0);
166         try {
167             mResolver.insert(MetadataSync.CONTENT_URI, newValues);
168         } catch (Exception e) {
169             // Expected.
170         }
171     }
172 
testInsertAndUpdateMetadataSync()173     public void testInsertAndUpdateMetadataSync() {
174         // Create a raw contact with backupId.
175         String backupId = "backupId10001";
176         long rawContactId = RawContactUtil.createRawContactWithAccountDataSet(
177                 mResolver, TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1);
178         Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
179         ContentValues values = new ContentValues();
180         values.put(RawContacts.BACKUP_ID, backupId);
181         assertEquals(1, mResolver.update(rawContactUri, values, null, null));
182 
183         assertStoredValue(rawContactUri, RawContacts._ID, rawContactId);
184         assertStoredValue(rawContactUri, RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
185         assertStoredValue(rawContactUri, RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
186         assertStoredValue(rawContactUri, RawContacts.BACKUP_ID, backupId);
187         assertStoredValue(rawContactUri, RawContacts.DATA_SET, TEST_DATA_SET1);
188 
189         String deleted = "0";
190         String insertJson = "{\n" +
191                 "  \"unique_contact_id\": {\n" +
192                 "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
193                 "    \"custom_account_type\": " + TEST_ACCOUNT_TYPE1 + ",\n" +
194                 "    \"account_name\": " + TEST_ACCOUNT_NAME1 + ",\n" +
195                 "    \"contact_id\": " + backupId + ",\n" +
196                 "    \"data_set\": \"GOOGLE_PLUS\"\n" +
197                 "  },\n" +
198                 "  \"contact_prefs\": {\n" +
199                 "    \"send_to_voicemail\": true,\n" +
200                 "    \"starred\": true,\n" +
201                 "    \"pinned\": 2\n" +
202                 "  }\n" +
203                 "  }";
204 
205         // Insert to MetadataSync table.
206         ContentValues insertedValues = new ContentValues();
207         insertedValues.put(MetadataSync.RAW_CONTACT_BACKUP_ID, backupId);
208         insertedValues.put(MetadataSync.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
209         insertedValues.put(MetadataSync.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
210         insertedValues.put(MetadataSync.DATA_SET, TEST_DATA_SET1);
211         insertedValues.put(MetadataSync.DATA, insertJson);
212         insertedValues.put(MetadataSync.DELETED, deleted);
213         Uri metadataUri = mResolver.insert(MetadataSync.CONTENT_URI, insertedValues);
214 
215         long metadataId = ContentUris.parseId(metadataUri);
216         assertEquals(true, metadataId > 0);
217 
218         // Check if RawContact table is updated  after inserting metadata.
219         assertStoredValue(rawContactUri, RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
220         assertStoredValue(rawContactUri, RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
221         assertStoredValue(rawContactUri, RawContacts.BACKUP_ID, backupId);
222         assertStoredValue(rawContactUri, RawContacts.DATA_SET, TEST_DATA_SET1);
223         assertStoredValue(rawContactUri, RawContacts.SEND_TO_VOICEMAIL, "1");
224         assertStoredValue(rawContactUri, RawContacts.STARRED, "1");
225         assertStoredValue(rawContactUri, RawContacts.PINNED, "2");
226 
227         // Update the MetadataSync table.
228         String updatedJson = "{\n" +
229                 "  \"unique_contact_id\": {\n" +
230                 "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
231                 "    \"custom_account_type\": " + TEST_ACCOUNT_TYPE1 + ",\n" +
232                 "    \"account_name\": " + TEST_ACCOUNT_NAME1 + ",\n" +
233                 "    \"contact_id\": " + backupId + ",\n" +
234                 "    \"data_set\": \"GOOGLE_PLUS\"\n" +
235                 "  },\n" +
236                 "  \"contact_prefs\": {\n" +
237                 "    \"send_to_voicemail\": false,\n" +
238                 "    \"starred\": false,\n" +
239                 "    \"pinned\": 1\n" +
240                 "  }\n" +
241                 "  }";
242         ContentValues updatedValues = new ContentValues();
243         updatedValues.put(MetadataSync.RAW_CONTACT_BACKUP_ID, backupId);
244         updatedValues.put(MetadataSync.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
245         updatedValues.put(MetadataSync.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
246         updatedValues.put(MetadataSync.DATA_SET, TEST_DATA_SET1);
247         updatedValues.put(MetadataSync.DATA, updatedJson);
248         updatedValues.put(MetadataSync.DELETED, deleted);
249         mResolver.insert(MetadataSync.CONTENT_URI, updatedValues);
250 
251         // Check if the insert (actually update) is correct.
252         assertStoredValue(rawContactUri, RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
253         assertStoredValue(rawContactUri, RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
254         assertStoredValue(rawContactUri, RawContacts.DATA_SET, TEST_DATA_SET1);
255         assertStoredValue(rawContactUri, RawContacts.SEND_TO_VOICEMAIL, "0");
256         assertStoredValue(rawContactUri, RawContacts.STARRED, "0");
257         assertStoredValue(rawContactUri, RawContacts.PINNED, "1");
258     }
259 
testInsertMetadata()260     public void testInsertMetadata() {
261         String backupId = "newBackupId";
262         String deleted = "0";
263         String insertJson = "{\n" +
264                 "  \"unique_contact_id\": {\n" +
265                 "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
266                 "    \"custom_account_type\": " + TEST_ACCOUNT_TYPE1 + ",\n" +
267                 "    \"account_name\": " + TEST_ACCOUNT_NAME1 + ",\n" +
268                 "    \"contact_id\": " + backupId + ",\n" +
269                 "    \"data_set\": \"GOOGLE_PLUS\"\n" +
270                 "  },\n" +
271                 "  \"contact_prefs\": {\n" +
272                 "    \"send_to_voicemail\": true,\n" +
273                 "    \"starred\": true,\n" +
274                 "    \"pinned\": 2\n" +
275                 "  }\n" +
276                 "  }";
277 
278         // Insert to MetadataSync table.
279         ContentValues insertedValues = new ContentValues();
280         insertedValues.put(MetadataSync.RAW_CONTACT_BACKUP_ID, backupId);
281         insertedValues.put(MetadataSync.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
282         insertedValues.put(MetadataSync.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
283         insertedValues.put(MetadataSync.DATA_SET, TEST_DATA_SET1);
284         insertedValues.put(MetadataSync.DATA, insertJson);
285         insertedValues.put(MetadataSync.DELETED, deleted);
286         Uri metadataUri = mResolver.insert(MetadataSync.CONTENT_URI, insertedValues);
287 
288         long metadataId = ContentUris.parseId(metadataUri);
289         assertEquals(true, metadataId > 0);
290     }
291 
testFailUpdateDeletedMetadata()292     public void testFailUpdateDeletedMetadata() {
293         String backupId = "backupId001";
294         String newData = "{\n" +
295                 "  \"unique_contact_id\": {\n" +
296                 "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
297                 "    \"custom_account_type\": " + TEST_ACCOUNT_TYPE1 + ",\n" +
298                 "    \"account_name\": " + TEST_ACCOUNT_NAME1 + ",\n" +
299                 "    \"contact_id\": " + backupId + ",\n" +
300                 "    \"data_set\": \"GOOGLE_PLUS\"\n" +
301                 "  },\n" +
302                 "  \"contact_prefs\": {\n" +
303                 "    \"send_to_voicemail\": false,\n" +
304                 "    \"starred\": false,\n" +
305                 "    \"pinned\": 1\n" +
306                 "  }\n" +
307                 "  }";
308 
309         ContentValues  newValues =  new ContentValues();
310         newValues.put(MetadataSync.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
311         newValues.put(MetadataSync.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
312         newValues.put(MetadataSync.DATA_SET, TEST_DATA_SET1);
313         newValues.put(MetadataSync.RAW_CONTACT_BACKUP_ID, backupId);
314         newValues.put(MetadataSync.DATA, newData);
315         newValues.put(MetadataSync.DELETED, 1);
316 
317         try {
318             mResolver.insert(MetadataSync.CONTENT_URI, newValues);
319             fail("the update was expected to fail, but it succeeded");
320         } catch (IllegalArgumentException e) {
321             // Expected
322         }
323     }
324 
testInsertWithNullData()325     public void testInsertWithNullData() {
326         ContentValues  newValues =  new ContentValues();
327         String data = null;
328         String backupId = "backupId002";
329         newValues.put(MetadataSync.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
330         newValues.put(MetadataSync.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
331         newValues.put(MetadataSync.DATA_SET, TEST_DATA_SET1);
332         newValues.put(MetadataSync.RAW_CONTACT_BACKUP_ID, backupId);
333         newValues.put(MetadataSync.DATA, data);
334         newValues.put(MetadataSync.DELETED, 0);
335 
336         try {
337             mResolver.insert(MetadataSync.CONTENT_URI, newValues);
338         } catch (IllegalArgumentException e) {
339             // Expected.
340         }
341     }
342 
testDeleteMetadata()343     public void testDeleteMetadata() {
344         //insert another metadata for TEST_ACCOUNT
345         insertMetadata(TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1, "2", TEST_DATA1, 0);
346         Cursor c = mResolver.query(MetadataSync.CONTENT_URI, null, SELECTION_BY_TEST_ACCOUNT1,
347                 null, null);
348         assertEquals(2, c.getCount());
349         int numOfDeletion = mResolver.delete(MetadataSync.CONTENT_URI, SELECTION_BY_TEST_ACCOUNT1,
350                 null);
351         assertEquals(2, numOfDeletion);
352         c = mResolver.query(MetadataSync.CONTENT_URI, null, SELECTION_BY_TEST_ACCOUNT1,
353                 null, null);
354         assertEquals(0, c.getCount());
355     }
356 
testBulkInsert()357     public void testBulkInsert() {
358         Cursor c = mResolver.query(MetadataSync.CONTENT_URI, new String[]{MetadataSync._ID},
359                 SELECTION_BY_TEST_ACCOUNT1, null, null);
360         assertEquals(1, c.getCount());
361 
362         ContentValues values1 = getMetadataContentValues(
363                 TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1, "123", TEST_DATA1, 0);
364         ContentValues values2 = getMetadataContentValues(
365                 TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1, "456", TEST_DATA1, 0);
366         ContentValues[] values = new ContentValues[] {values1, values2};
367 
368         mResolver.bulkInsert(MetadataSync.CONTENT_URI, values);
369         c = mResolver.query(MetadataSync.CONTENT_URI, new String[] {MetadataSync._ID},
370                 SELECTION_BY_TEST_ACCOUNT1, null, null);
371         assertEquals(3, c.getCount());
372     }
373 
testBatchOperations()374     public void testBatchOperations() throws Exception {
375         // Two mentadata_sync entries in the beginning, one for TEST_ACCOUNT1 and another for
376         // TEST_ACCOUNT2
377         Cursor c = mResolver.query(MetadataSync.CONTENT_URI, new String[] {MetadataSync._ID},
378                 null, null, null);
379         assertEquals(2, c.getCount());
380 
381         String updatedData = "{\n" +
382                 "  \"unique_contact_id\": {\n" +
383                 "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
384                 "    \"custom_account_type\": " + TEST_ACCOUNT_TYPE1 + ",\n" +
385                 "    \"account_name\": " + TEST_ACCOUNT_NAME1 + ",\n" +
386                 "    \"contact_id\": " + TEST_BACKUP_ID1 + ",\n" +
387                 "    \"data_set\": \"GOOGLE_PLUS\"\n" +
388                 "  },\n" +
389                 "  \"contact_prefs\": {\n" +
390                 "    \"send_to_voicemail\": true,\n" +
391                 "    \"starred\": false,\n" +
392                 "    \"pinned\": 5\n" +
393                 "  }\n" +
394                 "  }";
395 
396         String newBackupId = "2222";
397         String newData = "{\n" +
398                 "  \"unique_contact_id\": {\n" +
399                 "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
400                 "    \"custom_account_type\": " + TEST_ACCOUNT_TYPE1 + ",\n" +
401                 "    \"account_name\": " + TEST_ACCOUNT_NAME1 + ",\n" +
402                 "    \"contact_id\": " + newBackupId + ",\n" +
403                 "    \"data_set\": \"GOOGLE_PLUS\"\n" +
404                 "  },\n" +
405                 "  \"contact_prefs\": {\n" +
406                 "    \"send_to_voicemail\": true,\n" +
407                 "    \"starred\": false,\n" +
408                 "    \"pinned\": 5\n" +
409                 "  }\n" +
410                 "  }";
411 
412         ArrayList<ContentProviderOperation> ops = Lists.newArrayList();
413         ops.add(ContentProviderOperation.newInsert(MetadataSync.CONTENT_URI)
414                 .withValue(MetadataSync.ACCOUNT_NAME, TEST_ACCOUNT_NAME1)
415                 .withValue(MetadataSync.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1)
416                 .withValue(MetadataSync.DATA_SET, TEST_DATA_SET1)
417                 .withValue(MetadataSync.RAW_CONTACT_BACKUP_ID, TEST_BACKUP_ID1)
418                 .withValue(MetadataSync.DATA, updatedData)
419                 .withValue(MetadataSync.DELETED, 0)
420                 .build());
421 
422         ops.add(ContentProviderOperation.newInsert(MetadataSync.CONTENT_URI)
423                 .withValue(MetadataSync.ACCOUNT_NAME, TEST_ACCOUNT_NAME1)
424                 .withValue(MetadataSync.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1)
425                 .withValue(MetadataSync.DATA_SET, TEST_DATA_SET1)
426                 .withValue(MetadataSync.RAW_CONTACT_BACKUP_ID, newBackupId)
427                 .withValue(MetadataSync.DATA, newData)
428                 .withValue(MetadataSync.DELETED, 0)
429                 .build());
430 
431         ops.add(ContentProviderOperation.newDelete(MetadataSync.CONTENT_URI)
432                 .withSelection(SELECTION_BY_TEST_ACCOUNT2, null)
433                 .build());
434 
435         // Batch three operations: update the metadata_entry of TEST_ACCOUNT1; insert one new
436         // metadata_entry for TEST_ACCOUNT1; delete metadata_entry of TEST_ACCOUNT2
437         mResolver.applyBatch(MetadataSync.METADATA_AUTHORITY, ops);
438 
439         // After the batch operations, there should be two metadata_entry for TEST_ACCOUNT1 with
440         // new data value and no metadata_entry for TEST_ACCOUNT2.
441         c = mResolver.query(MetadataSync.CONTENT_URI, new String[] {MetadataSync.DATA},
442                 SELECTION_BY_TEST_ACCOUNT1, null, null);
443         assertEquals(2, c.getCount());
444         Set<String> actualData = new HashSet<>();
445         while (c.moveToNext()) {
446             actualData.add(c.getString(0));
447         }
448         c.close();
449         MoreAsserts.assertContentsInAnyOrder(actualData, updatedData, newData);
450 
451         c = mResolver.query(MetadataSync.CONTENT_URI, new String[] {MetadataSync._ID},
452                 SELECTION_BY_TEST_ACCOUNT2, null, null);
453         assertEquals(0, c.getCount());
454     }
455 
testQueryMetadataSyncState()456     public void testQueryMetadataSyncState() {
457         String selection = MetadataSyncState.ACCOUNT_NAME + "=?1 AND " +
458                 MetadataSyncState.ACCOUNT_TYPE + "=?2 AND " + MetadataSyncState.DATA_SET + "=?3";
459         final String[] args = new String[]{TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1};
460         final String[] projection = new String[]{MetadataSyncState.STATE};
461         Cursor c = mResolver.query(MetadataSyncState.CONTENT_URI, projection, selection, args,
462                 null);
463         assertEquals(1, c.getCount());
464         c.moveToFirst();
465         assertTrue(Arrays.equals(TEST_SYNC_STATE1, c.getBlob(0)));
466         c.close();
467     }
468 
testUpdateMetadataSyncState()469     public void testUpdateMetadataSyncState() {
470         mResolver.update(MetadataSyncState.CONTENT_URI, getSyncStateValues(TEST_ACCOUNT_NAME1,
471                 TEST_ACCOUNT_TYPE1, TEST_DATA_SET1, TEST_SYNC_STATE2), null, null);
472         String selection = MetadataSyncState.ACCOUNT_NAME + "=?1 AND " +
473                 MetadataSyncState.ACCOUNT_TYPE + "=?2 AND " + MetadataSyncState.DATA_SET + "=?3";
474         final String[] args = new String[]{TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1};
475         final String[] projection =  new String[] {MetadataSyncState.STATE};
476         Cursor c = mResolver.query(MetadataSyncState.CONTENT_URI, projection, selection, args,
477                 null);
478 
479         assertEquals(1, c.getCount());
480         c.moveToFirst();
481         assertTrue(Arrays.equals(TEST_SYNC_STATE2, c.getBlob(0)));
482         c.close();
483     }
484 
testUpdateMetadataSyncState_NonExisting()485     public void testUpdateMetadataSyncState_NonExisting() {
486         // Delete the existing one first.
487         String selection = MetadataSyncState.ACCOUNT_NAME + "=?1 AND " +
488                 MetadataSyncState.ACCOUNT_TYPE + "=?2 AND " + MetadataSyncState.DATA_SET + "=?3";
489         final String[] args = new String[]{TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1};
490 
491         mResolver.delete(MetadataSyncState.CONTENT_URI, selection, args);
492 
493         mResolver.update(MetadataSyncState.CONTENT_URI, getSyncStateValues(TEST_ACCOUNT_NAME1,
494                 TEST_ACCOUNT_TYPE1, TEST_DATA_SET1, TEST_SYNC_STATE2), null, null);
495         final String[] projection =  new String[] {MetadataSyncState.STATE};
496         Cursor c = mResolver.query(MetadataSyncState.CONTENT_URI, projection, selection, args,
497                 null);
498 
499         assertEquals(1, c.getCount());
500         c.moveToFirst();
501         assertTrue(Arrays.equals(TEST_SYNC_STATE2, c.getBlob(0)));
502         c.close();
503     }
504 
testDeleteMetadataSyncState()505     public void testDeleteMetadataSyncState() {
506         String selection = MetadataSyncState.ACCOUNT_NAME + "=?1 AND " +
507                 MetadataSyncState.ACCOUNT_TYPE + "=?2 AND " + MetadataSyncState.DATA_SET + "=?3";
508         final String[] args = new String[]{TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1};
509         final String[] projection = new String[]{MetadataSyncState.STATE};
510         Cursor c = mResolver.query(MetadataSyncState.CONTENT_URI, projection, selection, args,
511                 null);
512         assertEquals(1, c.getCount());
513         c.close();
514 
515         mResolver.delete(MetadataSyncState.CONTENT_URI, selection, args);
516         c = mResolver.query(MetadataSyncState.CONTENT_URI, projection, selection, args,
517                 null);
518         assertEquals(0, c.getCount());
519         c.close();
520     }
521 
setupData()522     private void setupData() {
523         long rawContactId1 = RawContactUtil.createRawContactWithAccountDataSet(
524                 mResolver, TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1);
525         createAccount(TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1);
526         insertMetadata(getDefaultValues());
527         insertMetadataSyncState(TEST_ACCOUNT_NAME1, TEST_ACCOUNT_TYPE1, TEST_DATA_SET1,
528                 TEST_SYNC_STATE1);
529 
530         // Insert another entry for another account
531         createAccount(TEST_ACCOUNT_NAME2, TEST_ACCOUNT_TYPE2, TEST_DATA_SET2);
532         insertMetadata(TEST_ACCOUNT_NAME2, TEST_ACCOUNT_TYPE2, TEST_DATA_SET2, TEST_BACKUP_ID2,
533                 TEST_DATA2, 0);
534         insertMetadataSyncState(TEST_ACCOUNT_NAME2, TEST_ACCOUNT_TYPE2, TEST_DATA_SET2,
535                 TEST_SYNC_STATE2);
536     }
537 
getDefaultValues()538     private ContentValues getDefaultValues() {
539         defaultValues = new ContentValues();
540         defaultValues.put(MetadataSync.ACCOUNT_NAME, TEST_ACCOUNT_NAME1);
541         defaultValues.put(MetadataSync.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE1);
542         defaultValues.put(MetadataSync.DATA_SET, TEST_DATA_SET1);
543         defaultValues.put(MetadataSync.RAW_CONTACT_BACKUP_ID, TEST_BACKUP_ID1);
544         defaultValues.put(MetadataSync.DATA, TEST_DATA1);
545         defaultValues.put(MetadataSync.DELETED, 0);
546         return defaultValues;
547     }
548 
insertMetadata(String accountName, String accountType, String dataSet, String backupId, String data, int deleted)549     private long insertMetadata(String accountName, String accountType, String dataSet,
550             String backupId, String data, int deleted) {
551         return insertMetadata(getMetadataContentValues(
552                 accountName, accountType, dataSet, backupId, data, deleted));
553     }
554 
getMetadataContentValues(String accountName, String accountType, String dataSet, String backupId, String data, int deleted)555     private ContentValues getMetadataContentValues(String accountName, String accountType,
556             String dataSet, String backupId, String data, int deleted) {
557         ContentValues values = new ContentValues();
558         values.put(MetadataSync.ACCOUNT_NAME, accountName);
559         values.put(MetadataSync.ACCOUNT_TYPE, accountType);
560         values.put(MetadataSync.DATA_SET, dataSet);
561         values.put(MetadataSync.RAW_CONTACT_BACKUP_ID, backupId);
562         values.put(MetadataSync.DATA, data);
563         values.put(MetadataSync.DELETED, deleted);
564         return values;
565     }
566 
insertMetadata(ContentValues values)567     private long insertMetadata(ContentValues values) {
568         return ContentUris.parseId(mResolver.insert(MetadataSync.CONTENT_URI, values));
569     }
570 
insertMetadataSyncState(String accountName, String accountType, String dataSet, byte[] state)571     private long insertMetadataSyncState(String accountName, String accountType,
572             String dataSet, byte[] state) {
573         return ContentUris.parseId(mResolver.insert(MetadataSyncState.CONTENT_URI,
574                 getSyncStateValues(accountName, accountType, dataSet, state)));
575     }
576 
getSyncStateValues(String accountName, String accountType, String dataSet, byte[] state)577     private ContentValues getSyncStateValues(String accountName, String accountType,
578             String dataSet, byte[] state) {
579         ContentValues values = new ContentValues();
580         values.put(MetadataSyncState.ACCOUNT_NAME, accountName);
581         values.put(MetadataSyncState.ACCOUNT_TYPE, accountType);
582         values.put(MetadataSyncState.DATA_SET, dataSet);
583         values.put(MetadataSyncState.STATE, state);
584         return values;
585     }
586 }
587