Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / net / tools / flip_server / spdy_interface_test.cc
index 4dbfea8..98eb3bf 100644 (file)
@@ -25,15 +25,14 @@ using ::testing::InSequence;
 using ::testing::InvokeWithoutArgs;
 using ::testing::Return;
 using ::testing::SaveArg;
+using ::testing::Values;
 
 namespace {
 
 struct StringSaver {
  public:
   StringSaver() : data(NULL), size(0) {}
-  void Save() {
-    string = std::string(data, size);
-  }
+  void Save() { string = std::string(data, size); }
 
   const char* data;
   size_t size;
@@ -45,24 +44,23 @@ class SpdyFramerVisitor : public BufferedSpdyFramerVisitorInterface {
   virtual ~SpdyFramerVisitor() {}
   MOCK_METHOD1(OnError, void(SpdyFramer::SpdyError));
   MOCK_METHOD2(OnStreamError, void(SpdyStreamId, const std::string&));
-  MOCK_METHOD7(OnSynStream, void(SpdyStreamId,
-                                 SpdyStreamId,
-                                 SpdyPriority,
-                                 uint8,
-                                 bool,
-                                 bool,
-                                 const SpdyHeaderBlock&));
-  MOCK_METHOD3(OnSynStream, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
+  MOCK_METHOD6(OnSynStream,
+               void(SpdyStreamId,
+                    SpdyStreamId,
+                    SpdyPriority,
+                    bool,
+                    bool,
+                    const SpdyHeaderBlock&));
   MOCK_METHOD3(OnSynReply, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
   MOCK_METHOD3(OnHeaders, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
+  MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId, size_t, bool));
   MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId,
                                        const char*,
                                        size_t,
                                        bool));
-  MOCK_METHOD1(OnStreamFrameData, void(bool));
-  MOCK_METHOD1(OnSettings, void(bool));
+  MOCK_METHOD1(OnSettings, void(bool clear_persisted));
   MOCK_METHOD3(OnSetting, void(SpdySettingsIds, uint8, uint32));
-  MOCK_METHOD1(OnPing, void(uint32));
+  MOCK_METHOD1(OnPing, void(SpdyPingId unique_id));
   MOCK_METHOD2(OnRstStream, void(SpdyStreamId, SpdyRstStreamStatus));
   MOCK_METHOD2(OnGoAway, void(SpdyStreamId, SpdyGoAwayStatus));
   MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId, uint32));
@@ -83,39 +81,42 @@ class FakeSMConnection : public SMConnection {
                      log_prefix) {}
 
   MOCK_METHOD0(Cleanup, void());
-  MOCK_METHOD8(InitSMConnection, void(SMConnectionPoolInterface*,
-                                      SMInterface*,
-                                      EpollServer*,
-                                      int,
-                                      std::string,
-                                      std::string,
-                                      std::string,
-                                      bool));
+  MOCK_METHOD8(InitSMConnection,
+               void(SMConnectionPoolInterface*,
+                    SMInterface*,
+                    EpollServer*,
+                    int,
+                    std::string,
+                    std::string,
+                    std::string,
+                    bool));
 };
 
-class SpdySMWithMockSMInterfaceFactory : public SpdySM {
+// This class is almost SpdySM, except one function.
+// This class is the test target of tests in this file.
+class TestSpdySM : public SpdySM {
  public:
-  virtual ~SpdySMWithMockSMInterfaceFactory() {}
-  SpdySMWithMockSMInterfaceFactory(SMConnection* connection,
-                                   SMInterface* sm_http_interface,
-                                   EpollServer* epoll_server,
-                                   MemoryCache* memory_cache,
-                                   FlipAcceptor* acceptor)
+  virtual ~TestSpdySM() {}
+  TestSpdySM(SMConnection* connection,
+             SMInterface* sm_http_interface,
+             EpollServer* epoll_server,
+             MemoryCache* memory_cache,
+             FlipAcceptor* acceptor,
+             SpdyMajorVersion version)
       : SpdySM(connection,
                sm_http_interface,
                epoll_server,
                memory_cache,
-               acceptor) {}
+               acceptor,
+               version) {}
 
   MOCK_METHOD2(FindOrMakeNewSMConnectionInterface,
                SMInterface*(const std::string&, const std::string&));
 };
 
