Split NetworkStackUtils to frameworks/libs/net
Split DeviceConfig and collections-related utilities to CollectionUtils and DeviceConfigUtils in frameworks/libs/net. Also add implementations for contains(array, value), to avoid usage of internal non-API utils. The original tests are based on mockito-extended, so also add to NetworkStackTests as a dependency. This also requires setting the test app as debuggable in its manifest. Bug: 17454103 Test: atest NetworkStaticLibTests Change-Id: Ie9bed66a08b7370ebe50d0a7240b788f8b31aa77
This commit is contained in:
parent
128c31f0b8
commit
b86b34da48
8 changed files with 590 additions and 1 deletions
|
|
@ -143,6 +143,7 @@ filegroup {
|
|||
name: "net-utils-services-common-srcs",
|
||||
srcs: [
|
||||
"device/android/net/NetworkFactory.java",
|
||||
"device/com/android/net/module/util/CollectionUtils.java",
|
||||
],
|
||||
visibility: [
|
||||
"//frameworks/base/services/net",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.net.module.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Utilities for {@link Collection} and arrays.
|
||||
*/
|
||||
public final class CollectionUtils {
|
||||
private CollectionUtils() {}
|
||||
|
||||
/**
|
||||
* @return True if the array is null or 0-length.
|
||||
*/
|
||||
public static <T> boolean isEmpty(@Nullable T[] array) {
|
||||
return array == null || array.length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int array from the given Integer list.
|
||||
*/
|
||||
@NonNull
|
||||
public static int[] toIntArray(@NonNull Collection<Integer> list) {
|
||||
int[] array = new int[list.size()];
|
||||
int i = 0;
|
||||
for (Integer item : list) {
|
||||
array[i] = item;
|
||||
i++;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a long array from the given long list.
|
||||
*/
|
||||
@NonNull
|
||||
public static long[] toLongArray(@NonNull Collection<Long> list) {
|
||||
long[] array = new long[list.size()];
|
||||
int i = 0;
|
||||
for (Long item : list) {
|
||||
array[i] = item;
|
||||
i++;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if there exists at least one element in the sparse array for which
|
||||
* condition {@code predicate}
|
||||
*/
|
||||
public static <T> boolean any(@NonNull SparseArray<T> array, @NonNull Predicate<T> predicate) {
|
||||
for (int i = 0; i < array.size(); ++i) {
|
||||
if (predicate.test(array.valueAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the array contains the specified value.
|
||||
*/
|
||||
public static boolean contains(@Nullable int[] array, int value) {
|
||||
if (array == null) return false;
|
||||
for (int element : array) {
|
||||
if (element == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the array contains the specified value.
|
||||
*/
|
||||
public static <T> boolean contains(@Nullable T[] array, @Nullable T value) {
|
||||
if (array == null) return false;
|
||||
for (T element : array) {
|
||||
if (Objects.equals(element, value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.net.module.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.BoolRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Utilities for modules to query {@link DeviceConfig} and flags.
|
||||
*/
|
||||
public final class DeviceConfigUtils {
|
||||
private DeviceConfigUtils() {}
|
||||
|
||||
private static final String TAG = DeviceConfigUtils.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* Look up the value of a property for a particular namespace from {@link DeviceConfig}.
|
||||
* @param namespace The namespace containing the property to look up.
|
||||
* @param name The name of the property to look up.
|
||||
* @param defaultValue The value to return if the property does not exist or has no valid value.
|
||||
* @return the corresponding value, or defaultValue if none exists.
|
||||
*/
|
||||
@Nullable
|
||||
public static String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name,
|
||||
@Nullable String defaultValue) {
|
||||
String value = DeviceConfig.getProperty(namespace, name);
|
||||
return value != null ? value : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the value of a property for a particular namespace from {@link DeviceConfig}.
|
||||
* @param namespace The namespace containing the property to look up.
|
||||
* @param name The name of the property to look up.
|
||||
* @param defaultValue The value to return if the property does not exist or its value is null.
|
||||
* @return the corresponding value, or defaultValue if none exists.
|
||||
*/
|
||||
public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
|
||||
int defaultValue) {
|
||||
String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */);
|
||||
try {
|
||||
return (value != null) ? Integer.parseInt(value) : defaultValue;
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the value of a property for a particular namespace from {@link DeviceConfig}.
|
||||
*
|
||||
* Flags like timeouts should use this method and set an appropriate min/max range: if invalid
|
||||
* values like "0" or "1" are pushed to devices, everything would timeout. The min/max range
|
||||
* protects against this kind of breakage.
|
||||
* @param namespace The namespace containing the property to look up.
|
||||
* @param name The name of the property to look up.
|
||||
* @param minimumValue The minimum value of a property.
|
||||
* @param maximumValue The maximum value of a property.
|
||||
* @param defaultValue The value to return if the property does not exist or its value is null.
|
||||
* @return the corresponding value, or defaultValue if none exists or the fetched value is
|
||||
* not in the provided range.
|
||||
*/
|
||||
public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
|
||||
int minimumValue, int maximumValue, int defaultValue) {
|
||||
int value = getDeviceConfigPropertyInt(namespace, name, defaultValue);
|
||||
if (value < minimumValue || value > maximumValue) return defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the value of a property for a particular namespace from {@link DeviceConfig}.
|
||||
* @param namespace The namespace containing the property to look up.
|
||||
* @param name The name of the property to look up.
|
||||
* @param defaultValue The value to return if the property does not exist or its value is null.
|
||||
* @return the corresponding value, or defaultValue if none exists.
|
||||
*/
|
||||
public static boolean getDeviceConfigPropertyBoolean(@NonNull String namespace,
|
||||
@NonNull String name, boolean defaultValue) {
|
||||
String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */);
|
||||
return (value != null) ? Boolean.parseBoolean(value) : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not one specific experimental feature for a particular namespace from
|
||||
* {@link DeviceConfig} is enabled by comparing module package version
|
||||
* with current version of property. If this property version is valid, the corresponding
|
||||
* experimental feature would be enabled, otherwise disabled.
|
||||
*
|
||||
* This is useful to ensure that if a module install is rolled back, flags are not left fully
|
||||
* rolled out on a version where they have not been well tested.
|
||||
* @param context The global context information about an app environment.
|
||||
* @param namespace The namespace containing the property to look up.
|
||||
* @param name The name of the property to look up.
|
||||
* @return true if this feature is enabled, or false if disabled.
|
||||
*/
|
||||
public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace,
|
||||
@NonNull String name) {
|
||||
return isFeatureEnabled(context, namespace, name, false /* defaultEnabled */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not one specific experimental feature for a particular namespace from
|
||||
* {@link DeviceConfig} is enabled by comparing module package version
|
||||
* with current version of property. If this property version is valid, the corresponding
|
||||
* experimental feature would be enabled, otherwise disabled.
|
||||
*
|
||||
* This is useful to ensure that if a module install is rolled back, flags are not left fully
|
||||
* rolled out on a version where they have not been well tested.
|
||||
* @param context The global context information about an app environment.
|
||||
* @param namespace The namespace containing the property to look up.
|
||||
* @param name The name of the property to look up.
|
||||
* @param defaultEnabled The value to return if the property does not exist or its value is
|
||||
* null.
|
||||
* @return true if this feature is enabled, or false if disabled.
|
||||
*/
|
||||
public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace,
|
||||
@NonNull String name, boolean defaultEnabled) {
|
||||
try {
|
||||
final int propertyVersion = getDeviceConfigPropertyInt(namespace, name,
|
||||
0 /* default value */);
|
||||
final long packageVersion = context.getPackageManager().getPackageInfo(
|
||||
context.getPackageName(), 0).getLongVersionCode();
|
||||
return (propertyVersion == 0 && defaultEnabled)
|
||||
|| (propertyVersion != 0 && packageVersion >= (long) propertyVersion);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "Could not find the package name", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets boolean config from resources.
|
||||
*/
|
||||
public static boolean getResBooleanConfig(@NonNull final Context context,
|
||||
@BoolRes int configResource, final boolean defaultValue) {
|
||||
final Resources res = context.getResources();
|
||||
try {
|
||||
return res.getBoolean(configResource);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.net.module.util;
|
||||
|
||||
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* Various utilities used in connectivity code.
|
||||
*/
|
||||
public final class ConnectivityUtils {
|
||||
private ConnectivityUtils() {}
|
||||
|
||||
|
||||
/**
|
||||
* Return IP address and port in a string format.
|
||||
*/
|
||||
public static String addressAndPortToString(InetAddress address, int port) {
|
||||
return String.format(
|
||||
(address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d",
|
||||
address.getHostAddress(), port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the provided address is non-null and an IPv6 Unique Local Address (RFC4193).
|
||||
*/
|
||||
public static boolean isIPv6ULA(@Nullable InetAddress addr) {
|
||||
return addr instanceof Inet6Address
|
||||
&& ((addr.getAddress()[0] & 0xfe) == 0xfc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code int} nearest in value to {@code value}.
|
||||
*
|
||||
* @param value any {@code long} value
|
||||
* @return the same value cast to {@code int} if it is in the range of the {@code int}
|
||||
* type, {@link Integer#MAX_VALUE} if it is too large, or {@link Integer#MIN_VALUE} if
|
||||
* it is too small
|
||||
*/
|
||||
public static int saturatedCast(long value) {
|
||||
if (value > Integer.MAX_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
if (value < Integer.MIN_VALUE) {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
return (int) value;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ android_library {
|
|||
static_libs: [
|
||||
"net-utils-framework-common",
|
||||
"androidx.test.rules",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
"net-utils-device-common",
|
||||
"net-tests-utils-host-device-common",
|
||||
],
|
||||
|
|
@ -29,6 +30,11 @@ android_test {
|
|||
static_libs: [
|
||||
"NetworkStaticLibTestsLib",
|
||||
],
|
||||
jni_libs: [
|
||||
// For mockito extended
|
||||
"libdexmakerjvmtiagent",
|
||||
"libstaticjvmtiagent",
|
||||
],
|
||||
jarjar_rules: "jarjar-rules.txt",
|
||||
test_suites: ["device-tests"],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application>
|
||||
<application android:debuggable="true">
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.net.module.util;
|
||||
|
||||
import static android.net.InetAddresses.parseNumericAddress;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** Tests for ConnectivityUtils */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class ConnectivityUtilsTest {
|
||||
@Test
|
||||
public void testIsIPv6ULA() {
|
||||
assertTrue(isIPv6ULA(parseNumericAddress("fc00::")));
|
||||
assertTrue(isIPv6ULA(parseNumericAddress("fc00::1")));
|
||||
assertTrue(isIPv6ULA(parseNumericAddress("fc00:1234::5678")));
|
||||
assertTrue(isIPv6ULA(parseNumericAddress("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
|
||||
|
||||
assertFalse(isIPv6ULA(parseNumericAddress("fe00::")));
|
||||
assertFalse(isIPv6ULA(parseNumericAddress("2480:1248::123:456")));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* 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.net.module.util;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.eq;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Resources;
|
||||
import android.provider.DeviceConfig;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
|
||||
/**
|
||||
* Tests for DeviceConfigUtils.
|
||||
*
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class DeviceConfigUtilsTest {
|
||||
private static final String TEST_NAME_SPACE = "connectivity";
|
||||
private static final String TEST_EXPERIMENT_FLAG = "experiment_flag";
|
||||
private static final int TEST_FLAG_VALUE = 28;
|
||||
private static final String TEST_FLAG_VALUE_STRING = "28";
|
||||
private static final int TEST_DEFAULT_FLAG_VALUE = 0;
|
||||
private static final int TEST_MAX_FLAG_VALUE = 1000;
|
||||
private static final int TEST_MIN_FLAG_VALUE = 100;
|
||||
private static final long TEST_PACKAGE_VERSION = 290000000;
|
||||
private static final String TEST_PACKAGE_NAME = "test.package.name";
|
||||
private MockitoSession mSession;
|
||||
|
||||
@Mock private Context mContext;
|
||||
@Mock private PackageManager mPm;
|
||||
@Mock private PackageInfo mPi;
|
||||
@Mock private Resources mResources;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mSession = mockitoSession().spyStatic(DeviceConfig.class).startMocking();
|
||||
|
||||
final PackageInfo pi = new PackageInfo();
|
||||
pi.setLongVersionCode(TEST_PACKAGE_VERSION);
|
||||
|
||||
doReturn(mPm).when(mContext).getPackageManager();
|
||||
doReturn(TEST_PACKAGE_NAME).when(mContext).getPackageName();
|
||||
doReturn(pi).when(mPm).getPackageInfo(anyString(), anyInt());
|
||||
doReturn(mResources).when(mContext).getResources();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mSession.finishMocking();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDeviceConfigPropertyInt_Null() {
|
||||
doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
|
||||
eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertEquals(TEST_DEFAULT_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt(
|
||||
TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG,
|
||||
TEST_DEFAULT_FLAG_VALUE /* default value */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDeviceConfigPropertyInt_NotNull() {
|
||||
doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
|
||||
eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertEquals(TEST_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt(
|
||||
TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG,
|
||||
TEST_DEFAULT_FLAG_VALUE /* default value */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDeviceConfigPropertyInt_NormalValue() {
|
||||
doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
|
||||
eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertEquals(TEST_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt(
|
||||
TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, 0 /* minimum value */,
|
||||
TEST_MAX_FLAG_VALUE /* maximum value */,
|
||||
TEST_DEFAULT_FLAG_VALUE /* default value */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDeviceConfigPropertyInt_NullValue() {
|
||||
doReturn(null).when(() -> DeviceConfig.getProperty(
|
||||
eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertEquals(TEST_DEFAULT_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt(
|
||||
TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, 0 /* minimum value */,
|
||||
TEST_MAX_FLAG_VALUE /* maximum value */,
|
||||
TEST_DEFAULT_FLAG_VALUE /* default value */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDeviceConfigPropertyInt_OverMaximumValue() {
|
||||
doReturn(Integer.toString(TEST_MAX_FLAG_VALUE + 10)).when(() -> DeviceConfig.getProperty(
|
||||
eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertEquals(TEST_DEFAULT_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt(
|
||||
TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_MIN_FLAG_VALUE /* minimum value */,
|
||||
TEST_MAX_FLAG_VALUE /* maximum value */,
|
||||
TEST_DEFAULT_FLAG_VALUE /* default value */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDeviceConfigPropertyInt_BelowMinimumValue() {
|
||||
doReturn(Integer.toString(TEST_MIN_FLAG_VALUE - 10)).when(() -> DeviceConfig.getProperty(
|
||||
eq(TEST_NAME_SPACE), eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertEquals(TEST_DEFAULT_FLAG_VALUE, DeviceConfigUtils.getDeviceConfigPropertyInt(
|
||||
TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG, TEST_MIN_FLAG_VALUE /* minimum value */,
|
||||
TEST_MAX_FLAG_VALUE /* maximum value */,
|
||||
TEST_DEFAULT_FLAG_VALUE /* default value */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDeviceConfigPropertyBoolean_Null() {
|
||||
doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
|
||||
eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertFalse(DeviceConfigUtils.getDeviceConfigPropertyBoolean(
|
||||
TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG,
|
||||
false /* default value */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDeviceConfigPropertyBoolean_NotNull() {
|
||||
doReturn("true").when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
|
||||
eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertTrue(DeviceConfigUtils.getDeviceConfigPropertyBoolean(
|
||||
TEST_NAME_SPACE, TEST_EXPERIMENT_FLAG,
|
||||
false /* default value */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeatureIsEnabledWithExceptionsEnabled() {
|
||||
doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
|
||||
eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertTrue(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
|
||||
TEST_EXPERIMENT_FLAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeatureIsNotEnabled() {
|
||||
doReturn(null).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
|
||||
eq(TEST_EXPERIMENT_FLAG)));
|
||||
assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
|
||||
TEST_EXPERIMENT_FLAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeatureIsEnabledWithException() throws Exception {
|
||||
doReturn(TEST_FLAG_VALUE_STRING).when(() -> DeviceConfig.getProperty(eq(TEST_NAME_SPACE),
|
||||
eq(TEST_EXPERIMENT_FLAG)));
|
||||
doThrow(NameNotFoundException.class).when(mPm).getPackageInfo(anyString(), anyInt());
|
||||
assertFalse(DeviceConfigUtils.isFeatureEnabled(mContext, TEST_NAME_SPACE,
|
||||
TEST_EXPERIMENT_FLAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetResBooleanConfig() {
|
||||
final int someResId = 1234;
|
||||
doReturn(true).when(mResources).getBoolean(someResId);
|
||||
assertTrue(DeviceConfigUtils.getResBooleanConfig(mContext, someResId, false));
|
||||
doReturn(false).when(mResources).getBoolean(someResId);
|
||||
assertFalse(DeviceConfigUtils.getResBooleanConfig(mContext, someResId, false));
|
||||
doThrow(new Resources.NotFoundException()).when(mResources).getBoolean(someResId);
|
||||
assertFalse(DeviceConfigUtils.getResBooleanConfig(mContext, someResId, false));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue