spdy network tests now use http network transaction (production code).
BUG=NONE
TEST=net_unittests

Review URL: http://codereview.chromium.org/2804045

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52670 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index 5235427..88b35339 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -31,7 +31,7 @@
 namespace {
 
 // Helper to manage the lifetimes of the dependencies for a
-// SpdyNetworkTransaction.
+// HttpNetworkTransaction.
 class SessionDependencies {
  public:
   // Default set of dependencies -- "null" proxy service.
@@ -85,6 +85,9 @@
     // By default, all tests turn off compression.
     EnableCompression(false);
     google_get_request_initialized_ = false;
+    HttpNetworkTransaction::SetUseAlternateProtocols(true);
+    HttpNetworkTransaction::SetNextProtos(
+        "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy");
   }
 
   virtual void TearDown() {
@@ -106,60 +109,168 @@
     spdy::SpdyFramer::set_enable_compression_default(enabled);
   }
 
-  TransactionHelperResult TransactionHelper(const HttpRequestInfo& request,
-                                            DelayedSocketData* data,
-                                            const BoundNetLog& log) {
-    SessionDependencies session_deps;
-    HttpNetworkSession* session = CreateSession(&session_deps);
-    return TransactionHelperWithSession(request, data, log, &session_deps,
-                                        session);
-  }
+  class StartTransactionCallback;
+  class DeleteSessionCallback;
 
-  TransactionHelperResult TransactionHelperWithSession(
-      const HttpRequestInfo& request, DelayedSocketData* data,
-      const BoundNetLog& log, SessionDependencies* session_deps,
-      HttpNetworkSession* session) {
-    CHECK(session);
-    CHECK(session_deps);
+  // A helper class that handles all the initial npn/ssl setup.
+  class NormalSpdyTransactionHelper {
+   public:
+    NormalSpdyTransactionHelper(const HttpRequestInfo& request,
+                                const BoundNetLog& log)
+        : request_(request), session_(CreateSession(&session_deps_)),
+          log_(log), add_data_allowed_(true) {}
 
-    TransactionHelperResult out;
+    void RunPreTestSetup() {
+      // Disallow future calls to AddData
+      add_data_allowed_ = false;
 
-    // We disable SSL for this test.
-    SpdySession::SetSSLMode(false);
+      // Set up http data.
+      MockRead data_reads[] = {
+        MockRead("HTTP/1.1 200 OK\r\n"),
+        MockRead("Alternate-Protocol: 443:npn-spdy/1\r\n\r\n"),
+        MockRead("hello world"),
+        MockRead(true, OK),
+      };
+      first_transaction_.reset(
+          new StaticSocketDataProvider(data_reads, arraysize(data_reads),
+                                       NULL, 0));
+      session_deps_.socket_factory.AddSocketDataProvider(
+          first_transaction_.get());
 
-    scoped_ptr<SpdyNetworkTransaction> trans(
-        new SpdyNetworkTransaction(session));
+      // Set up actual test data. Also add one SSLSocketDataProvider per
+      // DataProvider.
+      for(DataVector::iterator it = data_vector_.begin();
+          it != data_vector_.end(); ++it) {
+        linked_ptr<SSLSocketDataProvider> ssl_(
+            new SSLSocketDataProvider(true, OK));
+        ssl_->next_proto_status = SSLClientSocket::kNextProtoNegotiated;
+        ssl_->next_proto = "spdy/1";
+        ssl_->was_npn_negotiated = true;
+        ssl_vector_.push_back(ssl_);
+        session_deps_.socket_factory.AddSSLSocketDataProvider(ssl_.get());
+        session_deps_.socket_factory.AddSocketDataProvider(*it);
+      }
 
-    session_deps->socket_factory.AddSocketDataProvider(data);
+      // We first send an http request. The Alternate-Protocol header switches
+      // the HttpNetworkTransaction into SSL/SPDY mode.
+      trans_http_.reset(new HttpNetworkTransaction(session_));
+      int rv = trans_http_->Start(&request_, &callback, log_);
+      EXPECT_EQ(ERR_IO_PENDING, rv);
+      EXPECT_EQ(OK, callback.WaitForResult());
+      const HttpResponseInfo* response = trans_http_->GetResponseInfo();
+      EXPECT_TRUE(response != NULL);
+      EXPECT_TRUE(response->headers != NULL);
+      EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+      std::string response_data;
+      EXPECT_EQ(OK, ReadTransaction(trans_http_.get(), &response_data));
+      EXPECT_EQ("hello world", response_data);
 
-    TestCompletionCallback callback;
-
-    out.rv = trans->Start(&request, &callback, log);
-    EXPECT_LT(out.rv, 0);  // We expect an IO Pending or some sort of error.
-    if (out.rv != ERR_IO_PENDING)
-      return out;
-
-    out.rv = callback.WaitForResult();
-    if (out.rv != OK) {
-      session->spdy_session_pool()->ClearSessions();
-      return out;
+      // We're now ready to use SSL-npn SPDY.
+      trans_.reset(new HttpNetworkTransaction(session_));
     }
 
-    const HttpResponseInfo* response = trans->GetResponseInfo();
-    EXPECT_TRUE(response->headers != NULL);
-    EXPECT_TRUE(response->was_fetched_via_spdy);
-    out.status_line = response->headers->GetStatusLine();
-    out.response_info = *response;  // Make a copy so we can verify.
+    // Start the transaction, read some data, finish.
+    void RunDefaultTest() {
+      output_.rv = trans_->Start(&request_, &callback, log_);
 
-    out.rv = ReadTransaction(trans.get(), &out.response_data);
-    EXPECT_EQ(OK, out.rv);
+      // We expect an IO Pending or some sort of error.
+      EXPECT_LT(output_.rv, 0);
+      if (output_.rv != ERR_IO_PENDING)
+        return;
 
-    // Verify that we consumed all test data.
-    EXPECT_TRUE(data->at_read_eof());
-    EXPECT_TRUE(data->at_write_eof());
+      output_.rv = callback.WaitForResult();
+      if (output_.rv != OK) {
+        session_->spdy_session_pool()->ClearSessions();
+        return;
+      }
 
-    return out;
-  }
+      // Verify responses.
+      const HttpResponseInfo* response = trans_->GetResponseInfo();
+      ASSERT_TRUE(response != NULL);
+      ASSERT_TRUE(response->headers != NULL);
+      EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+      EXPECT_TRUE(response->was_fetched_via_spdy);
+      EXPECT_TRUE(response->was_npn_negotiated);
+      EXPECT_TRUE(response->was_alternate_protocol_available);
+      output_.status_line = response->headers->GetStatusLine();
+      output_.response_info = *response;  // Make a copy so we can verify.
+      output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
+      EXPECT_EQ(OK, output_.rv);
+      return;
+    }
+
+    // Most tests will want to call this function. In particular, the MockReads
+    // should end with an empty read, and that read needs to be processed to
+    // ensure proper deletion of the spdy_session_pool.
+    void VerifyDataConsumed() {
+      for(DataVector::iterator it = data_vector_.begin();
+          it != data_vector_.end(); ++it) {
+        EXPECT_TRUE((*it)->at_read_eof()) << "Read count: "
+                                          << (*it)->read_count()
+                                          << " Read index: "
+                                          << (*it)->read_index();
+        EXPECT_TRUE((*it)->at_write_eof()) << "Write count: "
+                                           << (*it)->write_count()
+                                           << " Write index: "
+                                           << (*it)->write_index();
+      }
+    }
+
+    // Occasionally a test will expect to error out before certain reads are
+    // processed. In that case we want to explicitly ensure that the reads were
+    // not processed.
+    void VerifyDataNotConsumed() {
+      for(DataVector::iterator it = data_vector_.begin();
+          it != data_vector_.end(); ++it) {
+        EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: "
+                                           << (*it)->read_count()
+                                           << " Read index: "
+                                           << (*it)->read_index();
+        EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: "
+                                            << (*it)->write_count()
+                                            << " Write index: "
+                                            << (*it)->write_index();
+
+      }
+    }
+
+    void RunToCompletion(StaticSocketDataProvider* data) {
+      AddData(data);
+      RunPreTestSetup();
+      RunDefaultTest();
+      VerifyDataConsumed();
+    }
+    // Only call AddData before calling RunPreTestSetup!!
+    void AddData(StaticSocketDataProvider* data) {
+      EXPECT_TRUE(add_data_allowed_);
+      data_vector_.push_back(data);
+    }
+
+    void SetSession(scoped_refptr<HttpNetworkSession>& session) {
+      session_ = session;
+    }
+    HttpNetworkTransaction* trans() { return trans_.get(); }
+    void ResetTrans() { trans_.reset(); }
+    TransactionHelperResult& output() { return output_; }
+    HttpRequestInfo& request() { return request_; }
+    scoped_refptr<HttpNetworkSession>& session() { return session_; }
+
+   private:
+    typedef std::vector<StaticSocketDataProvider*> DataVector;
+    typedef std::vector<linked_ptr<SSLSocketDataProvider> > SSLVector;
+    HttpRequestInfo request_;
+    SessionDependencies session_deps_;
+    scoped_refptr<HttpNetworkSession> session_;
+    TransactionHelperResult output_;
+    scoped_ptr<StaticSocketDataProvider> first_transaction_;
+    SSLVector ssl_vector_;
+    TestCompletionCallback callback;
+    scoped_ptr<HttpNetworkTransaction> trans_;
+    scoped_ptr<HttpNetworkTransaction> trans_http_;
+    DataVector data_vector_;
+    const BoundNetLog& log_;
+    bool add_data_allowed_;
+  };
 
   void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
                                              int expected_status);
@@ -183,12 +294,12 @@
 
 //-----------------------------------------------------------------------------
 
-// Verify SpdyNetworkTransaction constructor.
+// Verify HttpNetworkTransaction constructor.
 TEST_F(SpdyNetworkTransactionTest, Constructor) {
   SessionDependencies session_deps;
   scoped_refptr<HttpNetworkSession> session =
       CreateSession(&session_deps);
-  scoped_ptr<HttpTransaction> trans(new SpdyNetworkTransaction(session));
+  scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session));
 }
 
 TEST_F(SpdyNetworkTransactionTest, Get) {
@@ -207,9 +318,10 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                  data.get(),
-                                                  BoundNetLog());
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
@@ -243,8 +355,10 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(2, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  TransactionHelperResult out = TransactionHelper(request, data.get(),
-                                                  BoundNetLog());
+  NormalSpdyTransactionHelper helper(request,
+                                     BoundNetLog());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
@@ -278,7 +392,10 @@
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
 
-  TransactionHelperResult out = TransactionHelper(request, data, BoundNetLog());
+  NormalSpdyTransactionHelper helper(request,
+                                     BoundNetLog());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
@@ -312,8 +429,13 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(0, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  TransactionHelperResult out = TransactionHelper(request, data.get(),
-                                                  BoundNetLog());
+  NormalSpdyTransactionHelper helper(request,
+                                     BoundNetLog());
+  helper.AddData(data.get());
+  helper.RunPreTestSetup();
+  helper.RunDefaultTest();
+  helper.VerifyDataNotConsumed();
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
 }
 
@@ -327,21 +449,16 @@
 
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(1, reads, arraysize(reads), NULL, 0));
-  TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                  data.get(),
-                                                  BoundNetLog());
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv);
 }
 
 // Test that the transaction doesn't crash when we get two replies on the same
 // stream ID. See http://crbug.com/45639.
 TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
