Merge "Enable Int and String flags." into tm-qpr-dev
This commit is contained in:
@@ -24,6 +24,7 @@ private const val FIELD_VALUE = "value"
|
|||||||
private const val FIELD_TYPE = "type"
|
private const val FIELD_TYPE = "type"
|
||||||
private const val TYPE_BOOLEAN = "boolean"
|
private const val TYPE_BOOLEAN = "boolean"
|
||||||
private const val TYPE_STRING = "string"
|
private const val TYPE_STRING = "string"
|
||||||
|
private const val TYPE_INT = "int"
|
||||||
|
|
||||||
private const val TAG = "FlagSerializer"
|
private const val TAG = "FlagSerializer"
|
||||||
|
|
||||||
@@ -77,4 +78,10 @@ object StringFlagSerializer : FlagSerializer<String>(
|
|||||||
JSONObject::getString
|
JSONObject::getString
|
||||||
)
|
)
|
||||||
|
|
||||||
|
object IntFlagSerializer : FlagSerializer<Int>(
|
||||||
|
TYPE_INT,
|
||||||
|
JSONObject::put,
|
||||||
|
JSONObject::getInt
|
||||||
|
)
|
||||||
|
|
||||||
class InvalidFlagStorageException : Exception("Data found but is invalid")
|
class InvalidFlagStorageException : Exception("Data found but is invalid")
|
||||||
|
|||||||
@@ -44,4 +44,10 @@ interface FeatureFlags : FlagListenable, Dumpable {
|
|||||||
|
|
||||||
/** Returns a string value for the given flag. */
|
/** Returns a string value for the given flag. */
|
||||||
fun getString(flag: ResourceStringFlag): String
|
fun getString(flag: ResourceStringFlag): String
|
||||||
|
|
||||||
|
/** Returns an int value for a given flag/ */
|
||||||
|
fun getInt(flag: IntFlag): Int
|
||||||
|
|
||||||
|
/** Returns an int value for a given flag/ */
|
||||||
|
fun getInt(flag: ResourceIntFlag): Int
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
|||||||
private final Map<Integer, Flag<?>> mAllFlags;
|
private final Map<Integer, Flag<?>> mAllFlags;
|
||||||
private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
|
private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
|
||||||
private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
|
private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
|
||||||
|
private final Map<Integer, Integer> mIntFlagCache = new TreeMap<>();
|
||||||
private final Restarter mRestarter;
|
private final Restarter mRestarter;
|
||||||
|
|
||||||
private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
|
private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
|
||||||
@@ -209,6 +210,31 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
|||||||
return mStringFlagCache.get(id);
|
return mStringFlagCache.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public int getInt(@NonNull IntFlag flag) {
|
||||||
|
int id = flag.getId();
|
||||||
|
if (!mIntFlagCache.containsKey(id)) {
|
||||||
|
mIntFlagCache.put(id,
|
||||||
|
readFlagValue(id, flag.getDefault(), IntFlagSerializer.INSTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mIntFlagCache.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public int getInt(@NonNull ResourceIntFlag flag) {
|
||||||
|
int id = flag.getId();
|
||||||
|
if (!mIntFlagCache.containsKey(id)) {
|
||||||
|
mIntFlagCache.put(id,
|
||||||
|
readFlagValue(id, mResources.getInteger(flag.getResourceId()),
|
||||||
|
IntFlagSerializer.INSTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mIntFlagCache.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
/** Specific override for Boolean flags that checks against the teamfood list. */
|
/** Specific override for Boolean flags that checks against the teamfood list. */
|
||||||
private boolean readFlagValue(int id, boolean defaultValue) {
|
private boolean readFlagValue(int id, boolean defaultValue) {
|
||||||
Boolean result = readBooleanFlagOverride(id);
|
Boolean result = readBooleanFlagOverride(id);
|
||||||
@@ -351,6 +377,16 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setIntFlagInternal(Flag<?> flag, int value) {
|
||||||
|
if (flag instanceof IntFlag) {
|
||||||
|
setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE);
|
||||||
|
} else if (flag instanceof ResourceIntFlag) {
|
||||||
|
setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown flag type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
|||||||
@@ -165,6 +165,18 @@ public class FeatureFlagsRelease implements FeatureFlags {
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public int getInt(@NonNull IntFlag flag) {
|
||||||
|
return flag.getDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public int getInt(@NonNull ResourceIntFlag flag) {
|
||||||
|
return mResources.getInteger(flag.getResourceId());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
|
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
|
||||||
pw.println("can override: false");
|
pw.println("can override: false");
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public class FlagCommand implements Command {
|
|||||||
|
|
||||||
private final List<String> mOnCommands = List.of("true", "on", "1", "enabled");
|
private final List<String> mOnCommands = List.of("true", "on", "1", "enabled");
|
||||||
private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
|
private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
|
||||||
|
private final List<String> mSetCommands = List.of("set", "put");
|
||||||
private final FeatureFlagsDebug mFeatureFlags;
|
private final FeatureFlagsDebug mFeatureFlags;
|
||||||
private final Map<Integer, Flag<?>> mAllFlags;
|
private final Map<Integer, Flag<?>> mAllFlags;
|
||||||
|
|
||||||
@@ -60,12 +61,6 @@ public class FlagCommand implements Command {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.size() > 2) {
|
|
||||||
pw.println("Invalid number of arguments.");
|
|
||||||
help(pw);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int id = 0;
|
int id = 0;
|
||||||
try {
|
try {
|
||||||
id = Integer.parseInt(args.get(0));
|
id = Integer.parseInt(args.get(0));
|
||||||
@@ -85,48 +80,113 @@ public class FlagCommand implements Command {
|
|||||||
Flag<?> flag = mAllFlags.get(id);
|
Flag<?> flag = mAllFlags.get(id);
|
||||||
|
|
||||||
String cmd = "";
|
String cmd = "";
|
||||||
if (args.size() == 2) {
|
if (args.size() > 1) {
|
||||||
cmd = args.get(1).toLowerCase();
|
cmd = args.get(1).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("erase".equals(cmd) || "reset".equals(cmd)) {
|
if ("erase".equals(cmd) || "reset".equals(cmd)) {
|
||||||
|
if (args.size() > 2) {
|
||||||
|
pw.println("Invalid number of arguments to reset a flag.");
|
||||||
|
help(pw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mFeatureFlags.eraseFlag(flag);
|
mFeatureFlags.eraseFlag(flag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean newValue = true;
|
boolean shouldSet = true;
|
||||||
if (args.size() == 1 || "toggle".equals(cmd)) {
|
if (args.size() == 1) {
|
||||||
boolean enabled = isBooleanFlagEnabled(flag);
|
shouldSet = false;
|
||||||
|
}
|
||||||
if (args.size() == 1) {
|
if (isBooleanFlag(flag)) {
|
||||||
pw.println("Flag " + id + " is " + enabled);
|
if (args.size() > 2) {
|
||||||
|
pw.println("Invalid number of arguments for a boolean flag.");
|
||||||
|
help(pw);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
boolean newValue = isBooleanFlagEnabled(flag);
|
||||||
newValue = !enabled;
|
if ("toggle".equals(cmd)) {
|
||||||
} else {
|
newValue = !newValue;
|
||||||
newValue = mOnCommands.contains(cmd);
|
} else if (mOnCommands.contains(cmd)) {
|
||||||
if (!newValue && !mOffCommands.contains(cmd)) {
|
newValue = true;
|
||||||
|
} else if (mOffCommands.contains(cmd)) {
|
||||||
|
newValue = false;
|
||||||
|
} else if (shouldSet) {
|
||||||
pw.println("Invalid on/off argument supplied");
|
pw.println("Invalid on/off argument supplied");
|
||||||
help(pw);
|
help(pw);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pw.flush(); // Next command will restart sysui, so flush before we do so.
|
pw.println("Flag " + id + " is " + newValue);
|
||||||
mFeatureFlags.setBooleanFlagInternal(flag, newValue);
|
pw.flush(); // Next command will restart sysui, so flush before we do so.
|
||||||
|
if (shouldSet) {
|
||||||
|
mFeatureFlags.setBooleanFlagInternal(flag, newValue);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if (isStringFlag(flag)) {
|
||||||
|
if (shouldSet) {
|
||||||
|
if (args.size() != 3) {
|
||||||
|
pw.println("Invalid number of arguments a StringFlag.");
|
||||||
|
help(pw);
|
||||||
|
return;
|
||||||
|
} else if (!mSetCommands.contains(cmd)) {
|
||||||
|
pw.println("Unknown command: " + cmd);
|
||||||
|
help(pw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String value = args.get(2);
|
||||||
|
pw.println("Setting Flag " + id + " to " + value);
|
||||||
|
pw.flush(); // Next command will restart sysui, so flush before we do so.
|
||||||
|
mFeatureFlags.setStringFlagInternal(flag, args.get(2));
|
||||||
|
} else {
|
||||||
|
pw.println("Flag " + id + " is " + getStringFlag(flag));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (isIntFlag(flag)) {
|
||||||
|
if (shouldSet) {
|
||||||
|
if (args.size() != 3) {
|
||||||
|
pw.println("Invalid number of arguments for an IntFlag.");
|
||||||
|
help(pw);
|
||||||
|
return;
|
||||||
|
} else if (!mSetCommands.contains(cmd)) {
|
||||||
|
pw.println("Unknown command: " + cmd);
|
||||||
|
help(pw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int value = Integer.parseInt(args.get(2));
|
||||||
|
pw.println("Setting Flag " + id + " to " + value);
|
||||||
|
pw.flush(); // Next command will restart sysui, so flush before we do so.
|
||||||
|
mFeatureFlags.setIntFlagInternal(flag, value);
|
||||||
|
} else {
|
||||||
|
pw.println("Flag " + id + " is " + getIntFlag(flag));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void help(PrintWriter pw) {
|
public void help(PrintWriter pw) {
|
||||||
pw.println(
|
pw.println("Usage: adb shell cmd statusbar flag <id> [options]");
|
||||||
"Usage: adb shell cmd statusbar flag <id> "
|
pw.println();
|
||||||
|
pw.println(" Boolean Flag Options: "
|
||||||
+ "[true|false|1|0|on|off|enable|disable|toggle|erase|reset]");
|
+ "[true|false|1|0|on|off|enable|disable|toggle|erase|reset]");
|
||||||
|
pw.println(" String Flag Options: [set|put \"<value>\"]");
|
||||||
|
pw.println(" Int Flag Options: [set|put <value>]");
|
||||||
|
pw.println();
|
||||||
pw.println("The id can either be a numeric integer or the corresponding field name");
|
pw.println("The id can either be a numeric integer or the corresponding field name");
|
||||||
pw.println(
|
pw.println(
|
||||||
"If no argument is supplied after the id, the flags runtime value is output");
|
"If no argument is supplied after the id, the flags runtime value is output");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isBooleanFlag(Flag<?> flag) {
|
||||||
|
return (flag instanceof BooleanFlag)
|
||||||
|
|| (flag instanceof ResourceBooleanFlag)
|
||||||
|
|| (flag instanceof SysPropFlag)
|
||||||
|
|| (flag instanceof DeviceConfigBooleanFlag);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isBooleanFlagEnabled(Flag<?> flag) {
|
private boolean isBooleanFlagEnabled(Flag<?> flag) {
|
||||||
if (flag instanceof ReleasedFlag) {
|
if (flag instanceof ReleasedFlag) {
|
||||||
return mFeatureFlags.isEnabled((ReleasedFlag) flag);
|
return mFeatureFlags.isEnabled((ReleasedFlag) flag);
|
||||||
@@ -141,6 +201,34 @@ public class FlagCommand implements Command {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isStringFlag(Flag<?> flag) {
|
||||||
|
return (flag instanceof StringFlag) || (flag instanceof ResourceStringFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStringFlag(Flag<?> flag) {
|
||||||
|
if (flag instanceof StringFlag) {
|
||||||
|
return mFeatureFlags.getString((StringFlag) flag);
|
||||||
|
} else if (flag instanceof ResourceStringFlag) {
|
||||||
|
return mFeatureFlags.getString((ResourceStringFlag) flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIntFlag(Flag<?> flag) {
|
||||||
|
return (flag instanceof IntFlag) || (flag instanceof ResourceIntFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getIntFlag(Flag<?> flag) {
|
||||||
|
if (flag instanceof IntFlag) {
|
||||||
|
return mFeatureFlags.getInt((IntFlag) flag);
|
||||||
|
} else if (flag instanceof ResourceIntFlag) {
|
||||||
|
return mFeatureFlags.getInt((ResourceIntFlag) flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private int flagNameToId(String flagName) {
|
private int flagNameToId(String flagName) {
|
||||||
List<Field> fields = Flags.getFlagFields();
|
List<Field> fields = Flags.getFlagFields();
|
||||||
for (Field field : fields) {
|
for (Field field : fields) {
|
||||||
@@ -176,13 +264,15 @@ public class FlagCommand implements Command {
|
|||||||
for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) {
|
for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) {
|
||||||
pw.print(" ");
|
pw.print(" ");
|
||||||
}
|
}
|
||||||
pw.println("ID Enabled?");
|
pw.println("ID Value");
|
||||||
for (int i = 0; i < longestFieldName; i++) {
|
for (int i = 0; i < longestFieldName; i++) {
|
||||||
pw.print("=");
|
pw.print("=");
|
||||||
}
|
}
|
||||||
pw.println(" ==== ========");
|
pw.println(" ==== =====");
|
||||||
for (Field field : fields) {
|
for (Field field : fields) {
|
||||||
int id = fieldToId(field);
|
int id = fieldToId(field);
|
||||||
|
Flag<?> flag = mAllFlags.get(id);
|
||||||
|
|
||||||
if (id == 0 || !mAllFlags.containsKey(id)) {
|
if (id == 0 || !mAllFlags.containsKey(id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -192,7 +282,15 @@ public class FlagCommand implements Command {
|
|||||||
pw.print(" ");
|
pw.print(" ");
|
||||||
}
|
}
|
||||||
pw.printf("%-4d ", id);
|
pw.printf("%-4d ", id);
|
||||||
pw.println(isBooleanFlagEnabled(mAllFlags.get(id)));
|
if (isBooleanFlag(flag)) {
|
||||||
|
pw.println(isBooleanFlagEnabled(mAllFlags.get(id)));
|
||||||
|
} else if (isStringFlag(flag)) {
|
||||||
|
pw.println(getStringFlag(flag));
|
||||||
|
} else if (isIntFlag(flag)) {
|
||||||
|
pw.println(getIntFlag(flag));
|
||||||
|
} else {
|
||||||
|
pw.println("<unknown flag type>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager.NameNotFoundException
|
import android.content.pm.PackageManager.NameNotFoundException
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
import android.content.res.Resources.NotFoundException
|
||||||
import android.test.suitebuilder.annotation.SmallTest
|
import android.test.suitebuilder.annotation.SmallTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.statusbar.commandline.CommandRegistry
|
import com.android.systemui.statusbar.commandline.CommandRegistry
|
||||||
@@ -245,6 +246,43 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun readIntFlag() {
|
||||||
|
whenever(flagManager.readFlagValue<Int>(eq(3), any())).thenReturn(22)
|
||||||
|
whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(48)
|
||||||
|
assertThat(mFeatureFlagsDebug.getInt(IntFlag(1, 12))).isEqualTo(12)
|
||||||
|
assertThat(mFeatureFlagsDebug.getInt(IntFlag(2, 93))).isEqualTo(93)
|
||||||
|
assertThat(mFeatureFlagsDebug.getInt(IntFlag(3, 8))).isEqualTo(22)
|
||||||
|
assertThat(mFeatureFlagsDebug.getInt(IntFlag(4, 234))).isEqualTo(48)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun readResourceIntFlag() {
|
||||||
|
whenever(resources.getInteger(1001)).thenReturn(88)
|
||||||
|
whenever(resources.getInteger(1002)).thenReturn(61)
|
||||||
|
whenever(resources.getInteger(1003)).thenReturn(9342)
|
||||||
|
whenever(resources.getInteger(1004)).thenThrow(NotFoundException("unknown resource"))
|
||||||
|
whenever(resources.getInteger(1005)).thenThrow(NotFoundException("unknown resource"))
|
||||||
|
whenever(resources.getInteger(1006)).thenThrow(NotFoundException("unknown resource"))
|
||||||
|
|
||||||
|
whenever(flagManager.readFlagValue<Int>(eq(3), any())).thenReturn(20)
|
||||||
|
whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(500)
|
||||||
|
whenever(flagManager.readFlagValue<Int>(eq(5), any())).thenReturn(9519)
|
||||||
|
|
||||||
|
assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(1, 1001))).isEqualTo(88)
|
||||||
|
assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(2, 1002))).isEqualTo(61)
|
||||||
|
assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(3, 1003))).isEqualTo(20)
|
||||||
|
|
||||||
|
Assert.assertThrows(NotFoundException::class.java) {
|
||||||
|
mFeatureFlagsDebug.getInt(ResourceIntFlag(4, 1004))
|
||||||
|
}
|
||||||
|
// Test that resource is loaded (and validated) even when the setting is set.
|
||||||
|
// This prevents developers from not noticing when they reference an invalid resource.
|
||||||
|
Assert.assertThrows(NotFoundException::class.java) {
|
||||||
|
mFeatureFlagsDebug.getInt(ResourceIntFlag(5, 1005))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun broadcastReceiver_IgnoresInvalidData() {
|
fun broadcastReceiver_IgnoresInvalidData() {
|
||||||
addFlag(UnreleasedFlag(1))
|
addFlag(UnreleasedFlag(1))
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ class FlagCommandTest : SysuiTestCase() {
|
|||||||
private val flagMap = mutableMapOf<Int, Flag<*>>()
|
private val flagMap = mutableMapOf<Int, Flag<*>>()
|
||||||
private val flagA = UnreleasedFlag(500)
|
private val flagA = UnreleasedFlag(500)
|
||||||
private val flagB = ReleasedFlag(501)
|
private val flagB = ReleasedFlag(501)
|
||||||
|
private val stringFlag = StringFlag(502, "abracadabra")
|
||||||
|
private val intFlag = IntFlag(503, 12)
|
||||||
|
|
||||||
private lateinit var cmd: FlagCommand
|
private lateinit var cmd: FlagCommand
|
||||||
|
|
||||||
@@ -44,26 +46,59 @@ class FlagCommandTest : SysuiTestCase() {
|
|||||||
|
|
||||||
whenever(featureFlags.isEnabled(any(UnreleasedFlag::class.java))).thenReturn(false)
|
whenever(featureFlags.isEnabled(any(UnreleasedFlag::class.java))).thenReturn(false)
|
||||||
whenever(featureFlags.isEnabled(any(ReleasedFlag::class.java))).thenReturn(true)
|
whenever(featureFlags.isEnabled(any(ReleasedFlag::class.java))).thenReturn(true)
|
||||||
|
whenever(featureFlags.getString(any(StringFlag::class.java))).thenAnswer { invocation ->
|
||||||
|
(invocation.getArgument(0) as StringFlag).default
|
||||||
|
}
|
||||||
|
whenever(featureFlags.getInt(any(IntFlag::class.java))).thenAnswer { invocation ->
|
||||||
|
(invocation.getArgument(0) as IntFlag).default
|
||||||
|
}
|
||||||
|
|
||||||
flagMap.put(flagA.id, flagA)
|
flagMap.put(flagA.id, flagA)
|
||||||
flagMap.put(flagB.id, flagB)
|
flagMap.put(flagB.id, flagB)
|
||||||
|
flagMap.put(stringFlag.id, stringFlag)
|
||||||
|
flagMap.put(intFlag.id, intFlag)
|
||||||
|
|
||||||
cmd = FlagCommand(featureFlags, flagMap)
|
cmd = FlagCommand(featureFlags, flagMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun readFlagCommand() {
|
fun readBooleanFlagCommand() {
|
||||||
cmd.execute(pw, listOf(flagA.id.toString()))
|
cmd.execute(pw, listOf(flagA.id.toString()))
|
||||||
Mockito.verify(featureFlags).isEnabled(flagA)
|
Mockito.verify(featureFlags).isEnabled(flagA)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setFlagCommand() {
|
fun readStringFlagCommand() {
|
||||||
|
cmd.execute(pw, listOf(stringFlag.id.toString()))
|
||||||
|
Mockito.verify(featureFlags).getString(stringFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun readIntFlag() {
|
||||||
|
cmd.execute(pw, listOf(intFlag.id.toString()))
|
||||||
|
Mockito.verify(featureFlags).getInt(intFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setBooleanFlagCommand() {
|
||||||
cmd.execute(pw, listOf(flagB.id.toString(), "on"))
|
cmd.execute(pw, listOf(flagB.id.toString(), "on"))
|
||||||
Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, true)
|
Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun toggleFlagCommand() {
|
fun setStringFlagCommand() {
|
||||||
|
cmd.execute(pw, listOf(stringFlag.id.toString(), "set", "foobar"))
|
||||||
|
Mockito.verify(featureFlags).setStringFlagInternal(stringFlag, "foobar")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun setIntFlag() {
|
||||||
|
cmd.execute(pw, listOf(intFlag.id.toString(), "put", "123"))
|
||||||
|
Mockito.verify(featureFlags).setIntFlagInternal(intFlag, 123)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toggleBooleanFlagCommand() {
|
||||||
cmd.execute(pw, listOf(flagB.id.toString(), "toggle"))
|
cmd.execute(pw, listOf(flagB.id.toString(), "toggle"))
|
||||||
Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, false)
|
Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import java.io.PrintWriter
|
|||||||
class FakeFeatureFlags : FeatureFlags {
|
class FakeFeatureFlags : FeatureFlags {
|
||||||
private val booleanFlags = mutableMapOf<Int, Boolean>()
|
private val booleanFlags = mutableMapOf<Int, Boolean>()
|
||||||
private val stringFlags = mutableMapOf<Int, String>()
|
private val stringFlags = mutableMapOf<Int, String>()
|
||||||
|
private val intFlags = mutableMapOf<Int, Int>()
|
||||||
private val knownFlagNames = mutableMapOf<Int, String>()
|
private val knownFlagNames = mutableMapOf<Int, String>()
|
||||||
private val flagListeners = mutableMapOf<Int, MutableSet<FlagListenable.Listener>>()
|
private val flagListeners = mutableMapOf<Int, MutableSet<FlagListenable.Listener>>()
|
||||||
private val listenerFlagIds = mutableMapOf<FlagListenable.Listener, MutableSet<Int>>()
|
private val listenerFlagIds = mutableMapOf<FlagListenable.Listener, MutableSet<Int>>()
|
||||||
@@ -95,6 +96,10 @@ class FakeFeatureFlags : FeatureFlags {
|
|||||||
|
|
||||||
override fun getString(flag: ResourceStringFlag): String = requireStringValue(flag.id)
|
override fun getString(flag: ResourceStringFlag): String = requireStringValue(flag.id)
|
||||||
|
|
||||||
|
override fun getInt(flag: IntFlag): Int = requireIntValue(flag.id)
|
||||||
|
|
||||||
|
override fun getInt(flag: ResourceIntFlag): Int = requireIntValue(flag.id)
|
||||||
|
|
||||||
override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) {
|
override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) {
|
||||||
flagListeners.getOrPut(flag.id) { mutableSetOf() }.add(listener)
|
flagListeners.getOrPut(flag.id) { mutableSetOf() }.add(listener)
|
||||||
listenerFlagIds.getOrPut(listener) { mutableSetOf() }.add(flag.id)
|
listenerFlagIds.getOrPut(listener) { mutableSetOf() }.add(flag.id)
|
||||||
@@ -118,11 +123,16 @@ class FakeFeatureFlags : FeatureFlags {
|
|||||||
|
|
||||||
private fun requireBooleanValue(flagId: Int): Boolean {
|
private fun requireBooleanValue(flagId: Int): Boolean {
|
||||||
return booleanFlags[flagId]
|
return booleanFlags[flagId]
|
||||||
?: error("Flag ${flagName(flagId)} was accessed but not specified.")
|
?: error("Flag ${flagName(flagId)} was accessed as boolean but not specified.")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requireStringValue(flagId: Int): String {
|
private fun requireStringValue(flagId: Int): String {
|
||||||
return stringFlags[flagId]
|
return stringFlags[flagId]
|
||||||
?: error("Flag ${flagName(flagId)} was accessed but not specified.")
|
?: error("Flag ${flagName(flagId)} was accessed as string but not specified.")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requireIntValue(flagId: Int): Int {
|
||||||
|
return intFlags[flagId]
|
||||||
|
?: error("Flag ${flagName(flagId)} was accessed as int but not specified.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user