// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.base.cached_flags;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.chromium.base.test.util.BaseFlagTestRule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.FeatureList;
import org.chromium.base.FeatureList.TestValues;
import org.chromium.base.FeatureMap;
import org.chromium.base.task.test.PausedExecutorTestRule;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.cached_flags.CachedFlagsSafeMode.Behavior;
import java.util.Arrays;
/** Unit Tests for {@link CachedFlagsSafeMode}, the Safe Mode mechanism for {@link CachedFlag}. */
@RunWith(BaseRobolectricTestRunner.class)
public class CachedFeatureFlagsSafeModeUnitTest {
@Rule public PausedExecutorTestRule mExecutorRule = new PausedExecutorTestRule();
private static final FeatureMap FEATURE_MAP = BaseFlagTestRule.FEATURE_MAP;
private static final String CRASHY_FEATURE = "CrashyFeature";
private static final String OK_FEATURE = "OkFeature";
private static final boolean CRASHY_FEATURE_DEFAULT = false;
private static final boolean OK_FEATURE_DEFAULT = false;
private static final CachedFlag sCrashyFeature =
new CachedFlag(FEATURE_MAP, CRASHY_FEATURE, CRASHY_FEATURE_DEFAULT);
private static final CachedFlag sOkFeature =
new CachedFlag(FEATURE_MAP, OK_FEATURE, OK_FEATURE_DEFAULT);
private static final String BOOL_PARAM_NAME = "BoolParam";
private static final String INT_PARAM_NAME = "IntParam";
private static final String DOUBLE_PARAM_NAME = "DoubleParam";
private static final String STRING_PARAM_NAME = "StringParam";
private static final boolean BOOL_PARAM_DEFAULT = false;
private static final int INT_PARAM_DEFAULT = 111;
private static final double DOUBLE_PARAM_DEFAULT = 55.5;
private static final String STRING_PARAM_DEFAULT = "foo";
private static final boolean BOOL_PARAM_NATIVE_1 = false;
private static final int INT_PARAM_NATIVE_1 = 222;
private static final double DOUBLE_PARAM_NATIVE_1 = 66.5;
private static final String STRING_PARAM_NATIVE_1 = "bar";
private static final boolean BOOL_PARAM_NATIVE_2 = true;
private static final int INT_PARAM_NATIVE_2 = 333;
private static final double DOUBLE_PARAM_NATIVE_2 = 77.5;
private static final String STRING_PARAM_NATIVE_2 = "baz";
private static final BooleanCachedFieldTrialParameter BOOL_PARAM =
new BooleanCachedFieldTrialParameter(
FEATURE_MAP, OK_FEATURE, BOOL_PARAM_NAME, BOOL_PARAM_DEFAULT);
private static final IntCachedFieldTrialParameter INT_PARAM =
new IntCachedFieldTrialParameter(
FEATURE_MAP, OK_FEATURE, INT_PARAM_NAME, INT_PARAM_DEFAULT);
private static final DoubleCachedFieldTrialParameter DOUBLE_PARAM =
new DoubleCachedFieldTrialParameter(
FEATURE_MAP, OK_FEATURE, DOUBLE_PARAM_NAME, DOUBLE_PARAM_DEFAULT);
private static final StringCachedFieldTrialParameter STRING_PARAM =
new StringCachedFieldTrialParameter(
FEATURE_MAP, OK_FEATURE, STRING_PARAM_NAME, STRING_PARAM_DEFAULT);
@Before
public void setUp() {
CachedFlagsSafeMode.getInstance().enableForTesting();
clearMemory();
}
@After
public void tearDown() {
FeatureList.setTestFeatures(null);
clearMemory();
}
@Test
public void testTwoCrashesInARow_engageSafeMode() {
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// There are no safe values.
// There are no cached values, so the defaults false/false/defaults are used.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertEquals(CRASHY_FEATURE_DEFAULT, sCrashyFeature.isEnabled());
assertEquals(OK_FEATURE_DEFAULT, sOkFeature.isEnabled());
assertCachedParamsEqualDefaults();
endCleanRun(
false,
true,
BOOL_PARAM_NATIVE_1,
INT_PARAM_NATIVE_1,
DOUBLE_PARAM_NATIVE_1,
STRING_PARAM_NATIVE_1);
// Safe values became false/false/defaults.
// Cached values became false/true/native1.
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// Safe values are false/false/defaults.
// Cached values are false/true/native1, from previous run.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertFalse(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative1();
endCleanRun(
true,
true,
BOOL_PARAM_NATIVE_2,
INT_PARAM_NATIVE_2,
DOUBLE_PARAM_NATIVE_2,
STRING_PARAM_NATIVE_2);
// Safe values became false/true/native1.
// Cached values became true(crashy)/true/native2.
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// Safe values are false/true/native1.
// Cached values remain true(crashy)/true/native2 and are used.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative2();
endCrashyRun();
// Cached values remain true(crashy)/true/native2.
startRun();
// Crash streak is 1. Do not engage Safe Mode.
// Safe values are false/true/native1.
// Cached values remain true(crashy)/true/native2 and are used.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative2();
endCrashyRun();
// Cached values remain true(crashy)/true/native2.
startRun();
// Crash streak is 2. Engage Safe Mode.
// Safe values are false/true/native1, and are used during this run.
// Cached values remain true(crashy)/true/native2, but are not used because Safe Mode is
// engaged.
assertEquals(
Behavior.ENGAGED_WITH_SAFE_VALUES,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertFalse(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative1();
endCleanRun(
true,
false,
BOOL_PARAM_NATIVE_2,
INT_PARAM_NATIVE_2,
DOUBLE_PARAM_NATIVE_2,
STRING_PARAM_NATIVE_2);
// Cached values became true(crashy)/false/native2, cached from native.
startRun();
// Second run of Safe Mode.
// Safe values are false/true/native1, and are used during this run.
// Cached values true(crashy)/false/native2 are used, cached from native last run, but are
// not used because Safe Mode is engaged.
assertEquals(
Behavior.ENGAGED_WITH_SAFE_VALUES,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertFalse(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative1();
endCleanRun(
false,
false,
BOOL_PARAM_NATIVE_2,
INT_PARAM_NATIVE_2,
DOUBLE_PARAM_NATIVE_2,
STRING_PARAM_NATIVE_2);
// Cached values became false/false/native2, cached from native.
startRun();
// Crash streak is 1. Do not engage Safe Mode.
// Safe values are still false/true/native1.
// Cached values false/false/native2 are used, cached from native last run.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertFalse(sCrashyFeature.isEnabled());
assertFalse(sOkFeature.isEnabled());
assertCachedParamsEqualNative2();
}
@Test
public void testSafeModeFetchesBadConfig_keepsStreak() {
startRun();
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCleanRunCachingIrrelevantValues();
startRun();
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCleanRunCachingIrrelevantValues();
startRun();
// Crash streak is 0. Do not engage Safe Mode.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCrashyRun();
startRun();
// Crash streak is 1. Do not engage Safe Mode.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCrashyRun();
startRun();
// Crash streak is 2. Engage Safe Mode.
assertEquals(
Behavior.ENGAGED_WITH_SAFE_VALUES,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCleanRunCachingIrrelevantValues();
startRun();
// Second run of safe mode.
assertEquals(
Behavior.ENGAGED_WITH_SAFE_VALUES,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCleanRunCachingIrrelevantValues();
startRun();
// Crash streak is 1. Do not engage Safe Mode.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCrashyRun();
startRun();
// Crash streak is back directly to 2. Engage Safe Mode.
assertEquals(
Behavior.ENGAGED_WITH_SAFE_VALUES,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
}
@Test
public void testSafeModeFetchesGoodConfig_decreasesStreak() {
startRun();
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCleanRunCachingIrrelevantValues();
startRun();
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCleanRunCachingIrrelevantValues();
startRun();
// Crash streak is 0. Do not engage Safe Mode.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCrashyRun();
startRun();
// Crash streak is 1. Do not engage Safe Mode.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCrashyRun();
startRun();
// Crash streak is 2. Engage Safe Mode.
assertEquals(
Behavior.ENGAGED_WITH_SAFE_VALUES,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCleanRunCachingIrrelevantValues();
startRun();
// Second run of safe mode.
assertEquals(
Behavior.ENGAGED_WITH_SAFE_VALUES,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCleanRunCachingIrrelevantValues();
startRun();
// Crash streak is 1. Do not engage Safe Mode.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCleanRunCachingIrrelevantValues();
startRun();
// Crash streak is down to 0. Do not engage Safe Mode.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
endCrashyRun();
startRun();
// Crash streak is 1. Do not engage Safe Mode.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
}
@Test
public void testTwoCrashesInterrupted_normalMode() {
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// There are no safe values.
// There are no cached values, so the defaults false/false/defaults are used.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertEquals(CRASHY_FEATURE_DEFAULT, sCrashyFeature.isEnabled());
assertEquals(OK_FEATURE_DEFAULT, sOkFeature.isEnabled());
assertCachedParamsEqualDefaults();
endCleanRun(
true,
true,
BOOL_PARAM_NATIVE_2,
INT_PARAM_NATIVE_2,
DOUBLE_PARAM_NATIVE_2,
STRING_PARAM_NATIVE_2);
// Safe values became false/false/defaults.
// Cached values became true(flaky)/true/native2.
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// Safe values are false/false/defaults.
// Cached values are true(flaky)/true/native2.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative2();
endCrashyRun();
// Cached values remain true(crashy)/true/native2.
startRun();
// Crash streak is 1. Do not engage Safe Mode.
// Safe values are false/false/defaults.
// Cached values are true(flaky)/true/native2.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
// Cached values are the flaky ones cached from native.
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative2();
endCleanRun(
true,
true,
BOOL_PARAM_NATIVE_2,
INT_PARAM_NATIVE_2,
DOUBLE_PARAM_NATIVE_2,
STRING_PARAM_NATIVE_2);
// Safe values became true(flaky)/true/native2.
// Cached values remain true(flaky)/true/native2.
startRun();
// Crash streak is 0, do not engage, use flaky values.
// Safe values are true(flaky)/true/native2.
// Cached values are true(flaky)/true/native2.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative2();
}
/**
* Tests that decrementing the crash streak to account for an aborted run prevents Safe Mode
* from engaging.
*/
@Test
public void testTwoFREs_normalMode() {
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// There are no safe values.
// There are no cached values, so the defaults false/false/defaults are used.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertEquals(CRASHY_FEATURE_DEFAULT, sCrashyFeature.isEnabled());
assertEquals(OK_FEATURE_DEFAULT, sOkFeature.isEnabled());
assertCachedParamsEqualDefaults();
endFirstRunWithKill();
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// There are no safe values.
// There are no cached values, so the defaults false/false/defaults are used.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertEquals(CRASHY_FEATURE_DEFAULT, sCrashyFeature.isEnabled());
assertEquals(OK_FEATURE_DEFAULT, sOkFeature.isEnabled());
assertCachedParamsEqualDefaults();
endFirstRunWithKill();
startRun();
// Crash streak is 0, do not engage, use flaky values.
// There are no safe values.
// There are no cached values, so the defaults false/false/defaults are used.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertEquals(CRASHY_FEATURE_DEFAULT, sCrashyFeature.isEnabled());
assertEquals(OK_FEATURE_DEFAULT, sOkFeature.isEnabled());
assertCachedParamsEqualDefaults();
}
@Test
public void testTwoCrashesInARow_engageSafeModeWithoutSafeValues() {
// Simulate a cache without writing safe values. This happens before Safe Mode was
// implemented and will become rare as clients start writing safe values.
// Cache a crashy value.
FeatureList.TestValues testValues = new TestValues();
testValues.addFeatureFlagOverride(CRASHY_FEATURE, true);
testValues.addFeatureFlagOverride(OK_FEATURE, true);
testValues.addFieldTrialParamOverride(
OK_FEATURE, BOOL_PARAM_NAME, Boolean.toString(BOOL_PARAM_NATIVE_1));
testValues.addFieldTrialParamOverride(
OK_FEATURE, INT_PARAM_NAME, Integer.toString(INT_PARAM_NATIVE_1));
testValues.addFieldTrialParamOverride(
OK_FEATURE, DOUBLE_PARAM_NAME, Double.toString(DOUBLE_PARAM_NATIVE_1));
testValues.addFieldTrialParamOverride(OK_FEATURE, STRING_PARAM_NAME, STRING_PARAM_NATIVE_1);
FeatureList.setTestValues(testValues);
CachedFlagUtils.cacheNativeFlags(Arrays.asList(sCrashyFeature, sOkFeature));
CachedFlagUtils.cacheFieldTrialParameters(
Arrays.asList(BOOL_PARAM, INT_PARAM, DOUBLE_PARAM, STRING_PARAM));
clearMemory();
// Cached values became true(crashy)/true/native1.
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// There are no safe values.
// Cached values are true(crashy)/true/native1.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative1();
endCrashyRun();
// Cached values remain true(crashy)/true/native1.
startRun();
// Crash streak is 1. Do not engage Safe Mode.
// There are no safe values.
// Cached values are true(crashy)/true/native1.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative1();
endCrashyRun();
// Cached values remain true(crashy)/true/native1.
startRun();
// Crash streak is 2. Engage Safe Mode without safe values.
// There are no safe values.
// Cached values are true(crashy)/true/native1, but the default values false/false/defaults
// are returned since Safe Mode is falling back to default.
assertEquals(
Behavior.ENGAGED_WITHOUT_SAFE_VALUES,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertEquals(CRASHY_FEATURE_DEFAULT, sCrashyFeature.isEnabled());
assertEquals(OK_FEATURE_DEFAULT, sOkFeature.isEnabled());
assertCachedParamsEqualDefaults();
}
@Test
public void testTwoCrashesInARow_engageSafeModeIgnoringOutdated() {
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// There are no safe values.
// There are no cached values, so the defaults false/false/defaults are used.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertEquals(CRASHY_FEATURE_DEFAULT, sCrashyFeature.isEnabled());
assertEquals(OK_FEATURE_DEFAULT, sOkFeature.isEnabled());
assertCachedParamsEqualDefaults();
endCleanRun(
false,
true,
BOOL_PARAM_NATIVE_1,
INT_PARAM_NATIVE_1,
DOUBLE_PARAM_NATIVE_1,
STRING_PARAM_NATIVE_1);
// Safe values became false/false/defaults.
// Cached values became false/true/native1.
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// Safe values are false/false/defaults.
// Cached values are false/true/native1, from previous run.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertFalse(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative1();
endCleanRun(
true,
true,
BOOL_PARAM_NATIVE_2,
INT_PARAM_NATIVE_2,
DOUBLE_PARAM_NATIVE_2,
STRING_PARAM_NATIVE_2);
// Safe values became false/true/native1.
// Cached values became true(crashy)/true/native2.
// Pretend safe values are from an older version
CachedFlagsSafeMode.getSafeValuePreferences()
.edit()
.putString(CachedFlagsSafeMode.PREF_SAFE_VALUES_VERSION, "1.0.0.0")
.apply();
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// Safe values are false/true/native1, but from another version.
// Cached values are true(crashy)/true/native2.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative2();
endCrashyRun();
// Cached values remain true(crashy)/true/native2.
startRun();
// Crash streak is 1. Do not engage Safe Mode.
// Safe values are false/true/native1, but from another version.
// Cached values are true(crashy)/true/native2.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative2();
endCrashyRun();
// Cached values remain true(crashy)/true/native2.
startRun();
assertEquals(
Behavior.ENGAGED_IGNORING_OUTDATED_SAFE_VALUES,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
// Crash streak is 2. Engage Safe Mode with obsolete safe values.
// Safe values are false/true/native1, but from another version.
// Cached values are true(crashy)/true/native2, but the default values false/false/defaults
// are returned since Safe Mode is falling back to default.
assertEquals(CRASHY_FEATURE_DEFAULT, sCrashyFeature.isEnabled());
assertEquals(OK_FEATURE_DEFAULT, sOkFeature.isEnabled());
assertCachedParamsEqualDefaults();
}
@Test
public void testMultipleStartCheckpoints_normalMode() {
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// There are no safe values.
// There are no cached values, so the defaults false/false are used.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertFalse(sCrashyFeature.isEnabled());
assertFalse(sOkFeature.isEnabled());
endCleanRun(
true,
true,
BOOL_PARAM_NATIVE_1,
INT_PARAM_NATIVE_1,
DOUBLE_PARAM_NATIVE_1,
STRING_PARAM_NATIVE_1);
// Safe values became false/false/defaults.
// Cached values became true(crashy)/true/native1.
startRun();
startRun();
startRun();
startRun();
// Crash streak is 0. Do not engage Safe Mode.
// Safe values are false/false/defaults.
// Cached values are true(crashy)/true/native1.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
assertTrue(sCrashyFeature.isEnabled());
assertTrue(sOkFeature.isEnabled());
assertCachedParamsEqualNative1();
endCrashyRun();
// Cached values remain true(crashy)/true/native1.
startRun();
// Crash streak is 1, despite the multiple startRun() calls above. Do not engage Safe Mode.
assertEquals(
Behavior.NOT_ENGAGED_BELOW_THRESHOLD,
CachedFlagsSafeMode.getInstance().getBehaviorForTesting());
}
private void startRun() {
// Enter safe mode or not before the start checkpoint, since that's what happens and should
// be supported.
sCrashyFeature.isEnabled();
CachedFlagsSafeMode.getInstance().onStartOrResumeCheckpoint();
// Only flags and params that are checked before native flags are cached need to be switched
// to safe values.
BOOL_PARAM.getValue();
INT_PARAM.getValue();
DOUBLE_PARAM.getValue();
STRING_PARAM.getValue();
}
private void endFirstRunWithKill() {
CachedFlagsSafeMode.getInstance().onPauseCheckpoint();
clearMemory();
}
private void endCrashyRun() {
clearMemory();
}
private void endCleanRunCachingIrrelevantValues() {
endCleanRun(
false,
false,
BOOL_PARAM_NATIVE_1,
INT_PARAM_NATIVE_1,
DOUBLE_PARAM_NATIVE_1,
STRING_PARAM_NATIVE_1);
}
private void endCleanRun(
boolean crashyFeatureValue,
boolean okFeatureValue,
boolean boolParamValue,
int intParamValue,
double doubleParamValue,
String stringParamValue) {
FeatureList.TestValues testValues = new TestValues();
testValues.addFeatureFlagOverride(CRASHY_FEATURE, crashyFeatureValue);
testValues.addFeatureFlagOverride(OK_FEATURE, okFeatureValue);
testValues.addFieldTrialParamOverride(
OK_FEATURE, BOOL_PARAM_NAME, Boolean.toString(boolParamValue));
testValues.addFieldTrialParamOverride(
OK_FEATURE, INT_PARAM_NAME, Integer.toString(intParamValue));
testValues.addFieldTrialParamOverride(
OK_FEATURE, DOUBLE_PARAM_NAME, Double.toString(doubleParamValue));
testValues.addFieldTrialParamOverride(OK_FEATURE, STRING_PARAM_NAME, stringParamValue);
FeatureList.setTestValues(testValues);
CachedFlagUtils.cacheNativeFlags(Arrays.asList(sCrashyFeature, sOkFeature));
CachedFlagUtils.cacheFieldTrialParameters(
Arrays.asList(BOOL_PARAM, INT_PARAM, DOUBLE_PARAM, STRING_PARAM));
CachedFlagsSafeMode.getInstance().onEndCheckpoint();
mExecutorRule.runAllBackgroundAndUi();
assertTrue(
CachedFlagsSafeMode.getSafeValuePreferences()
.contains("Chrome.Flags.CachedFlag.CrashyFeature"));
clearMemory();
}
private void assertCachedParamsEqualDefaults() {
assertEquals(BOOL_PARAM_DEFAULT, BOOL_PARAM.getValue());
assertEquals(INT_PARAM_DEFAULT, INT_PARAM.getValue());
assertEquals(DOUBLE_PARAM_DEFAULT, DOUBLE_PARAM.getValue(), 1e-10);
assertEquals(STRING_PARAM_DEFAULT, STRING_PARAM.getValue());
}
private void assertCachedParamsEqualNative1() {
assertEquals(BOOL_PARAM_NATIVE_1, BOOL_PARAM.getValue());
assertEquals(INT_PARAM_NATIVE_1, INT_PARAM.getValue());
assertEquals(DOUBLE_PARAM_NATIVE_1, DOUBLE_PARAM.getValue(), 1e-10);
assertEquals(STRING_PARAM_NATIVE_1, STRING_PARAM.getValue());
}
private void assertCachedParamsEqualNative2() {
assertEquals(BOOL_PARAM_NATIVE_2, BOOL_PARAM.getValue());
assertEquals(INT_PARAM_NATIVE_2, INT_PARAM.getValue());
assertEquals(DOUBLE_PARAM_NATIVE_2, DOUBLE_PARAM.getValue(), 1e-10);
assertEquals(STRING_PARAM_NATIVE_2, STRING_PARAM.getValue());
}
private static void clearMemory() {
CachedFlagUtils.resetFlagsForTesting();
CachedFlagsSafeMode.getInstance().clearMemoryForTesting();
}
}