  void setupServiceValidationWithAdditionalHeaders() {
    std::string yaml = R"EOF(
    timeout: 1s
    interval: 1s
    interval_jitter: 1s
    unhealthy_threshold: 2
    healthy_threshold: 2
    http_health_check:
      service_name_matcher:
        prefix: locations
      path: /healthcheck
      host: "www.envoyproxy.io"
      request_headers_to_add:
        - header:
            key: x-envoy-ok
            value: ok
        - header:
            key: x-envoy-cool
            value: cool
        - header:
            key: x-envoy-awesome
            value: awesome
        # The following entry replaces the current user-agent.
        - header:
            key: user-agent
            value: CoolEnvoy/HC
          append: false
        - header:
            key: x-protocol
            value: "%PROTOCOL%"
        - header:
            key: x-upstream-metadata
            value: "%UPSTREAM_METADATA([\"namespace\", \"key\"])%"
        - header:
            key: x-downstream-remote-address
            value: "%DOWNSTREAM_REMOTE_ADDRESS%"
        - header:
            key: x-downstream-remote-address-without-port
            value: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
        - header:
            key: x-downstream-local-address
            value: "%DOWNSTREAM_LOCAL_ADDRESS%"
        - header:
            key: x-downstream-local-address-without-port
            value: "%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%"
        - header:
            key: x-start-time
            value: "%START_TIME(%s.%9f)%"
    )EOF";

    allocHealthChecker(yaml);
    addCompletionCallback();
  }

  void setupServiceValidationWithoutUserAgent() {
    std::string yaml = R"EOF(
    timeout: 1s
    interval: 1s
    interval_jitter: 1s
    unhealthy_threshold: 2
    healthy_threshold: 2
    http_health_check:
      service_name_matcher:
        prefix: locations
      path: /healthcheck
      host: "www.envoyproxy.io"
      # The following entry removes the default "user-agent" header.
      request_headers_to_remove: ["user-agent"]
    )EOF";

    allocHealthChecker(yaml);
    addCompletionCallback();
  }

  void expectSessionCreate(const HostWithHealthCheckMap& health_check_map) {
    // Expectations are in LIFO order.
    TestSessionPtr new_test_session(new TestSession());
    new_test_session->timeout_timer_ = new Event::MockTimer(&dispatcher_);
    new_test_session->interval_timer_ = new Event::MockTimer(&dispatcher_);
    test_sessions_.emplace_back(std::move(new_test_session));
    expectClientCreate(test_sessions_.size() - 1, health_check_map);
  }

  void expectClientCreate(size_t index, const HostWithHealthCheckMap& health_check_map) {
    TestSession& test_session = *test_sessions_[index];
    test_session.codec_ = new NiceMock<Http::MockClientConnection>();
    ON_CALL(*test_session.codec_, protocol()).WillByDefault(Return(Http::Protocol::Http11));
    test_session.client_connection_ = new NiceMock<Network::MockClientConnection>();
    connection_index_.push_back(index);
    codec_index_.push_back(index);

    EXPECT_CALL(dispatcher_, createClientConnection_(_, _, _, _))
        .Times(testing::AnyNumber())
        .WillRepeatedly(InvokeWithoutArgs([&]() -> Network::ClientConnection* {
          const uint32_t index = connection_index_.front();
          connection_index_.pop_front();
          return test_sessions_[index]->client_connection_;
        }));
    EXPECT_CALL(*health_checker_, createCodecClient_(_))
        .WillRepeatedly(
            Invoke([&](Upstream::Host::CreateConnectionData& conn_data) -> Http::CodecClient* {
              if (!health_check_map.empty()) {
                const auto& health_check_config =
                    health_check_map.at(conn_data.host_description_->address()->asString());
                // To make sure health checker checks the correct port.
                EXPECT_EQ(health_check_config.port_value(),
                          conn_data.host_description_->healthCheckAddress()->ip()->port());
              }
              const uint32_t index = codec_index_.front();
              codec_index_.pop_front();
              TestSession& test_session = *test_sessions_[index];
              std::shared_ptr<Upstream::MockClusterInfo> cluster{
                  new NiceMock<Upstream::MockClusterInfo>()};
              Event::MockDispatcher dispatcher_;
              test_session.codec_client_ = new CodecClientForTest(
                  Http::CodecType::HTTP1, std::move(conn_data.connection_), test_session.codec_,
                  nullptr, Upstream::makeTestHost(cluster, "tcp://127.0.0.1:9000", simTime()),
                  dispatcher_);
              return test_session.codec_client_;
            }));
  void setupServiceValidationWithAdditionalHeaders() {
    std::string yaml = R"EOF(
    timeout: 1s
    interval: 1s
    interval_jitter: 1s
    unhealthy_threshold: 2
    healthy_threshold: 2
    http_health_check:
      service_name_matcher:
        prefix: locations
      path: /healthcheck
      host: "www.envoyproxy.io"
      request_headers_to_add:
        - header:
            key: x-envoy-ok
            value: ok
        - header:
            key: x-envoy-cool
            value: cool
        - header:
            key: x-envoy-awesome
            value: awesome
        # The following entry replaces the current user-agent.
        - header:
            key: user-agent
            value: CoolEnvoy/HC
          append: false
        - header:
            key: x-protocol
            value: "%PROTOCOL%"
        - header:
            key: x-upstream-metadata
            value: "%UPSTREAM_METADATA([\"namespace\", \"key\"])%"
        - header:
            key: x-downstream-remote-address
            value: "%DOWNSTREAM_REMOTE_ADDRESS%"
        - header:
            key: x-downstream-remote-address-without-port
            value: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
        - header:
            key: x-downstream-local-address
            value: "%DOWNSTREAM_LOCAL_ADDRESS%"
        - header:
            key: x-downstream-local-address-without-port
            value: "%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%"
        - header:
            key: x-start-time
            value: "%START_TIME(%s.%9f)%"
    )EOF";

    allocHealthChecker(yaml);
    addCompletionCallback();
  }

  void setupServiceValidationWithoutUserAgent() {
    std::string yaml = R"EOF(
    timeout: 1s
    interval: 1s
    interval_jitter: 1s
    unhealthy_threshold: 2
    healthy_threshold: 2
    http_health_check:
      service_name_matcher:
        prefix: locations
      path: /healthcheck
      host: "www.envoyproxy.io"
      # The following entry removes the default "user-agent" header.
      request_headers_to_remove: ["user-agent"]
    )EOF";

    allocHealthChecker(yaml);
    addCompletionCallback();
  }

  void expectSessionCreate(const HostWithHealthCheckMap& health_check_map) {
    // Expectations are in LIFO order.
    TestSessionPtr new_test_session(new TestSession());
    new_test_session->timeout_timer_ = new Event::MockTimer(&dispatcher_);
    new_test_session->interval_timer_ = new Event::MockTimer(&dispatcher_);
    test_sessions_.emplace_back(std::move(new_test_session));
    expectClientCreate(test_sessions_.size() - 1, health_check_map);
  }

  void expectClientCreate(size_t index, const HostWithHealthCheckMap& health_check_map) {
    TestSession& test_session = *test_sessions_[index];
    test_session.codec_ = new NiceMock<Http::MockClientConnection>();
    ON_CALL(*test_session.codec_, protocol()).WillByDefault(Return(Http::Protocol::Http11));
    test_session.client_connection_ = new NiceMock<Network::MockClientConnection>();
    connection_index_.push_back(index);
    codec_index_.push_back(index);

    EXPECT_CALL(dispatcher_, createClientConnection_(_, _, _, _))
        .Times(testing::AnyNumber())
        .WillRepeatedly(InvokeWithoutArgs([&]() -> Network::ClientConnection* {
          const uint32_t index = connection_index_.front();
          connection_index_.pop_front();
          return test_sessions_[index]->client_connection_;
        }));
    EXPECT_CALL(*health_checker_, createCodecClient_(_))
        .WillRepeatedly(
            Invoke([&](Upstream::Host::CreateConnectionData& conn_data) -> Http::CodecClient* {
              if (!health_check_map.empty()) {
                const auto& health_check_config =
                    health_check_map.at(conn_data.host_description_->address()->asString());
                // To make sure health checker checks the correct port.
                EXPECT_EQ(health_check_config.port_value(),
                          conn_data.host_description_->healthCheckAddress()->ip()->port());
              }
              const uint32_t index = codec_index_.front();
              codec_index_.pop_front();
              TestSession& test_session = *test_sessions_[index];
              std::shared_ptr<Upstream::MockClusterInfo> cluster{
                  new NiceMock<Upstream::MockClusterInfo>()};
              Event::MockDispatcher dispatcher_;
              test_session.codec_client_ = new CodecClientForTest(
                  Http::CodecType::HTTP1, std::move(conn_data.connection_), test_session.codec_,
                  nullptr, Upstream::makeTestHost(cluster, "tcp: 
                  dispatcher_);
              return test_session.codec_client_;
            }));