1 /* 2 * Copyright (C) 2009 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.Context; 20 import android.database.Cursor; 21 import android.database.DatabaseUtils; 22 import android.database.sqlite.SQLiteDatabase; 23 import android.net.Uri; 24 import android.provider.BaseColumns; 25 import android.provider.CallLog; 26 import android.provider.CallLog.Calls; 27 import android.provider.ContactsContract.Contacts; 28 import android.provider.ContactsContract.Data; 29 import android.provider.ContactsContract.Groups; 30 import android.provider.ContactsContract.RawContacts; 31 import android.test.mock.MockContext; 32 import android.test.suitebuilder.annotation.LargeTest; 33 34 import java.io.ByteArrayOutputStream; 35 import java.io.File; 36 import java.io.IOException; 37 import java.io.InputStream; 38 39 /** 40 * Unit tests for {@link LegacyContactImporter}. 41 * 42 * Run the test like this: 43 * <code> 44 * adb shell am instrument -e class com.android.providers.contacts.LegacyContactImporterTest -w \ 45 * com.android.providers.contacts.tests/android.test.InstrumentationTestRunner 46 * </code> 47 */ 48 @LargeTest 49 public class LegacyContactImporterTest extends BaseContactsProvider2Test { 50 51 private static class LegacyMockContext extends MockContext { 52 53 private String mFileName; 54 LegacyMockContext(String fileName)55 public LegacyMockContext(String fileName) { 56 mFileName = fileName; 57 } 58 59 @Override openOrCreateDatabase(String file, int mode, SQLiteDatabase.CursorFactory factory)60 public SQLiteDatabase openOrCreateDatabase(String file, int mode, 61 SQLiteDatabase.CursorFactory factory) { 62 return SQLiteDatabase.openDatabase(mFileName, factory, SQLiteDatabase.OPEN_READONLY); 63 } 64 65 @Override getDatabasePath(String name)66 public File getDatabasePath(String name) { 67 return new File(mFileName); 68 } 69 } 70 createLegacyMockContext(String folder)71 private LegacyMockContext createLegacyMockContext(String folder) throws IOException { 72 Context context = getTestContext(); 73 File tempDb = new File(context.getFilesDir(), "legacy_contacts.db"); 74 if (tempDb.exists()) { 75 tempDb.delete(); 76 } 77 createSQLiteDatabaseFromDumpFile(tempDb.getPath(), 78 new File(folder, "legacy_contacts.sql").getPath()); 79 return new LegacyMockContext(tempDb.getPath()); 80 } 81 createSQLiteDatabaseFromDumpFile(String tempDbPath, String dumpFileAssetPath)82 private void createSQLiteDatabaseFromDumpFile(String tempDbPath, String dumpFileAssetPath) 83 throws IOException { 84 85 final String[] ignoredTables = new String[] {"android_metadata", "sqlite_sequence"}; 86 87 Context context = getTestContext(); 88 SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(tempDbPath, null); 89 try { 90 String data = readAssetAsString(dumpFileAssetPath); 91 String[] commands = data.split(";\r|;\n|;\r\n"); 92 for (String command : commands) { 93 boolean ignore = false; 94 for (String ignoredTable : ignoredTables) { 95 if (command.contains(ignoredTable)) { 96 ignore = true; 97 break; 98 } 99 } 100 if (!ignore) { 101 database.execSQL(command); 102 } 103 } 104 105 assertTrue( 106 "Database Version not set. Be sure to add " + 107 "'PRAGMA user_version = <number>;' to the SQL Script", 108 database.getVersion() != 0); 109 } finally { 110 database.close(); 111 } 112 } 113 114 @Override setUp()115 protected void setUp() throws Exception { 116 SynchronousContactsProvider2.resetOpenHelper(); 117 super.setUp(); 118 addProvider(TestCallLogProvider.class, CallLog.AUTHORITY); 119 } 120 121 @Override tearDown()122 protected void tearDown() throws Exception { 123 super.tearDown(); 124 SynchronousContactsProvider2.resetOpenHelper(); 125 } 126 testContactUpgrade1()127 public void testContactUpgrade1() throws Exception { 128 testAssetSet("test1"); 129 } 130 testSyncedContactsUpgrade()131 public void testSyncedContactsUpgrade() throws Exception { 132 testAssetSet("testSynced"); 133 } 134 testUnsyncedContactsUpgrade()135 public void testUnsyncedContactsUpgrade() throws Exception { 136 testAssetSet("testUnsynced"); 137 } 138 testAssetSet(String folder)139 private void testAssetSet(String folder) throws Exception { 140 ContactsProvider2 provider = (ContactsProvider2)getProvider(); 141 LegacyContactImporter importer = 142 new LegacyContactImporter(createLegacyMockContext(folder), provider); 143 provider.importLegacyContacts(importer); 144 145 assertQueryResults(folder + "/expected_groups.txt", Groups.CONTENT_URI, new String[]{ 146 Groups._ID, 147 Groups.ACCOUNT_NAME, 148 Groups.ACCOUNT_TYPE, 149 Groups.DIRTY, 150 Groups.GROUP_VISIBLE, 151 Groups.NOTES, 152 Groups.RES_PACKAGE, 153 Groups.SOURCE_ID, 154 Groups.SYSTEM_ID, 155 Groups.TITLE, 156 Groups.VERSION, 157 Groups.SYNC1, 158 Groups.SYNC2, 159 Groups.SYNC3, 160 Groups.SYNC4, 161 }); 162 163 assertQueryResults(folder + "/expected_contacts.txt", Contacts.CONTENT_URI, new String[]{ 164 Contacts._ID, 165 Contacts.DISPLAY_NAME_PRIMARY, 166 Contacts.SORT_KEY_PRIMARY, 167 Contacts.PHOTO_ID, 168 Contacts.TIMES_CONTACTED, 169 Contacts.LAST_TIME_CONTACTED, 170 Contacts.CUSTOM_RINGTONE, 171 Contacts.SEND_TO_VOICEMAIL, 172 Contacts.STARRED, 173 Contacts.IN_VISIBLE_GROUP, 174 Contacts.HAS_PHONE_NUMBER, 175 Contacts.LOOKUP_KEY, 176 }); 177 178 assertQueryResults(folder + "/expected_raw_contacts.txt", RawContacts.CONTENT_URI, 179 new String[]{ 180 RawContacts._ID, 181 RawContacts.ACCOUNT_NAME, 182 RawContacts.ACCOUNT_TYPE, 183 RawContacts.DELETED, 184 RawContacts.DIRTY, 185 RawContacts.SOURCE_ID, 186 RawContacts.VERSION, 187 RawContacts.SYNC1, 188 RawContacts.SYNC2, 189 RawContacts.SYNC3, 190 RawContacts.SYNC4, 191 RawContacts.DISPLAY_NAME_SOURCE, 192 RawContacts.DISPLAY_NAME_PRIMARY, 193 RawContacts.DISPLAY_NAME_ALTERNATIVE, 194 RawContacts.SORT_KEY_PRIMARY, 195 RawContacts.SORT_KEY_ALTERNATIVE, 196 }); 197 198 assertQueryResults(folder + "/expected_data.txt", Data.CONTENT_URI, new String[]{ 199 Data._ID, 200 Data.RAW_CONTACT_ID, 201 Data.MIMETYPE, 202 Data.DATA1, 203 Data.DATA2, 204 Data.DATA3, 205 Data.DATA4, 206 Data.DATA5, 207 Data.DATA6, 208 Data.DATA7, 209 Data.DATA8, 210 Data.DATA9, 211 Data.DATA10, 212 Data.DATA11, 213 Data.DATA12, 214 Data.DATA13, 215 Data.DATA14, 216 Data.DATA15, 217 Data.IS_PRIMARY, 218 Data.IS_SUPER_PRIMARY, 219 Data.DATA_VERSION, 220 Data.SYNC1, 221 Data.SYNC2, 222 Data.SYNC3, 223 Data.SYNC4, 224 }); 225 226 assertQueryResults(folder + "/expected_calls.txt", Calls.CONTENT_URI, new String[]{ 227 Calls._ID, 228 Calls.NUMBER, 229 Calls.DATE, 230 Calls.DURATION, 231 Calls.NEW, 232 Calls.TYPE, 233 Calls.CACHED_NAME, 234 Calls.CACHED_NUMBER_LABEL, 235 Calls.CACHED_NUMBER_TYPE, 236 }); 237 238 provider.getDatabaseHelper().close(); 239 } 240 assertQueryResults(String fileName, Uri uri, String[] projection)241 private void assertQueryResults(String fileName, Uri uri, String[] projection) 242 throws Exception { 243 String expected = readAssetAsString(fileName).trim(); 244 String actual = dumpCursorToString(uri, projection).trim(); 245 assertEquals("Checking golden file " + fileName, expected, actual); 246 } 247 readAssetAsString(String fileName)248 private String readAssetAsString(String fileName) throws IOException { 249 Context context = getTestContext(); 250 InputStream input = context.getAssets().open(fileName); 251 ByteArrayOutputStream contents = new ByteArrayOutputStream(); 252 int len; 253 byte[] data = new byte[1024]; 254 do { 255 len = input.read(data); 256 if (len > 0) contents.write(data, 0, len); 257 } while (len == data.length); 258 return contents.toString(); 259 } 260 dumpCursorToString(Uri uri, String[] projection)261 private String dumpCursorToString(Uri uri, String[] projection) { 262 Cursor c = mResolver.query(uri, projection, null, null, BaseColumns._ID); 263 if (c == null) { 264 return "Null cursor"; 265 } 266 267 String cursorDump = DatabaseUtils.dumpCursorToString(c); 268 c.close(); 269 return insertLineNumbers(cursorDump); 270 } 271 insertLineNumbers(String multiline)272 private String insertLineNumbers(String multiline) { 273 String[] lines = multiline.split("\n"); 274 StringBuilder sb = new StringBuilder(); 275 276 // Ignore the first line that is a volatile header and the last line which is "<<<<<" 277 for (int i = 1; i < lines.length - 1; i++) { 278 sb.append(i).append(" ").append(lines[i]).append('\n'); 279 } 280 return sb.toString(); 281 } 282 283 284 public static class TestCallLogProvider extends CallLogProvider { 285 private static ContactsDatabaseHelper mDbHelper; 286 287 @Override getDatabaseHelper(final Context context)288 protected ContactsDatabaseHelper getDatabaseHelper(final Context context) { 289 if (mDbHelper == null) { 290 mDbHelper = new ContactsDatabaseHelper(context); 291 } 292 return mDbHelper; 293 } 294 } 295 } 296