-  SessionDependencies session_deps;
-  HttpNetworkSession* session = CreateSession(&session_deps);
-
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
   scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0));
   MockWrite writes[] = { CreateMockWrite(*req) };
 
@@ -354,20 +471,19 @@
     MockRead(true, 0, 0)  // EOF
   };
 
-  HttpRequestInfo request;
-  request.method = "GET";
-  request.url = GURL("http://www.google.com/");
-  request.load_flags = 0;
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  session_deps.socket_factory.AddSocketDataProvider(data.get());
 
-  scoped_ptr<SpdyNetworkTransaction> trans(
-      new SpdyNetworkTransaction(session));
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.AddData(data.get());
+  helper.RunPreTestSetup();
+
+  HttpNetworkTransaction* trans = helper.trans();
 
   TestCompletionCallback callback;
-  int rv = trans->Start(&request, &callback, BoundNetLog());
+  int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
@@ -376,8 +492,10 @@
   EXPECT_TRUE(response->headers != NULL);
   EXPECT_TRUE(response->was_fetched_via_spdy);
   std::string response_data;
-  rv = ReadTransaction(trans.get(), &response_data);
+  rv = ReadTransaction(trans, &response_data);
   EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
+
+  helper.VerifyDataConsumed();
 }
 
 TEST_F(SpdyNetworkTransactionTest, CancelledTransaction) {
@@ -385,7 +503,6 @@
   scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0));
   MockWrite writes[] = {
     CreateMockWrite(*req),
-    MockRead(true, 0, 0)  // EOF
   };
 
   scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0));
