NormalModeOutputRateCalculator implements ModeOutputRateCalculator { @Override public OutputRateCalculationResult calculateOutputRate(double currentRate, double maximumOutputRate, SendCounters counters) { double calculatedRate = currentRate; OutputRateCalculator.Mode calculatedMode = OutputRateCalculator.Mode.NORMAL; if (!counters.failuresRatioExceeds(failuresSpeedupToleranceRatio) && currentRate < maximumOutputRate) { double rateAddOn = (maximumOutputRate - currentRate) * rateConvergenceFactor; calculatedRate = Math.min(maximumOutputRate, currentRate + rateAddOn); } else if (counters.majorityOfFailures()) { calculatedRate = slowModeRate; calculatedMode = OutputRateCalculator.Mode.SLOW; } else if (counters.failuresRatioExceeds(failuresNochangeToleranceRatio)) { calculatedRate = Math.max(slowModeRate, currentRate * (1 - rateConvergenceFactor)); } return new OutputRateCalculationResult(calculatedRate, calculatedMode); } NormalModeOutputRateCalculator(double rateConvergenceFactor, 
                                   double slowModeRate,
                                   double failuresSpeedupToleranceRatio,
                                   double failuresNochangeToleranceRatio); @Override OutputRateCalculationResult calculateOutputRate(double currentRate,
                                                           double maximumOutputRate,
                                                           SendCounters counters);  }
@Test public void shouldIncreaseRateWhenFailuresBelowToleranceOccuredAndNotAboveMaximumRate() { NormalModeOutputRateCalculator calculator = new NormalModeOutputRateCalculator(0.5, SLOW_RATE, 0.4, 0.5); counters.incrementSuccesses().incrementSuccesses().incrementFailures(); assertThat(calculator.calculateOutputRate(10, 20, counters).rate()).isEqualTo(15); }
@Test public void shouldNotIncreaseRateWhenNoFailuresOccuredAndAlreadyAtMaximum() { counters.incrementSuccesses(); assertThat(calculator.calculateOutputRate(20, 20, counters)).hasRate(20); }
@Test public void shouldNotSlowDownWhenRatioOfFailuresIsBelowGivenThreshold() { NormalModeOutputRateCalculator calculator = new NormalModeOutputRateCalculator(0.5, SLOW_RATE, 0.0, 0.38); counters.incrementSuccesses().incrementSuccesses() .incrementFailures(); assertThat(calculator.calculateOutputRate(20, 20, counters)).hasRate(20); }
@Test public void shouldSlowDownWhenRatioOfFailuresExceedsGivenThreshold() { NormalModeOutputRateCalculator calculator = new NormalModeOutputRateCalculator(0.5, SLOW_RATE, 0.1, 0.38); counters.incrementSuccesses().incrementSuccesses().incrementSuccesses() .incrementFailures().incrementFailures(); assertThat(calculator.calculateOutputRate(20, 20, counters)).hasRate(10); }
@Test public void shouldNotLimitRateWhenThereWereNoEvents() { assertThat(calculator.calculateOutputRate(20, 20, counters)).hasRate(20); }
@Test public void shouldSwitchToSlowModeWhenCalculatedRateIsBelowSlowModeRate() { counters.incrementSuccesses() .incrementFailures(); assertThat(calculator.calculateOutputRate(8, 20, counters)).hasRate(SLOW_RATE); }
@Test public void shouldSwitchToSlowModeWhenThereWereMoreFailuresThanSuccesses() { counters.incrementSuccesses() .incrementFailures().incrementFailures(); assertThat(calculator.calculateOutputRate(10, 20, counters)).hasRate(5).isInMode(OutputRateCalculator.Mode.SLOW); }