TEST_F(RouterTest, UpstreamTimingRetry) {
  NiceMock<Http::MockRequestEncoder> encoder;
  Http::ResponseDecoder* response_decoder = nullptr;
  EXPECT_CALL(cm_.thread_local_cluster_.conn_pool_, newStream(_, _))
      .WillOnce(Invoke(
          [&](Http::ResponseDecoder& decoder,
              Http::ConnectionPool::Callbacks& callbacks) -> Http::ConnectionPool::Cancellable* {
            response_decoder = &decoder;
            callbacks.onPoolReady(encoder, cm_.thread_local_cluster_.conn_pool_.host_,
                                  upstream_stream_info_, Http::Protocol::Http10);
            return nullptr;
          }));
  expectResponseTimerCreate();

  StreamInfo::StreamInfoImpl stream_info(test_time_, nullptr);
  ON_CALL(callbacks_, streamInfo()).WillByDefault(ReturnRef(stream_info));

  // Check that upstream timing is updated after the first request.
  Http::TestRequestHeaderMapImpl headers{{"x-envoy-retry-on", "5xx"}};
  HttpTestUtility::addDefaultHeaders(headers);
  router_.decodeHeaders(headers, false);

  router_.retry_state_->expectHeadersRetry();

  test_time_.advanceTimeWait(std::chrono::milliseconds(32));
  Buffer::OwnedImpl data;
  router_.decodeData(data, true);
  EXPECT_EQ(1U,
            callbacks_.route_->route_entry_.virtual_cluster_.stats().upstream_rq_total_.value());

  test_time_.advanceTimeWait(std::chrono::milliseconds(43));

  EXPECT_CALL(cm_.thread_local_cluster_.conn_pool_, newStream(_, _))
      .WillOnce(Invoke(
          [&](Http::ResponseDecoder& decoder,
              Http::ConnectionPool::Callbacks& callbacks) -> Http::ConnectionPool::Cancellable* {
            response_decoder = &decoder;
            callbacks.onPoolReady(encoder, cm_.thread_local_cluster_.conn_pool_.host_,
                                  upstream_stream_info_, Http::Protocol::Http10);
            return nullptr;
          }));

  // Check that upstream timing is not set when a retry will occur.
  Http::ResponseHeaderMapPtr bad_response_headers(
      new Http::TestResponseHeaderMapImpl{{":status", "503"}});
  response_decoder->decodeHeaders(std::move(bad_response_headers), true);
  EXPECT_FALSE(stream_info.firstUpstreamTxByteSent().has_value());
  EXPECT_FALSE(stream_info.lastUpstreamTxByteSent().has_value());
  EXPECT_FALSE(stream_info.firstUpstreamRxByteReceived().has_value());
  EXPECT_FALSE(stream_info.lastUpstreamRxByteReceived().has_value());

  router_.retry_state_->callback_();
  EXPECT_CALL(*router_.retry_state_, shouldRetryHeaders(_, _)).WillOnce(Return(RetryStatus::No));
  MonotonicTime retry_time = test_time_.monotonicTime();

  Http::ResponseHeaderMapPtr good_response_headers(
      new Http::TestResponseHeaderMapImpl{{":status", "200"}});
  response_decoder->decodeHeaders(std::move(good_response_headers), false);

  test_time_.advanceTimeWait(std::chrono::milliseconds(153));

  response_decoder->decodeData(data, true);

  EXPECT_TRUE(stream_info.firstUpstreamTxByteSent().has_value());
  EXPECT_TRUE(stream_info.lastUpstreamTxByteSent().has_value());
  EXPECT_TRUE(stream_info.firstUpstreamRxByteReceived().has_value());
  EXPECT_TRUE(stream_info.lastUpstreamRxByteReceived().has_value());

  EXPECT_EQ(stream_info.lastUpstreamRxByteReceived().value() -
                stream_info.firstUpstreamRxByteReceived().value(),
            std::chrono::milliseconds(153));

  // Time spent in upstream tx is 0 because we're using simulated time and
  // don't have a good way to insert a "sleep" there, but values being present
  // and equal to the time the retry was sent is good enough of a test.
  EXPECT_EQ(stream_info.lastUpstreamTxByteSent().value() -
                stream_info.firstUpstreamTxByteSent().value(),
            std::chrono::milliseconds(0));
  EXPECT_EQ(stream_info.lastUpstreamTxByteSent().value() +
                stream_info.startTimeMonotonic().time_since_epoch(),
            retry_time.time_since_epoch());
  EXPECT_EQ(stream_info.firstUpstreamTxByteSent().value() +
                stream_info.startTimeMonotonic().time_since_epoch(),
            retry_time.time_since_epoch());
}