TEST_F(HttpHealthCheckerImplTest, HealthCheckIntervals) {
  setupHealthCheckIntervalOverridesHC();
  cluster_->prioritySet().getMockHostSet(0)->hosts_ = {
      makeTestHost(cluster_->info_, "tcp://128.0.0.1:80", simTime())};
  expectSessionCreate();
  expectStreamCreate(0);
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  health_checker_->start();

  // First check should respect no_traffic_interval setting.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(5000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);
  cluster_->info_->stats().upstream_cx_total_.inc();

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // Follow up successful checks should respect interval setting.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(1000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // Follow up successful checks should respect interval setting.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(1000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // A logical failure is not considered a network failure, therefore the unhealthy threshold is
  // ignored and health state changes immediately. Since the threshold is ignored, next health
  // check respects "unhealthy_interval".
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Changed));
  EXPECT_CALL(event_logger_, logEjectUnhealthy(_, _, _));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(2000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "503", false);

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // Subsequent failing checks should respect unhealthy_interval.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(2000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "503", false);

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // Subsequent failing checks should respect unhealthy_interval.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(2000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "503", false);

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // When transitioning to a successful state, checks should respect healthy_edge_interval. Health
  // state should be delayed pending healthy threshold.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::ChangePending));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(4000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::ChangePending));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(4000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // After the healthy threshold is reached, health state should change while checks should respect
  // the default interval.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Changed));
  EXPECT_CALL(event_logger_, logAddHealthy(_, _, false));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(1000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // Subsequent checks shouldn't change the state.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(1000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // First failed check after a run of successful ones should respect unhealthy_edge_interval. A
  // timeout, being a network type failure, should respect unhealthy threshold before changing the
  // health state.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::ChangePending));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(3000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  test_sessions_[0]->timeout_timer_->invokeCallback();
  EXPECT_FALSE(cluster_->prioritySet().getMockHostSet(0)->hosts_[0]->healthFlagGet(
      Host::HealthFlag::ACTIVE_HC_TIMEOUT));

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a network timeout.
  expectClientCreate(0);
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::ChangePending));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(3000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  test_sessions_[0]->timeout_timer_->invokeCallback();
  EXPECT_FALSE(cluster_->prioritySet().getMockHostSet(0)->hosts_[0]->healthFlagGet(
      Host::HealthFlag::ACTIVE_HC_TIMEOUT));

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a network timeout.
  expectClientCreate(0);
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // Subsequent failing checks should respect unhealthy_interval. As the unhealthy threshold is
  // reached, health state should also change.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Changed));
  EXPECT_CALL(event_logger_, logEjectUnhealthy(_, _, _));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(2000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  test_sessions_[0]->timeout_timer_->invokeCallback();
  EXPECT_TRUE(cluster_->prioritySet().getMockHostSet(0)->hosts_[0]->healthFlagGet(
      Host::HealthFlag::ACTIVE_HC_TIMEOUT));

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a network timeout.
  expectClientCreate(0);
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // Remaining failing checks shouldn't change the state.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(2000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  test_sessions_[0]->timeout_timer_->invokeCallback();

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a network timeout.
  expectClientCreate(0);
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // When transitioning to a successful state, checks should respect healthy_edge_interval.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::ChangePending));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(4000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);
  EXPECT_TRUE(cluster_->prioritySet().getMockHostSet(0)->hosts_[0]->healthFlagGet(
      Host::HealthFlag::ACTIVE_HC_TIMEOUT));

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::ChangePending));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(4000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);
  EXPECT_TRUE(cluster_->prioritySet().getMockHostSet(0)->hosts_[0]->healthFlagGet(
      Host::HealthFlag::ACTIVE_HC_TIMEOUT));

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // After the healthy threshold is reached, health state should change while checks should respect
  // the default interval.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Changed));
  EXPECT_CALL(event_logger_, logAddHealthy(_, _, false));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(1000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);
  EXPECT_FALSE(cluster_->prioritySet().getMockHostSet(0)->hosts_[0]->healthFlagGet(
      Host::HealthFlag::ACTIVE_HC_TIMEOUT));

  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_, _));
  // Needed after a response is sent.
  expectStreamCreate(0);
  test_sessions_[0]->interval_timer_->invokeCallback();

  // Subsequent checks shouldn't change the state.
  EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
  EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(std::chrono::milliseconds(1000), _));
  EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer());
  respond(0, "200", false);
}