@@ -393,42 +510,43 @@
     CreateMockRead(*resp),
     // This following read isn't used by the test, except during the
     // RunAllPending() call at the end since the SpdySession survives the
-    // SpdyNetworkTransaction and still tries to continue Read()'ing.  Any
+    // HttpNetworkTransaction and still tries to continue Read()'ing.  Any
     // MockRead will do here.
     MockRead(true, 0, 0)  // EOF
   };
 
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
-  SessionDependencies session_deps;
-  scoped_ptr<SpdyNetworkTransaction> trans(
-      new SpdyNetworkTransaction(CreateSession(&session_deps)));
-
   StaticSocketDataProvider data(reads, arraysize(reads),
                                 writes, arraysize(writes));
-  session_deps.socket_factory.AddSocketDataProvider(&data);
+
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.AddData(&data);
+  helper.RunPreTestSetup();
+  HttpNetworkTransaction* trans = helper.trans();
 
   TestCompletionCallback callback;
-
   int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
-  trans.reset();  // Cancel the transaction.
+  helper.ResetTrans();  // Cancel the transaction.
 
   // Flush the MessageLoop while the SessionDependencies (in particular, the
   // MockClientSocketFactory) are still alive.
   MessageLoop::current()->RunAllPending();
+  helper.VerifyDataNotConsumed();
 }
 
-class StartTransactionCallback : public CallbackRunner< Tuple1<int> > {
+class SpdyNetworkTransactionTest::StartTransactionCallback
+    : public CallbackRunner< Tuple1<int> > {
  public:
   explicit StartTransactionCallback(
-      const scoped_refptr<HttpNetworkSession>& session)
-      : session_(session) {}
+      scoped_refptr<HttpNetworkSession>& session,
+      NormalSpdyTransactionHelper& helper)
+      : session_(session), helper_(helper) {}
 
   // We try to start another transaction, which should succeed.
   virtual void RunWithParams(const Tuple1<int>& params) {
-    scoped_ptr<HttpTransaction> trans(new SpdyNetworkTransaction(session_));
+    scoped_ptr<HttpNetworkTransaction> trans(
+        new HttpNetworkTransaction(session_));
     TestCompletionCallback callback;
     HttpRequestInfo request;
     request.method = "GET";
@@ -436,10 +554,12 @@
     request.load_flags = 0;
     int rv = trans->Start(&request, &callback, BoundNetLog());
     EXPECT_EQ(ERR_IO_PENDING, rv);
+    rv = callback.WaitForResult();
   }
 
  private:
-  const scoped_refptr<HttpNetworkSession>& session_;
+  scoped_refptr<HttpNetworkSession>& session_;
+  NormalSpdyTransactionHelper& helper_;
 };
 
 // Verify that the client can correctly deal with the user callback attempting
@@ -465,54 +585,58 @@
     MockRead(true, ERR_IO_PENDING, 3),  // Force a pause
     MockRead(true, reinterpret_cast<const char*>(kGetBodyFrame2),
              arraysize(kGetBodyFrame2), 4),
-    MockRead(true, 0, 0, 5),  // EOF
+    MockRead(true, ERR_IO_PENDING, 5),  // Force a pause
+    MockRead(true, 0, 0, 6),  // EOF
   };
   MockRead reads2[] = {
     CreateMockRead(*resp, 2),
     MockRead(true, 0, 0, 3),  // EOF
   };
 
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
-  SessionDependencies session_deps;
-  scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps);
-  scoped_ptr<HttpTransaction> trans(new SpdyNetworkTransaction(session));
   scoped_refptr<OrderedSocketData> data(
       new OrderedSocketData(reads, arraysize(reads),
                             writes, arraysize(writes)));
-  scoped_refptr<OrderedSocketData> data2(
-      new OrderedSocketData(reads2, arraysize(reads2),
+  scoped_refptr<DelayedSocketData> data2(
+      new DelayedSocketData(0, reads2, arraysize(reads2),
                             writes2, arraysize(writes2)));
-  session_deps.socket_factory.AddSocketDataProvider(data);
-  session_deps.socket_factory.AddSocketDataProvider(data2);
+
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.AddData(data.get());
+  helper.AddData(data2.get());
+  helper.RunPreTestSetup();
+  HttpNetworkTransaction* trans = helper.trans();
 
   // Start the transaction with basic parameters.
   TestCompletionCallback callback;
-  int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
+  int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
 
-  StartTransactionCallback callback2(session);
+  StartTransactionCallback callback2(helper.session(), helper);
   const int kSize = 3000;
   scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize);
   rv = trans->Read(buf, kSize, &callback2);
+  // This forces an err_IO_pending, which sets the callback.
   data->CompleteRead();
-  data2->CompleteRead();
+  // This finishes the read.
+  data->CompleteRead();
+  helper.VerifyDataConsumed();
 }
 
-class DeleteSessionCallback : public CallbackRunner< Tuple1<int> > {
+class SpdyNetworkTransactionTest::DeleteSessionCallback
+    : public CallbackRunner< Tuple1<int> > {
  public:
-  explicit DeleteSessionCallback(SpdyNetworkTransaction* trans1) :
-      trans(trans1) {}
+  explicit DeleteSessionCallback(NormalSpdyTransactionHelper& helper) :
+      helper_(helper) {}
 
   // We kill the transaction, which deletes the session and stream.
   virtual void RunWithParams(const Tuple1<int>& params) {
-    delete trans;
+    helper_.ResetTrans();
   }
 
  private:
-  const SpdyNetworkTransaction* trans;
+  NormalSpdyTransactionHelper& helper_;
 };
 
 // Verify that the client can correctly deal with the user callback deleting the
@@ -531,31 +655,25 @@
     MockRead(true, 0, 0, 5),  // EOF
   };
 
