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