1/* 2 * Copyright (C) 2012 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.providers.contacts; 18 19import static com.android.providers.contacts.TestUtils.cv; 20 21import com.google.android.collect.Lists; 22 23import android.content.ContentProviderOperation; 24import android.content.ContentValues; 25import android.provider.ContactsContract; 26import android.provider.ContactsContract.CommonDataKinds.StructuredName; 27import android.provider.ContactsContract.Contacts; 28import android.provider.ContactsContract.Data; 29import android.provider.ContactsContract.Profile; 30import android.provider.ContactsContract.RawContacts; 31import android.test.suitebuilder.annotation.LargeTest; 32import android.util.Log; 33 34import java.util.ArrayList; 35 36/** 37 * Tests to make sure we're handling DB transactions properly in regard to two databases, 38 * the profile db and the contacts db. 39 */ 40@LargeTest 41public class ContactsProvider2TransactionTest extends BaseContactsProvider2Test { 42 private SynchronousContactsProvider2 mProvider; 43 44 @Override 45 protected void setUp() throws Exception { 46 super.setUp(); 47 48 mProvider = (SynchronousContactsProvider2) getProvider(); 49 } 50 51 @Override 52 protected void tearDown() throws Exception { 53 super.tearDown(); 54 55 mProvider = null; 56 } 57 58 /** 59 * Make sure we start/finish transactions on the right databases for insert. 60 */ 61 public void testTransactionCallback_insert() { 62 63 final ContentValues values = cv(RawContacts.LAST_TIME_CONTACTED, 12345); 64 65 // Insert a raw contact. 66 mProvider.resetTrasactionCallbackCalledFlags(); 67 mResolver.insert(RawContacts.CONTENT_URI, values); 68 69 // Make sure we only COMMIT on the contacts DB, but there was no transaction on the 70 // profile db. 71 mProvider.assertCommitTransactionCalledForContactMode(); 72 mProvider.assertNoTransactionsForProfileMode(); 73 74 75 // Insert a profile raw contact. 76 mProvider.resetTrasactionCallbackCalledFlags(); 77 mResolver.insert(Profile.CONTENT_RAW_CONTACTS_URI, values); 78 79 // Even though we only touched the profile DB, we also start and finish a transaction 80 // on the contacts db. AbstractContactsProvider does that to avoid deadlocks. 81 mProvider.assertCommitTransactionCalledForContactMode(); 82 mProvider.assertCommitTransactionCalledForProfileMode(); 83 } 84 85 /** 86 * Make sure we start/finish transactions on the right databases for update. 87 */ 88 public void testTransactionCallback_update() { 89 90 final ContentValues values = cv(RawContacts.LAST_TIME_CONTACTED, 12345); 91 92 // Make sure to create a raw contact and a profile raw contact. 93 mResolver.insert(RawContacts.CONTENT_URI, values); 94 mResolver.insert(Profile.CONTENT_RAW_CONTACTS_URI, values); 95 96 values.clear(); 97 values.put(RawContacts.LAST_TIME_CONTACTED, 99999); 98 99 // Update all raw contacts. 100 mProvider.resetTrasactionCallbackCalledFlags(); 101 assertTrue(mResolver.update(RawContacts.CONTENT_URI, values, null, null) > 0); 102 103 // Make sure we only COMMIT on the contacts DB, but there was no transaction on the 104 // profile db. 105 mProvider.assertCommitTransactionCalledForContactMode(); 106 mProvider.assertNoTransactionsForProfileMode(); 107 108 109 // Update all profile raw contacts. 110 mProvider.resetTrasactionCallbackCalledFlags(); 111 assertTrue(mResolver.update(Profile.CONTENT_RAW_CONTACTS_URI, values, null, null) > 0); 112 113 // Even though we only touched the profile DB, we also start and finish a transaction 114 // on the contacts db. AbstractContactsProvider does that to avoid deadlocks. 115 mProvider.assertCommitTransactionCalledForContactMode(); 116 mProvider.assertCommitTransactionCalledForProfileMode(); 117 } 118 119 /** 120 * Make sure we start/finish transactions on the right databases for delete. 121 */ 122 public void testTransactionCallback_delete() { 123 124 final ContentValues values = cv(RawContacts.LAST_TIME_CONTACTED, 12345); 125 126 // Make sure to create a raw contact and a profile raw contact. 127 mResolver.insert(RawContacts.CONTENT_URI, values); 128 mResolver.insert(Profile.CONTENT_RAW_CONTACTS_URI, values); 129 130 // Delete all raw contacts. 131 mProvider.resetTrasactionCallbackCalledFlags(); 132 assertTrue(mResolver.delete(RawContacts.CONTENT_URI, null, null) > 0); 133 134 // Make sure we only COMMIT on the contacts DB, but there was no transaction on the 135 // profile db. 136 mProvider.assertCommitTransactionCalledForContactMode(); 137 mProvider.assertNoTransactionsForProfileMode(); 138 139 // Delete all profile raw contact. 140 mProvider.resetTrasactionCallbackCalledFlags(); 141 assertTrue(mResolver.delete(Profile.CONTENT_RAW_CONTACTS_URI, null, null) > 0); 142 143 // Even though we only touched the profile DB, we also start and finish a transaction 144 // on the contacts db. AbstractContactsProvider does that to avoid deadlocks. 145 mProvider.assertCommitTransactionCalledForContactMode(); 146 mProvider.assertCommitTransactionCalledForProfileMode(); 147 } 148 /** 149 * Make sure we start/finish transactions on the right databases for bulk insert. 150 */ 151 public void testTransactionCallback_bulkInsert() { 152 153 final ContentValues values = cv(RawContacts.LAST_TIME_CONTACTED, 12345); 154 155 // Insert a raw contact. 156 mProvider.resetTrasactionCallbackCalledFlags(); 157 mResolver.bulkInsert(RawContacts.CONTENT_URI, new ContentValues[] {values}); 158 159 // Make sure we only COMMIT on the contacts DB, but there was no transaction on the 160 // profile db. 161 mProvider.assertCommitTransactionCalledForContactMode(); 162 mProvider.assertNoTransactionsForProfileMode(); 163 164 165 // Insert a profile raw contact. 166 mProvider.resetTrasactionCallbackCalledFlags(); 167 mResolver.bulkInsert(Profile.CONTENT_RAW_CONTACTS_URI, new ContentValues[] {values}); 168 169 // Even though we only touched the profile DB, we also start and finish a transaction 170 // on the contacts db. AbstractContactsProvider does that to avoid deadlocks. 171 mProvider.assertCommitTransactionCalledForContactMode(); 172 mProvider.assertCommitTransactionCalledForProfileMode(); 173 } 174 175 /** 176 * Add an operation to create a raw contact. 177 */ 178 private static void addInsertContactOperations(ArrayList<ContentProviderOperation> ops) { 179 ContentProviderOperation.Builder b; 180 b = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI); 181 b.withValue(RawContacts.STARRED, 1); 182 b.withValue(RawContacts.TIMES_CONTACTED, 200001); 183 ops.add(b.build()); 184 185 b = ContentProviderOperation.newInsert(Data.CONTENT_URI); 186 b.withValueBackReference(Data.RAW_CONTACT_ID, ops.size() - 1); 187 b.withValue(StructuredName.DISPLAY_NAME, "Regular Contact"); 188 b.withValue(StructuredName.GIVEN_NAME, "Regular"); 189 b.withValue(StructuredName.FAMILY_NAME, "Contact"); 190 b.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 191 ops.add(b.build()); 192 } 193 194 /** 195 * Check for a contact created that'll be created for {@link #addInsertContactOperations}. 196 */ 197 private void checkStoredContact() { 198 assertStoredValues(Contacts.CONTENT_URI, cv( 199 Contacts.DISPLAY_NAME, "Regular Contact", 200 RawContacts.TIMES_CONTACTED, 200001 201 )); 202 } 203 204 /** 205 * Add an operation to create a profile raw contact. 206 */ 207 private static void addInsertProfileOperations(ArrayList<ContentProviderOperation> ops) { 208 ContentProviderOperation.Builder b; 209 b = ContentProviderOperation.newInsert(Profile.CONTENT_RAW_CONTACTS_URI); 210 b.withValue(RawContacts.STARRED, 1); 211 b.withValue(RawContacts.TIMES_CONTACTED, 100001); 212 ops.add(b.build()); 213 214 b = ContentProviderOperation.newInsert(Data.CONTENT_URI); 215 b.withValueBackReference(Data.RAW_CONTACT_ID, ops.size() - 1); 216 b.withValue(StructuredName.DISPLAY_NAME, "Profile Contact"); 217 b.withValue(StructuredName.GIVEN_NAME, "Profile"); 218 b.withValue(StructuredName.FAMILY_NAME, "Contact"); 219 b.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 220 ops.add(b.build()); 221 } 222 223 /** 224 * Check for a profile contact created that'll be created for 225 * {@link #addInsertProfileOperations}. 226 */ 227 private void checkStoredProfile() { 228 assertStoredValues(Profile.CONTENT_URI, cv( 229 Contacts.DISPLAY_NAME, "Profile Contact", 230 RawContacts.TIMES_CONTACTED, 100001 231 )); 232 } 233 234 public void testTransactionCallback_contactBatch() throws Exception { 235 final ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 236 237 addInsertContactOperations(ops); 238 239 mProvider.resetTrasactionCallbackCalledFlags(); 240 241 // Execute the operations. 242 mResolver.applyBatch(ContactsContract.AUTHORITY, ops); 243 244 // Check the result 245 mProvider.assertCommitTransactionCalledForContactMode(); 246 mProvider.assertNoTransactionsForProfileMode(); 247 248 checkStoredContact(); 249 } 250 251 public void testTransactionCallback_profileBatch() throws Exception { 252 final ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 253 254 addInsertProfileOperations(ops); 255 256 mProvider.resetTrasactionCallbackCalledFlags(); 257 258 // Execute the operations. 259 mResolver.applyBatch(ContactsContract.AUTHORITY, ops); 260 261 // Check the result 262 mProvider.assertCommitTransactionCalledForContactMode(); 263 mProvider.assertCommitTransactionCalledForProfileMode(); 264 265 checkStoredProfile(); 266 } 267 268 public void testTransactionCallback_mixedBatch() throws Exception { 269 final ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 270 271 // Create a raw contact and a profile raw contact in a single batch. 272 273 addInsertContactOperations(ops); 274 addInsertProfileOperations(ops); 275 276 mProvider.resetTrasactionCallbackCalledFlags(); 277 278 // Execute the operations. 279 mResolver.applyBatch(ContactsContract.AUTHORITY, ops); 280 281 // Check the result 282 mProvider.assertCommitTransactionCalledForContactMode(); 283 mProvider.assertCommitTransactionCalledForProfileMode(); 284 285 checkStoredProfile(); 286 checkStoredContact(); 287 } 288 289 public void testTransactionCallback_mixedBatchReversed() throws Exception { 290 final ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); 291 292 // Create a profile raw contact and a raw contact in a single batch. 293 294 addInsertProfileOperations(ops); 295 addInsertContactOperations(ops); 296 297 mProvider.resetTrasactionCallbackCalledFlags(); 298 299 // Execute the operations. 300 mResolver.applyBatch(ContactsContract.AUTHORITY, ops); 301 302 // Check the result 303 mProvider.assertCommitTransactionCalledForContactMode(); 304 mProvider.assertCommitTransactionCalledForProfileMode(); 305 306 checkStoredProfile(); 307 checkStoredContact(); 308 } 309} 310