TEST_F(GrpcHealthCheckerImplTest, SuccessWithAdditionalHeaders) {
  const std::string ENVOY_OK_KEY = "x-envoy-ok";
  const std::string ENVOY_OK_VAL = "ok";
  const std::string ENVOY_COOL_KEY = "x-envoy-cool";
  const std::string ENVOY_COOL_VAL = "cool";
  const std::string ENVOY_AWESOME_KEY = "x-envoy-awesome";
  const std::string ENVOY_AWESOME_VAL = "awesome";
  const std::string USER_AGENT_KEY = "user-agent";
  const std::string USER_AGENT_VAL = "CoolEnvoy/HC";
  const std::string PROTOCOL_KEY = "x-protocol";
  const std::string PROTOCOL_VAL = "%PROTOCOL%";
  const std::string DOWNSTREAM_LOCAL_ADDRESS_KEY = "x-downstream-local-address";
  const std::string DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT_KEY =
      "x-downstream-local-address-without-port";
  const std::string DOWNSTREAM_REMOTE_ADDRESS_KEY = "x-downstream-remote-address";
  const std::string DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT_KEY =
      "x-downstream-remote-address-without-port";
  const std::string START_TIME_KEY = "x-start-time";
  const std::string UPSTREAM_METADATA_KEY = "x-upstream-metadata";

  setupHCWithHeaders(
      {{ENVOY_OK_KEY, ENVOY_OK_VAL},
       {ENVOY_COOL_KEY, ENVOY_COOL_VAL},
       {ENVOY_AWESOME_KEY, ENVOY_AWESOME_VAL},
       {USER_AGENT_KEY, USER_AGENT_VAL},
       {PROTOCOL_KEY, PROTOCOL_VAL},
       {DOWNSTREAM_LOCAL_ADDRESS_KEY, "%DOWNSTREAM_LOCAL_ADDRESS%"},
       {DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT_KEY, "%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%"},
       {DOWNSTREAM_REMOTE_ADDRESS_KEY, "%DOWNSTREAM_REMOTE_ADDRESS%"},
       {DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT_KEY, "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"},
       {START_TIME_KEY, "%START_TIME(%s.%9f)%"},
       {UPSTREAM_METADATA_KEY, "%UPSTREAM_METADATA([\"namespace\", \"key\"])%"}});

  auto metadata = TestUtility::parseYaml<envoy::config::core::v3::Metadata>(
      R"EOF(
        filter_metadata:
          namespace:
            key: value
      )EOF");

  cluster_->prioritySet().getMockHostSet(0)->hosts_ = {
      makeTestHost(cluster_->info_, "tcp://127.0.0.1:80", metadata, simTime())};

  cluster_->info_->stats().upstream_cx_total_.inc();

  expectSessionCreate();
  expectHealthcheckStart(0);

  EXPECT_CALL(test_sessions_[0]->request_encoder_, encodeHeaders(_, false))
      .WillOnce(Invoke([&](const Http::RequestHeaderMap& headers, bool) -> Http::Status {
        EXPECT_EQ(Http::Headers::get().ContentTypeValues.Grpc, headers.getContentTypeValue());
        EXPECT_EQ(std::string("/grpc.health.v1.Health/Check"), headers.getPathValue());
        EXPECT_EQ(Http::Headers::get().SchemeValues.Http, headers.getSchemeValue());
        EXPECT_NE(nullptr, headers.Method());
        EXPECT_EQ(cluster_->info_->name(), headers.getHostValue());
        EXPECT_EQ(ENVOY_OK_VAL,
                  headers.get(Http::LowerCaseString(ENVOY_OK_KEY))[0]->value().getStringView());
        EXPECT_EQ(ENVOY_COOL_VAL,
                  headers.get(Http::LowerCaseString(ENVOY_COOL_KEY))[0]->value().getStringView());
        EXPECT_EQ(
            ENVOY_AWESOME_VAL,
            headers.get(Http::LowerCaseString(ENVOY_AWESOME_KEY))[0]->value().getStringView());
        EXPECT_EQ(USER_AGENT_VAL, headers.getUserAgentValue());
        EXPECT_EQ("HTTP/2",
                  headers.get(Http::LowerCaseString(PROTOCOL_KEY))[0]->value().getStringView());
        EXPECT_EQ("127.0.0.1:0",
                  headers.get(Http::LowerCaseString(DOWNSTREAM_LOCAL_ADDRESS_KEY))[0]
                      ->value()
                      .getStringView());
        EXPECT_EQ("127.0.0.1",
                  headers.get(Http::LowerCaseString(DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT_KEY))[0]
                      ->value()
                      .getStringView());
        EXPECT_EQ("127.0.0.1:0",
                  headers.get(Http::LowerCaseString(DOWNSTREAM_REMOTE_ADDRESS_KEY))[0]
                      ->value()
                      .getStringView());
        EXPECT_EQ("127.0.0.1",
                  headers.get(Http::LowerCaseString(DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT_KEY))[0]
                      ->value()
                      .getStringView());
        Envoy::DateFormatter date_formatter("%s.%9f");
        std::string current_start_time =
            date_formatter.fromTime(dispatcher_.timeSource().systemTime());
        EXPECT_EQ(current_start_time,
                  headers.get(Http::LowerCaseString(START_TIME_KEY))[0]->value().getStringView());
        EXPECT_EQ(
            "value",
            headers.get(Http::LowerCaseString(UPSTREAM_METADATA_KEY))[0]->value().getStringView());
        EXPECT_EQ(std::chrono::milliseconds(1000).count(),
                  Envoy::Grpc::Common::getGrpcTimeout(headers).value().count());
        return Http::okStatus();
      }));
  EXPECT_CALL(test_sessions_[0]->request_encoder_, encodeData(_, true))
      .WillOnce(Invoke([&](Buffer::Instance& data, bool) {
        std::vector<Grpc::Frame> decoded_frames;
        Grpc::Decoder decoder;
        ASSERT_TRUE(decoder.decode(data, decoded_frames));
        ASSERT_EQ(1U, decoded_frames.size());
        auto& frame = decoded_frames[0];
        Buffer::ZeroCopyInputStreamImpl stream(std::move(frame.data_));
        grpc::health::v1::HealthCheckRequest request;
        ASSERT_TRUE(request.ParseFromZeroCopyStream(&stream));
        EXPECT_EQ("service", request.service());
      }));

  health_checker_->start();

  EXPECT_CALL(runtime_.snapshot_, getInteger("health_check.max_interval", _));
  EXPECT_CALL(runtime_.snapshot_, getInteger("health_check.min_interval", _))
      .WillOnce(Return(45000));
  expectHealthcheckStop(0, 45000);

  // Host state should not be changed (remains healthy).
  EXPECT_CALL(*this, onHostStatus(cluster_->prioritySet().getMockHostSet(0)->hosts_[0],
                                  HealthTransition::Unchanged));
  respondServiceStatus(0, grpc::health::v1::HealthCheckResponse::SERVING);
  expectHostHealthy(true);
}
TEST_F(GrpcHealthCheckerImplTest, SuccessWithAdditionalHeaders) {
  const std::string ENVOY_OK_KEY = "x-envoy-ok";
  const std::string ENVOY_OK_VAL = "ok";
  const std::string ENVOY_COOL_KEY = "x-envoy-cool";
  const std::string ENVOY_COOL_VAL = "cool";
  const std::string ENVOY_AWESOME_KEY = "x-envoy-awesome";
  const std::string ENVOY_AWESOME_VAL = "awesome";
  const std::string USER_AGENT_KEY = "user-agent";
  const std::string USER_AGENT_VAL = "CoolEnvoy/HC";
  const std::string PROTOCOL_KEY = "x-protocol";
  const std::string PROTOCOL_VAL = "%PROTOCOL%";
  const std::string DOWNSTREAM_LOCAL_ADDRESS_KEY = "x-downstream-local-address";
  const std::string DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT_KEY =
      "x-downstream-local-address-without-port";
  const std::string DOWNSTREAM_REMOTE_ADDRESS_KEY = "x-downstream-remote-address";
  const std::string DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT_KEY =
      "x-downstream-remote-address-without-port";
  const std::string START_TIME_KEY = "x-start-time";
  const std::string UPSTREAM_METADATA_KEY = "x-upstream-metadata";

  setupHCWithHeaders(
      {{ENVOY_OK_KEY, ENVOY_OK_VAL},
       {ENVOY_COOL_KEY, ENVOY_COOL_VAL},
       {ENVOY_AWESOME_KEY, ENVOY_AWESOME_VAL},
       {USER_AGENT_KEY, USER_AGENT_VAL},
       {PROTOCOL_KEY, PROTOCOL_VAL},
       {DOWNSTREAM_LOCAL_ADDRESS_KEY, "%DOWNSTREAM_LOCAL_ADDRESS%"},
       {DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT_KEY, "%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%"},
       {DOWNSTREAM_REMOTE_ADDRESS_KEY, "%DOWNSTREAM_REMOTE_ADDRESS%"},
       {DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT_KEY, "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"},
       {START_TIME_KEY, "%START_TIME(%s.%9f)%"},
       {UPSTREAM_METADATA_KEY, "%UPSTREAM_METADATA([\"namespace\", \"key\"])%"}});

  auto metadata = TestUtility::parseYaml<envoy::config::core::v3::Metadata>(
      R"EOF(
        filter_metadata:
          namespace:
            key: value
      )EOF");

  cluster_->prioritySet().getMockHostSet(0)->hosts_ = {
      makeTestHost(cluster_->info_, "tcp://127.0.0.1:80", metadata, simTime())};

  cluster_->info_->stats().upstream_cx_total_.inc();

  expectSessionCreate();
  expectHealthcheckStart(0);

  EXPECT_CALL(test_sessions_[0]->request_encoder_, encodeHeaders(_, false))
      .WillOnce(Invoke([&](const Http::RequestHeaderMap& headers, bool) -> Http::Status {
        EXPECT_EQ(Http::Headers::get().ContentTypeValues.Grpc, headers.getContentTypeValue());
        EXPECT_EQ(std::string("/grpc.health.v1.Health/Check"), headers.getPathValue());
        EXPECT_EQ(Http::Headers::get().SchemeValues.Http, headers.getSchemeValue());
        EXPECT_NE(nullptr, headers.Method());
        EXPECT_EQ(cluster_->info_->name(), headers.getHostValue());
        EXPECT_EQ(ENVOY_OK_VAL,
                  headers.get(Http::LowerCaseString(ENVOY_OK_KEY))[0]->value().getStringView());
        EXPECT_EQ(ENVOY_COOL_VAL,
                  headers.get(Http::LowerCaseString(ENVOY_COOL_KEY))[0]->value().getStringView());
        EXPECT_EQ(
            ENVOY_AWESOME_VAL,
            headers.get(Http::LowerCaseString(ENVOY_AWESOME_KEY))[0]->value().getStringView());
        EXPECT_EQ(USER_AGENT_VAL, headers.getUserAgentValue());
        EXPECT_EQ("HTTP/2",
                  headers.get(Http::LowerCaseString(PROTOCOL_KEY))[0]->value().getStringView());
        EXPECT_EQ("127.0.0.1:0",
                  headers.get(Http::LowerCaseString(DOWNSTREAM_LOCAL_ADDRESS_KEY))[0]
                      ->value()
                      .getStringView());
        EXPECT_EQ("127.0.0.1",
                  headers.get(Http::LowerCaseString(DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT_KEY))[0]
                      ->value()
                      .getStringView());
        EXPECT_EQ("127.0.0.1:0",
                  headers.get(Http::LowerCaseString(DOWNSTREAM_REMOTE_ADDRESS_KEY))[0]
                      ->value()
                      .getStringView());
        EXPECT_EQ("127.0.0.1",
                  headers.get(Http::LowerCaseString(DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT_KEY))[0]
                      ->value()
                      .getStringView());
        Envoy::DateFormatter date_formatter("%s.%9f");
        std::string current_start_time =
            date_formatter.fromTime(dispatcher_.timeSource().systemTime());
        EXPECT_EQ(current_start_time,
                  headers.get(Http::LowerCaseString(START_TIME_KEY))[0]->value().getStringView());
        EXPECT_EQ(
            "value",
            headers.get(Http::LowerCaseString(UPSTREAM_METADATA_KEY))[0]->value().getStringView());
        EXPECT_EQ(std::chrono::milliseconds(1000).count(),
                  Envoy::Grpc::Common::getGrpcTimeout(headers).value().count());
        return Http::okStatus();
      }));
  EXPECT_CALL(test_sessions_[0]->request_encoder_, encodeData(_, true))
      .WillOnce(Invoke([&](Buffer::Instance& data, bool) {
        std::vector<Grpc::Frame> decoded_frames;
        Grpc::Decoder decoder;
        ASSERT_TRUE(decoder.decode(data, decoded_frames));
        ASSERT_EQ(1U, decoded_frames.size());
        auto& frame = decoded_frames[0];
        Buffer::ZeroCopyInputStreamImpl stream(std::move(frame.data_));
        grpc::health::v1::HealthCheckRequest request;
        ASSERT_TRUE(request.ParseFromZeroCopyStream(&stream));
        EXPECT_EQ("service", request.service());
      }));

  health_checker_->start();

  EXPECT_CALL(runtime_.snapshot_, getInteger("health_check.max_interval", _));
  EXPECT_CALL(runtime_.snapshot_, getInteger("health_check.min_interval", _))
      .WillOnce(Return(45000));
  expectHealthcheckStop(0, 45000);

   
  EXPECT_CALL(*this, onHostStatus(cluster_->prioritySet().getMockHostSet(0)->hosts_[0],
                                  HealthTransition::Unchanged));
  respondServiceStatus(0, grpc::health::v1::HealthCheckResponse::SERVING);
  expectHostHealthy(true);
}