Adds a test case that invokes nghttp2 directly to parse a sample frame sequence.

PiperOrigin-RevId: 374940755
diff --git a/http2/adapter/nghttp2_test.cc b/http2/adapter/nghttp2_test.cc
new file mode 100644
index 0000000..c9ccd0f
--- /dev/null
+++ b/http2/adapter/nghttp2_test.cc
@@ -0,0 +1,93 @@
+#include "third_party/nghttp2/src/lib/includes/nghttp2/nghttp2.h"
+#include "http2/adapter/mock_nghttp2_callbacks.h"
+#include "http2/adapter/test_frame_sequence.h"
+#include "http2/adapter/test_utils.h"
+#include "common/platform/api/quiche_test.h"
+
+namespace http2 {
+namespace adapter {
+namespace test {
+namespace {
+
+using testing::_;
+
+enum FrameType {
+  DATA,
+  HEADERS,
+  PRIORITY,
+  RST_STREAM,
+  SETTINGS,
+  PUSH_PROMISE,
+  PING,
+  GOAWAY,
+  WINDOW_UPDATE,
+};
+
+nghttp2_option* GetOptions() {
+  nghttp2_option* options;
+  nghttp2_option_new(&options);
+  // Set some common options for compatibility.
+  nghttp2_option_set_no_closed_streams(options, 1);
+  nghttp2_option_set_no_auto_window_update(options, 1);
+  nghttp2_option_set_max_send_header_block_length(options, 0x2000000);
+  nghttp2_option_set_max_outbound_ack(options, 10000);
+  return options;
+}
+
+// Verifies nghttp2 behavior when acting as a client.
+TEST(Nghttp2ClientTest, ClientReceivesUnexpectedHeaders) {
+  testing::StrictMock<MockNghttp2Callbacks> mock_callbacks;
+  auto nghttp2_callbacks = MockNghttp2Callbacks::GetCallbacks();
+  nghttp2_option* options = GetOptions();
+  nghttp2_session* ptr;
+  nghttp2_session_client_new2(&ptr, nghttp2_callbacks.get(), &mock_callbacks,
+                              options);
+
+  auto client_session = MakeSessionPtr(ptr);
+
+  const std::string initial_frames = TestFrameSequence()
+                                         .ServerPreface()
+                                         .Ping(42)
+                                         .WindowUpdate(0, 1000)
+                                         .Serialize();
+
+  testing::InSequence seq;
+  EXPECT_CALL(mock_callbacks, OnBeginFrame(HasFrameHeader(0, SETTINGS, 0)));
+  EXPECT_CALL(mock_callbacks, OnFrameRecv(IsSettings(testing::IsEmpty())));
+  EXPECT_CALL(mock_callbacks, OnBeginFrame(HasFrameHeader(0, PING, 0)));
+  EXPECT_CALL(mock_callbacks, OnFrameRecv(IsPing(42)));
+  EXPECT_CALL(mock_callbacks,
+              OnBeginFrame(HasFrameHeader(0, WINDOW_UPDATE, 0)));
+  EXPECT_CALL(mock_callbacks, OnFrameRecv(IsWindowUpdate(1000)));
+
+  nghttp2_session_mem_recv(client_session.get(),
+                           ToUint8Ptr(initial_frames.data()),
+                           initial_frames.size());
+
+  const std::string unexpected_stream_frames =
+      TestFrameSequence()
+          .Headers(1,
+                   {{":status", "200"},
+                    {"server", "my-fake-server"},
+                    {"date", "Tue, 6 Apr 2021 12:54:01 GMT"}},
+                   /*fin=*/false)
+          .Data(1, "This is the response body.")
+          .RstStream(3, Http2ErrorCode::INTERNAL_ERROR)
+          .GoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!")
+          .Serialize();
+
+  EXPECT_CALL(mock_callbacks, OnBeginFrame(HasFrameHeader(1, HEADERS, _)));
+  EXPECT_CALL(mock_callbacks, OnInvalidFrameRecv(IsHeaders(1, _, _), _));
+  // No events from the DATA, RST_STREAM or GOAWAY.
+
+  nghttp2_session_mem_recv(client_session.get(),
+                           ToUint8Ptr(unexpected_stream_frames.data()),
+                           unexpected_stream_frames.size());
+
+  nghttp2_option_del(options);
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace adapter
+}  // namespace http2