content: package pl.allegro.tech.hermes.consumers.consumer.rate.calculator;
  
  import static pl.allegro.tech.hermes.consumers.test.HermesConsumersAssertions.assertThat;
  
  import java.time.Clock;
  import org.junit.Test;
  import pl.allegro.tech.hermes.consumers.consumer.rate.SendCounters;
  
  public class NormalModeOutputRateCalculatorTest {
  
    private static final int SLOW_RATE = 5;
  
    private final NormalModeOutputRateCalculator calculator =
        new NormalModeOutputRateCalculator(0.5, SLOW_RATE, 0.1, 0.4);
  
    private final SendCounters counters = new SendCounters(Clock.systemDefaultZone());
  
    @Test
    public void shouldIncreaseRateWhenFailuresBelowToleranceOccuredAndNotAboveMaximumRate() {
      // given
      NormalModeOutputRateCalculator calculator =
          new NormalModeOutputRateCalculator(0.5, SLOW_RATE, 0.4, 0.5);
      counters.incrementSuccesses().incrementSuccesses().incrementFailures();
  
      // when then
      assertThat(calculator.calculateOutputRate(10, 20, counters).rate()).isEqualTo(15);
    }
  
    @Test
    public void shouldNotIncreaseRateWhenNoFailuresOccuredAndAlreadyAtMaximum() {
      // given
      counters.incrementSuccesses();
  
      // when then
      assertThat(calculator.calculateOutputRate(20, 20, counters)).hasRate(20);
    }
  
    @Test
    public void shouldNotSlowDownWhenRatioOfFailuresIsBelowGivenThreshold() {
      // given
      NormalModeOutputRateCalculator calculator =
          new NormalModeOutputRateCalculator(0.5, SLOW_RATE, 0.0, 0.38);
      counters.incrementSuccesses().incrementSuccesses().incrementFailures();
  
      // when then
      assertThat(calculator.calculateOutputRate(20, 20, counters)).hasRate(20);
    }
  
    @Test
    public void shouldSlowDownWhenRatioOfFailuresExceedsGivenThreshold() {
      // given
      NormalModeOutputRateCalculator calculator =
          new NormalModeOutputRateCalculator(0.5, SLOW_RATE, 0.1, 0.38);
      counters
          .incrementSuccesses()
          .incrementSuccesses()
          .incrementSuccesses()
          .incrementFailures()
          .incrementFailures();
  
      // when then
      assertThat(calculator.calculateOutputRate(20, 20, counters)).hasRate(10);
    }
  
    @Test
    public void shouldNotLimitRateWhenThereWereNoEvents() {
      assertThat(calculator.calculateOutputRate(20, 20, counters)).hasRate(20);
    }
  
    @Test
    public void shouldSwitchToSlowModeWhenCalculatedRateIsBelowSlowModeRate() {
      // given
      counters.incrementSuccesses().incrementFailures();
  
      // when then
      assertThat(calculator.calculateOutputRate(8, 20, counters)).hasRate(SLOW_RATE);
    }
  
    @Test
    public void shouldSwitchToSlowModeWhenThereWereMoreFailuresThanSuccesses() {
      // given
      counters.incrementSuccesses().incrementFailures().incrementFailures();
  
      // when then
      assertThat(calculator.calculateOutputRate(10, 20, counters))
          .hasRate(5)
          .isInMode(OutputRateCalculator.Mode.SLOW);
    }
  }
  