replicant-packages_apps_Email/tests/src/com/android/email/SecurityPolicyTests.java

644 lines
29 KiB
Java

/*
* Copyright (C) 2010 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.email;
import com.android.email.provider.ContentCache;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.ProviderTestUtils;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.Message;
import com.android.emailcommon.service.PolicySet;
import android.app.admin.DevicePolicyManager;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.ContextWrapper;
import android.net.Uri;
import android.test.ProviderTestCase2;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
/**
* This is a series of unit tests for backup/restore of the SecurityPolicy class.
*
* You can run this entire test case with:
* runtest -c com.android.email.SecurityPolicyTests email
*/
@MediumTest
public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
private Context mMockContext;
private static final PolicySet EMPTY_POLICY_SET =
new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, false);
public SecurityPolicyTests() {
super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY);
}
@Override
protected void setUp() throws Exception {
super.setUp();
mMockContext = new MockContext2(getMockContext(), this.mContext);
// Invalidate all caches, since we reset the database for each test
ContentCache.invalidateAllCachesForTest();
}
/**
* Delete any dummy accounts we set up for this test
*/
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* Private context wrapper used to add back getPackageName() for these tests.
*
* This class also implements {@link Context} method(s) that are called during tests.
*/
private static class MockContext2 extends ContextWrapper {
private final Context mRealContext;
public MockContext2(Context mockContext, Context realContext) {
super(mockContext);
mRealContext = realContext;
}
@Override
public Context getApplicationContext() {
return this;
}
@Override
public String getPackageName() {
return mRealContext.getPackageName();
}
@Override
public Object getSystemService(String name) {
return mRealContext.getSystemService(name);
}
}
/**
* Retrieve the security policy object, and inject the mock context so it works as expected
*/
private SecurityPolicy getSecurityPolicy() {
SecurityPolicy sp = SecurityPolicy.getInstance(mMockContext);
sp.setContext(mMockContext);
return sp;
}
public void testPolicySetConstructor() {
// We know that EMPTY_POLICY_SET doesn't generate an Exception or we wouldn't be here
// Try some illegal parameters
try {
new PolicySet(100, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false);
fail("Too-long password allowed");
} catch (IllegalArgumentException e) {
}
try {
new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG + 1, 0, 0, false, 0, 0, 0, false);
fail("Illegal password mode allowed");
} catch (IllegalArgumentException e) {
}
PolicySet ps = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0,
PolicySet.SCREEN_LOCK_TIME_MAX + 1, false, 0, 0, 0, false);
assertEquals(PolicySet.SCREEN_LOCK_TIME_MAX, ps.getMaxScreenLockTimeForTest());
ps = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE,
PolicySet.PASSWORD_MAX_FAILS_MAX + 1, 0, false, 0, 0, 0, false);
assertEquals(PolicySet.PASSWORD_MAX_FAILS_MAX, ps.getMaxPasswordFailsForTest());
// All password related fields should be zero when password mode is NONE
// Illegal values for these fields should be ignored
ps = new PolicySet(999/*length*/, PolicySet.PASSWORD_MODE_NONE,
999/*fails*/, 9999/*screenlock*/, false, 999/*expir*/, 999/*history*/,
999/*complex*/, false);
assertEquals(0, ps.mMinPasswordLength);
assertEquals(0, ps.mMaxScreenLockTime);
assertEquals(0, ps.mMaxPasswordFails);
assertEquals(0, ps.mPasswordExpirationDays);
assertEquals(0, ps.mPasswordHistory);
assertEquals(0, ps.mPasswordComplexChars);
// With a simple password, we should set complex chars to zero
ps = new PolicySet(4/*length*/, PolicySet.PASSWORD_MODE_SIMPLE,
0, 0, false, 0, 0, 3/*complex*/, false);
assertEquals(4, ps.mMinPasswordLength);
assertEquals(0, ps.mPasswordComplexChars);
}
/**
* Test business logic of aggregating accounts with policies
*/
public void testAggregator() {
SecurityPolicy sp = getSecurityPolicy();
// with no accounts, should return empty set
assertEquals(EMPTY_POLICY_SET, sp.computeAggregatePolicy());
// with accounts having no security, empty set
Account a1 = ProviderTestUtils.setupAccount("no-sec-1", false, mMockContext);
a1.mSecurityFlags = 0;
a1.save(mMockContext);
Account a2 = ProviderTestUtils.setupAccount("no-sec-2", false, mMockContext);
a2.mSecurityFlags = 0;
a2.save(mMockContext);
assertEquals(EMPTY_POLICY_SET, sp.computeAggregatePolicy());
// with a single account in security mode, should return same security as in account
// first test with partially-populated policies
Account a3 = ProviderTestUtils.setupAccount("sec-3", false, mMockContext);
PolicySet p3ain = new PolicySet(10, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
false);
p3ain.writeAccount(a3, null, true, mMockContext);
PolicySet p3aout = sp.computeAggregatePolicy();
assertNotNull(p3aout);
assertEquals(p3ain, p3aout);
// Repeat that test with fully-populated policies
PolicySet p3bin = new PolicySet(10, PolicySet.PASSWORD_MODE_SIMPLE, 15, 16, false, 6, 2, 3,
false);
p3bin.writeAccount(a3, null, true, mMockContext);
PolicySet p3bout = sp.computeAggregatePolicy();
assertNotNull(p3bout);
assertEquals(p3bin, p3bout);
// add another account which mixes it up (some fields will change, others will not)
// pw length and pw mode - max logic - will change because larger #s here
// fail count and lock timer - min logic - will *not* change because larger #s here
// wipe required - OR logic - will *not* change here because false
// expiration - will not change because 0 (unspecified)
// max complex chars - max logic - will change
// encryption required - OR logic - will *not* change here because false
PolicySet p4in = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 0, 5, 7,
false);
Account a4 = ProviderTestUtils.setupAccount("sec-4", false, mMockContext);
p4in.writeAccount(a4, null, true, mMockContext);
PolicySet p4out = sp.computeAggregatePolicy();
assertNotNull(p4out);
assertEquals(20, p4out.mMinPasswordLength);
assertEquals(PolicySet.PASSWORD_MODE_STRONG, p4out.mPasswordMode);
assertEquals(15, p4out.mMaxPasswordFails);
assertEquals(16, p4out.mMaxScreenLockTime);
assertEquals(6, p4out.mPasswordExpirationDays);
assertEquals(5, p4out.mPasswordHistory);
assertEquals(7, p4out.mPasswordComplexChars);
assertFalse(p4out.mRequireRemoteWipe);
assertFalse(p4out.mRequireEncryption);
// add another account which mixes it up (the remaining fields will change)
// pw length and pw mode - max logic - will *not* change because smaller #s here
// fail count and lock timer - min logic - will change because smaller #s here
// wipe required - OR logic - will change here because true
// expiration time - min logic - will change because lower here
// history & complex chars - will not change because 0 (unspecified)
// encryption required - OR logic - will change here because true
PolicySet p5in = new PolicySet(4, PolicySet.PASSWORD_MODE_SIMPLE, 5, 6, true, 1, 0, 0,
true);
Account a5 = ProviderTestUtils.setupAccount("sec-5", false, mMockContext);
p5in.writeAccount(a5, null, true, mMockContext);
PolicySet p5out = sp.computeAggregatePolicy();
assertNotNull(p5out);
assertEquals(20, p5out.mMinPasswordLength);
assertEquals(PolicySet.PASSWORD_MODE_STRONG, p5out.mPasswordMode);
assertEquals(5, p5out.mMaxPasswordFails);
assertEquals(6, p5out.mMaxScreenLockTime);
assertEquals(1, p5out.mPasswordExpirationDays);
assertEquals(5, p5out.mPasswordHistory);
assertEquals(7, p5out.mPasswordComplexChars);
assertTrue(p5out.mRequireRemoteWipe);
assertTrue(p5out.mRequireEncryption);
}
/**
* Make sure aggregator (and any other direct DB accessors) handle the case of upgraded
* accounts properly (where the security flags will be NULL instead of zero).
*/
public void testNullFlags() {
SecurityPolicy sp = getSecurityPolicy();
Account a1 = ProviderTestUtils.setupAccount("null-sec-1", true, mMockContext);
ContentValues cv = new ContentValues();
cv.putNull(AccountColumns.SECURITY_FLAGS);
Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, a1.mId);
mMockContext.getContentResolver().update(uri, cv, null, null);
Account a2 = ProviderTestUtils.setupAccount("no-sec-2", false, mMockContext);
a2.mSecurityFlags = 0;
a2.save(mMockContext);
assertEquals(EMPTY_POLICY_SET, sp.computeAggregatePolicy());
}
/**
* Make sure the fields are encoded properly for their max ranges. This is looking
* for any encoding mask/shift errors, which would cause bits to overflow into other fields.
*/
@SmallTest
public void testFieldIsolation() {
// Check PASSWORD_LENGTH
PolicySet p = new PolicySet(PolicySet.PASSWORD_LENGTH_MAX, PolicySet.PASSWORD_MODE_SIMPLE,
0, 0, false, 0, 0 ,0, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(PolicySet.PASSWORD_LENGTH_MAX, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
assertEquals(0, p.mMaxScreenLockTime);
assertEquals(0, p.mPasswordExpirationDays);
assertEquals(0, p.mPasswordHistory);
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
// Check PASSWORD_MODE
p = new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG, 0, 0, false, 0, 0, 0, false);
assertEquals(PolicySet.PASSWORD_MODE_STRONG, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
assertEquals(0, p.mMaxScreenLockTime);
assertEquals(0, p.mPasswordExpirationDays);
assertEquals(0, p.mPasswordHistory);
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
// Check PASSWORD_FAILS (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, PolicySet.PASSWORD_MAX_FAILS_MAX, 0,
false, 0, 0, 0, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(PolicySet.PASSWORD_MAX_FAILS_MAX, p.mMaxPasswordFails);
assertEquals(0, p.mMaxScreenLockTime);
assertEquals(0, p.mPasswordExpirationDays);
assertEquals(0, p.mPasswordHistory);
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
// Check SCREEN_LOCK_TIME (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0, PolicySet.SCREEN_LOCK_TIME_MAX,
false, 0, 0, 0, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
assertEquals(PolicySet.SCREEN_LOCK_TIME_MAX, p.mMaxScreenLockTime);
assertEquals(0, p.mPasswordExpirationDays);
assertEquals(0, p.mPasswordHistory);
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
// Check REQUIRE_REMOTE_WIPE
p = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, true, 0, 0, 0, false);
assertEquals(PolicySet.PASSWORD_MODE_NONE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
assertEquals(0, p.mMaxScreenLockTime);
assertEquals(0, p.mPasswordExpirationDays);
assertEquals(0, p.mPasswordHistory);
assertEquals(0, p.mPasswordComplexChars);
assertTrue(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
// Check PASSWORD_EXPIRATION (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false,
PolicySet.PASSWORD_EXPIRATION_MAX, 0, 0, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
assertEquals(0, p.mMaxScreenLockTime);
assertEquals(PolicySet.PASSWORD_EXPIRATION_MAX, p.mPasswordExpirationDays);
assertEquals(0, p.mPasswordHistory);
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
// Check PASSWORD_HISTORY (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0,
PolicySet.PASSWORD_HISTORY_MAX, 0, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
assertEquals(0, p.mMaxScreenLockTime);
assertEquals(0, p.mPasswordExpirationDays);
assertEquals(PolicySet.PASSWORD_HISTORY_MAX, p.mPasswordHistory);
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
// Check PASSWORD_COMPLEX_CHARS (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG, 0, 0, false, 0, 0,
PolicySet.PASSWORD_COMPLEX_CHARS_MAX, false);
assertEquals(PolicySet.PASSWORD_MODE_STRONG, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
assertEquals(0, p.mMaxScreenLockTime);
assertEquals(0, p.mPasswordExpirationDays);
assertEquals(0, p.mPasswordHistory);
assertEquals(PolicySet.PASSWORD_COMPLEX_CHARS_MAX, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
// Check REQUIRE_ENCRYPTION
p = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, true);
assertEquals(PolicySet.PASSWORD_MODE_NONE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
assertEquals(0, p.mMaxScreenLockTime);
assertEquals(0, p.mPasswordExpirationDays);
assertEquals(0, p.mPasswordHistory);
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertTrue(p.mRequireEncryption);
}
/**
* Test encoding into an Account and out again
*/
@SmallTest
public void testAccountEncoding() {
PolicySet p1 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
Account a = new Account();
final String SYNC_KEY = "test_sync_key";
p1.writeAccount(a, SYNC_KEY, false, null);
PolicySet p2 = new PolicySet(a);
assertEquals(p1, p2);
}
/**
* Test equality. Note, the tests for inequality are poor, as each field should
* be tested individually.
*/
@SmallTest
public void testEquals() {
PolicySet p1 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
PolicySet p2 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
PolicySet p3 = new PolicySet(2, PolicySet.PASSWORD_MODE_SIMPLE, 5, 6, true, 7, 8, 9, false);
assertTrue(p1.equals(p2));
assertFalse(p2.equals(p3));
}
/**
* Test the API to set/clear policy hold flags in an account
*/
public void testSetClearHoldFlag() {
SecurityPolicy sp = getSecurityPolicy();
Account a1 = ProviderTestUtils.setupAccount("holdflag-1", false, mMockContext);
a1.mFlags = Account.FLAGS_NOTIFY_NEW_MAIL;
a1.save(mMockContext);
Account a2 = ProviderTestUtils.setupAccount("holdflag-2", false, mMockContext);
a2.mFlags = Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD;
a2.save(mMockContext);
// confirm clear until set
Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId);
assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL, a1a.mFlags);
sp.setAccountHoldFlag(mMockContext, a1, true);
assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1.mFlags);
Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId);
assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1b.mFlags);
// confirm set until cleared
Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId);
assertEquals(Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD, a2a.mFlags);
sp.setAccountHoldFlag(mMockContext, a2, false);
assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2.mFlags);
Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId);
assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2b.mFlags);
}
// private static class MockController extends Controller {
// protected MockController(Context context) {
// super(context);
// }
// }
/**
* Test the response to disabling DeviceAdmin status
*
* TODO: Reenable the 2nd portion of this test - it fails because it gets into the Controller
* and spins up an account backup on another thread.
*/
public void testDisableAdmin() {
Account a1 = ProviderTestUtils.setupAccount("disable-1", false, mMockContext);
PolicySet p1 = new PolicySet(10, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
false);
p1.writeAccount(a1, "sync-key-1", true, mMockContext);
Account a2 = ProviderTestUtils.setupAccount("disable-2", false, mMockContext);
PolicySet p2 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
false);
p2.writeAccount(a2, "sync-key-2", true, mMockContext);
Account a3 = ProviderTestUtils.setupAccount("disable-3", false, mMockContext);
a3.mSecurityFlags = 0;
a3.mSecuritySyncKey = null;
a3.save(mMockContext);
SecurityPolicy sp = getSecurityPolicy();
// Confirm that "enabling" device admin does not change security status (flags & sync key)
PolicySet before = sp.getAggregatePolicy();
sp.onAdminEnabled(true); // "enabled" should not change anything
PolicySet after1 = sp.getAggregatePolicy();
assertEquals(before, after1);
Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId);
assertNotNull(a1a.mSecuritySyncKey);
Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId);
assertNotNull(a2a.mSecuritySyncKey);
Account a3a = Account.restoreAccountWithId(mMockContext, a3.mId);
assertNull(a3a.mSecuritySyncKey);
// Simulate revoke of device admin; directly call deleteSecuredAccounts, which is normally
// called from a background thread
// MockController mockController = new MockController(mMockContext);
// Controller.injectMockControllerForTest(mockController);
// try {
// sp.deleteSecuredAccounts(mMockContext);
// PolicySet after2 = sp.getAggregatePolicy();
// assertEquals(SecurityPolicy.NO_POLICY_SET, after2);
// Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId);
// assertNull(a1b);
// Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId);
// assertNull(a2b);
// Account a3b = Account.restoreAccountWithId(mMockContext, a3.mId);
// assertNull(a3b.mSecuritySyncKey);
// } finally {
// Controller.injectMockControllerForTest(null);
// }
}
/**
* Test the scanner that finds expiring accounts
*/
public void testFindExpiringAccount() {
SecurityPolicy sp = getSecurityPolicy();
Account a1 = ProviderTestUtils.setupAccount("expiring-1", true, mMockContext);
// With no expiring accounts, this should return null.
long nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
assertEquals(-1, nextExpiringAccountId);
// Add a single expiring account
Account a2 = ProviderTestUtils.setupAccount("expiring-2", false, mMockContext);
PolicySet p2 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
false);
p2.writeAccount(a2, "sync-key-2", true, mMockContext);
// The expiring account should be returned
nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
assertEquals(a2.mId, nextExpiringAccountId);
// Add an account with a longer expiration
Account a3 = ProviderTestUtils.setupAccount("expiring-3", false, mMockContext);
PolicySet p3 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 60, 0, 0,
false);
p3.writeAccount(a3, "sync-key-3", true, mMockContext);
// The original expiring account (a2) should be returned
nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
assertEquals(a2.mId, nextExpiringAccountId);
// Add an account with a shorter expiration
Account a4 = ProviderTestUtils.setupAccount("expiring-4", false, mMockContext);
PolicySet p4 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 15, 0, 0,
false);
p4.writeAccount(a4, "sync-key-4", true, mMockContext);
// The new expiring account (a4) should be returned
nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
assertEquals(a4.mId, nextExpiringAccountId);
}
/**
* Lightweight subclass of the Controller class allows injection of mock context
*/
public static class TestController extends Controller {
protected TestController(Context providerContext, Context systemContext) {
super(systemContext);
setProviderContext(providerContext);
}
}
/**
* Test the scanner that wipes expiring accounts
*/
public void testWipeExpiringAccounts() {
SecurityPolicy sp = getSecurityPolicy();
TestController testController = new TestController(mMockContext, getContext());
// Two accounts - a1 is normal, a2 has security (but no expiration)
Account a1 = ProviderTestUtils.setupAccount("expired-1", true, mMockContext);
Account a2 = ProviderTestUtils.setupAccount("expired-2", false, mMockContext);
PolicySet p2 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
false);
p2.writeAccount(a2, "sync-key-2", true, mMockContext);
// Add a mailbox & messages to each account
long account1Id = a1.mId;
long account2Id = a2.mId;
Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
long box1Id = box1.mId;
ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mMockContext);
ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false, true, mMockContext);
Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account2Id, true, mMockContext);
long box2Id = box2.mId;
ProviderTestUtils.setupMessage("message3", account2Id, box2Id, false, true, mMockContext);
ProviderTestUtils.setupMessage("message4", account2Id, box2Id, false, true, mMockContext);
// Run the expiration code - should do nothing
boolean wiped = sp.wipeExpiredAccounts(mMockContext, testController);
assertFalse(wiped);
// check mailboxes & messages not wiped
assertEquals(2, EmailContent.count(mMockContext, Account.CONTENT_URI));
assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI));
// Add 3rd account that really expires
Account a3 = ProviderTestUtils.setupAccount("expired-3", false, mMockContext);
PolicySet p3 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
false);
p3.writeAccount(a3, "sync-key-3", true, mMockContext);
// Add mailbox & messages to 3rd account
long account3Id = a3.mId;
Mailbox box3 = ProviderTestUtils.setupMailbox("box3", account3Id, true, mMockContext);
long box3Id = box3.mId;
ProviderTestUtils.setupMessage("message5", account3Id, box3Id, false, true, mMockContext);
ProviderTestUtils.setupMessage("message6", account3Id, box3Id, false, true, mMockContext);
// check new counts
assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI));
assertEquals(3, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
assertEquals(6, EmailContent.count(mMockContext, Message.CONTENT_URI));
// Run the expiration code - wipe acct #3
wiped = sp.wipeExpiredAccounts(mMockContext, testController);
assertTrue(wiped);
// check new counts - account survives but data is wiped
assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI));
assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI));
// Check security hold states - only #3 should be in hold
Account account = Account.restoreAccountWithId(mMockContext, account1Id);
assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD);
account = Account.restoreAccountWithId(mMockContext, account2Id);
assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD);
account = Account.restoreAccountWithId(mMockContext, account3Id);
assertEquals(Account.FLAGS_SECURITY_HOLD, account.mFlags & Account.FLAGS_SECURITY_HOLD);
}
/**
* Test the code that clears unsupported policies
* TODO inject a mock DPM so we can directly control & test all cases, no matter what device
*/
public void testClearUnsupportedPolicies() {
PolicySet p1 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
PolicySet p2 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, true);
SecurityPolicy sp = getSecurityPolicy();
DevicePolicyManager dpm = sp.getDPM();
boolean hasEncryption =
dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
PolicySet p1Result = sp.clearUnsupportedPolicies(p1);
PolicySet p2Result = sp.clearUnsupportedPolicies(p2);
// No changes expected when encryptionRequested was false
assertEquals(p1, p1Result);
if (hasEncryption) {
// No changes expected
assertEquals(p2, p2Result);
} else {
PolicySet p2Expect =
new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
assertEquals(p2Expect, p2Result);
}
}
}