Merge "Add TestableDeviceConfig"

This commit is contained in:
Linus Tufvesson
2019-02-26 16:37:47 +00:00
committed by Android (Google) Code Review
5 changed files with 400 additions and 216 deletions

View File

@@ -18,15 +18,11 @@ package android.provider;
import static android.provider.DeviceConfig.OnPropertyChangedListener;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.fail;
import static com.google.common.truth.Truth.assertThat;
import android.app.ActivityThread;
import android.content.ContentResolver;
import android.os.Bundle;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
@@ -37,8 +33,8 @@ import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** Tests that ensure appropriate settings are backed up. */
@Presubmit
@@ -51,8 +47,6 @@ public class DeviceConfigTest {
private static final String sValue = "value1";
private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
private final Object mLock = new Object();
@After
public void cleanUp() {
deleteViaContentProvider(sNamespace, sKey);
@@ -61,14 +55,14 @@ public class DeviceConfigTest {
@Test
public void getProperty_empty() {
String result = DeviceConfig.getProperty(sNamespace, sKey);
assertNull(result);
assertThat(result).isNull();
}
@Test
public void setAndGetProperty_sameNamespace() {
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
String result = DeviceConfig.getProperty(sNamespace, sKey);
assertEquals(sValue, result);
assertThat(result).isEqualTo(sValue);
}
@Test
@@ -76,7 +70,7 @@ public class DeviceConfigTest {
String newNamespace = "namespace2";
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
String result = DeviceConfig.getProperty(newNamespace, sKey);
assertNull(result);
assertThat(result).isNull();
}
@Test
@@ -86,9 +80,9 @@ public class DeviceConfigTest {
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
DeviceConfig.setProperty(newNamespace, sKey, newValue, false);
String result = DeviceConfig.getProperty(sNamespace, sKey);
assertEquals(sValue, result);
assertThat(result).isEqualTo(sValue);
result = DeviceConfig.getProperty(newNamespace, sKey);
assertEquals(newValue, result);
assertThat(result).isEqualTo(newValue);
// clean up
deleteViaContentProvider(newNamespace, sKey);
@@ -100,59 +94,30 @@ public class DeviceConfigTest {
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
DeviceConfig.setProperty(sNamespace, sKey, newValue, false);
String result = DeviceConfig.getProperty(sNamespace, sKey);
assertEquals(newValue, result);
assertThat(result).isEqualTo(newValue);
}
@Test
public void testListener() {
setPropertyAndAssertSuccessfulChange(sNamespace, sKey, sValue);
}
public void testListener() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
private void setPropertyAndAssertSuccessfulChange(String setNamespace, String setName,
String setValue) {
final AtomicBoolean success = new AtomicBoolean();
OnPropertyChangedListener changeListener = (namespace, name, value) -> {
assertThat(namespace).isEqualTo(sNamespace);
assertThat(name).isEqualTo(sKey);
assertThat(value).isEqualTo(sValue);
countDownLatch.countDown();
};
OnPropertyChangedListener changeListener = new OnPropertyChangedListener() {
@Override
public void onPropertyChanged(String namespace, String name, String value) {
assertEquals(setNamespace, namespace);
assertEquals(setName, name);
assertEquals(setValue, value);
success.set(true);
synchronized (mLock) {
mLock.notifyAll();
}
}
};
Executor executor = ActivityThread.currentApplication().getMainExecutor();
DeviceConfig.addOnPropertyChangedListener(setNamespace, executor, changeListener);
try {
DeviceConfig.setProperty(setNamespace, setName, setValue, false);
final long startTimeMillis = SystemClock.uptimeMillis();
synchronized (mLock) {
while (true) {
if (success.get()) {
return;
}
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
if (elapsedTimeMillis >= WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS) {
fail("Could not change setting for "
+ WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS + " ms");
}
final long remainingTimeMillis = WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS
- elapsedTimeMillis;
try {
mLock.wait(remainingTimeMillis);
} catch (InterruptedException ie) {
/* ignore */
}
}
}
DeviceConfig.addOnPropertyChangedListener(sNamespace,
ActivityThread.currentApplication().getMainExecutor(), changeListener);
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
assertThat(countDownLatch.await(
WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
} finally {
DeviceConfig.removeOnPropertyChangedListener(changeListener);
}
}
private static boolean deleteViaContentProvider(String namespace, String key) {
@@ -160,7 +125,7 @@ public class DeviceConfigTest {
String compositeName = namespace + "/" + key;
Bundle result = resolver.call(
DeviceConfig.CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, compositeName, null);
assertNotNull(result);
assertThat(result).isNotNull();
return compositeName.equals(result.getString(Settings.NameValueTable.VALUE));
}

View File

@@ -23,6 +23,7 @@ android_test {
"androidx.test.runner",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
"truth-prebuilt",
],
libs: [

View File

@@ -28,28 +28,24 @@ import static android.provider.DeviceConfig.ActivityManager.KEY_USE_COMPACTION;
import static com.android.server.am.ActivityManagerService.Injector;
import static com.android.server.am.AppCompactor.compactActionIntToString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static com.google.common.truth.Truth.assertThat;
import android.os.Handler;
import android.os.HandlerThread;
import android.provider.DeviceConfig;
import android.support.test.uiautomator.UiDevice;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.appop.AppOpsService;
import com.android.server.testables.TestableDeviceConfig;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -59,42 +55,21 @@ import java.util.concurrent.TimeUnit;
* Build/Install/Run:
* atest FrameworksServicesTests:AppCompactorTest
*/
@RunWith(AndroidJUnit4.class)
@RunWith(MockitoJUnitRunner.class)
public final class AppCompactorTest {
private static final String CLEAR_DEVICE_CONFIG_KEY_CMD =
"device_config delete activity_manager";
@Mock private AppOpsService mAppOpsService;
@Mock
private AppOpsService mAppOpsService;
private AppCompactor mCompactorUnderTest;
private HandlerThread mHandlerThread;
private Handler mHandler;
private CountDownLatch mCountDown;
private static void clearDeviceConfig() throws IOException {
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
uiDevice.executeShellCommand(
CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_USE_COMPACTION);
uiDevice.executeShellCommand(
CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_1);
uiDevice.executeShellCommand(
CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_2);
uiDevice.executeShellCommand(
CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_1);
uiDevice.executeShellCommand(
CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_2);
uiDevice.executeShellCommand(
CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_3);
uiDevice.executeShellCommand(
CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_4);
uiDevice.executeShellCommand(
CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_STATSD_SAMPLE_RATE);
}
@Rule
public TestableDeviceConfig mDeviceConfig = new TestableDeviceConfig();
@Before
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
clearDeviceConfig();
public void setUp() {
mHandlerThread = new HandlerThread("");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
@@ -111,38 +86,37 @@ public final class AppCompactorTest {
}
@After
public void tearDown() throws IOException {
public void tearDown() {
mHandlerThread.quit();
mCountDown = null;
clearDeviceConfig();
}
@Test
public void init_setsDefaults() {
mCompactorUnderTest.init();
assertThat(mCompactorUnderTest.useCompaction(),
is(mCompactorUnderTest.DEFAULT_USE_COMPACTION));
assertThat(mCompactorUnderTest.mCompactActionSome, is(
compactActionIntToString(mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1)));
assertThat(mCompactorUnderTest.mCompactActionFull, is(
compactActionIntToString(mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2)));
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
assertThat(mCompactorUnderTest.mStatsdSampleRate,
is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE));
assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
AppCompactor.DEFAULT_USE_COMPACTION);
assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1));
assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2));
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
AppCompactor.DEFAULT_STATSD_SAMPLE_RATE);
}
@Test
public void init_withDeviceConfigSetsParameters() {
// When the DeviceConfig already has a flag value stored (note this test will need to
// change if the default value changes from false).
assertThat(mCompactorUnderTest.DEFAULT_USE_COMPACTION, is(false));
assertThat(AppCompactor.DEFAULT_USE_COMPACTION).isFalse();
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_USE_COMPACTION, "true", false);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
@@ -169,62 +143,63 @@ public final class AppCompactorTest {
// Then calling init will read and set that flag.
mCompactorUnderTest.init();
assertThat(mCompactorUnderTest.useCompaction(), is(true));
assertThat(mCompactorUnderTest.mCompactionThread.isAlive(), is(true));
assertThat(mCompactorUnderTest.useCompaction()).isTrue();
assertThat(mCompactorUnderTest.mCompactionThread.isAlive()).isTrue();
assertThat(mCompactorUnderTest.mCompactActionSome,
is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1)));
assertThat(mCompactorUnderTest.mCompactActionFull,
is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1)));
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1));
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1));
assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1));
assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1));
assertThat(mCompactorUnderTest.mStatsdSampleRate,
is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f));
assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1));
assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1));
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1);
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1);
assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1);
assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
}
@Test
public void useCompaction_listensToDeviceConfigChanges() throws InterruptedException {
assertThat(mCompactorUnderTest.useCompaction(),
is(mCompactorUnderTest.DEFAULT_USE_COMPACTION));
assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
AppCompactor.DEFAULT_USE_COMPACTION);
// When we call init and change some the flag value...
mCompactorUnderTest.init();
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_USE_COMPACTION, "true", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then that new flag value is updated in the implementation.
assertThat(mCompactorUnderTest.useCompaction(), is(true));
assertThat(mCompactorUnderTest.mCompactionThread.isAlive(), is(true));
assertThat(mCompactorUnderTest.useCompaction()).isTrue();
assertThat(mCompactorUnderTest.mCompactionThread.isAlive()).isTrue();
// And again, setting the flag the other way.
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_USE_COMPACTION, "false", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCompactorUnderTest.useCompaction(), is(false));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(mCompactorUnderTest.useCompaction()).isFalse();
}
@Test
public void useCompaction_listensToDeviceConfigChangesBadValues() throws InterruptedException {
assertThat(mCompactorUnderTest.useCompaction(),
is(mCompactorUnderTest.DEFAULT_USE_COMPACTION));
assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
AppCompactor.DEFAULT_USE_COMPACTION);
mCompactorUnderTest.init();
// When we push an invalid flag value...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_USE_COMPACTION, "foobar", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then we set the default.
assertThat(mCompactorUnderTest.useCompaction(), is(AppCompactor.DEFAULT_USE_COMPACTION));
assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
AppCompactor.DEFAULT_USE_COMPACTION);
}
@Test
@@ -236,19 +211,19 @@ public final class AppCompactorTest {
// There are four possible values for compactAction[Some|Full].
for (int i = 1; i < 5; i++) {
mCountDown = new CountDownLatch(2);
int expectedSome = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1 + i) % 4 + 1;
int expectedSome = (AppCompactor.DEFAULT_COMPACT_ACTION_1 + i) % 4 + 1;
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_1, Integer.toString(expectedSome), false);
int expectedFull = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2 + i) % 4 + 1;
int expectedFull = (AppCompactor.DEFAULT_COMPACT_ACTION_2 + i) % 4 + 1;
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_2, Integer.toString(expectedFull), false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then the updates are reflected in the flags.
assertThat(mCompactorUnderTest.mCompactActionSome,
is(compactActionIntToString(expectedSome)));
assertThat(mCompactorUnderTest.mCompactActionFull,
is(compactActionIntToString(expectedFull)));
assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
compactActionIntToString(expectedSome));
assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
compactActionIntToString(expectedFull));
}
}
@@ -262,25 +237,25 @@ public final class AppCompactorTest {
KEY_COMPACT_ACTION_1, "foo", false);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_2, "foo", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then the default values are reflected in the flag
assertThat(mCompactorUnderTest.mCompactActionSome,
is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1)));
assertThat(mCompactorUnderTest.mCompactActionFull,
is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2)));
assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1));
assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2));
mCountDown = new CountDownLatch(2);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_1, "", false);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_ACTION_2, "", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(mCompactorUnderTest.mCompactActionSome,
is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1)));
assertThat(mCompactorUnderTest.mCompactActionFull,
is(compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2)));
assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1));
assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2));
}
@Test
@@ -301,22 +276,22 @@ public final class AppCompactorTest {
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_4,
Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then those flags values are reflected in the compactor.
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1));
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1));
assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1));
assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1));
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1);
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1);
assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1);
}
@Test
public void compactThrottle_listensToDeviceConfigChangesBadValues()
throws IOException, InterruptedException {
throws InterruptedException {
mCompactorUnderTest.init();
// When one of the throttles is overridden with a bad value...
@@ -324,58 +299,55 @@ public final class AppCompactorTest {
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_1, "foo", false);
// Then all the throttles have the defaults set.
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
clearDeviceConfig();
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
// Repeat for each of the throttle keys.
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_2, "foo", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
clearDeviceConfig();
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_3, "foo", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
clearDeviceConfig();
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_THROTTLE_4, "foo", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1));
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_2));
assertThat(mCompactorUnderTest.mCompactThrottleFullSome,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3));
assertThat(mCompactorUnderTest.mCompactThrottleFullFull,
is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
}
@Test
@@ -387,11 +359,11 @@ public final class AppCompactorTest {
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_STATSD_SAMPLE_RATE,
Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then that override is reflected in the compactor.
assertThat(mCompactorUnderTest.mStatsdSampleRate,
is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f));
assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
}
@Test
@@ -403,11 +375,11 @@ public final class AppCompactorTest {
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then that override is reflected in the compactor.
assertThat(mCompactorUnderTest.mStatsdSampleRate,
is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE));
assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
AppCompactor.DEFAULT_STATSD_SAMPLE_RATE);
}
@Test
@@ -420,19 +392,19 @@ public final class AppCompactorTest {
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_STATSD_SAMPLE_RATE,
Float.toString(-1.0f), false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then the values is capped in the range.
assertThat(mCompactorUnderTest.mStatsdSampleRate, is(0.0f));
assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(0.0f);
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
KEY_COMPACT_STATSD_SAMPLE_RATE,
Float.toString(1.01f), false);
assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
// Then the values is capped in the range.
assertThat(mCompactorUnderTest.mStatsdSampleRate, is(1.0f));
assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(1.0f);
}
private class TestInjector extends Injector {

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2019 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.testables;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import android.provider.DeviceConfig;
import android.util.Pair;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
/**
* TestableDeviceConfig uses ExtendedMockito to replace the real implementation of DeviceConfig
* with essentially a local HashMap in the callers process. This allows for unit testing that do not
* modify the real DeviceConfig on the device at all.
*
* <p>TestableDeviceConfig should be defined as a rule on your test so it can clean up after itself.
* Like the following:</p>
* <pre class="prettyprint">
* &#064;Rule
* public final TestableDeviceConfig mTestableDeviceConfig = new TestableDeviceConfig();
* </pre>
*/
public final class TestableDeviceConfig implements TestRule {
private StaticMockitoSession mMockitoSession;
private Map<DeviceConfig.OnPropertyChangedListener, Pair<String, Executor>>
mOnPropertyChangedListenerMap = new HashMap<>();
private Map<String, String> mKeyValueMap = new ConcurrentHashMap<>();
/**
* Clears out all local overrides.
*/
public void clearDeviceConfig() {
mKeyValueMap.clear();
}
@Override
public Statement apply(Statement base, Description description) {
mMockitoSession = mockitoSession()
.initMocks(this)
.strictness(Strictness.LENIENT)
.spyStatic(DeviceConfig.class)
.startMocking();
doAnswer((Answer<Void>) invocationOnMock -> {
String namespace = invocationOnMock.getArgument(0);
Executor executor = invocationOnMock.getArgument(1);
DeviceConfig.OnPropertyChangedListener onPropertyChangedListener =
invocationOnMock.getArgument(2);
mOnPropertyChangedListenerMap.put(
onPropertyChangedListener, new Pair<>(namespace, executor));
return null;
}).when(() -> DeviceConfig.addOnPropertyChangedListener(
anyString(), any(Executor.class),
any(DeviceConfig.OnPropertyChangedListener.class)));
doAnswer((Answer<Boolean>) invocationOnMock -> {
String namespace = invocationOnMock.getArgument(0);
String name = invocationOnMock.getArgument(1);
String value = invocationOnMock.getArgument(2);
mKeyValueMap.put(getKey(namespace, name), value);
for (DeviceConfig.OnPropertyChangedListener listener :
mOnPropertyChangedListenerMap.keySet()) {
if (namespace.equals(mOnPropertyChangedListenerMap.get(listener).first)) {
mOnPropertyChangedListenerMap.get(listener).second.execute(
() -> listener.onPropertyChanged(namespace, name, value));
}
}
return true;
}
).when(() -> DeviceConfig.setProperty(anyString(), anyString(), anyString(), anyBoolean()));
doAnswer((Answer<String>) invocationOnMock -> {
String namespace = invocationOnMock.getArgument(0);
String name = invocationOnMock.getArgument(1);
return mKeyValueMap.get(getKey(namespace, name));
}).when(() -> DeviceConfig.getProperty(anyString(), anyString()));
return new TestWatcher() {
@Override
protected void succeeded(Description description) {
mMockitoSession.finishMocking();
mOnPropertyChangedListenerMap.clear();
}
@Override
protected void failed(Throwable e, Description description) {
mMockitoSession.finishMocking(e);
mOnPropertyChangedListenerMap.clear();
}
}.apply(base, description);
}
private static String getKey(String namespace, String name) {
return namespace + "/" + name;
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2019 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.testables;
import static android.provider.DeviceConfig.OnPropertyChangedListener;
import static com.google.common.truth.Truth.assertThat;
import android.app.ActivityThread;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** Tests that ensure appropriate settings are backed up. */
@Presubmit
@RunWith(AndroidJUnit4.class)
@SmallTest
public class TestableDeviceConfigTest {
private static final String sNamespace = "namespace1";
private static final String sKey = "key1";
private static final String sValue = "value1";
private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
@Rule
public TestableDeviceConfig mTestableDeviceConfig = new TestableDeviceConfig();
@Test
public void getProperty_empty() {
String result = DeviceConfig.getProperty(sNamespace, sKey);
assertThat(result).isNull();
}
@Test
public void setAndGetProperty_sameNamespace() {
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
String result = DeviceConfig.getProperty(sNamespace, sKey);
assertThat(result).isEqualTo(sValue);
}
@Test
public void setAndGetProperty_differentNamespace() {
String newNamespace = "namespace2";
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
String result = DeviceConfig.getProperty(newNamespace, sKey);
assertThat(result).isNull();
}
@Test
public void setAndGetProperty_multipleNamespaces() {
String newNamespace = "namespace2";
String newValue = "value2";
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
DeviceConfig.setProperty(newNamespace, sKey, newValue, false);
String result = DeviceConfig.getProperty(sNamespace, sKey);
assertThat(result).isEqualTo(sValue);
result = DeviceConfig.getProperty(newNamespace, sKey);
assertThat(result).isEqualTo(newValue);
}
@Test
public void setAndGetProperty_overrideValue() {
String newValue = "value2";
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
DeviceConfig.setProperty(sNamespace, sKey, newValue, false);
String result = DeviceConfig.getProperty(sNamespace, sKey);
assertThat(result).isEqualTo(newValue);
}
@Test
public void testListener() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
OnPropertyChangedListener changeListener = (namespace, name, value) -> {
assertThat(namespace).isEqualTo(sNamespace);
assertThat(name).isEqualTo(sKey);
assertThat(value).isEqualTo(sValue);
countDownLatch.countDown();
};
try {
DeviceConfig.addOnPropertyChangedListener(sNamespace,
ActivityThread.currentApplication().getMainExecutor(), changeListener);
DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
assertThat(countDownLatch.await(
WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
} finally {
DeviceConfig.removeOnPropertyChangedListener(changeListener);
}
}
}