• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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