-class FlipSpdySMTest : public ::testing::Test {
+class SpdySMTestBase : public ::testing::TestWithParam<SpdyMajorVersion> {
  public:
-  FlipSpdySMTest(SpdyMajorVersion version = SPDY2,
-                 FlipHandlerType type = FLIP_HANDLER_PROXY)
-      : spdy_version_(version) {
+  explicit SpdySMTestBase(FlipHandlerType type) {
     SSLState* ssl_state = NULL;
     mock_another_interface_.reset(new MockSMInterface);
     memory_cache_.reset(new MemoryCache);
@@ -142,19 +143,19 @@ class FlipSpdySMTest : public ::testing::Test {
                                            acceptor_.get(),
                                            "log_prefix"));
 
-    interface_.reset(new SpdySMWithMockSMInterfaceFactory(
-        connection_.get(),
-        mock_another_interface_.get(),
-        epoll_server_.get(),
-        memory_cache_.get(),
-        acceptor_.get()));
+    interface_.reset(new TestSpdySM(connection_.get(),
+                                    mock_another_interface_.get(),
+                                    epoll_server_.get(),
+                                    memory_cache_.get(),
+                                    acceptor_.get(),
+                                    GetParam()));
 
-    spdy_framer_.reset(new BufferedSpdyFramer(spdy_version_, true));
+    spdy_framer_.reset(new BufferedSpdyFramer(GetParam(), true));
     spdy_framer_visitor_.reset(new SpdyFramerVisitor);
     spdy_framer_->set_visitor(spdy_framer_visitor_.get());
   }
 
-  virtual void TearDown() OVERRIDE {
+  virtual ~SpdySMTestBase() {
     if (acceptor_->listen_fd_ >= 0) {
       epoll_server_->UnregisterFD(acceptor_->listen_fd_);
       close(acceptor_->listen_fd_);
@@ -174,59 +175,94 @@ class FlipSpdySMTest : public ::testing::Test {
   }
 
  protected:
-  SpdyMajorVersion spdy_version_;
   scoped_ptr<MockSMInterface> mock_another_interface_;
   scoped_ptr<MemoryCache> memory_cache_;
   scoped_ptr<FlipAcceptor> acceptor_;
   scoped_ptr<EpollServer> epoll_server_;
   scoped_ptr<FakeSMConnection> connection_;
-  scoped_ptr<SpdySMWithMockSMInterfaceFactory> interface_;
+  scoped_ptr<TestSpdySM> interface_;
   scoped_ptr<BufferedSpdyFramer> spdy_framer_;
   scoped_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
 };
 
-class FlipSpdy2SMTest : public FlipSpdySMTest {
+class SpdySMProxyTest : public SpdySMTestBase {
  public:
-  FlipSpdy2SMTest(): FlipSpdySMTest(SPDY2) {}
-  virtual ~FlipSpdy2SMTest() {}
+  SpdySMProxyTest() : SpdySMTestBase(FLIP_HANDLER_PROXY) {}
+  virtual ~SpdySMProxyTest() {}
 };
 
-class FlipSpdy2SMTestNonProxy : public FlipSpdySMTest {
+class SpdySMServerTest : public SpdySMTestBase {
  public:
-  FlipSpdy2SMTestNonProxy(): FlipSpdySMTest(SPDY2, FLIP_HANDLER_SPDY_SERVER) {}
-  virtual ~FlipSpdy2SMTestNonProxy() {}
+  SpdySMServerTest() : SpdySMTestBase(FLIP_HANDLER_SPDY_SERVER) {}
+  virtual ~SpdySMServerTest() {}
 };
 
-TEST_F(FlipSpdySMTest, InitSMConnection) {
+INSTANTIATE_TEST_CASE_P(SpdySMProxyTest,
+                        SpdySMProxyTest,
+                        Values(SPDY2, SPDY3, SPDY4));
+INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(SPDY2));
+
+TEST_P(SpdySMProxyTest, InitSMConnection) {
   {
     InSequence s;
     EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _));
   }
-  interface_->InitSMConnection(NULL,
-                               NULL,
-                               epoll_server_.get(),
-                               -1,
-                               "",
-                               "",
-                               "",
-                               false);
+  interface_->InitSMConnection(
+      NULL, NULL, epoll_server_.get(), -1, "", "", "", false);
 }
 
-TEST_F(FlipSpdySMTest, OnSynStream) {
+TEST_P(SpdySMProxyTest, OnSynStream_SPDY2) {
+  if (GetParam() != SPDY2) {
+    // This test case is for SPDY2.
+    return;
+  }
   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
   uint32 stream_id = 92;
   uint32 associated_id = 43;
   std::string expected = "GET /path HTTP/1.0\r\n"
-      "method: GET\r\n"
-      "scheme: http\r\n"
-      "url: http://www.example.com/path\r\n"
-      "version: HTTP/1.0\r\n\r\n";
+      "Host: 127.0.0.1\r\n"
+      "hoge: fuga\r\n\r\n";
   SpdyHeaderBlock block;
   block["method"] = "GET";
-  block["url"] = "http://www.example.com/path";
+  block["url"] = "/path";
   block["scheme"] = "http";
   block["version"] = "HTTP/1.0";
+  block["hoge"] = "fuga";
+  StringSaver saver;
+  {
+    InSequence s;
+    EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _))
+        .WillOnce(Return(mock_interface.get()));
+    EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
+    EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _))
+        .WillOnce(DoAll(SaveArg<0>(&saver.data),
+                        SaveArg<1>(&saver.size),
+                        InvokeWithoutArgs(&saver, &StringSaver::Save),
+                        Return(0)));
+  }
+  visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
+  ASSERT_EQ(expected, saver.string);
+}
+
+TEST_P(SpdySMProxyTest, OnSynStream) {
+  if (GetParam() == SPDY2) {
+    // This test case is not for SPDY2.
+    return;
+  }
+  BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
+  scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
+  uint32 stream_id = 92;
+  uint32 associated_id = 43;
+  std::string expected = "GET /path HTTP/1.1\r\n"
+      "Host: 127.0.0.1\r\n"
+      "foo: bar\r\n\r\n";
+  SpdyHeaderBlock block;
+  block[":method"] = "GET";
+  block[":host"] = "www.example.com";
+  block[":path"] = "/path";
+  block[":scheme"] = "http";
+  block["foo"] = "bar";
   StringSaver saver;
   {
     InSequence s;
@@ -240,17 +276,21 @@ TEST_F(FlipSpdySMTest, OnSynStream) {
                         InvokeWithoutArgs(&saver, &StringSaver::Save),
                         Return(0)));
   }
-  visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
+  visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
   ASSERT_EQ(expected, saver.string);
 }
 
