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