-  HttpRequestInfo request;
-  request.method = "GET";
-  request.url = GURL("http://www.google.com/");
-  request.load_flags = 0;
-
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
-  SessionDependencies session_deps;
-  SpdyNetworkTransaction * trans =
-      new SpdyNetworkTransaction(CreateSession(&session_deps));
   scoped_refptr<OrderedSocketData> data(
       new OrderedSocketData(reads, arraysize(reads),
                             writes, arraysize(writes)));
-  session_deps.socket_factory.AddSocketDataProvider(data);
+
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.AddData(data.get());
+  helper.RunPreTestSetup();
+  HttpNetworkTransaction* trans = helper.trans();
 
   // Start the transaction with basic parameters.
   TestCompletionCallback callback;
-  int rv = trans->Start(&request, &callback, BoundNetLog());
+  int rv = trans->Start(&helper.request(), &callback, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
 
   // Setup a user callback which will delete the session, and clear out the
   // memory holding the stream object. Note that the callback deletes trans.
-  DeleteSessionCallback callback2(trans);
+  DeleteSessionCallback callback2(helper);
   const int kSize = 3000;
   scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(kSize);
   rv = trans->Read(buf, kSize, &callback2);
@@ -564,6 +682,7 @@
 
   // Finish running rest of tasks.
   MessageLoop::current()->RunAllPending();
+  helper.VerifyDataConsumed();
 }
 
 // Verify that various SynReply headers parse correctly through the
@@ -625,9 +744,11 @@
     scoped_refptr<DelayedSocketData> data(
         new DelayedSocketData(1, reads, arraysize(reads),
                               writes, arraysize(writes)));
-    TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                    data.get(),
-                                                    BoundNetLog());
+    NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                       BoundNetLog());
+    helper.RunToCompletion(data.get());
+    TransactionHelperResult out = helper.output();
+
     EXPECT_EQ(OK, out.rv);
     EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
     EXPECT_EQ("hello!", out.response_data);
@@ -770,9 +891,11 @@
     scoped_refptr<DelayedSocketData> data(
         new DelayedSocketData(1, reads, arraysize(reads),
                               writes, arraysize(writes)));
-    TransactionHelperResult out = TransactionHelper(request,
-                                                    data.get(),
-                                                    BoundNetLog());
+    NormalSpdyTransactionHelper helper(request,
+                                       BoundNetLog());
+    helper.RunToCompletion(data.get());
+    TransactionHelperResult out = helper.output();
+
     EXPECT_EQ(OK, out.rv) << i;
     EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i;
     EXPECT_EQ("hello!", out.response_data) << i;
@@ -855,7 +978,6 @@
     scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0));
     MockWrite writes[] = {
       CreateMockWrite(*req),
-      MockWrite(true, 0, 0)  // EOF
     };
 
     scoped_ptr<spdy::SpdyFrame> resp(
@@ -873,9 +995,10 @@
     scoped_refptr<DelayedSocketData> data(
         new DelayedSocketData(1, reads, arraysize(reads),
                               writes, arraysize(writes)));
-    TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                    data.get(),
-                                                    BoundNetLog());
+    NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                       BoundNetLog());
+    helper.RunToCompletion(data.get());
+    TransactionHelperResult out = helper.output();
     EXPECT_EQ(ERR_INVALID_RESPONSE, out.rv);
   }
 }
@@ -911,302 +1034,14 @@
     scoped_refptr<DelayedSocketData> data(
         new DelayedSocketData(1, reads, arraysize(reads),
                               writes, arraysize(writes)));
-    TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                    data.get(),
-                                                    BoundNetLog());
+    NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                       BoundNetLog());
+    helper.RunToCompletion(data.get());
+    TransactionHelperResult out = helper.output();
     EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
   }
 }
 
