Adds a test case that demonstrates a significant difference in flow control behavior between nghttp2 and oghttp2.

PiperOrigin-RevId: 481166007
diff --git a/quiche/http2/adapter/adapter_impl_comparison_test.cc b/quiche/http2/adapter/adapter_impl_comparison_test.cc
index cce014b..364e996 100644
--- a/quiche/http2/adapter/adapter_impl_comparison_test.cc
+++ b/quiche/http2/adapter/adapter_impl_comparison_test.cc
@@ -38,6 +38,92 @@
   // non-existent streams between nghttp2_adapter and oghttp2_adapter.
 }
 
+TEST(AdapterImplComparisonTest, SubmitWindowUpdateBumpsWindow) {
+  RecordingHttp2Visitor nghttp2_visitor;
+  std::unique_ptr<NgHttp2Adapter> nghttp2_adapter =
+      NgHttp2Adapter::CreateClientAdapter(nghttp2_visitor);
+
+  RecordingHttp2Visitor oghttp2_visitor;
+  OgHttp2Adapter::Options options;
+  options.perspective = Perspective::kClient;
+  std::unique_ptr<OgHttp2Adapter> oghttp2_adapter =
+      OgHttp2Adapter::Create(oghttp2_visitor, options);
+
+  int result;
+
+  const std::vector<Header> request_headers =
+      ToHeaders({{":method", "POST"},
+                 {":scheme", "https"},
+                 {":authority", "example.com"},
+                 {":path", "/"}});
+  const int kInitialFlowControlWindow = 65535;
+  const int kConnectionWindowIncrease = 192 * 1024;
+
+  const int32_t nghttp2_stream_id =
+      nghttp2_adapter->SubmitRequest(request_headers, nullptr, nullptr);
+
+  // Both the connection and stream flow control windows are increased.
+  nghttp2_adapter->SubmitWindowUpdate(0, kConnectionWindowIncrease);
+  nghttp2_adapter->SubmitWindowUpdate(nghttp2_stream_id,
+                                      kConnectionWindowIncrease);
+  result = nghttp2_adapter->Send();
+  EXPECT_EQ(0, result);
+  int nghttp2_window = nghttp2_adapter->GetReceiveWindowSize();
+  EXPECT_EQ(kInitialFlowControlWindow + kConnectionWindowIncrease,
+            nghttp2_window);
+
+  const int32_t oghttp2_stream_id =
+      oghttp2_adapter->SubmitRequest(request_headers, nullptr, nullptr);
+  // Both the connection and stream flow control windows are increased.
+  oghttp2_adapter->SubmitWindowUpdate(0, kConnectionWindowIncrease);
+  oghttp2_adapter->SubmitWindowUpdate(oghttp2_stream_id,
+                                      kConnectionWindowIncrease);
+  result = oghttp2_adapter->Send();
+  EXPECT_EQ(0, result);
+  int oghttp2_window = oghttp2_adapter->GetReceiveWindowSize();
+  EXPECT_EQ(kInitialFlowControlWindow + kConnectionWindowIncrease,
+            oghttp2_window);
+
+  // nghttp2 and oghttp2 agree on the advertised window.
+  EXPECT_EQ(nghttp2_window, oghttp2_window);
+
+  ASSERT_EQ(nghttp2_stream_id, oghttp2_stream_id);
+
+  const int kMaxFrameSize = 16 * 1024;
+  const std::string body_chunk(kMaxFrameSize, 'a');
+  auto sequence = TestFrameSequence();
+  sequence.ServerPreface().Headers(nghttp2_stream_id, {{":status", "200"}},
+                                   /*fin=*/false);
+  // This loop generates enough DATA frames to consume the window increase.
+  const int kNumFrames = kConnectionWindowIncrease / kMaxFrameSize;
+  for (int i = 0; i < kNumFrames; ++i) {
+    sequence.Data(nghttp2_stream_id, body_chunk);
+  }
+  const std::string frames = sequence.Serialize();
+
+  nghttp2_adapter->ProcessBytes(frames);
+  // Marking the data consumed causes a window update, which is reflected in the
+  // advertised window size.
+  nghttp2_adapter->MarkDataConsumedForStream(nghttp2_stream_id,
+                                             kNumFrames * kMaxFrameSize);
+  result = nghttp2_adapter->Send();
+  EXPECT_EQ(0, result);
+  nghttp2_window = nghttp2_adapter->GetReceiveWindowSize();
+
+  oghttp2_adapter->ProcessBytes(frames);
+  oghttp2_adapter->MarkDataConsumedForStream(oghttp2_stream_id,
+                                             kNumFrames * kMaxFrameSize);
+  result = oghttp2_adapter->Send();
+  EXPECT_EQ(0, result);
+  oghttp2_window = oghttp2_adapter->GetReceiveWindowSize();
+
+  const int kMinExpectation =
+      (kInitialFlowControlWindow + kConnectionWindowIncrease) / 2;
+  EXPECT_GT(nghttp2_window, kMinExpectation);
+  // BUG! oghttp2 does not maintain the larger window persistently.
+  EXPECT_LT(oghttp2_window, kMinExpectation);
+}
+
 TEST(AdapterImplComparisonTest, ServerHandlesFrames) {
   RecordingHttp2Visitor nghttp2_visitor;
   std::unique_ptr<NgHttp2Adapter> nghttp2_adapter =