Adds a `OgHttp2Session` unit test exercising the case where the visitor returns false in `OnEndStream()`.

PiperOrigin-RevId: 488664335
diff --git a/quiche/http2/adapter/nghttp2_session_test.cc b/quiche/http2/adapter/nghttp2_session_test.cc
index 61500bb..f11c490 100644
--- a/quiche/http2/adapter/nghttp2_session_test.cc
+++ b/quiche/http2/adapter/nghttp2_session_test.cc
@@ -319,6 +319,55 @@
       "Extension frame payload for stream 1 is null!");
 }
 
+TEST_F(NgHttp2SessionTest, ServerSeesErrorOnEndStream) {
+  NgHttp2Session session(Perspective::kServer, CreateCallbacks(), options_,
+                         &visitor_);
+
+  const std::string frames = TestFrameSequence()
+                                 .ClientPreface()
+                                 .Headers(1,
+                                          {{":method", "POST"},
+                                           {":scheme", "https"},
+                                           {":authority", "example.com"},
+                                           {":path", "/"}},
+                                          /*fin=*/false)
+                                 .Data(1, "Request body", true)
+                                 .Serialize();
+  testing::InSequence s;
+
+  // Client preface (empty SETTINGS)
+  EXPECT_CALL(visitor_, OnFrameHeader(0, 0, SETTINGS, 0));
+  EXPECT_CALL(visitor_, OnSettingsStart());
+  EXPECT_CALL(visitor_, OnSettingsEnd());
+  // Stream 1
+  EXPECT_CALL(visitor_, OnFrameHeader(1, _, HEADERS, 0x4));
+  EXPECT_CALL(visitor_, OnBeginHeadersForStream(1));
+  EXPECT_CALL(visitor_, OnHeaderForStream(1, ":method", "POST"));
+  EXPECT_CALL(visitor_, OnHeaderForStream(1, ":scheme", "https"));
+  EXPECT_CALL(visitor_, OnHeaderForStream(1, ":authority", "example.com"));
+  EXPECT_CALL(visitor_, OnHeaderForStream(1, ":path", "/"));
+  EXPECT_CALL(visitor_, OnEndHeadersForStream(1));
+
+  EXPECT_CALL(visitor_, OnFrameHeader(1, _, DATA, 0x1));
+  EXPECT_CALL(visitor_, OnBeginDataForStream(1, _));
+  EXPECT_CALL(visitor_, OnDataForStream(1, "Request body"));
+  EXPECT_CALL(visitor_, OnEndStream(1)).WillOnce(testing::Return(false));
+
+  const int64_t result = session.ProcessBytes(frames);
+  EXPECT_EQ(NGHTTP2_ERR_CALLBACK_FAILURE, result);
+
+  EXPECT_TRUE(session.want_write());
+
+  EXPECT_CALL(visitor_, OnBeforeFrameSent(SETTINGS, 0, _, 0x1));
+  EXPECT_CALL(visitor_, OnFrameSent(SETTINGS, 0, _, 0x1, 0));
+
+  ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr()));
+  EXPECT_THAT(visitor_.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS}));
+  visitor_.Clear();
+
+  EXPECT_FALSE(session.want_write());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace adapter
diff --git a/quiche/http2/adapter/oghttp2_session_test.cc b/quiche/http2/adapter/oghttp2_session_test.cc
index 59f5c4b..f536cd7 100644
--- a/quiche/http2/adapter/oghttp2_session_test.cc
+++ b/quiche/http2/adapter/oghttp2_session_test.cc
@@ -933,6 +933,68 @@
                             SpdyFrameType::HEADERS}));
 }
 
+TEST(OgHttp2SessionTest, ServerSeesErrorOnEndStream) {
+  DataSavingVisitor visitor;
+  OgHttp2Session::Options options;
+  options.perspective = Perspective::kServer;
+  OgHttp2Session session(visitor, options);
+
+  const std::string frames = TestFrameSequence()
+                                 .ClientPreface()
+                                 .Headers(1,
+                                          {{":method", "POST"},
+                                           {":scheme", "https"},
+                                           {":authority", "example.com"},
+                                           {":path", "/"}},
+                                          /*fin=*/false)
+                                 .Data(1, "Request body", true)
+                                 .Serialize();
+  testing::InSequence s;
+
+  // Client preface (empty SETTINGS)
+  EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
+  EXPECT_CALL(visitor, OnSettingsStart());
+  EXPECT_CALL(visitor, OnSettingsEnd());
+  // Stream 1
+  EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 0x4));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
+  EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST"));
+  EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https"));
+  EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com"));
+  EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/"));
+  EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+
+  EXPECT_CALL(visitor, OnFrameHeader(1, _, DATA, 0x1));
+  EXPECT_CALL(visitor, OnBeginDataForStream(1, _));
+  EXPECT_CALL(visitor, OnDataForStream(1, "Request body"));
+  EXPECT_CALL(visitor, OnEndStream(1)).WillOnce(testing::Return(false));
+  EXPECT_CALL(
+      visitor,
+      OnConnectionError(Http2VisitorInterface::ConnectionError::kParseError));
+
+  const int64_t result = session.ProcessBytes(frames);
+  EXPECT_EQ(/*NGHTTP2_ERR_CALLBACK_FAILURE=*/-902, result);
+
+  EXPECT_TRUE(session.want_write());
+
+  EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
+  EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
+  EXPECT_CALL(visitor, OnBeforeFrameSent(GOAWAY, 0, _, 0x0));
+  EXPECT_CALL(
+      visitor,
+      OnFrameSent(GOAWAY, 0, _, 0x0,
+                  static_cast<int>(
+                      Http2VisitorInterface::ConnectionError::kParseError)));
+
+  int send_result = session.Send();
+  EXPECT_EQ(0, send_result);
+  EXPECT_THAT(visitor.data(),
+              EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::GOAWAY}));
+  visitor.Clear();
+
+  EXPECT_FALSE(session.want_write());
+}
+
 }  // namespace test
 }  // namespace adapter
 }  // namespace http2