-TEST_F(FlipSpdySMTest, OnStreamFrameData) {
+TEST_P(SpdySMProxyTest, OnStreamFrameData_SPDY2) {
+  if (GetParam() != SPDY2) {
+    // This test case is for SPDY2.
+    return;
+  }
   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
   uint32 stream_id = 92;
   uint32 associated_id = 43;
   SpdyHeaderBlock block;
-  testing::MockFunction<void(int)> checkpoint;
+  testing::MockFunction<void(int)> checkpoint;  // NOLINT
 
   scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12));
   block["method"] = "GET";
@@ -259,6 +299,40 @@ TEST_F(FlipSpdySMTest, OnStreamFrameData) {
   block["version"] = "HTTP/1.0";
   {
     InSequence s;
+    EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _))
+        .WillOnce(Return(mock_interface.get()));
+    EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
+    EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1);
+    EXPECT_CALL(checkpoint, Call(0));
+    EXPECT_CALL(*mock_interface,
+                ProcessWriteInput(frame->data(), frame->size())).Times(1);
+  }
+
+  visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
+  checkpoint.Call(0);
+  visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
+}
+
+TEST_P(SpdySMProxyTest, OnStreamFrameData) {
+  if (GetParam() == SPDY2) {
+    // This test case is not for SPDY2.
+    return;
+  }
+  BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
+  scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
+  uint32 stream_id = 92;
+  uint32 associated_id = 43;
+  SpdyHeaderBlock block;
+  testing::MockFunction<void(int)> checkpoint;  // NOLINT
+
+  scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12));
+  block[":method"] = "GET";
+  block[":host"] = "www.example.com";
+  block[":path"] = "/path";
+  block[":scheme"] = "http";
+  block["foo"] = "bar";
+  {
+    InSequence s;
     EXPECT_CALL(*interface_,
                 FindOrMakeNewSMConnectionInterface(_, _))
         .WillOnce(Return(mock_interface.get()));
@@ -269,12 +343,12 @@ TEST_F(FlipSpdySMTest, OnStreamFrameData) {
                 ProcessWriteInput(frame->data(), frame->size())).Times(1);
   }
 
