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.messaging.datamodel; 18 19 import android.content.ContentProvider; 20 import android.content.ContentValues; 21 import android.database.Cursor; 22 import android.net.Uri; 23 import android.test.suitebuilder.annotation.SmallTest; 24 import android.text.TextUtils; 25 26 import com.android.messaging.BugleTestCase; 27 import com.android.messaging.FakeContentProvider; 28 import com.android.messaging.FakeContext; 29 import com.android.messaging.FakeFactory; 30 import com.android.messaging.datamodel.DatabaseHelper.ParticipantColumns; 31 import com.android.messaging.datamodel.data.ParticipantData; 32 import com.android.messaging.datamodel.data.ParticipantData.ParticipantsQuery; 33 import com.android.messaging.ui.UIIntents; 34 import com.android.messaging.util.ContactUtil; 35 36 import org.junit.Assert; 37 import org.mockito.Mock; 38 39 /** 40 * Utility class for testing ParticipantRefresh class for different scenarios. 41 */ 42 @SmallTest 43 public class ParticipantRefreshTest extends BugleTestCase { 44 private FakeContext mContext; 45 FakeFactory mFakeFactory; 46 @Mock protected UIIntents mMockUIIntents; 47 protected FakeDataModel mFakeDataModel; 48 49 @Override setUp()50 public void setUp() throws Exception { 51 super.setUp(); 52 53 mContext = new FakeContext(getTestContext()); 54 55 final ContentProvider provider = new MessagingContentProvider(); 56 provider.attachInfo(mContext, null); 57 mContext.addContentProvider(MessagingContentProvider.AUTHORITY, provider); 58 59 mFakeDataModel = new FakeDataModel(mContext); 60 mFakeFactory = FakeFactory.registerWithFakeContext(getTestContext(), mContext) 61 .withDataModel(mFakeDataModel) 62 .withUIIntents(mMockUIIntents); 63 } 64 65 /** 66 * Add some phonelookup result into take PhoneLookup content provider. This will be 67 * used for doing phone lookup during participant refresh. 68 */ addPhoneLookup(final String phone, final Object[][] lookupResult)69 private void addPhoneLookup(final String phone, final Object[][] lookupResult) { 70 final Uri uri = ContactUtil.lookupPhone(mContext, phone).getUri(); 71 final FakeContentProvider phoneLookup = new FakeContentProvider(mContext, 72 uri, false); 73 phoneLookup.addOverrideData(uri, null, null, ContactUtil.PhoneLookupQuery.PROJECTION, 74 lookupResult); 75 mFakeFactory.withProvider(uri, phoneLookup); 76 } 77 78 /** 79 * Add some participant to test database. 80 */ addParticipant(final String normalizedDestination, final long contactId, final String name, final String photoUrl)81 private void addParticipant(final String normalizedDestination, final long contactId, 82 final String name, final String photoUrl) { 83 final DatabaseWrapper db = DataModel.get().getDatabase(); 84 final ContentValues values = new ContentValues(); 85 86 values.put(ParticipantColumns.NORMALIZED_DESTINATION, normalizedDestination); 87 values.put(ParticipantColumns.CONTACT_ID, contactId); 88 values.put(ParticipantColumns.FULL_NAME, name); 89 values.put(ParticipantColumns.PROFILE_PHOTO_URI, photoUrl); 90 91 db.beginTransaction(); 92 try { 93 db.insert(DatabaseHelper.PARTICIPANTS_TABLE, null, values); 94 db.setTransactionSuccessful(); 95 } finally { 96 db.endTransaction(); 97 } 98 } 99 100 /** 101 * Verify that participant in the database has expected contacdtId, name and photoUrl fields. 102 */ verifyParticipant(final String normalizedDestination, final long contactId, final String name, final String photoUrl)103 private void verifyParticipant(final String normalizedDestination, final long contactId, 104 final String name, final String photoUrl) { 105 final DatabaseWrapper db = DataModel.get().getDatabase(); 106 db.beginTransaction(); 107 try { 108 final String selection = ParticipantColumns.NORMALIZED_DESTINATION + "=?"; 109 final String[] selectionArgs = new String[] { normalizedDestination }; 110 111 final Cursor cursor = db.query(DatabaseHelper.PARTICIPANTS_TABLE, 112 ParticipantsQuery.PROJECTION, selection, selectionArgs, null, null, null); 113 114 if (cursor == null || cursor.getCount() != 1) { 115 Assert.fail("Should have participants for:" + normalizedDestination); 116 return; 117 } 118 119 cursor.moveToFirst(); 120 final int currentContactId = cursor.getInt(ParticipantsQuery.INDEX_CONTACT_ID); 121 final String currentName = cursor.getString(ParticipantsQuery.INDEX_FULL_NAME); 122 final String currentPhotoUrl = 123 cursor.getString(ParticipantsQuery.INDEX_PROFILE_PHOTO_URI); 124 if (currentContactId != contactId) { 125 Assert.fail("Contact Id doesn't match. normalizedNumber=" + normalizedDestination + 126 " expected=" + contactId + " actual=" + currentContactId); 127 return; 128 } 129 130 if (!TextUtils.equals(currentName, name)) { 131 Assert.fail("Name doesn't match. normalizedNumber=" + normalizedDestination + 132 " expected=" + name + " actual=" + currentName); 133 return; 134 } 135 136 if (!TextUtils.equals(currentPhotoUrl, photoUrl)) { 137 Assert.fail("Contact Id doesn't match. normalizedNumber=" + normalizedDestination + 138 " expected=" + photoUrl + " actual=" + currentPhotoUrl); 139 return; 140 } 141 142 db.setTransactionSuccessful(); 143 } finally { 144 db.endTransaction(); 145 } 146 } 147 148 /** 149 * Verify that incremental refresh will resolve previously not resolved participants. 150 */ testIncrementalRefreshNotResolvedSingleMatch()151 public void testIncrementalRefreshNotResolvedSingleMatch() { 152 addParticipant("650-123-1233", ParticipantData.PARTICIPANT_CONTACT_ID_NOT_RESOLVED, 153 null, null); 154 addPhoneLookup("650-123-1233", new Object[][] { 155 { 1L, "John", "content://photo/john", "650-123-1233", null, null, null } 156 }); 157 158 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_INCREMENTAL); 159 verifyParticipant("650-123-1233", 1, "John", "content://photo/john"); 160 } 161 162 /** 163 * Verify that incremental refresh will resolve previously not resolved participants. 164 */ testIncrementalRefreshNotResolvedMultiMatch()165 public void testIncrementalRefreshNotResolvedMultiMatch() { 166 addParticipant("650-123-1233", ParticipantData.PARTICIPANT_CONTACT_ID_NOT_RESOLVED, 167 null, null); 168 addPhoneLookup("650-123-1233", new Object[][] { 169 { 1L, "John", "content://photo/john", "650-123-1233", null, null, null }, 170 { 2L, "Joe", "content://photo/joe", "650-123-1233", null, null, null } 171 }); 172 173 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_INCREMENTAL); 174 verifyParticipant("650-123-1233", 1, "John", "content://photo/john"); 175 } 176 177 /** 178 * Verify that incremental refresh will not touch already-resolved participants. 179 */ testIncrementalRefreshResolvedSingleMatch()180 public void testIncrementalRefreshResolvedSingleMatch() { 181 addParticipant("650-123-1233", 1, "Joh", "content://photo/joh"); 182 addPhoneLookup("650-123-1233", new Object[][] { 183 { 1L, "John", "content://photo/john", "650-123-1233", null, null, null } 184 }); 185 186 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_INCREMENTAL); 187 verifyParticipant("650-123-1233", 1, "John", "content://photo/john"); 188 } 189 190 /** 191 * Verify that full refresh will correct already-resolved participants if needed 192 */ testFullRefreshResolvedSingleMatch()193 public void testFullRefreshResolvedSingleMatch() { 194 addParticipant("650-123-1233", 1, "Joh", "content://photo/joh"); 195 addPhoneLookup("650-123-1233", new Object[][] { 196 { 1L, "John", "content://photo/john", "650-123-1233", null, null, null } 197 }); 198 199 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_FULL); 200 verifyParticipant("650-123-1233", 1, "John", "content://photo/john"); 201 } 202 203 /** 204 * Verify that incremental refresh will not touch participant that is marked as not found. 205 */ testIncrementalRefreshNotFound()206 public void testIncrementalRefreshNotFound() { 207 addParticipant("650-123-1233", ParticipantData.PARTICIPANT_CONTACT_ID_NOT_FOUND, 208 null, null); 209 addPhoneLookup("650-123-1233", new Object[][] { 210 { 1L, "John", "content://photo/john", "650-123-1233", null, null, null } 211 }); 212 213 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_INCREMENTAL); 214 verifyParticipant("650-123-1233", 1, "John", "content://photo/john"); 215 } 216 217 /** 218 * Verify that full refresh will resolve participant that is marked as not found. 219 */ testFullRefreshNotFound()220 public void testFullRefreshNotFound() { 221 addParticipant("650-123-1233", ParticipantData.PARTICIPANT_CONTACT_ID_NOT_FOUND, 222 null, null); 223 addPhoneLookup("650-123-1233", new Object[][] { 224 { 1L, "John", "content://photo/john", "650-123-1233", null, null, null } 225 }); 226 227 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_FULL); 228 verifyParticipant("650-123-1233", 1, "John", "content://photo/john"); 229 } 230 231 /** 232 * Verify that refresh take consideration of current contact_id when having multiple matches. 233 */ testFullRefreshResolvedMultiMatch1()234 public void testFullRefreshResolvedMultiMatch1() { 235 addParticipant("650-123-1233", 1, "Joh", "content://photo/joh"); 236 addPhoneLookup("650-123-1233", new Object[][] { 237 { 1L, "John", "content://photo/john", "650-123-1233", null, null, null }, 238 { 2L, "Joe", "content://photo/joe", "650-123-1233", null, null, null } 239 }); 240 241 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_FULL); 242 verifyParticipant("650-123-1233", 1, "John", "content://photo/john"); 243 } 244 245 /** 246 * Verify that refresh take consideration of current contact_id when having multiple matches. 247 */ testFullRefreshResolvedMultiMatch2()248 public void testFullRefreshResolvedMultiMatch2() { 249 addParticipant("650-123-1233", 2, "Joh", "content://photo/joh"); 250 addPhoneLookup("650-123-1233", new Object[][] { 251 { 1L, "John", "content://photo/john", "650-123-1233", null, null, null }, 252 { 2L, "Joe", "content://photo/joe", "650-123-1233", null, null, null } 253 }); 254 255 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_FULL); 256 verifyParticipant("650-123-1233", 1, "John", "content://photo/john"); 257 } 258 259 /** 260 * Verify that refresh take first contact in case current contact_id no longer matches. 261 */ testFullRefreshResolvedMultiMatch3()262 public void testFullRefreshResolvedMultiMatch3() { 263 addParticipant("650-123-1233", 3, "Joh", "content://photo/joh"); 264 addPhoneLookup("650-123-1233", new Object[][] { 265 { 1L, "John", "content://photo/john", "650-123-1233", null, null, null }, 266 { 2L, "Joe", "content://photo/joe", "650-123-1233", null, null, null } 267 }); 268 269 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_FULL); 270 verifyParticipant("650-123-1233", 1, "John", "content://photo/john"); 271 } 272 273 /** 274 * Verify that refresh take first contact in case current contact_id no longer matches. 275 */ testFullRefreshResolvedBeforeButNotFoundNow()276 public void testFullRefreshResolvedBeforeButNotFoundNow() { 277 addParticipant("650-123-1233", 1, "Joh", "content://photo/joh"); 278 addPhoneLookup("650-123-1233", new Object[][] {}); 279 280 ParticipantRefresh.refreshParticipants(ParticipantRefresh.REFRESH_MODE_FULL); 281 verifyParticipant("650-123-1233", ParticipantData.PARTICIPANT_CONTACT_ID_NOT_FOUND, 282 null, null); 283 } 284 } 285