1 2 /* 3 * Copyright (C) 2016 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License 16 */ 17 18 package com.android.server.accounts; 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.Matchers.anyString; 25 import static org.mockito.Mockito.times; 26 import static org.mockito.Mockito.verify; 27 28 import android.accounts.Account; 29 import android.content.Context; 30 import android.database.Cursor; 31 import android.database.sqlite.SQLiteStatement; 32 import android.os.Build; 33 import android.util.Pair; 34 35 import androidx.test.InstrumentationRegistry; 36 import androidx.test.filters.SmallTest; 37 import androidx.test.runner.AndroidJUnit4; 38 39 import org.junit.After; 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 import org.mockito.Mock; 44 import org.mockito.MockitoAnnotations; 45 46 import java.io.File; 47 import java.io.PrintWriter; 48 import java.util.Arrays; 49 import java.util.List; 50 import java.util.Map; 51 52 /** 53 * Tests for {@link AccountsDb}. 54 * <p>Run with:<pre> 55 * m FrameworksServicesTests && 56 * adb install \ 57 * -r out/target/product/marlin/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && 58 * adb shell am instrument -e class com.android.server.accounts.AccountsDbTest \ 59 * -w com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner 60 * </pre> 61 */ 62 @RunWith(AndroidJUnit4.class) 63 @SmallTest 64 public class AccountsDbTest { 65 private static final String PREN_DB = "pren.db"; 66 private static final String DE_DB = "de.db"; 67 private static final String CE_DB = "ce.db"; 68 69 private AccountsDb mAccountsDb; 70 private File preNDb; 71 private File deDb; 72 private File ceDb; 73 74 @Mock private PrintWriter mockWriter; 75 76 @Before setUp()77 public void setUp() { 78 MockitoAnnotations.initMocks(this); 79 Context context = InstrumentationRegistry.getContext(); 80 preNDb = new File(context.getCacheDir(), PREN_DB); 81 ceDb = new File(context.getCacheDir(), CE_DB); 82 deDb = new File(context.getCacheDir(), DE_DB); 83 deleteDbFiles(); 84 mAccountsDb = AccountsDb.create(context, 0, preNDb, deDb); 85 } 86 87 @After tearDown()88 public void tearDown() { 89 deleteDbFiles(); 90 } 91 deleteDbFiles()92 private void deleteDbFiles() { 93 AccountsDb.deleteDbFileWarnIfFailed(preNDb); 94 AccountsDb.deleteDbFileWarnIfFailed(ceDb); 95 AccountsDb.deleteDbFileWarnIfFailed(deDb); 96 } 97 98 @Test testCeNotAvailableInitially()99 public void testCeNotAvailableInitially() { 100 // If the CE database is not attached to the DE database then any calls that modify the CE 101 // database will result in a Log.wtf call that will crash this process on eng builds. To 102 // allow the test to run through to completion skip this test on eng builds. 103 if (Build.IS_ENG) { 104 return; 105 } 106 Account account = new Account("name", "example.com"); 107 long id = mAccountsDb.insertCeAccount(account, ""); 108 assertEquals("Insert into CE should fail until CE database is attached", -1, id); 109 } 110 111 @Test testDeAccountInsertFindDelete()112 public void testDeAccountInsertFindDelete() { 113 Account account = new Account("name", "example.com"); 114 long accId = 1; 115 mAccountsDb.insertDeAccount(account, accId); 116 long actualId = mAccountsDb.findDeAccountId(account); 117 assertEquals(accId, actualId); 118 // Delete and verify that account no longer exists 119 mAccountsDb.deleteDeAccount(accId); 120 actualId = mAccountsDb.findDeAccountId(account); 121 assertEquals(-1, actualId); 122 } 123 124 @Test testCeAccountInsertFindDelete()125 public void testCeAccountInsertFindDelete() { 126 mAccountsDb.attachCeDatabase(ceDb); 127 Account account = new Account("name", "example.com"); 128 long accId = mAccountsDb.insertCeAccount(account, "password"); 129 long actualId = mAccountsDb.findCeAccountId(account); 130 assertEquals(accId, actualId); 131 // Delete and verify that account no longer exists 132 mAccountsDb.deleteCeAccount(accId); 133 actualId = mAccountsDb.findCeAccountId(account); 134 assertEquals(-1, actualId); 135 } 136 137 @Test testAuthTokenInsertFindDelete()138 public void testAuthTokenInsertFindDelete() { 139 mAccountsDb.attachCeDatabase(ceDb); 140 Account account = new Account("name", "example.com"); 141 long accId = mAccountsDb.insertCeAccount(account, "password"); 142 mAccountsDb.insertDeAccount(account, accId); 143 long authTokenId = mAccountsDb.insertAuthToken(accId, "type", "token"); 144 Map<String, String> authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); 145 assertEquals(1, authTokensByAccount.size()); 146 try (Cursor cursor = mAccountsDb.findAuthtokenForAllAccounts(account.type, "token")) { 147 assertTrue(cursor.moveToNext()); 148 } 149 try (Cursor cursor = mAccountsDb.findAuthtokenForAllAccounts(account.type, "nosuchtoken")) { 150 assertFalse(cursor.moveToNext()); 151 } 152 mAccountsDb.deleteAuthToken(String.valueOf(authTokenId)); 153 // Verify that token no longer exists 154 authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); 155 assertEquals(0, authTokensByAccount.size()); 156 } 157 158 @Test testAuthTokenDeletes()159 public void testAuthTokenDeletes() { 160 mAccountsDb.attachCeDatabase(ceDb); 161 // 1st account 162 Account account = new Account("name", "example.com"); 163 long accId = mAccountsDb.insertCeAccount(account, "password"); 164 mAccountsDb.insertDeAccount(account, accId); 165 mAccountsDb.insertAuthToken(accId, "type", "token"); 166 mAccountsDb.insertAuthToken(accId, "type2", "token2"); 167 // 2nd account 168 Account account2 = new Account("name", "example2.com"); 169 long accId2 = mAccountsDb.insertCeAccount(account2, "password"); 170 mAccountsDb.insertDeAccount(account2, accId2); 171 mAccountsDb.insertAuthToken(accId2, "type", "token"); 172 173 mAccountsDb.deleteAuthTokensByAccountId(accId2); 174 Map<String, String> authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account2); 175 assertEquals(0, authTokensByAccount.size()); 176 // Authtokens from account 1 are still there 177 authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); 178 assertEquals(2, authTokensByAccount.size()); 179 180 // Delete authtokens from account 1 and verify 181 mAccountsDb.deleteAuthtokensByAccountIdAndType(accId, "type"); 182 authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); 183 assertEquals(1, authTokensByAccount.size()); 184 mAccountsDb.deleteAuthtokensByAccountIdAndType(accId, "type2"); 185 authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); 186 assertEquals(0, authTokensByAccount.size()); 187 } 188 189 @Test testExtrasInsertFindDelete()190 public void testExtrasInsertFindDelete() { 191 mAccountsDb.attachCeDatabase(ceDb); 192 Account account = new Account("name", "example.com"); 193 long accId = mAccountsDb.insertCeAccount(account, "password"); 194 mAccountsDb.insertDeAccount(account, accId); 195 String extraKey = "extra_key"; 196 String extraValue = "extra_value"; 197 long extraId = mAccountsDb.insertExtra(accId, extraKey, extraValue); 198 // Test find methods 199 long actualExtraId = mAccountsDb.findExtrasIdByAccountId(accId, extraKey); 200 assertEquals(extraId, actualExtraId); 201 Map<String, String> extras = mAccountsDb.findUserExtrasForAccount(account); 202 assertEquals(1, extras.size()); 203 assertEquals(extraValue, extras.get(extraKey)); 204 // Test update 205 String newExtraValue = "extra_value2"; 206 mAccountsDb.updateExtra(extraId, newExtraValue); 207 String newValue = mAccountsDb.findUserExtrasForAccount(account).get(extraKey); 208 assertEquals(newExtraValue, newValue); 209 210 // Delete account and verify that extras cascade removed 211 mAccountsDb.deleteCeAccount(accId); 212 actualExtraId = mAccountsDb.findExtrasIdByAccountId(accId, extraKey); 213 assertEquals(-1, actualExtraId); 214 } 215 216 @Test testGrantsInsertFindDelete()217 public void testGrantsInsertFindDelete() { 218 mAccountsDb.attachCeDatabase(ceDb); 219 Account account = new Account("name", "example.com"); 220 long accId = mAccountsDb.insertCeAccount(account, "password"); 221 mAccountsDb.insertDeAccount(account, accId); 222 int testUid = 100500; 223 long grantId = mAccountsDb.insertGrant(accId, "tokenType", testUid); 224 assertTrue(grantId > 0); 225 List<Integer> allUidGrants = mAccountsDb.findAllUidGrants(); 226 List<Integer> expectedUids = Arrays.asList(testUid); 227 assertEquals(expectedUids, allUidGrants); 228 229 long matchingGrantsCount = mAccountsDb.findMatchingGrantsCount( 230 testUid, "tokenType", account); 231 assertEquals(1, matchingGrantsCount); 232 // Test nonexistent type 233 matchingGrantsCount = mAccountsDb.findMatchingGrantsCount( 234 testUid, "noSuchType", account); 235 assertEquals(0, matchingGrantsCount); 236 237 matchingGrantsCount = mAccountsDb.findMatchingGrantsCountAnyToken(testUid, account); 238 assertEquals(1, matchingGrantsCount); 239 240 List<Pair<String, Integer>> allAccountGrants = mAccountsDb.findAllAccountGrants(); 241 assertEquals(1, allAccountGrants.size()); 242 assertEquals(account.name, allAccountGrants.get(0).first); 243 assertEquals(testUid, (int)allAccountGrants.get(0).second); 244 245 mAccountsDb.deleteGrantsByUid(testUid); 246 allUidGrants = mAccountsDb.findAllUidGrants(); 247 assertTrue("Test grants should be removed", allUidGrants.isEmpty()); 248 } 249 250 @Test testSharedAccountsInsertFindDelete()251 public void testSharedAccountsInsertFindDelete() { 252 Account account = new Account("name", "example.com"); 253 long accId = 0; 254 mAccountsDb.insertDeAccount(account, accId); 255 long sharedAccId = mAccountsDb.insertSharedAccount(account); 256 long foundSharedAccountId = mAccountsDb.findSharedAccountId(account); 257 assertEquals(sharedAccId, foundSharedAccountId); 258 List<Account> sharedAccounts = mAccountsDb.getSharedAccounts(); 259 List<Account> expectedList = Arrays.asList(account); 260 assertEquals(expectedList, sharedAccounts); 261 262 // Delete and verify 263 mAccountsDb.deleteSharedAccount(account); 264 foundSharedAccountId = mAccountsDb.findSharedAccountId(account); 265 assertEquals(-1, foundSharedAccountId); 266 } 267 268 @Test testMetaInsertFindDelete()269 public void testMetaInsertFindDelete() { 270 int testUid = 100500; 271 String authenticatorType = "authType"; 272 mAccountsDb.insertOrReplaceMetaAuthTypeAndUid(authenticatorType, testUid); 273 Map<String, Integer> metaAuthUid = mAccountsDb.findMetaAuthUid(); 274 assertEquals(1, metaAuthUid.size()); 275 assertEquals(testUid, (int)metaAuthUid.get(authenticatorType)); 276 277 // Delete and verify 278 boolean deleteResult = mAccountsDb.deleteMetaByAuthTypeAndUid(authenticatorType, testUid); 279 assertTrue(deleteResult); 280 metaAuthUid = mAccountsDb.findMetaAuthUid(); 281 assertEquals(0, metaAuthUid.size()); 282 } 283 284 @Test testUpdateDeAccountLastAuthenticatedTime()285 public void testUpdateDeAccountLastAuthenticatedTime() { 286 Account account = new Account("name", "example.com"); 287 long accId = 1; 288 mAccountsDb.insertDeAccount(account, accId); 289 long now = System.currentTimeMillis(); 290 mAccountsDb.updateAccountLastAuthenticatedTime(account); 291 long time = mAccountsDb.findAccountLastAuthenticatedTime(account); 292 assertTrue("LastAuthenticatedTime should be current", time >= now); 293 } 294 295 @Test testRenameAccount()296 public void testRenameAccount() { 297 mAccountsDb.attachCeDatabase(ceDb); 298 Account account = new Account("name", "example.com"); 299 long accId = mAccountsDb.insertCeAccount(account, "password"); 300 mAccountsDb.insertDeAccount(account, accId); 301 mAccountsDb.renameDeAccount(accId, "newName", "name"); 302 Account newAccount = mAccountsDb.findAllDeAccounts().get(accId); 303 assertEquals("newName", newAccount.name); 304 305 String prevName = mAccountsDb.findDeAccountPreviousName(newAccount); 306 assertEquals("name", prevName); 307 mAccountsDb.renameCeAccount(accId, "newName"); 308 long foundAccId = mAccountsDb.findCeAccountId(account); 309 assertEquals("Account shouldn't be found under the old name", -1, foundAccId); 310 foundAccId = mAccountsDb.findCeAccountId(newAccount); 311 assertEquals(accId, foundAccId); 312 } 313 314 @Test testUpdateCeAccountPassword()315 public void testUpdateCeAccountPassword() { 316 mAccountsDb.attachCeDatabase(ceDb); 317 Account account = new Account("name", "example.com"); 318 long accId = mAccountsDb.insertCeAccount(account, "password"); 319 String newPassword = "newPassword"; 320 mAccountsDb.updateCeAccountPassword(accId, newPassword); 321 String actualPassword = mAccountsDb 322 .findAccountPasswordByNameAndType(account.name, account.type); 323 assertEquals(newPassword, actualPassword); 324 } 325 326 @Test testFindCeAccountsNotInDe()327 public void testFindCeAccountsNotInDe() { 328 mAccountsDb.attachCeDatabase(ceDb); 329 Account account = new Account("name", "example.com"); 330 long accId = mAccountsDb.insertCeAccount(account, "password"); 331 mAccountsDb.insertDeAccount(account, accId); 332 333 Account accountNotInDe = new Account("name2", "example.com"); 334 mAccountsDb.insertCeAccount(accountNotInDe, "password"); 335 336 List<Account> ceAccounts = mAccountsDb.findCeAccountsNotInDe(); 337 List<Account> expectedList = Arrays.asList(accountNotInDe); 338 assertEquals(expectedList, ceAccounts); 339 } 340 341 @Test testCrossDbTransactions()342 public void testCrossDbTransactions() { 343 mAccountsDb.attachCeDatabase(ceDb); 344 mAccountsDb.beginTransaction(); 345 Account account = new Account("name", "example.com"); 346 long accId; 347 accId = mAccountsDb.insertCeAccount(account, "password"); 348 accId = mAccountsDb.insertDeAccount(account, accId); 349 long actualId = mAccountsDb.findCeAccountId(account); 350 assertEquals(accId, actualId); 351 actualId = mAccountsDb.findDeAccountId(account); 352 assertEquals(accId, actualId); 353 mAccountsDb.endTransaction(); 354 // Verify that records were removed 355 actualId = mAccountsDb.findCeAccountId(account); 356 assertEquals(-1, actualId); 357 actualId = mAccountsDb.findDeAccountId(account); 358 assertEquals(-1, actualId); 359 } 360 361 @Test testFindDeAccountByAccountId()362 public void testFindDeAccountByAccountId() { 363 long accId = 10; 364 Account account = new Account("name", "example.com"); 365 assertNull(mAccountsDb.findDeAccountByAccountId(accId)); 366 367 mAccountsDb.insertDeAccount(account, accId); 368 369 Account foundAccount = mAccountsDb.findDeAccountByAccountId(accId); 370 assertEquals(account, foundAccount); 371 } 372 373 @Test testVisibilityFindSetDelete()374 public void testVisibilityFindSetDelete() { 375 long accId = 10; 376 String packageName1 = "com.example.one"; 377 String packageName2 = "com.example.two"; 378 Account account = new Account("name", "example.com"); 379 assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); 380 381 mAccountsDb.insertDeAccount(account, accId); 382 assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); 383 assertNull(mAccountsDb.findAccountVisibility(accId, packageName1)); 384 385 mAccountsDb.setAccountVisibility(accId, packageName1, 1); 386 assertEquals(mAccountsDb.findAccountVisibility(account, packageName1), Integer.valueOf(1)); 387 assertEquals(mAccountsDb.findAccountVisibility(accId, packageName1), Integer.valueOf(1)); 388 389 mAccountsDb.setAccountVisibility(accId, packageName2, 2); 390 assertEquals(mAccountsDb.findAccountVisibility(accId, packageName2), Integer.valueOf(2)); 391 392 mAccountsDb.setAccountVisibility(accId, packageName2, 3); 393 assertEquals(mAccountsDb.findAccountVisibility(accId, packageName2), Integer.valueOf(3)); 394 395 Map<String, Integer> vis = mAccountsDb.findAllVisibilityValuesForAccount(account); 396 assertEquals(vis.size(), 2); 397 assertEquals(vis.get(packageName1), Integer.valueOf(1)); 398 assertEquals(vis.get(packageName2), Integer.valueOf(3)); 399 400 assertTrue(mAccountsDb.deleteAccountVisibilityForPackage(packageName1)); 401 assertNull(mAccountsDb.findAccountVisibility(accId, packageName1)); 402 assertFalse(mAccountsDb.deleteAccountVisibilityForPackage(packageName1)); // 2nd attempt. 403 } 404 405 @Test testFindAllVisibilityValues()406 public void testFindAllVisibilityValues() { 407 long accId = 10; 408 long accId2 = 11; 409 String packageName1 = "com.example.one"; 410 String packageName2 = "com.example.two"; 411 Account account = new Account("name", "example.com"); 412 Account account2 = new Account("name2", "example2.com"); 413 assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); 414 415 mAccountsDb.insertDeAccount(account, accId); 416 assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); 417 assertNull(mAccountsDb.findAccountVisibility(accId, packageName1)); 418 mAccountsDb.insertDeAccount(account2, accId2); 419 420 mAccountsDb.setAccountVisibility(accId, packageName1, 1); 421 mAccountsDb.setAccountVisibility(accId, packageName2, 2); 422 mAccountsDb.setAccountVisibility(accId2, packageName1, 1); 423 424 Map<Account, Map<String, Integer>> vis = mAccountsDb.findAllVisibilityValues(); 425 assertEquals(vis.size(), 2); 426 Map<String, Integer> accnt1Visibility = vis.get(account); 427 assertEquals(accnt1Visibility.size(), 2); 428 assertEquals(accnt1Visibility.get(packageName1), Integer.valueOf(1)); 429 assertEquals(accnt1Visibility.get(packageName2), Integer.valueOf(2)); 430 Map<String, Integer> accnt2Visibility = vis.get(account2); 431 assertEquals(accnt2Visibility.size(), 1); 432 assertEquals(accnt2Visibility.get(packageName1), Integer.valueOf(1)); 433 434 mAccountsDb.setAccountVisibility(accId2, packageName2, 3); 435 vis = mAccountsDb.findAllVisibilityValues(); 436 accnt2Visibility = vis.get(account2); 437 assertEquals(accnt2Visibility.size(), 2); 438 assertEquals(accnt2Visibility.get(packageName2), Integer.valueOf(3)); 439 } 440 441 @Test testVisibilityCleanupTrigger()442 public void testVisibilityCleanupTrigger() { 443 long accId = 10; 444 String packageName1 = "com.example.one"; 445 Account account = new Account("name", "example.com"); 446 447 assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); 448 mAccountsDb.insertDeAccount(account, accId); 449 assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); 450 451 mAccountsDb.setAccountVisibility(accId, packageName1, 1); 452 assertEquals(mAccountsDb.findAccountVisibility(accId, packageName1), Integer.valueOf(1)); 453 454 assertTrue(mAccountsDb.deleteDeAccount(accId)); // Trigger should remove visibility. 455 assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); 456 } 457 458 @Test testDumpDebugTable()459 public void testDumpDebugTable() { 460 long accId = 10; 461 long insertionPoint = mAccountsDb.reserveDebugDbInsertionPoint(); 462 463 SQLiteStatement logStatement = mAccountsDb.getStatementForLogging(); 464 465 logStatement.bindLong(1, accId); 466 logStatement.bindString(2, "action"); 467 logStatement.bindString(3, "date"); 468 logStatement.bindLong(4, 10); 469 logStatement.bindString(5, "table"); 470 logStatement.bindLong(6, insertionPoint); 471 logStatement.execute(); 472 473 mAccountsDb.dumpDebugTable(mockWriter); 474 475 verify(mockWriter, times(3)).println(anyString()); 476 } 477 478 @Test testReserveDebugDbInsertionPoint()479 public void testReserveDebugDbInsertionPoint() { 480 long insertionPoint = mAccountsDb.reserveDebugDbInsertionPoint(); 481 long insertionPoint2 = mAccountsDb.reserveDebugDbInsertionPoint(); 482 483 assertEquals(0, insertionPoint); 484 assertEquals(1, insertionPoint2); 485 } 486 } 487