-// Server push:
-// ------------
-// Client: Send the original SYN request.
-// Server: Receive the SYN request.
-// Server: Send a SYN reply, with X-Associated-Content and URL(s).
-// Server: For each URL, send a SYN_STREAM with the URL and a stream ID,
-//         followed by one or more Data frames (the last one with a FIN).
-// Client: Requests the URL(s).
-// Client: Receives the SYN_STREAMs, and the associated Data frames, and
-//         associates the URLs with the incoming stream IDs.
-//
-// There are three possibilities when the client tries to send the second
-// request (which doesn't make it to the wire):
-//
-// 1. The push data has arrived and is complete.
-// 2. The push data has started arriving, but hasn't finished.
-// 3. The push data has not yet arrived.
-
-// Enum for ServerPush.
-enum TestTypes {
-  // Simulate that the server sends the first request, notifying the client
-  // that it *will* push the second stream.  But the client issues the
-  // request for the second stream before the push data arrives.
-  PUSH_AFTER_REQUEST,
-  // Simulate that the server is sending the pushed stream data before the
-  // client requests it.  The SpdySession will buffer the response and then
-  // deliver the data when the client does make the request.
-  PUSH_BEFORE_REQUEST,
-  // Simulate that the server is sending the pushed stream data before the
-  // client requests it, but the stream has not yet finished when the request
-  // occurs.  The SpdySession will buffer the response and then deliver the
-  // data when the response is complete.
-  PUSH_DURING_REQUEST,
-  DONE
-};
-
-// Creates and processes a SpdyNetworkTransaction for server push, based on
-//   |session|.
-// |data| holds the expected writes, and the reads.
-// |url| is the web page we want.  In pass 2, it contains the resource we expect
-//   to be pushed.
-// |expected_data| is the data we expect to get in response.
-// |test_type| is one of PUSH_AFTER_REQUEST, PUSH_BEFORE_REQUEST, or
-//   PUSH_DURING_REQUEST, indicating the type of test we're running.
-// |pass| is 1 for the first request, and 2 for the request for the push data.
-// |response| is the response information for the request.  It will be used to
-//   verify the response time stamps.
-static void MakeRequest(scoped_refptr<HttpNetworkSession> session,
-                        scoped_refptr<OrderedSocketData> data,
-                        const GURL& url,
-                        const std::string& expected_data,
-                        int test_type,
-                        int pass,
-                        HttpResponseInfo* response) {
-  SpdyNetworkTransaction trans(session.get());
-
-  HttpRequestInfo request;
-  request.method = "GET";
-  request.url = url;
-  request.load_flags = 0;
-  TestCompletionCallback callback;
-
-  // Allows the STOP_LOOP flag to work.
-  data->SetCompletionCallback(&callback);
-  // Sends a request.  In pass 1, this goes on the wire; in pass 2, it is
-  // preempted by the push data.
-  int rv = trans.Start(&request, &callback, BoundNetLog());
-  EXPECT_EQ(ERR_IO_PENDING, rv);
-
-  // In the case where we are pushing beforehand, complete the next read now.
-  if ((pass == 2) && (test_type == PUSH_AFTER_REQUEST)) {
-    data->CompleteRead();
-  }
-
-  // Process messages until either a FIN or a STOP_LOOP is encountered.
-  rv = callback.WaitForResult();
-  if ((pass == 2) && (test_type == PUSH_DURING_REQUEST)) {
-    // We should be in the middle of a request, so we're pending.
-    EXPECT_EQ(ERR_IO_PENDING, rv);
-  } else {
-    EXPECT_EQ(OK, rv);
-  }
-
-  // Verify the SYN_REPLY.
-  // Copy the response info, because trans goes away
-  *response = *trans.GetResponseInfo();
-  EXPECT_TRUE(response->headers != NULL);
-  EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
-
-  // In the case where we are Complete the next read now.
-  if (((pass == 1) &&
-      ((test_type == PUSH_BEFORE_REQUEST) ||
-          (test_type == PUSH_DURING_REQUEST)))) {
-    data->CompleteRead();
-  }
-
-  // Verify the body.
-  std::string response_data;
-  rv = ReadTransaction(&trans, &response_data);
-  EXPECT_EQ(OK, rv);
-  EXPECT_EQ(expected_data, response_data);
-  // Remove callback, so that if another STOP_LOOP occurs, there is no crash.
-  data->SetCompletionCallback(NULL);
-}
-
-TEST_F(SpdyNetworkTransactionTest, ServerPush) {
-  spdy::SpdyFramer framer;
-
-  // Reply with the X-Associated-Content header.
-  const char* const kSynReplyHeaders[] = {
-      "x-associated-content", "1??http://www.google.com/foo.dat",
-  };
-  scoped_ptr<spdy::SpdyFrame> syn_reply(
-      ConstructSpdyGetSynReply(kSynReplyHeaders, 1));
-
-  const char* const kSynPushHeaders[] = {
-      "path", "/foo.dat",
-      "status", "200",
-      "url", "/foo.dat",
-      "version", "HTTP/1.1",
-  };
-  spdy::SpdyHeaderBlock headers;
-  AppendHeadersToSpdyFrame(kSynPushHeaders, 4, &headers);
-  scoped_ptr<spdy::SpdyFrame> syn_push(
-      framer.CreateSynStream(2,  // Stream ID
-                             0,  // Associated stream ID
-                             SPDY_PRIORITY_LOWEST,
-                             spdy::CONTROL_FLAG_NONE,
-                             false,
-                             &headers));
-
-  // Body for stream 2
-  const char syn_body_data1[] = "hello";
-  const char syn_body_data2[] = "hello my darling hello my baby";
-  const char* syn_body_data = NULL;
-
-  scoped_ptr<spdy::SpdyFrame> push_body_frame(
-    framer.CreateDataFrame(2, syn_body_data1, strlen(syn_body_data1),
-                           spdy::DATA_FLAG_FIN));
-  scoped_ptr<spdy::SpdyFrame> push_body_frame1(
-    framer.CreateDataFrame(2, syn_body_data2, strlen(syn_body_data2),
-                           spdy::DATA_FLAG_FIN));
-
-  scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0));
-  MockWrite writes[] = { CreateMockWrite(*req) };
-
-  // This array is for request before and after push is received.  The push
-  // body is only one 'packet', to allow the initial transaction to read all
-  // the push data before .
-  scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame());
-  MockRead reads1[] = {
-    CreateMockRead(*syn_reply.get(), 2),                            // 0
-    CreateMockRead(*body.get(), 1),                                 // 1
-    MockRead(true, ERR_IO_PENDING, 4),  // Force a pause            // 2
-    CreateMockRead(*syn_push.get(), 5),                             // 3
-    CreateMockRead(*push_body_frame.get(), 6),                      // 4
-    MockRead(true, ERR_IO_PENDING, 7),  // Force a pause            // 5
-    MockRead(true, 0, 0, 8)  // EOF                                 // 6
-  };
-
-  // This array is for request while push is being received.  It extends
-  // the push body so we can 'interrupt' it.
-  scoped_array<MockRead> chopped_reads(
-      ChopReadFrame(*push_body_frame1.get(), 4));
-  chopped_reads[0].sequence_number = 5;
-  // Force a pause by skipping a sequence number.
-  chopped_reads[1].sequence_number = 7;
-  chopped_reads[2].sequence_number = 8;
-  chopped_reads[3].sequence_number = 9;
-  MockRead reads2[] = {
-    CreateMockRead(*syn_reply.get(), 2),                            // 0
-    CreateMockRead(*body.get(), 3),                                 // 1
-    CreateMockRead(*syn_push.get(), 4),                             // 2
-    chopped_reads[0],                                               // 3
-    chopped_reads[1],                                               // 4
-    chopped_reads[2],                                               // 5
-    chopped_reads[3],                                               // 6
-    MockRead(true, ERR_IO_PENDING, MockRead::STOPLOOP | 10),        // 7
-    // So we can do a final CompleteRead(), which cleans up memory.
-    MockRead(true, NULL, 0, 11)                                     // 8
-  };
-
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
-  base::Time zero_time = base::Time::FromInternalValue(0);
-  for (int test_type = PUSH_AFTER_REQUEST; test_type < DONE; ++test_type) {
-    DLOG(INFO) << "Test " << test_type;
-
-    // Select the data to use.
-    MockRead* reads = NULL;
-    size_t num_reads = 0;
-    size_t num_writes = arraysize(writes);
-    int first_push_data_frame = 0;
-    if (test_type == PUSH_DURING_REQUEST) {
-      reads = reads2;
-      num_reads = arraysize(reads2);
-      syn_body_data = syn_body_data2;
-      first_push_data_frame = 3;
-    } else {
-      reads = reads1;
-      num_reads = arraysize(reads1);
-      syn_body_data = syn_body_data1;
-      first_push_data_frame = 4;
-    }
-    // Clear timestamp data
-    for (size_t w = 0; w < num_writes; ++w) {
-      writes[w].time_stamp = zero_time;
-    }
-    for (size_t r = 0; r < num_reads; ++r) {
-      reads[r].time_stamp = zero_time;
-    }
-
-    // Setup a mock session.
-    SessionDependencies session_deps;
-    scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
-    scoped_refptr<OrderedSocketData> data(
-        new OrderedSocketData(reads, num_reads, writes, num_writes));
-    session_deps.socket_factory.AddSocketDataProvider(data.get());
-    HttpResponseInfo response1;
-    HttpResponseInfo response2;
-
-    DLOG(INFO) << "Sending request 1";
-
-    // Issue the first request.
-    MakeRequest(session,
-                data,
-                GURL("http://www.google.com/"),
-                "hello!",
-                test_type,
-                1,
-                &response1);
-
-    DLOG(INFO) << "Sending X-Associated-Content request";
-
-    // This value should be set to something later than the one in
-    // 'response1.request_time'.
-    base::Time request1_time = writes[0].time_stamp;
-    // We don't have a |writes| entry for the second request,
-    // so put in Now() as the request time.  It's not as accurate,
-    // but it will work.
-    base::Time request2_time = base::Time::Now();
-
-    // Issue a second request for the X-Associated-Content.
-    MakeRequest(session,
-                data,
-                GURL("http://www.google.com/foo.dat"),
-                syn_body_data,
-                test_type,
-                2,
-                &response2);
-
-    // Complete the next read now and teardown.
-    data->CompleteRead();
-
-    // Verify that we consumed all test data.
-    EXPECT_TRUE(data->at_read_eof());
-    EXPECT_TRUE(data->at_write_eof());
-
-    // Check the timings
-
-    // Verify that all the time stamps were set.
-    EXPECT_GE(response1.request_time.ToInternalValue(),
-        zero_time.ToInternalValue());
-    EXPECT_GE(response2.request_time.ToInternalValue(),
-        zero_time.ToInternalValue());
-    EXPECT_GE(response1.response_time.ToInternalValue(),
-        zero_time.ToInternalValue());
-    EXPECT_GE(response2.response_time.ToInternalValue(),
-        zero_time.ToInternalValue());
-
-    // Verify that the values make sense.
-    // First request.
-    EXPECT_LE(response1.request_time.ToInternalValue(),
-        request1_time.ToInternalValue());
-    EXPECT_LE(response1.response_time.ToInternalValue(),
-        reads[1].time_stamp.ToInternalValue());
-
-    // Push request.
-    EXPECT_GE(response2.request_time.ToInternalValue(),
-        request2_time.ToInternalValue());
-    // The response time should be between the server push SYN and DATA.
-    EXPECT_GE(response2.response_time.ToInternalValue(),
-      reads[first_push_data_frame - 1].time_stamp.ToInternalValue());
-    EXPECT_LE(response2.response_time.ToInternalValue(),
-      reads[first_push_data_frame].time_stamp.ToInternalValue());
-  }
-}
-
 // Test that we shutdown correctly on write errors.
 TEST_F(SpdyNetworkTransactionTest, WriteError) {
   scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0));