-  visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
+  visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
   checkpoint.Call(0);
   visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
 }
 
-TEST_F(FlipSpdySMTest, OnRstStream) {
+TEST_P(SpdySMProxyTest, OnRstStream) {
   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
   uint32 stream_id = 82;
   MemCacheIter mci;
@@ -293,14 +367,14 @@ TEST_F(FlipSpdySMTest, OnRstStream) {
   ASSERT_FALSE(HasStream(stream_id));
 }
 
-TEST_F(FlipSpdySMTest, ProcessReadInput) {
+TEST_P(SpdySMProxyTest, ProcessReadInput) {
   ASSERT_EQ(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
   interface_->ProcessReadInput("", 1);
   ASSERT_EQ(SpdyFramer::SPDY_READING_COMMON_HEADER,
             interface_->spdy_framer()->state());
 }
 
-TEST_F(FlipSpdySMTest, ResetForNewConnection) {
+TEST_P(SpdySMProxyTest, ResetForNewConnection) {
   uint32 stream_id = 13;
   MemCacheIter mci;
   mci.stream_id = stream_id;
@@ -324,7 +398,7 @@ TEST_F(FlipSpdySMTest, ResetForNewConnection) {
   ASSERT_EQ(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
 }
 
-TEST_F(FlipSpdySMTest, PostAcceptHook) {
+TEST_P(SpdySMProxyTest, PostAcceptHook) {
   interface_->PostAcceptHook();
 
   ASSERT_EQ(1u, connection_->output_list()->size());
@@ -334,19 +408,19 @@ TEST_F(FlipSpdySMTest, PostAcceptHook) {
   {
     InSequence s;
     EXPECT_CALL(*spdy_framer_visitor_, OnSettings(false));
-    EXPECT_CALL(*spdy_framer_visitor_, OnSetting(
-        SETTINGS_MAX_CONCURRENT_STREAMS, 0u, 100u));
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 0u, 100u));
   }
   spdy_framer_->ProcessInput(df->data, df->size);
 }
 
-TEST_F(FlipSpdySMTest, NewStream) {
+TEST_P(SpdySMProxyTest, NewStream) {
   // TODO(yhirano): SpdySM::NewStream leads to crash when
   // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER.
   // It should be fixed though I don't know the solution now.
 }
 
-TEST_F(FlipSpdySMTest, AddToOutputOrder) {
+TEST_P(SpdySMProxyTest, AddToOutputOrder) {
   uint32 stream_id = 13;
   MemCacheIter mci;
   mci.stream_id = stream_id;
@@ -362,12 +436,16 @@ TEST_F(FlipSpdySMTest, AddToOutputOrder) {
   ASSERT_TRUE(HasStream(stream_id));
 }
 
-TEST_F(FlipSpdySMTest, SendErrorNotFound) {
+TEST_P(SpdySMProxyTest, SendErrorNotFound_SPDY2) {
+  if (GetParam() != SPDY2) {
+    // This test is for SPDY2.
+    return;
+  }
   uint32 stream_id = 82;
   SpdyHeaderBlock actual_header_block;
   const char* actual_data;
   size_t actual_size;
-  testing::MockFunction<void(int)> checkpoint;
+  testing::MockFunction<void(int)> checkpoint;  // NOLINT
 
   interface_->SendErrorNotFound(stream_id);
 
@@ -375,11 +453,17 @@ TEST_F(FlipSpdySMTest, SendErrorNotFound) {
 
   {
     InSequence s;
-    EXPECT_CALL(*spdy_framer_visitor_,
-                OnSynReply(stream_id, false, _))
-        .WillOnce(SaveArg<2>(&actual_header_block));
+    if (GetParam() < SPDY4) {
+      EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    } else {
+      EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    }
     EXPECT_CALL(checkpoint, Call(0));
     EXPECT_CALL(*spdy_framer_visitor_,
+                OnDataFrameHeader(stream_id, _, true));
+    EXPECT_CALL(*spdy_framer_visitor_,
                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
         .WillOnce(DoAll(SaveArg<1>(&actual_data),
                         SaveArg<2>(&actual_size)));
@@ -401,7 +485,62 @@ TEST_F(FlipSpdySMTest, SendErrorNotFound) {
   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
 }
 
-TEST_F(FlipSpdySMTest, SendSynStream) {
+TEST_P(SpdySMProxyTest, SendErrorNotFound) {
+  if (GetParam() == SPDY2) {
+    // This test is not for SPDY2.
+    return;
+  }
+  uint32 stream_id = 82;
+  SpdyHeaderBlock actual_header_block;
+  const char* actual_data;
+  size_t actual_size;
+  testing::MockFunction<void(int)> checkpoint;  // NOLINT
+
+  interface_->SendErrorNotFound(stream_id);
+
+  ASSERT_EQ(2u, connection_->output_list()->size());
+
+  {
+    InSequence s;
+    if (GetParam() < SPDY4) {
+      EXPECT_CALL(*spdy_framer_visitor_,
+                  OnSynReply(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    } else {
+      EXPECT_CALL(*spdy_framer_visitor_,
+                  OnHeaders(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    }
+    EXPECT_CALL(checkpoint, Call(0));
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnDataFrameHeader(stream_id, _, true));
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnStreamFrameData(stream_id, _, _, false)).Times(1)
+        .WillOnce(DoAll(SaveArg<1>(&actual_data),
+                        SaveArg<2>(&actual_size)));
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
+  }
+
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+  spdy_framer_->ProcessInput(df->data, df->size);
+  checkpoint.Call(0);
+  df = *i++;
+  spdy_framer_->ProcessInput(df->data, df->size);
+
+  ASSERT_EQ(2, spdy_framer_->frames_received());
+  ASSERT_EQ(2u, actual_header_block.size());
+  ASSERT_EQ("404 Not Found", actual_header_block[":status"]);
+  ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
+  ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
+}
+
+TEST_P(SpdySMProxyTest, SendSynStream_SPDY2) {
+  if (GetParam() != SPDY2) {
+    // This test is for SPDY2.
+    return;
+  }
   uint32 stream_id = 82;
   BalsaHeaders headers;
   SpdyHeaderBlock actual_header_block;
@@ -417,8 +556,8 @@ TEST_F(FlipSpdySMTest, SendSynStream) {
   {
     InSequence s;
     EXPECT_CALL(*spdy_framer_visitor_,
-                OnSynStream(stream_id, 0, _, _, false, false, _))
-        .WillOnce(SaveArg<6>(&actual_header_block));
+                OnSynStream(stream_id, 0, _, false, false, _))
+        .WillOnce(SaveArg<5>(&actual_header_block));
   }
 
   spdy_framer_->ProcessInput(df->data, df->size);
@@ -430,7 +569,46 @@ TEST_F(FlipSpdySMTest, SendSynStream) {
   ASSERT_EQ("value1", actual_header_block["key1"]);
 }
 
-TEST_F(FlipSpdySMTest, SendSynReply) {
+TEST_P(SpdySMProxyTest, SendSynStream) {
+  if (GetParam() == SPDY2) {
+    // This test is not for SPDY2.
+    return;
+  }
+  uint32 stream_id = 82;
+  BalsaHeaders headers;
+  SpdyHeaderBlock actual_header_block;
+  headers.AppendHeader("key1", "value1");
+  headers.AppendHeader("Host", "www.example.com");
+  headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.1");
+
+  interface_->SendSynStream(stream_id, headers);
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+
+  {
+    InSequence s;
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnSynStream(stream_id, 0, _, false, false, _))
+        .WillOnce(SaveArg<5>(&actual_header_block));
+  }
+
+  spdy_framer_->ProcessInput(df->data, df->size);
+  ASSERT_EQ(1, spdy_framer_->frames_received());
+  ASSERT_EQ(5u, actual_header_block.size());
+  ASSERT_EQ("GET", actual_header_block[":method"]);
+  ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
+  ASSERT_EQ("/path", actual_header_block[":path"]);
+  ASSERT_EQ("www.example.com", actual_header_block[":host"]);
+  ASSERT_EQ("value1", actual_header_block["key1"]);
+}
+
+TEST_P(SpdySMProxyTest, SendSynReply_SPDY2) {
+  if (GetParam() != SPDY2) {
+    // This test is for SPDY2.
+    return;
+  }
   uint32 stream_id = 82;
   BalsaHeaders headers;
   SpdyHeaderBlock actual_header_block;
@@ -445,8 +623,13 @@ TEST_F(FlipSpdySMTest, SendSynReply) {
 
   {
     InSequence s;
-    EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
-        .WillOnce(SaveArg<2>(&actual_header_block));
+    if (GetParam() < SPDY4) {
+      EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    } else {
+      EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    }
   }
 
   spdy_framer_->ProcessInput(df->data, df->size);
@@ -457,7 +640,43 @@ TEST_F(FlipSpdySMTest, SendSynReply) {
   ASSERT_EQ("value1", actual_header_block["key1"]);
 }
 
-TEST_F(FlipSpdySMTest, SendDataFrame) {
+TEST_P(SpdySMProxyTest, SendSynReply) {
+  if (GetParam() == SPDY2) {
+    // This test is not for SPDY2.
+    return;
+  }
+  uint32 stream_id = 82;
+  BalsaHeaders headers;
+  SpdyHeaderBlock actual_header_block;
+  headers.AppendHeader("key1", "value1");
+  headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
+
+  interface_->SendSynReply(stream_id, headers);
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+
+  {
+    InSequence s;
+    if (GetParam() < SPDY4) {
+      EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    } else {
+      EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    }
+  }
+
+  spdy_framer_->ProcessInput(df->data, df->size);
+  ASSERT_EQ(1, spdy_framer_->frames_received());
+  ASSERT_EQ(3u, actual_header_block.size());
+  ASSERT_EQ("200 OK", actual_header_block[":status"]);
+  ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
+  ASSERT_EQ("value1", actual_header_block["key1"]);
+}
+
+TEST_P(SpdySMProxyTest, SendDataFrame) {
   uint32 stream_id = 133;
   SpdyDataFlags flags = DATA_FLAG_NONE;
   const char* actual_data;
@@ -472,9 +691,10 @@ TEST_F(FlipSpdySMTest, SendDataFrame) {
   {
     InSequence s;
     EXPECT_CALL(*spdy_framer_visitor_,
+                OnDataFrameHeader(stream_id, _, false));
+    EXPECT_CALL(*spdy_framer_visitor_,
                 OnStreamFrameData(stream_id, _, _, false))
-        .WillOnce(DoAll(SaveArg<1>(&actual_data),
-                        SaveArg<2>(&actual_size)));
+        .WillOnce(DoAll(SaveArg<1>(&actual_data), SaveArg<2>(&actual_size)));
   }
 
   spdy_framer_->ProcessInput(df->data, df->size);
@@ -482,24 +702,26 @@ TEST_F(FlipSpdySMTest, SendDataFrame) {
   ASSERT_EQ("hello", StringPiece(actual_data, actual_size));
 }
 
-TEST_F(FlipSpdySMTest, SendLongDataFrame) {
+TEST_P(SpdySMProxyTest, SendLongDataFrame) {
   uint32 stream_id = 133;
   SpdyDataFlags flags = DATA_FLAG_NONE;
   const char* actual_data;
   size_t actual_size;
 
-  std::string data =
-      std::string(kSpdySegmentSize, 'a') +
-      std::string(kSpdySegmentSize, 'b') +
-      "c";
+  std::string data = std::string(kSpdySegmentSize, 'a') +
+                     std::string(kSpdySegmentSize, 'b') + "c";
   interface_->SendDataFrame(stream_id, data.data(), data.size(), flags, true);
 
   {
     InSequence s;
-    EXPECT_CALL(*spdy_framer_visitor_,
-                OnStreamFrameData(stream_id, _, _, false)).Times(3)
-        .WillRepeatedly(DoAll(SaveArg<1>(&actual_data),
-                        SaveArg<2>(&actual_size)));
+    for (int i = 0; i < 3; ++i) {
+        EXPECT_CALL(*spdy_framer_visitor_,
+                    OnDataFrameHeader(stream_id, _, false));
+        EXPECT_CALL(*spdy_framer_visitor_,
+                    OnStreamFrameData(stream_id, _, _, false))
+            .WillOnce(DoAll(SaveArg<1>(&actual_data),
+                            SaveArg<2>(&actual_size)));
+    }
   }
 
   ASSERT_EQ(3u, connection_->output_list()->size());
@@ -519,7 +741,12 @@ TEST_F(FlipSpdySMTest, SendLongDataFrame) {
   ASSERT_EQ("c", StringPiece(actual_data, actual_size));
 }
 
-TEST_F(FlipSpdy2SMTest, SendEOF) {
+TEST_P(SpdySMProxyTest, SendEOF_SPDY2) {
+  // This test is for SPDY2.
+  if (GetParam() != SPDY2) {
+    return;
+  }
+
   uint32 stream_id = 82;
   // SPDY2 data frame
   char empty_data_frame[] = {'\0', '\0', '\0', '\x52', '\x1', '\0', '\0', '\0'};
@@ -545,7 +772,12 @@ TEST_F(FlipSpdy2SMTest, SendEOF) {
             StringPiece(df->data, df->size));
 }
 
-TEST_F(FlipSpdy2SMTest, SendEmptyDataFrame) {
+TEST_P(SpdySMProxyTest, SendEmptyDataFrame_SPDY2) {
+  // This test is for SPDY2.
+  if (GetParam() != SPDY2) {
+    return;
+  }
+
   uint32 stream_id = 133;
   SpdyDataFlags flags = DATA_FLAG_NONE;
   // SPDY2 data frame
@@ -561,23 +793,24 @@ TEST_F(FlipSpdy2SMTest, SendEmptyDataFrame) {
             StringPiece(df->data, df->size));
 }
 
-TEST_F(FlipSpdy2SMTestNonProxy, OnSynStream) {
+TEST_P(SpdySMServerTest, OnSynStream) {
   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
   uint32 stream_id = 82;
   SpdyHeaderBlock spdy_headers;
   spdy_headers["url"] = "http://www.example.com/path";
   spdy_headers["method"] = "GET";
   spdy_headers["scheme"] = "http";
+  spdy_headers["version"] = "HTTP/1.1";
 
   {
     BalsaHeaders headers;
     memory_cache_->InsertFile(&headers, "GET_/path", "");
   }
-  visitor->OnSynStream(stream_id, 0, 0, 0, true, true, spdy_headers);
+  visitor->OnSynStream(stream_id, 0, 0, true, true, spdy_headers);
   ASSERT_TRUE(HasStream(stream_id));
 }
 
-TEST_F(FlipSpdy2SMTestNonProxy, NewStream) {
+TEST_P(SpdySMServerTest, NewStream) {
   uint32 stream_id = 13;
   std::string filename = "foobar";
 
@@ -590,12 +823,12 @@ TEST_F(FlipSpdy2SMTestNonProxy, NewStream) {
   ASSERT_TRUE(HasStream(stream_id));
 }
 
-TEST_F(FlipSpdy2SMTestNonProxy, NewStreamError) {
+TEST_P(SpdySMServerTest, NewStreamError) {
   uint32 stream_id = 82;
   SpdyHeaderBlock actual_header_block;
   const char* actual_data;
   size_t actual_size;
-  testing::MockFunction<void(int)> checkpoint;
+  testing::MockFunction<void(int)> checkpoint;  // NOLINT
 
   interface_->NewStream(stream_id, 0, "nonexistingfile");
 
@@ -603,11 +836,17 @@ TEST_F(FlipSpdy2SMTestNonProxy, NewStreamError) {
 
   {
     InSequence s;
-    EXPECT_CALL(*spdy_framer_visitor_,
-                OnSynReply(stream_id, false, _))
-        .WillOnce(SaveArg<2>(&actual_header_block));
+    if (GetParam() < SPDY4) {
+      EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    } else {
+      EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
+          .WillOnce(SaveArg<2>(&actual_header_block));
+    }
     EXPECT_CALL(checkpoint, Call(0));
     EXPECT_CALL(*spdy_framer_visitor_,
+                OnDataFrameHeader(stream_id, _, true));
+    EXPECT_CALL(*spdy_framer_visitor_,
                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
         .WillOnce(DoAll(SaveArg<1>(&actual_data),
                         SaveArg<2>(&actual_size)));