/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.server.accounts; import android.accounts.Account; import android.content.Context; import android.database.Cursor; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; import android.util.Pair; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; import java.util.Arrays; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** * Tests for {@link AccountsDb}. *

Run with:

 * m FrameworksServicesTests &&
 * adb install \
 * -r out/target/product/marlin/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
 * adb shell am instrument -e class com.android.server.accounts.AccountsDbTest \
 * -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
 * 
*/ @RunWith(AndroidJUnit4.class) @SmallTest public class AccountsDbTest { private static final String PREN_DB = "pren.db"; private static final String DE_DB = "de.db"; private static final String CE_DB = "ce.db"; private AccountsDb mAccountsDb; private File preNDb; private File deDb; private File ceDb; @Before public void setUp() { Context context = InstrumentationRegistry.getContext(); preNDb = new File(context.getCacheDir(), PREN_DB); ceDb = new File(context.getCacheDir(), CE_DB); deDb = new File(context.getCacheDir(), DE_DB); deleteDbFiles(); mAccountsDb = AccountsDb.create(context, 0, preNDb, deDb); } @After public void tearDown() { deleteDbFiles(); } private void deleteDbFiles() { AccountsDb.deleteDbFileWarnIfFailed(preNDb); AccountsDb.deleteDbFileWarnIfFailed(ceDb); AccountsDb.deleteDbFileWarnIfFailed(deDb); } @Test public void testCeNotAvailableInitially() { Account account = new Account("name", "example.com"); long id = mAccountsDb.insertCeAccount(account, ""); assertEquals("Insert into CE should fail until CE database is attached", -1, id); } @Test public void testDeAccountInsertFindDelete() { Account account = new Account("name", "example.com"); long accId = 1; mAccountsDb.insertDeAccount(account, accId); long actualId = mAccountsDb.findDeAccountId(account); assertEquals(accId, actualId); // Delete and verify that account no longer exists mAccountsDb.deleteDeAccount(accId); actualId = mAccountsDb.findDeAccountId(account); assertEquals(-1, actualId); } @Test public void testCeAccountInsertFindDelete() { mAccountsDb.attachCeDatabase(ceDb); Account account = new Account("name", "example.com"); long accId = mAccountsDb.insertCeAccount(account, "password"); long actualId = mAccountsDb.findCeAccountId(account); assertEquals(accId, actualId); // Delete and verify that account no longer exists mAccountsDb.deleteCeAccount(accId); actualId = mAccountsDb.findCeAccountId(account); assertEquals(-1, actualId); } @Test public void testAuthTokenInsertFindDelete() { mAccountsDb.attachCeDatabase(ceDb); Account account = new Account("name", "example.com"); long accId = mAccountsDb.insertCeAccount(account, "password"); mAccountsDb.insertDeAccount(account, accId); long authTokenId = mAccountsDb.insertAuthToken(accId, "type", "token"); Map authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); assertEquals(1, authTokensByAccount.size()); try (Cursor cursor = mAccountsDb.findAuthtokenForAllAccounts(account.type, "token")) { assertTrue(cursor.moveToNext()); } try (Cursor cursor = mAccountsDb.findAuthtokenForAllAccounts(account.type, "nosuchtoken")) { assertFalse(cursor.moveToNext()); } mAccountsDb.deleteAuthToken(String.valueOf(authTokenId)); // Verify that token no longer exists authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); assertEquals(0, authTokensByAccount.size()); } @Test public void testAuthTokenDeletes() { mAccountsDb.attachCeDatabase(ceDb); // 1st account Account account = new Account("name", "example.com"); long accId = mAccountsDb.insertCeAccount(account, "password"); mAccountsDb.insertDeAccount(account, accId); mAccountsDb.insertAuthToken(accId, "type", "token"); mAccountsDb.insertAuthToken(accId, "type2", "token2"); // 2nd account Account account2 = new Account("name", "example2.com"); long accId2 = mAccountsDb.insertCeAccount(account2, "password"); mAccountsDb.insertDeAccount(account2, accId2); mAccountsDb.insertAuthToken(accId2, "type", "token"); mAccountsDb.deleteAuthTokensByAccountId(accId2); Map authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account2); assertEquals(0, authTokensByAccount.size()); // Authtokens from account 1 are still there authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); assertEquals(2, authTokensByAccount.size()); // Delete authtokens from account 1 and verify mAccountsDb.deleteAuthtokensByAccountIdAndType(accId, "type"); authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); assertEquals(1, authTokensByAccount.size()); mAccountsDb.deleteAuthtokensByAccountIdAndType(accId, "type2"); authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account); assertEquals(0, authTokensByAccount.size()); } @Test public void testExtrasInsertFindDelete() { mAccountsDb.attachCeDatabase(ceDb); Account account = new Account("name", "example.com"); long accId = mAccountsDb.insertCeAccount(account, "password"); mAccountsDb.insertDeAccount(account, accId); String extraKey = "extra_key"; String extraValue = "extra_value"; long extraId = mAccountsDb.insertExtra(accId, extraKey, extraValue); // Test find methods long actualExtraId = mAccountsDb.findExtrasIdByAccountId(accId, extraKey); assertEquals(extraId, actualExtraId); Map extras = mAccountsDb.findUserExtrasForAccount(account); assertEquals(1, extras.size()); assertEquals(extraValue, extras.get(extraKey)); // Test update String newExtraValue = "extra_value2"; mAccountsDb.updateExtra(extraId, newExtraValue); String newValue = mAccountsDb.findUserExtrasForAccount(account).get(extraKey); assertEquals(newExtraValue, newValue); // Delete account and verify that extras cascade removed mAccountsDb.deleteCeAccount(accId); actualExtraId = mAccountsDb.findExtrasIdByAccountId(accId, extraKey); assertEquals(-1, actualExtraId); } @Test public void testGrantsInsertFindDelete() { mAccountsDb.attachCeDatabase(ceDb); Account account = new Account("name", "example.com"); long accId = mAccountsDb.insertCeAccount(account, "password"); mAccountsDb.insertDeAccount(account, accId); int testUid = 100500; long grantId = mAccountsDb.insertGrant(accId, "tokenType", testUid); assertTrue(grantId > 0); List allUidGrants = mAccountsDb.findAllUidGrants(); List expectedUids = Arrays.asList(testUid); assertEquals(expectedUids, allUidGrants); long matchingGrantsCount = mAccountsDb.findMatchingGrantsCount( testUid, "tokenType", account); assertEquals(1, matchingGrantsCount); // Test nonexistent type matchingGrantsCount = mAccountsDb.findMatchingGrantsCount( testUid, "noSuchType", account); assertEquals(0, matchingGrantsCount); matchingGrantsCount = mAccountsDb.findMatchingGrantsCountAnyToken(testUid, account); assertEquals(1, matchingGrantsCount); List> allAccountGrants = mAccountsDb.findAllAccountGrants(); assertEquals(1, allAccountGrants.size()); assertEquals(account.name, allAccountGrants.get(0).first); assertEquals(testUid, (int)allAccountGrants.get(0).second); mAccountsDb.deleteGrantsByUid(testUid); allUidGrants = mAccountsDb.findAllUidGrants(); assertTrue("Test grants should be removed", allUidGrants.isEmpty()); } @Test public void testSharedAccountsInsertFindDelete() { Account account = new Account("name", "example.com"); long accId = 0; mAccountsDb.insertDeAccount(account, accId); long sharedAccId = mAccountsDb.insertSharedAccount(account); long foundSharedAccountId = mAccountsDb.findSharedAccountId(account); assertEquals(sharedAccId, foundSharedAccountId); List sharedAccounts = mAccountsDb.getSharedAccounts(); List expectedList = Arrays.asList(account); assertEquals(expectedList, sharedAccounts); // Delete and verify mAccountsDb.deleteSharedAccount(account); foundSharedAccountId = mAccountsDb.findSharedAccountId(account); assertEquals(-1, foundSharedAccountId); } @Test public void testMetaInsertFindDelete() { int testUid = 100500; String authenticatorType = "authType"; mAccountsDb.insertOrReplaceMetaAuthTypeAndUid(authenticatorType, testUid); Map metaAuthUid = mAccountsDb.findMetaAuthUid(); assertEquals(1, metaAuthUid.size()); assertEquals(testUid, (int)metaAuthUid.get(authenticatorType)); // Delete and verify boolean deleteResult = mAccountsDb.deleteMetaByAuthTypeAndUid(authenticatorType, testUid); assertTrue(deleteResult); metaAuthUid = mAccountsDb.findMetaAuthUid(); assertEquals(0, metaAuthUid.size()); } @Test public void testUpdateDeAccountLastAuthenticatedTime() { Account account = new Account("name", "example.com"); long accId = 1; mAccountsDb.insertDeAccount(account, accId); long now = System.currentTimeMillis(); mAccountsDb.updateAccountLastAuthenticatedTime(account); long time = mAccountsDb.findAccountLastAuthenticatedTime(account); assertTrue("LastAuthenticatedTime should be current", time >= now); } @Test public void testRenameAccount() { mAccountsDb.attachCeDatabase(ceDb); Account account = new Account("name", "example.com"); long accId = mAccountsDb.insertCeAccount(account, "password"); mAccountsDb.insertDeAccount(account, accId); mAccountsDb.renameDeAccount(accId, "newName", "name"); Account newAccount = mAccountsDb.findAllDeAccounts().get(accId); assertEquals("newName", newAccount.name); String prevName = mAccountsDb.findDeAccountPreviousName(newAccount); assertEquals("name", prevName); mAccountsDb.renameCeAccount(accId, "newName"); long foundAccId = mAccountsDb.findCeAccountId(account); assertEquals("Account shouldn't be found under the old name", -1, foundAccId); foundAccId = mAccountsDb.findCeAccountId(newAccount); assertEquals(accId, foundAccId); } @Test public void testUpdateCeAccountPassword() { mAccountsDb.attachCeDatabase(ceDb); Account account = new Account("name", "example.com"); long accId = mAccountsDb.insertCeAccount(account, "password"); String newPassword = "newPassword"; mAccountsDb.updateCeAccountPassword(accId, newPassword); String actualPassword = mAccountsDb .findAccountPasswordByNameAndType(account.name, account.type); assertEquals(newPassword, actualPassword); } @Test public void testFindCeAccountsNotInDe() { mAccountsDb.attachCeDatabase(ceDb); Account account = new Account("name", "example.com"); long accId = mAccountsDb.insertCeAccount(account, "password"); mAccountsDb.insertDeAccount(account, accId); Account accountNotInDe = new Account("name2", "example.com"); mAccountsDb.insertCeAccount(accountNotInDe, "password"); List ceAccounts = mAccountsDb.findCeAccountsNotInDe(); List expectedList = Arrays.asList(accountNotInDe); assertEquals(expectedList, ceAccounts); } @Test public void testCrossDbTransactions() { mAccountsDb.attachCeDatabase(ceDb); mAccountsDb.beginTransaction(); Account account = new Account("name", "example.com"); long accId; accId = mAccountsDb.insertCeAccount(account, "password"); accId = mAccountsDb.insertDeAccount(account, accId); long actualId = mAccountsDb.findCeAccountId(account); assertEquals(accId, actualId); actualId = mAccountsDb.findDeAccountId(account); assertEquals(accId, actualId); mAccountsDb.endTransaction(); // Verify that records were removed actualId = mAccountsDb.findCeAccountId(account); assertEquals(-1, actualId); actualId = mAccountsDb.findDeAccountId(account); assertEquals(-1, actualId); } @Test public void testFindDeAccountByAccountId() { long accId = 10; Account account = new Account("name", "example.com"); assertNull(mAccountsDb.findDeAccountByAccountId(accId)); mAccountsDb.insertDeAccount(account, accId); Account foundAccount = mAccountsDb.findDeAccountByAccountId(accId); assertEquals(account, foundAccount); } @Test public void testVisibilityFindSetDelete() { long accId = 10; String packageName1 = "com.example.one"; String packageName2 = "com.example.two"; Account account = new Account("name", "example.com"); assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); mAccountsDb.insertDeAccount(account, accId); assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); assertNull(mAccountsDb.findAccountVisibility(accId, packageName1)); mAccountsDb.setAccountVisibility(accId, packageName1, 1); assertEquals(mAccountsDb.findAccountVisibility(account, packageName1), Integer.valueOf(1)); assertEquals(mAccountsDb.findAccountVisibility(accId, packageName1), Integer.valueOf(1)); mAccountsDb.setAccountVisibility(accId, packageName2, 2); assertEquals(mAccountsDb.findAccountVisibility(accId, packageName2), Integer.valueOf(2)); mAccountsDb.setAccountVisibility(accId, packageName2, 3); assertEquals(mAccountsDb.findAccountVisibility(accId, packageName2), Integer.valueOf(3)); Map vis = mAccountsDb.findAllVisibilityValuesForAccount(account); assertEquals(vis.size(), 2); assertEquals(vis.get(packageName1), Integer.valueOf(1)); assertEquals(vis.get(packageName2), Integer.valueOf(3)); assertTrue(mAccountsDb.deleteAccountVisibilityForPackage(packageName1)); assertNull(mAccountsDb.findAccountVisibility(accId, packageName1)); assertFalse(mAccountsDb.deleteAccountVisibilityForPackage(packageName1)); // 2nd attempt. } @Test public void testFindAllVisibilityValues() { long accId = 10; long accId2 = 11; String packageName1 = "com.example.one"; String packageName2 = "com.example.two"; Account account = new Account("name", "example.com"); Account account2 = new Account("name2", "example2.com"); assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); mAccountsDb.insertDeAccount(account, accId); assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); assertNull(mAccountsDb.findAccountVisibility(accId, packageName1)); mAccountsDb.insertDeAccount(account2, accId2); mAccountsDb.setAccountVisibility(accId, packageName1, 1); mAccountsDb.setAccountVisibility(accId, packageName2, 2); mAccountsDb.setAccountVisibility(accId2, packageName1, 1); Map> vis = mAccountsDb.findAllVisibilityValues(); assertEquals(vis.size(), 2); Map accnt1Visibility = vis.get(account); assertEquals(accnt1Visibility.size(), 2); assertEquals(accnt1Visibility.get(packageName1), Integer.valueOf(1)); assertEquals(accnt1Visibility.get(packageName2), Integer.valueOf(2)); Map accnt2Visibility = vis.get(account2); assertEquals(accnt2Visibility.size(), 1); assertEquals(accnt2Visibility.get(packageName1), Integer.valueOf(1)); mAccountsDb.setAccountVisibility(accId2, packageName2, 3); vis = mAccountsDb.findAllVisibilityValues(); accnt2Visibility = vis.get(account2); assertEquals(accnt2Visibility.size(), 2); assertEquals(accnt2Visibility.get(packageName2), Integer.valueOf(3)); } @Test public void testVisibilityCleanupTrigger() { long accId = 10; String packageName1 = "com.example.one"; Account account = new Account("name", "example.com"); assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); mAccountsDb.insertDeAccount(account, accId); assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); mAccountsDb.setAccountVisibility(accId, packageName1, 1); assertEquals(mAccountsDb.findAccountVisibility(accId, packageName1), Integer.valueOf(1)); assertTrue(mAccountsDb.deleteDeAccount(accId)); // Trigger should remove visibility. assertNull(mAccountsDb.findAccountVisibility(account, packageName1)); } }