@@ -1215,23 +1050,15 @@
     MockWrite(true, req->data(), 10),
     // Followed by ERROR!
     MockWrite(true, ERR_FAILED),
-    MockWrite(true, 0, 0)  // EOF
-  };
-
-  scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0));
-  scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame());
-  MockRead reads[] = {
-    CreateMockRead(*resp.get(), 2),
-    CreateMockRead(*body),
-    MockRead(true, 0, 0)  // EOF
   };
 
   scoped_refptr<DelayedSocketData> data(
-      new DelayedSocketData(2, reads, arraysize(reads),
+      new DelayedSocketData(2, NULL, 0,
                             writes, arraysize(writes)));
-  TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                  data.get(),
-                                                  BoundNetLog());
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(ERR_FAILED, out.rv);
   data->Reset();
 }
@@ -1254,47 +1081,15 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(kChunks, reads, arraysize(reads),
                             writes.get(), kChunks));
-  TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                  data.get(),
-                                                  BoundNetLog());
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
 }
 
-TEST_F(SpdyNetworkTransactionTest, ConnectFailure) {
-  MockConnect connects[]  = {
-    MockConnect(true, ERR_NAME_NOT_RESOLVED),
-    MockConnect(false, ERR_NAME_NOT_RESOLVED),
-    MockConnect(true, ERR_INTERNET_DISCONNECTED),
-    MockConnect(false, ERR_INTERNET_DISCONNECTED)
-  };
-
-  for (size_t index = 0; index < arraysize(connects); ++index) {
-    scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0));
-    MockWrite writes[] = {
-      CreateMockWrite(*req),
-      MockWrite(true, 0, 0)  // EOF
-    };
-
-    scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0));
-    scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame());
-    MockRead reads[] = {
-      CreateMockRead(*resp),
-      CreateMockRead(*body),
-      MockRead(true, 0, 0)  // EOF
-    };
-
-    scoped_refptr<DelayedSocketData> data(
-        new DelayedSocketData(connects[index], 1, reads, arraysize(reads),
-                              writes, arraysize(writes)));
-    TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                    data.get(),
-                                                    BoundNetLog());
-    EXPECT_EQ(connects[index].result, out.rv);
-  }
-}
-
 // In this test, we enable compression, but get a uncompressed SynReply from
 // the server.  Verify that teardown is all clean.
 TEST_F(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
@@ -1304,7 +1099,6 @@
   scoped_ptr<spdy::SpdyFrame> compressed(ConstructSpdyGet(NULL, 0, true));
   MockWrite writes[] = {
     CreateMockWrite(*compressed),
-    MockWrite(true, 0, 0)  // EOF
   };
 
   scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0));
