GradualActivationStrategy implements ActivationStrategy { @Override public boolean isActive(FeatureState state, FeatureUser user) { if (user != null && Strings.isNotBlank(user.getName())) { String percentageAsString = state.getParameter(PARAM_PERCENTAGE); try { int percentage = Integer.valueOf(percentageAsString); if (percentage > 0) { int hashCode = Math.abs(calculateHashCode(user, state.getFeature())); return (hashCode % 100) < percentage; } } catch (NumberFormatException e) { log.error("Invalid gradual rollout percentage for feature " + state.getFeature().name() + ": " + percentageAsString); } } return false; }  @Override String getId(); @Override String getName(); @Override boolean isActive(FeatureState state, FeatureUser user); @Override Parameter[] getParameters(); static final String ID; static final String PARAM_PERCENTAGE; }
@Test void shouldAlwaysReturnFalseForZeroPercent() { FeatureState state = new FeatureState(GradualFeature.FEATURE); state.setEnabled(true); state.setParameter(GradualActivationStrategy.PARAM_PERCENTAGE, "0"); assertFalse(strategy.isActive(state, aUserWithHash(0))); assertFalse(strategy.isActive(state, aUserWithHash(1))); assertFalse(strategy.isActive(state, aUserWithHash(3))); assertFalse(strategy.isActive(state, aUserWithHash(10))); assertFalse(strategy.isActive(state, aUserWithHash(99))); assertFalse(strategy.isActive(state, aUserWithHash(100))); assertFalse(strategy.isActive(state, aUserWithHash(110))); }
@Test void shouldAlwaysReturnTrueForOneHundredPercent() { FeatureState state = new FeatureState(GradualFeature.FEATURE); state.setEnabled(true); state.setParameter(GradualActivationStrategy.PARAM_PERCENTAGE, "100"); assertTrue(strategy.isActive(state, aUserWithHash(0))); assertTrue(strategy.isActive(state, aUserWithHash(1))); assertTrue(strategy.isActive(state, aUserWithHash(3))); assertTrue(strategy.isActive(state, aUserWithHash(10))); assertTrue(strategy.isActive(state, aUserWithHash(99))); assertTrue(strategy.isActive(state, aUserWithHash(100))); assertTrue(strategy.isActive(state, aUserWithHash(110))); }
@Test void shouldWorkCorrectlyForOnePercent() { FeatureState state = new FeatureState(GradualFeature.FEATURE); state.setEnabled(true); state.setParameter(GradualActivationStrategy.PARAM_PERCENTAGE, "1"); assertTrue(strategy.isActive(state, aUserWithHash(0))); assertTrue(strategy.isActive(state, aUserWithHash(100))); assertFalse(strategy.isActive(state, aUserWithHash(1))); assertFalse(strategy.isActive(state, aUserWithHash(3))); assertFalse(strategy.isActive(state, aUserWithHash(10))); assertFalse(strategy.isActive(state, aUserWithHash(99))); assertFalse(strategy.isActive(state, aUserWithHash(110))); }
@Test void shouldWorkCorrectlyForNinetyNinePercent() { FeatureState state = new FeatureState(GradualFeature.FEATURE); state.setEnabled(true); state.setParameter(GradualActivationStrategy.PARAM_PERCENTAGE, "99"); assertTrue(strategy.isActive(state, aUserWithHash(0))); assertTrue(strategy.isActive(state, aUserWithHash(1))); assertTrue(strategy.isActive(state, aUserWithHash(3))); assertTrue(strategy.isActive(state, aUserWithHash(10))); assertTrue(strategy.isActive(state, aUserWithHash(98))); assertTrue(strategy.isActive(state, aUserWithHash(100))); assertFalse(strategy.isActive(state, aUserWithHash(99))); assertFalse(strategy.isActive(state, aUserWithHash(199))); }
@Test void shouldFindCorrectDecisionForIntermediateValues() { FeatureState state = new FeatureState(GradualFeature.FEATURE); state.setEnabled(true); state.setParameter(GradualActivationStrategy.PARAM_PERCENTAGE, "50"); assertTrue(strategy.isActive(state, aUserWithHash(0))); assertTrue(strategy.isActive(state, aUserWithHash(25))); assertTrue(strategy.isActive(state, aUserWithHash(49))); assertFalse(strategy.isActive(state, aUserWithHash(50))); assertFalse(strategy.isActive(state, aUserWithHash(99))); }
@Test void shouldReturnFalseForInvalidPercentage() { FeatureState state = new FeatureState(GradualFeature.FEATURE); state.setEnabled(true); state.setParameter(GradualActivationStrategy.PARAM_PERCENTAGE, "100x"); assertFalse(strategy.isActive(state, aUserWithHash(0))); assertFalse(strategy.isActive(state, aUserWithHash(99))); }