@@ -1318,9 +1112,10 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                  data.get(),
-                                                  BoundNetLog());
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv);
   data->Reset();
 
@@ -1345,27 +1140,21 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                  data.get(),
-                                                  log.bound());
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     log.bound());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
 
   // Check that the NetLog was filled reasonably.
-  // This test is intentionally non-specific about the exact ordering of
-  // the log; instead we just check to make sure that certain events exist.
+  // This test is intentionally non-specific about the exact ordering of the
+  // log; instead we just check to make sure that certain events exist, and that
+  // they are in the right order.
   EXPECT_LT(0u, log.entries().size());
   int pos = 0;
-  // We know the first event at position 0.
-  EXPECT_TRUE(net::LogContainsBeginEvent(
-      log.entries(), 0, net::NetLog::TYPE_SPDY_TRANSACTION_INIT_CONNECTION));
-  // For the rest of the events, allow additional events in the middle,
-  // but expect these to be logged in order.
   pos = net::ExpectLogContainsSomewhere(log.entries(), 0,
-      net::NetLog::TYPE_SPDY_TRANSACTION_INIT_CONNECTION,
-      net::NetLog::PHASE_END);
-  pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
       net::NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST,
       net::NetLog::PHASE_BEGIN);
   pos = net::ExpectLogContainsSomewhere(log.entries(), pos + 1,
@@ -1425,25 +1214,18 @@
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
 
-  // For this test, we can't use the TransactionHelper, because we are
-  // going to tightly control how the IOs fly.
-
-  TransactionHelperResult out;
-
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
-  SessionDependencies session_deps;
-  scoped_ptr<SpdyNetworkTransaction> trans(
-      new SpdyNetworkTransaction(CreateSession(&session_deps)));
-
-  session_deps.socket_factory.AddSocketDataProvider(data);
 
   TestCompletionCallback callback;
 
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.AddData(data.get());
+  helper.RunPreTestSetup();
+  HttpNetworkTransaction* trans = helper.trans();
   int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
+  TransactionHelperResult out = helper.output();
   out.rv = callback.WaitForResult();
   EXPECT_EQ(out.rv, OK);
 
@@ -1479,10 +1261,8 @@
   // MockClientSocketFactory) are still alive.
   MessageLoop::current()->RunAllPending();
 
-
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data->at_read_eof());
-  EXPECT_TRUE(data->at_write_eof());
+  helper.VerifyDataConsumed();
 
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
@@ -1526,25 +1306,17 @@
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
 
-  // For this test, we can't use the TransactionHelper, because we are
-  // going to tightly control how the IOs fly.
-
-  TransactionHelperResult out;
-
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
-  SessionDependencies session_deps;
-  scoped_ptr<SpdyNetworkTransaction> trans(
-      new SpdyNetworkTransaction(CreateSession(&session_deps)));
-
-  session_deps.socket_factory.AddSocketDataProvider(data);
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.AddData(data.get());
+  helper.RunPreTestSetup();
+  HttpNetworkTransaction* trans = helper.trans();
 
   TestCompletionCallback callback;
-
   int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
+  TransactionHelperResult out = helper.output();
   out.rv = callback.WaitForResult();
   EXPECT_EQ(out.rv, OK);
 
@@ -1586,8 +1358,7 @@
   MessageLoop::current()->RunAllPending();
 
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data->at_read_eof());
-  EXPECT_TRUE(data->at_write_eof());
+  helper.VerifyDataConsumed();
 
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
@@ -1630,25 +1401,17 @@
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
 
-  // For this test, we can't use the TransactionHelper, because we are
-  // going to tightly control how the IOs fly.
-
-  TransactionHelperResult out;
-
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
-  SessionDependencies session_deps;
-  scoped_ptr<SpdyNetworkTransaction> trans(
-      new SpdyNetworkTransaction(CreateSession(&session_deps)));
-
-  session_deps.socket_factory.AddSocketDataProvider(data);
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.AddData(data.get());
+  helper.RunPreTestSetup();
+  HttpNetworkTransaction* trans = helper.trans();
 
   TestCompletionCallback callback;
-
   int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
+  TransactionHelperResult out = helper.output();
   out.rv = callback.WaitForResult();
   EXPECT_EQ(out.rv, OK);
 
@@ -1686,8 +1449,7 @@
   MessageLoop::current()->RunAllPending();
 
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data->at_read_eof());
-  EXPECT_TRUE(data->at_write_eof());
+  helper.VerifyDataConsumed();
 
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
@@ -1727,25 +1489,18 @@
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
 
-  // For this test, we can't use the TransactionHelper, because we are
-  // going to tightly control how the IOs fly.
-
-  TransactionHelperResult out;
-
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
-  SessionDependencies session_deps;
-  scoped_ptr<SpdyNetworkTransaction> trans(
-      new SpdyNetworkTransaction(CreateSession(&session_deps)));
-
-  session_deps.socket_factory.AddSocketDataProvider(data);
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.AddData(data.get());
+  helper.RunPreTestSetup();
+  HttpNetworkTransaction* trans = helper.trans();
 
   TestCompletionCallback callback;
 
   int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
+  TransactionHelperResult out = helper.output();
   out.rv = callback.WaitForResult();
   EXPECT_EQ(out.rv, OK);
 
@@ -1788,8 +1543,7 @@
   MessageLoop::current()->RunAllPending();
 
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data->at_read_eof());
-  EXPECT_TRUE(data->at_write_eof());
+  helper.VerifyDataConsumed();
 }
 
 // Verify the case where we buffer data and cancel the transaction.
@@ -1815,24 +1569,17 @@
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
 
-  // For this test, we can't use the TransactionHelper, because we are
-  // going to tightly control how the IOs fly.
-  TransactionHelperResult out;
-
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
-  SessionDependencies session_deps;
-  scoped_ptr<SpdyNetworkTransaction> trans(
-      new SpdyNetworkTransaction(CreateSession(&session_deps)));
-
-  session_deps.socket_factory.AddSocketDataProvider(data);
-
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.AddData(data.get());
+  helper.RunPreTestSetup();
+  HttpNetworkTransaction* trans = helper.trans();
   TestCompletionCallback callback;
 
   int rv = trans->Start(&CreateGetRequest(), &callback, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
+  TransactionHelperResult out = helper.output();
   out.rv = callback.WaitForResult();
   EXPECT_EQ(out.rv, OK);
 
@@ -1854,7 +1601,7 @@
       data->CompleteRead();
       // Destroy the transaction, causing the stream to get cancelled
       // and orphaning the buffered IO task.
-      trans.reset();
+      helper.ResetTrans();
       break;
     }
     // We shouldn't get here in this test.
@@ -1864,6 +1611,9 @@
   // Flush the MessageLoop; this will cause the buffered IO task
   // to run for the final time.
   MessageLoop::current()->RunAllPending();
+
+  // Verify that we consumed all test data.
+  helper.VerifyDataConsumed();
 }
 
 // Test that if the server requests persistence of settings, that we save
@@ -1886,12 +1636,12 @@
     "version",  "HTTP/1.1"
   };
 
-  SessionDependencies session_deps;
-  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
 
   // Verify that no settings exist initially.
-  HostPortPair host_port_pair("www.google.com", 80);
-  EXPECT_TRUE(session->spdy_settings().Get(host_port_pair).empty());
+  HostPortPair host_port_pair("www.google.com", 443);
+  EXPECT_TRUE(helper.session()->spdy_settings().Get(host_port_pair).empty());
 
   // Construct the request.
   scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0));
@@ -1942,9 +1692,8 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  TransactionHelperResult out = TransactionHelperWithSession(
-      CreateGetRequest(), data.get(), BoundNetLog(),
-      &session_deps, session.get());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
@@ -1952,7 +1701,7 @@
   {
     // Verify we had two persisted settings.
     spdy::SpdySettings saved_settings =
-        session->spdy_settings().Get(host_port_pair);
+        helper.session()->spdy_settings().Get(host_port_pair);
     ASSERT_EQ(2u, saved_settings.size());
 
     // Verify the first persisted setting.
@@ -1991,12 +1740,12 @@
     "version",  "HTTP/1.1"
   };
 
-  SessionDependencies session_deps;
-  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps));
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
 
   // Verify that no settings exist initially.
-  HostPortPair host_port_pair("www.google.com", 80);
-  EXPECT_TRUE(session->spdy_settings().Get(host_port_pair).empty());
+  HostPortPair host_port_pair("www.google.com", 443);
+  EXPECT_TRUE(helper.session()->spdy_settings().Get(host_port_pair).empty());
 
   unsigned int kSampleId1 = 0x1;
   unsigned int kSampleValue1 = 0x0a0a0a0a;
@@ -2015,14 +1764,14 @@
     setting.set_id(kSampleId2);
     settings.push_back(std::make_pair(setting, kSampleValue2));
 
-    session->mutable_spdy_settings()->Set(host_port_pair, settings);
+    helper.session()->mutable_spdy_settings()->Set(host_port_pair, settings);
   }
 
-  EXPECT_EQ(2u, session->spdy_settings().Get(host_port_pair).size());
+  EXPECT_EQ(2u, helper.session()->spdy_settings().Get(host_port_pair).size());
 
   // Construct the SETTINGS frame.
   const spdy::SpdySettings& settings =
-      session->spdy_settings().Get(host_port_pair);
+      helper.session()->spdy_settings().Get(host_port_pair);
   scoped_ptr<spdy::SpdyFrame> settings_frame(ConstructSpdySettings(settings));
 
   // Construct the request.
@@ -2051,9 +1800,8 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(2, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  TransactionHelperResult out = TransactionHelperWithSession(
-      CreateGetRequest(), data.get(), BoundNetLog(),
-      &session_deps, session.get());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
   EXPECT_EQ("hello!", out.response_data);
@@ -2061,7 +1809,7 @@
   {
     // Verify we had two persisted settings.
     spdy::SpdySettings saved_settings =
-        session->spdy_settings().Get(host_port_pair);
+        helper.session()->spdy_settings().Get(host_port_pair);
     ASSERT_EQ(2u, saved_settings.size());
 
     // Verify the first persisted setting.
@@ -2093,9 +1841,10 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  TransactionHelperResult out = TransactionHelper(CreateGetRequest(),
-                                                  data.get(),
-                                                  BoundNetLog());
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     BoundNetLog());
+  helper.RunToCompletion(data.get());
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv);
 }
 
@@ -2112,22 +1861,17 @@
   scoped_refptr<DelayedSocketData> data(
       new DelayedSocketData(1, reads, arraysize(reads),
                             writes, arraysize(writes)));
-  TransactionHelperResult out;
-
-  // We disable SSL for this test.
-  SpdySession::SetSSLMode(false);
-
   BoundNetLog log;
-  SessionDependencies session_deps;
-  HttpNetworkSession* session = CreateSession(&session_deps);
-  scoped_ptr<SpdyNetworkTransaction> trans(
-      new SpdyNetworkTransaction(session));
-
-  session_deps.socket_factory.AddSocketDataProvider(data);
+  NormalSpdyTransactionHelper helper(CreateGetRequest(),
+                                     log);
+  helper.AddData(data.get());
+  helper.RunPreTestSetup();
+  HttpNetworkTransaction* trans = helper.trans();
 
   TestCompletionCallback callback;
-
+  TransactionHelperResult out;
   out.rv = trans->Start(&CreateGetRequest(), &callback, log);
+
   EXPECT_EQ(out.rv, ERR_IO_PENDING);
   out.rv = callback.WaitForResult();
   EXPECT_EQ(out.rv, OK);
@@ -2135,12 +1879,11 @@
   const HttpResponseInfo* response = trans->GetResponseInfo();
   EXPECT_TRUE(response->headers != NULL);
   EXPECT_TRUE(response->was_fetched_via_spdy);
-  out.rv = ReadTransaction(trans.get(), &out.response_data);
+  out.rv = ReadTransaction(trans, &out.response_data);
   EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv);
 
   // Verify that we consumed all test data.
-  EXPECT_TRUE(data->at_read_eof());
-  EXPECT_TRUE(data->at_write_eof());
+  helper.VerifyDataConsumed();
 }
 
 }  // namespace net