gfe-relnote: Decouple the QuicSession from the QuicStreamIdManager by introducing a QuicStreamIdManager::DelegateInterface which the session implements. Does not change behavior, merely adds a layer of abstraction which allows unit tests of QuicStreamIdManager to be simplified.

PiperOrigin-RevId: 270302454
Change-Id: I4a66803d4a2f1f640ef68ee6373af9b67423bac4
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index abeed2b..3bd13bc 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -310,6 +310,8 @@
 
 Http3DebugVisitor::~Http3DebugVisitor() {}
 
+// Expected unidirectional static streams Requirement can be found at
+// https://tools.ietf.org/html/draft-ietf-quic-http-22#section-6.2.
 QuicSpdySession::QuicSpdySession(
     QuicConnection* connection,
     QuicSession::Visitor* visitor,
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 23873d0..9d0c7bf 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -62,6 +62,7 @@
                          config_.GetMaxIncomingBidirectionalStreamsToSend()),
       v99_streamid_manager_(
           this,
+          num_expected_unidirectional_static_streams,
           kDefaultMaxStreamsPerConnection,
           kDefaultMaxStreamsPerConnection,
           config_.GetMaxIncomingBidirectionalStreamsToSend(),
@@ -771,6 +772,12 @@
   control_frame_manager_.WriteOrBufferWindowUpdate(id, byte_offset);
 }
 
+void QuicSession::OnError(QuicErrorCode error_code, std::string error_details) {
+  connection_->CloseConnection(
+      error_code, error_details,
+      ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+}
+
 void QuicSession::SendMaxStreams(QuicStreamCount stream_count,
                                  bool unidirectional) {
   control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional);
@@ -1049,6 +1056,7 @@
   // STREAMS_BLOCKED or MAX_STREAMS frames against the config and either send
   // the frames or discard them.
   if (VersionHasIetfQuicFrames(connection_->transport_version())) {
+    QuicConnection::ScopedPacketFlusher flusher(connection());
     v99_streamid_manager_.OnConfigNegotiated();
   }
 }
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index 6fb4c8d..758106f 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -41,9 +41,11 @@
 class QuicSessionPeer;
 }  // namespace test
 
-class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
-                                        public SessionNotifierInterface,
-                                        public QuicStreamFrameDataProducer {
+class QUIC_EXPORT_PRIVATE QuicSession
+    : public QuicConnectionVisitorInterface,
+      public SessionNotifierInterface,
+      public QuicStreamFrameDataProducer,
+      public QuicStreamIdManager::DelegateInterface {
  public:
   // An interface from the session to the entity owning the session.
   // This lets the session notify its owner (the Dispatcher) when the connection
@@ -147,6 +149,16 @@
   bool HasUnackedCryptoData() const override;
   bool HasUnackedStreamData() const override;
 
+  // QuicStreamIdManager::DelegateInterface methods:
+  void OnError(QuicErrorCode error_code, std::string error_details) override;
+  void SendMaxStreams(QuicStreamCount stream_count,
+                      bool unidirectional) override;
+  void SendStreamsBlocked(QuicStreamCount stream_count,
+                          bool unidirectional) override;
+  // The default implementation does nothing. Subclasses should override if
+  // for example they queue up stream requests.
+  void OnCanCreateNewOutgoingStream(bool unidirectional) override;
+
   // Called on every incoming packet. Passes |packet| through to |connection_|.
   virtual void ProcessUdpPacket(const QuicSocketAddress& self_address,
                                 const QuicSocketAddress& peer_address,
@@ -210,12 +222,6 @@
   // Sends a WINDOW_UPDATE frame.
   virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset);
 
-  // Send a MAX_STREAMS frame.
-  void SendMaxStreams(QuicStreamCount stream_count, bool unidirectional);
-
-  // Send a STREAMS_BLOCKED frame.
-  void SendStreamsBlocked(QuicStreamCount stream_count, bool unidirectional);
-
   // Create and transmit a STOP_SENDING frame
   virtual void SendStopSending(uint16_t code, QuicStreamId stream_id);
 
@@ -404,14 +410,6 @@
     return supported_versions_;
   }
 
-  // Called when new outgoing streams are available to be opened. This occurs
-  // when an extant, open, stream is moved to draining or closed. The default
-  // implementation does nothing. |unidirectional| indicates whether
-  // unidirectional or bidirectional streams are now available. If both become
-  // available at the same time then there will be two calls to this method, one
-  // with unidirectional==true, the other with it ==false.
-  virtual void OnCanCreateNewOutgoingStream(bool unidirectional);
-
   QuicStreamId next_outgoing_bidirectional_stream_id() const;
   QuicStreamId next_outgoing_unidirectional_stream_id() const;
 
diff --git a/quic/core/quic_stream_id_manager.cc b/quic/core/quic_stream_id_manager.cc
index 9d94157..57fd0a4 100644
--- a/quic/core/quic_stream_id_manager.cc
+++ b/quic/core/quic_stream_id_manager.cc
@@ -16,17 +16,23 @@
 
 namespace quic {
 
-#define ENDPOINT                                                   \
-  (session_->perspective() == Perspective::IS_SERVER ? " Server: " \
-                                                     : " Client: ")
+#define ENDPOINT \
+  (perspective_ == Perspective::IS_SERVER ? " Server: " : " Client: ")
 
 QuicStreamIdManager::QuicStreamIdManager(
-    QuicSession* session,
+    DelegateInterface* delegate,
     bool unidirectional,
+    Perspective perspective,
+    QuicTransportVersion transport_version,
+    QuicStreamCount num_expected_static_streams,
     QuicStreamCount max_allowed_outgoing_streams,
     QuicStreamCount max_allowed_incoming_streams)
-    : session_(session),
+    : delegate_(delegate),
       unidirectional_(unidirectional),
+      perspective_(perspective),
+      transport_version_(transport_version),
+      num_expected_static_streams_(num_expected_static_streams),
+      is_config_negotiated_(false),
       outgoing_max_streams_(max_allowed_outgoing_streams),
       next_outgoing_stream_id_(GetFirstOutgoingStreamId()),
       outgoing_stream_count_(0),
@@ -38,16 +44,15 @@
       incoming_initial_max_open_streams_(max_allowed_incoming_streams),
       incoming_stream_count_(0),
       largest_peer_created_stream_id_(
-          QuicUtils::GetInvalidStreamId(transport_version())),
+          QuicUtils::GetInvalidStreamId(transport_version)),
       max_streams_window_(0),
       pending_max_streams_(false),
       pending_streams_blocked_(
-          QuicUtils::GetInvalidStreamId(transport_version())) {
+          QuicUtils::GetInvalidStreamId(transport_version)) {
   CalculateIncomingMaxStreamsWindow();
 }
 
-QuicStreamIdManager::~QuicStreamIdManager() {
-}
+QuicStreamIdManager::~QuicStreamIdManager() {}
 
 bool QuicStreamIdManager::OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) {
   // Ensure that the frame has the correct directionality.
@@ -74,9 +79,8 @@
     // TODO(fkastenholz): revise when proper IETF Connection Close support is
     // done.
     QUIC_CODE_COUNT(quic_streams_blocked_too_big);
-    session_->connection()->CloseConnection(
-        QUIC_STREAMS_BLOCKED_ERROR, "Invalid stream count specified",
-        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    delegate_->OnError(QUIC_STREAMS_BLOCKED_ERROR,
+                       "Invalid stream count specified");
     return false;
   }
   if (frame.stream_count < incoming_actual_max_streams_) {
@@ -92,17 +96,14 @@
 // Used when configuration has been done and we have an initial
 // maximum stream count from the peer.
 bool QuicStreamIdManager::SetMaxOpenOutgoingStreams(size_t max_open_streams) {
-  if (unidirectional_ &&
-      max_open_streams <
-          session_->num_expected_unidirectional_static_streams()) {
-    // Requirement can be found at
-    // https://tools.ietf.org/html/draft-ietf-quic-http-22#section-6.2.
-    QUIC_DLOG(ERROR) << "Received max unidirectional stream "
-                     << max_open_streams << " < "
-                     << session_->num_expected_unidirectional_static_streams();
-    session_->connection()->CloseConnection(
-        QUIC_MAX_STREAMS_ERROR, "New unidirectional stream limit is too low.",
-        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+  if (max_open_streams < num_expected_static_streams_) {
+    QUIC_DLOG(ERROR) << "Received max streams " << max_open_streams << " < "
+                     << num_expected_static_streams_;
+    delegate_->OnError(QUIC_MAX_STREAMS_ERROR,
+                       unidirectional_
+                           ? "New unidirectional stream limit is too low."
+                           : "New bidirectional stream limit is too low.");
+
     return false;
   }
   if (using_default_max_streams_) {
@@ -114,10 +115,8 @@
     // be less than the number of existing outgoing streams. If that happens,
     // close the connection.
     if (max_open_streams < outgoing_stream_count_) {
-      session_->connection()->CloseConnection(
-          QUIC_MAX_STREAMS_ERROR,
-          "Stream limit less than existing stream count",
-          ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+      delegate_->OnError(QUIC_MAX_STREAMS_ERROR,
+                         "Stream limit less than existing stream count");
       return false;
     }
     using_default_max_streams_ = false;
@@ -133,11 +132,11 @@
   // if it would exceed the max 32 bits can express.
   outgoing_max_streams_ = std::min<size_t>(
       max_open_streams,
-      QuicUtils::GetMaxStreamCount(unidirectional_, session_->perspective()));
+      QuicUtils::GetMaxStreamCount(unidirectional_, perspective_));
 
   // Inform the higher layers that the stream limit has increased and that
   // new streams may be created.
-  session_->OnCanCreateNewOutgoingStream(unidirectional_);
+  delegate_->OnCanCreateNewOutgoingStream(unidirectional_);
 
   return true;
 }
@@ -148,9 +147,8 @@
   QuicStreamCount new_max = std::min(
       implementation_max, static_cast<QuicStreamCount>(max_open_streams));
   if (new_max < incoming_stream_count_) {
-    session_->connection()->CloseConnection(
-        QUIC_MAX_STREAMS_ERROR, "Stream limit less than existing stream count",
-        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    delegate_->OnError(QUIC_MAX_STREAMS_ERROR,
+                       "Stream limit less than existing stream count");
     return;
   }
   incoming_actual_max_streams_ = new_max;
@@ -170,15 +168,16 @@
 }
 
 void QuicStreamIdManager::SendMaxStreamsFrame() {
-  if (!session_->is_configured()) {
-    // Session not configured, so we can not send the MAX STREAMS frame yet.
-    // Remember that we would have sent one and then return. A new frame will
-    // be generated once the configuration is received.
+  if (!is_config_negotiated_) {
+    // The config has not yet been negotiated, so we can not send the
+    // MAX STREAMS frame yet. Record that we would have sent one and then
+    // return. A new frame will be generated once the configuration is
+    // received.
     pending_max_streams_ = true;
     return;
   }
   incoming_advertised_max_streams_ = incoming_actual_max_streams_;
-  session_->SendMaxStreams(incoming_advertised_max_streams_, unidirectional_);
+  delegate_->SendMaxStreams(incoming_advertised_max_streams_, unidirectional_);
 }
 
 void QuicStreamIdManager::OnStreamClosed(QuicStreamId stream_id) {
@@ -220,15 +219,14 @@
   }
   // Next stream ID would exceed the limit, need to inform the peer.
 
-  if (!session_->is_configured()) {
-    // Session not configured, so we can not send the STREAMS_BLOCKED frame yet.
-    // Remember that we would have sent one, and what the limit was when we were
-    // blocked, and return.
+  if (!is_config_negotiated_) {
+    // The config is not negotiated, so we can not send the STREAMS_BLOCKED
+    // frame yet. Record that we would have sent one, and what the limit was
+    // when we were blocked, and return.
     pending_streams_blocked_ = outgoing_max_streams_;
     return false;
   }
-
-  session_->SendStreamsBlocked(outgoing_max_streams_, unidirectional_);
+  delegate_->SendStreamsBlocked(outgoing_max_streams_, unidirectional_);
   QUIC_CODE_COUNT(quic_reached_outgoing_stream_id_limit);
   return false;
 }
@@ -273,11 +271,10 @@
                     << "Failed to create a new incoming stream with id:"
                     << stream_id << ", reaching MAX_STREAMS limit: "
                     << incoming_advertised_max_streams_ << ".";
-    session_->connection()->CloseConnection(
+    delegate_->OnError(
         QUIC_INVALID_STREAM_ID,
         QuicStrCat("Stream id ", stream_id, " would exceed stream count limit ",
-                   incoming_advertised_max_streams_),
-        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+                   incoming_advertised_max_streams_));
     return false;
   }
 
@@ -335,7 +332,7 @@
 }
 
 Perspective QuicStreamIdManager::perspective() const {
-  return session_->perspective();
+  return perspective_;
 }
 
 Perspective QuicStreamIdManager::peer_perspective() const {
@@ -343,7 +340,7 @@
 }
 
 QuicTransportVersion QuicStreamIdManager::transport_version() const {
-  return session_->transport_version();
+  return transport_version_;
 }
 
 size_t QuicStreamIdManager::available_incoming_streams() {
@@ -358,7 +355,7 @@
 }
 
 void QuicStreamIdManager::OnConfigNegotiated() {
-  QuicConnection::ScopedPacketFlusher flusher(session_->connection());
+  is_config_negotiated_ = true;
   // If a STREAMS_BLOCKED or MAX_STREAMS is pending, send it and clear
   // the pending state.
   if (pending_streams_blocked_ !=
@@ -366,7 +363,7 @@
     if (pending_streams_blocked_ >= outgoing_max_streams_) {
       // There is a pending STREAMS_BLOCKED frame and the current limit does not
       // let new streams be formed. Regenerate and send the frame.
-      session_->SendStreamsBlocked(outgoing_max_streams_, unidirectional_);
+      delegate_->SendStreamsBlocked(outgoing_max_streams_, unidirectional_);
     }
     pending_streams_blocked_ =
         QuicUtils::GetInvalidStreamId(transport_version());
diff --git a/quic/core/quic_stream_id_manager.h b/quic/core/quic_stream_id_manager.h
index 51524ba..1ac2947 100644
--- a/quic/core/quic_stream_id_manager.h
+++ b/quic/core/quic_stream_id_manager.h
@@ -17,8 +17,6 @@
 class QuicStreamIdManagerPeer;
 }  // namespace test
 
-class QuicSession;
-
 // Amount to increment a stream ID value to get the next stream ID in
 // the stream ID space.
 const QuicStreamId kV99StreamIdIncrement = 4;
@@ -31,8 +29,36 @@
 // This class manages the stream ids for Version 99/IETF QUIC.
 class QUIC_EXPORT_PRIVATE QuicStreamIdManager {
  public:
-  QuicStreamIdManager(QuicSession* session,
+  class DelegateInterface {
+   public:
+    virtual ~DelegateInterface() = default;
+
+    // Called when new outgoing streams are available to be opened. This occurs
+    // when an extant, open, stream is moved to draining or closed.
+    // |unidirectional| indicates whether unidirectional or bidirectional
+    // streams are now available. If both become available at the same time then
+    // there will be two calls to this method, one with unidirectional==true,
+    // the other with it ==false.
+    virtual void OnCanCreateNewOutgoingStream(bool unidirectional) = 0;
+
+    // Closes the connection when an error is encountered.
+    virtual void OnError(QuicErrorCode error_code,
+                         std::string error_details) = 0;
+
+    // Send a MAX_STREAMS frame.
+    virtual void SendMaxStreams(QuicStreamCount stream_count,
+                                bool unidirectional) = 0;
+
+    // Send a STREAMS_BLOCKED frame.
+    virtual void SendStreamsBlocked(QuicStreamCount stream_count,
+                                    bool unidirectional) = 0;
+  };
+
+  QuicStreamIdManager(DelegateInterface* delegate,
                       bool unidirectional,
+                      Perspective perspective,
+                      QuicTransportVersion transport_version,
+                      QuicStreamCount num_expected_static_streams,
                       QuicStreamCount max_allowed_outgoing_streams,
                       QuicStreamCount max_allowed_incoming_streams);
 
@@ -171,11 +197,23 @@
 
   // Back reference to the session containing this Stream ID Manager.
   // needed to access various session methods, such as perspective()
-  QuicSession* session_;
+  DelegateInterface* delegate_;
 
   // Whether this stream id manager is for unidrectional (true) or bidirectional
   // (false) streams.
-  bool unidirectional_;
+  const bool unidirectional_;
+
+  // Is this manager a client or a server.
+  const Perspective perspective_;
+
+  // Transport version used for this manager.
+  const QuicTransportVersion transport_version_;
+
+  // Number of expected static streams.
+  const QuicStreamCount num_expected_static_streams_;
+
+  // True if the config has been negotiated_;
+  bool is_config_negotiated_;
 
   // This is the number of streams that this node can initiate.
   // This limit is:
diff --git a/quic/core/quic_stream_id_manager_test.cc b/quic/core/quic_stream_id_manager_test.cc
index 7c1233b..748a10c 100644
--- a/quic/core/quic_stream_id_manager_test.cc
+++ b/quic/core/quic_stream_id_manager_test.cc
@@ -4,150 +4,68 @@
 #include "net/third_party/quiche/src/quic/core/quic_stream_id_manager.h"
 
 #include <cstdint>
-#include <set>
 #include <string>
 #include <utility>
 
-#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
-#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
-#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
-#include "net/third_party/quiche/src/quic/core/quic_packets.h"
-#include "net/third_party/quiche/src/quic/core/quic_session.h"
-#include "net/third_party/quiche/src/quic/core/quic_stream.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_flow_controller_peer.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h"
 #include "net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_stream_send_buffer_peer.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
 
 using testing::_;
 using testing::Invoke;
-using testing::Return;
 using testing::StrictMock;
 
 namespace quic {
 namespace test {
 namespace {
 
-class TestQuicStream : public QuicStream {
-  // TestQuicStream exists simply as a place to hang OnDataAvailable().
+class MockDelegate : public QuicStreamIdManager::DelegateInterface {
  public:
-  TestQuicStream(QuicStreamId id, QuicSession* session, StreamType type)
-      : QuicStream(id, session, /*is_static=*/false, type) {}
-
-  void OnDataAvailable() override {}
-};
-
-class TestQuicSession : public MockQuicSession {
- public:
-  TestQuicSession(QuicConnection* connection)
-      : MockQuicSession(connection, /*create_mock_crypto_stream=*/true) {
-    // Initialize to an invalid frame type to detect cases where the frame type
-    // is not set subsequently.
-    save_frame_.type = static_cast<QuicFrameType>(-1);
-    Initialize();
-  }
-
-  TestQuicStream* CreateIncomingStream(QuicStreamId id) override {
-    TestQuicStream* stream = new TestQuicStream(
-        id, this,
-        DetermineStreamType(id, transport_version(), perspective(),
-                            /*is_incoming=*/true, BIDIRECTIONAL));
-    ActivateStream(QuicWrapUnique(stream));
-    return stream;
-  }
-
-  bool SaveFrame(const QuicFrame& frame) {
-    save_frame_ = frame;
-    DeleteFrame(&const_cast<QuicFrame&>(frame));
-    return true;
-  }
-
-  const QuicFrame& save_frame() { return save_frame_; }
-
-  TestQuicStream* CreateOutgoingBidirectionalStream() {
-    if (!CanOpenNextOutgoingBidirectionalStream()) {
-      return nullptr;
-    }
-    QuicStreamId id = GetNextOutgoingBidirectionalStreamId();
-    TestQuicStream* stream = new TestQuicStream(id, this, BIDIRECTIONAL);
-    ActivateStream(QuicWrapUnique(stream));
-    return stream;
-  }
-
-  TestQuicStream* CreateOutgoingUnidirectionalStream() {
-    if (!CanOpenNextOutgoingUnidirectionalStream()) {
-      return nullptr;
-    }
-    QuicStreamId id = GetNextOutgoingUnidirectionalStreamId();
-    TestQuicStream* stream = new TestQuicStream(id, this, WRITE_UNIDIRECTIONAL);
-    ActivateStream(QuicWrapUnique(stream));
-    return stream;
-  }
-
- private:
-  QuicFrame save_frame_;
+  MOCK_METHOD1(OnCanCreateNewOutgoingStream, void(bool unidirectional));
+  MOCK_METHOD2(OnError,
+               void(QuicErrorCode error_code, std::string error_details));
+  MOCK_METHOD2(SendMaxStreams,
+               void(QuicStreamCount stream_count, bool unidirectional));
+  MOCK_METHOD2(SendStreamsBlocked,
+               void(QuicStreamCount stream_count, bool unidirectional));
 };
 
 class QuicStreamIdManagerTestBase : public QuicTestWithParam<bool> {
  protected:
   explicit QuicStreamIdManagerTestBase(Perspective perspective)
-      : connection_(new StrictMock<MockQuicConnection>(
-            &helper_,
-            &alarm_factory_,
-            perspective,
-            ParsedQuicVersionVector(
-                {{PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_99}}))) {
-    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
-    session_ = std::make_unique<TestQuicSession>(connection_);
-    stream_id_manager_ =
-        IsBidi() ? QuicSessionPeer::v99_bidirectional_stream_id_manager(
-                       session_.get())
-                 : QuicSessionPeer::v99_unidirectional_stream_id_manager(
-                       session_.get());
-  }
+      : stream_id_manager_(&delegate_,
+                           IsUnidi(),
+                           perspective,
+                           QUIC_VERSION_99,
+                           0,
+                           kDefaultMaxStreamsPerConnection,
+                           kDefaultMaxStreamsPerConnection) {}
 
-  QuicTransportVersion transport_version() const {
-    return connection_->transport_version();
-  }
-
-  void CloseStream(QuicStreamId id) { session_->CloseStream(id); }
+  QuicTransportVersion transport_version() const { return QUIC_VERSION_99; }
 
   QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
-    return QuicUtils::GetFirstBidirectionalStreamId(
-               connection_->transport_version(), Perspective::IS_CLIENT) +
+    return QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
+                                                    Perspective::IS_CLIENT) +
            kV99StreamIdIncrement * n;
   }
 
   QuicStreamId GetNthClientInitiatedUnidirectionalId(int n) {
-    return QuicUtils::GetFirstUnidirectionalStreamId(
-               connection_->transport_version(), Perspective::IS_CLIENT) +
+    return QuicUtils::GetFirstUnidirectionalStreamId(transport_version(),
+                                                     Perspective::IS_CLIENT) +
            kV99StreamIdIncrement * n;
   }
 
   QuicStreamId GetNthServerInitiatedBidirectionalId(int n) {
-    return QuicUtils::GetFirstBidirectionalStreamId(
-               connection_->transport_version(), Perspective::IS_SERVER) +
+    return QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
+                                                    Perspective::IS_SERVER) +
            kV99StreamIdIncrement * n;
   }
 
   QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) {
-    return QuicUtils::GetFirstUnidirectionalStreamId(
-               connection_->transport_version(), Perspective::IS_SERVER) +
+    return QuicUtils::GetFirstUnidirectionalStreamId(transport_version(),
+                                                     Perspective::IS_SERVER) +
            kV99StreamIdIncrement * n;
   }
 
@@ -172,11 +90,8 @@
   bool IsUnidi() { return GetParam() ? false : true; }
   bool IsBidi() { return GetParam(); }
 
-  MockQuicConnectionHelper helper_;
-  MockAlarmFactory alarm_factory_;
-  StrictMock<MockQuicConnection>* connection_;
-  std::unique_ptr<TestQuicSession> session_;
-  QuicStreamIdManager* stream_id_manager_;
+  StrictMock<MockDelegate> delegate_;
+  QuicStreamIdManager stream_id_manager_;
 };
 
 // Following tests are either client-specific (they depend, in some way, on
@@ -200,29 +115,29 @@
   // These fields are inited via the QuicSession constructor to default
   // values defined as a constant.
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
-            stream_id_manager_->outgoing_max_streams());
+            stream_id_manager_.outgoing_max_streams());
 
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
-            stream_id_manager_->incoming_actual_max_streams());
+            stream_id_manager_.incoming_actual_max_streams());
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
-            stream_id_manager_->incoming_advertised_max_streams());
+            stream_id_manager_.incoming_advertised_max_streams());
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
-            stream_id_manager_->incoming_initial_max_open_streams());
+            stream_id_manager_.incoming_initial_max_open_streams());
 
   // The window for advertising updates to the MAX STREAM ID is half the number
   // of streams allowed.
   EXPECT_EQ(kDefaultMaxStreamsPerConnection / kMaxStreamsWindowDivisor,
-            stream_id_manager_->max_streams_window());
+            stream_id_manager_.max_streams_window());
 }
 
 // This test checks that the stream advertisement window is set to 1
 // if the number of stream ids is 1. This is a special case in the code.
 TEST_P(QuicStreamIdManagerTestClient, CheckMaxStreamsWindow1) {
-  stream_id_manager_->SetMaxOpenIncomingStreams(1);
-  EXPECT_EQ(1u, stream_id_manager_->incoming_initial_max_open_streams());
-  EXPECT_EQ(1u, stream_id_manager_->incoming_actual_max_streams());
+  stream_id_manager_.SetMaxOpenIncomingStreams(1);
+  EXPECT_EQ(1u, stream_id_manager_.incoming_initial_max_open_streams());
+  EXPECT_EQ(1u, stream_id_manager_.incoming_actual_max_streams());
   // If streamid_count/2==0 (integer math) force it to 1.
-  EXPECT_EQ(1u, stream_id_manager_->max_streams_window());
+  EXPECT_EQ(1u, stream_id_manager_.max_streams_window());
 }
 
 // Now check that setting to a value larger than the maximum fails.
@@ -232,12 +147,13 @@
       QuicUtils::GetMaxStreamCount(!GetParam(), /* GetParam==true for bidi */
                                    Perspective::IS_CLIENT);
   // Ensure that the limit is less than the implementation maximum.
-  EXPECT_LT(stream_id_manager_->outgoing_max_streams(), implementation_max);
+  EXPECT_LT(stream_id_manager_.outgoing_max_streams(), implementation_max);
 
   // Try to go over.
-  stream_id_manager_->SetMaxOpenOutgoingStreams(implementation_max + 1);
+  EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidi()));
+  stream_id_manager_.SetMaxOpenOutgoingStreams(implementation_max + 1);
   // Should be pegged at the max.
-  EXPECT_EQ(implementation_max, stream_id_manager_->outgoing_max_streams());
+  EXPECT_EQ(implementation_max, stream_id_manager_.outgoing_max_streams());
 }
 
 // Now do the same for the incoming streams
@@ -245,79 +161,70 @@
   QuicStreamCount implementation_max =
       QuicUtils::GetMaxStreamCount(!GetParam(), /* GetParam==true for bidi */
                                    Perspective::IS_CLIENT);
-  stream_id_manager_->SetMaxOpenIncomingStreams(implementation_max - 1u);
+  stream_id_manager_.SetMaxOpenIncomingStreams(implementation_max - 1u);
   EXPECT_EQ(implementation_max - 1u,
-            stream_id_manager_->incoming_initial_max_open_streams());
+            stream_id_manager_.incoming_initial_max_open_streams());
   EXPECT_EQ(implementation_max - 1u,
-            stream_id_manager_->incoming_actual_max_streams());
+            stream_id_manager_.incoming_actual_max_streams());
   EXPECT_EQ((implementation_max - 1u) / 2u,
-            stream_id_manager_->max_streams_window());
+            stream_id_manager_.max_streams_window());
 
-  stream_id_manager_->SetMaxOpenIncomingStreams(implementation_max);
+  stream_id_manager_.SetMaxOpenIncomingStreams(implementation_max);
   EXPECT_EQ(implementation_max,
-            stream_id_manager_->incoming_initial_max_open_streams());
+            stream_id_manager_.incoming_initial_max_open_streams());
   EXPECT_EQ(implementation_max,
-            stream_id_manager_->incoming_actual_max_streams());
-  EXPECT_EQ(implementation_max / 2, stream_id_manager_->max_streams_window());
+            stream_id_manager_.incoming_actual_max_streams());
+  EXPECT_EQ(implementation_max / 2, stream_id_manager_.max_streams_window());
 
   // Reset to 1 so that we can detect the change.
-  stream_id_manager_->SetMaxOpenIncomingStreams(1u);
-  EXPECT_EQ(1u, stream_id_manager_->incoming_initial_max_open_streams());
-  EXPECT_EQ(1u, stream_id_manager_->incoming_actual_max_streams());
-  EXPECT_EQ(1u, stream_id_manager_->max_streams_window());
+  stream_id_manager_.SetMaxOpenIncomingStreams(1u);
+  EXPECT_EQ(1u, stream_id_manager_.incoming_initial_max_open_streams());
+  EXPECT_EQ(1u, stream_id_manager_.incoming_actual_max_streams());
+  EXPECT_EQ(1u, stream_id_manager_.max_streams_window());
   // Now try to exceed the max, without wrapping.
-  stream_id_manager_->SetMaxOpenIncomingStreams(implementation_max + 1);
+  stream_id_manager_.SetMaxOpenIncomingStreams(implementation_max + 1);
   EXPECT_EQ(implementation_max,
-            stream_id_manager_->incoming_initial_max_open_streams());
+            stream_id_manager_.incoming_initial_max_open_streams());
   EXPECT_EQ(implementation_max,
-            stream_id_manager_->incoming_actual_max_streams());
-  EXPECT_EQ(implementation_max / 2u, stream_id_manager_->max_streams_window());
+            stream_id_manager_.incoming_actual_max_streams());
+  EXPECT_EQ(implementation_max / 2u, stream_id_manager_.max_streams_window());
 }
 
 // Check the case of the stream count in a STREAMS_BLOCKED frame is less than
 // the count most recently advertised in a MAX_STREAMS frame. This should cause
 // a MAX_STREAMS frame with the most recently advertised count to be sent.
 TEST_P(QuicStreamIdManagerTestClient, ProcessStreamsBlockedOk) {
-  EXPECT_CALL(*connection_, SendControlFrame(_))
-      .WillRepeatedly(Invoke(session_.get(), &TestQuicSession::SaveFrame));
+  // Set the config negotiated so that the MAX_STREAMS is transmitted.
+  stream_id_manager_.OnConfigNegotiated();
+
   QuicStreamCount stream_count =
-      stream_id_manager_->incoming_initial_max_open_streams() - 1;
-  QuicStreamsBlockedFrame frame(0, stream_count, /*unidirectional=*/false);
-
-  // Simulate being configured so that the MAX_STREAMS is transmitted.
-  session_->OnConfigNegotiated();
-
-  session_->OnStreamsBlockedFrame(frame);
-
-  // We should see a MAX_STREAMS frame.
-  EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type);
-
-  // and it should advertise the current max-allowed value.
-  EXPECT_EQ(stream_id_manager_->incoming_initial_max_open_streams(),
-            session_->save_frame().max_streams_frame.stream_count);
+      stream_id_manager_.incoming_initial_max_open_streams();
+  QuicStreamsBlockedFrame frame(0, stream_count - 1, IsUnidi());
+  EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidi()));
+  stream_id_manager_.OnStreamsBlockedFrame(frame);
 }
 
 // Check the case of the stream count in a STREAMS_BLOCKED frame is equal to the
 // count most recently advertised in a MAX_STREAMS frame. No MAX_STREAMS
 // should be generated.
 TEST_P(QuicStreamIdManagerTestClient, ProcessStreamsBlockedNoOp) {
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
   QuicStreamCount stream_count =
-      stream_id_manager_->incoming_initial_max_open_streams();
-  QuicStreamsBlockedFrame frame(0, stream_count, /*unidirectional=*/false);
-  session_->OnStreamsBlockedFrame(frame);
+      stream_id_manager_.incoming_initial_max_open_streams();
+  QuicStreamsBlockedFrame frame(0, stream_count, IsUnidi());
+  EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
 }
 
 // Check the case of the stream count in a STREAMS_BLOCKED frame is greater than
 // the count most recently advertised in a MAX_STREAMS frame. Expect a
 // connection close with an error.
 TEST_P(QuicStreamIdManagerTestClient, ProcessStreamsBlockedTooBig) {
-  EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAMS_BLOCKED_ERROR, _, _));
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
+  EXPECT_CALL(delegate_, OnError(QUIC_STREAMS_BLOCKED_ERROR, _));
+  EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
+  EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
   QuicStreamCount stream_count =
-      stream_id_manager_->incoming_initial_max_open_streams() + 1;
-  QuicStreamsBlockedFrame frame(0, stream_count, /*unidirectional=*/false);
-  session_->OnStreamsBlockedFrame(frame);
+      stream_id_manager_.incoming_initial_max_open_streams() + 1;
+  QuicStreamsBlockedFrame frame(0, stream_count, IsUnidi());
+  stream_id_manager_.OnStreamsBlockedFrame(frame);
 }
 
 // Same basic tests as above, but calls
@@ -328,33 +235,31 @@
 // First test make sure that streams with ids below the limit are accepted.
 TEST_P(QuicStreamIdManagerTestClient, IsIncomingStreamIdValidBelowLimit) {
   QuicStreamId stream_id =
-      StreamCountToId(stream_id_manager_->incoming_actual_max_streams() - 1,
+      StreamCountToId(stream_id_manager_.incoming_actual_max_streams() - 1,
                       Perspective::IS_CLIENT);
-  EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
-  EXPECT_TRUE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId(stream_id));
+  EXPECT_CALL(delegate_, OnError(_, _)).Times(0);
+  EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
 }
 
 // Accept a stream with an ID that equals the limit.
 TEST_P(QuicStreamIdManagerTestClient, IsIncomingStreamIdValidAtLimit) {
-  QuicStreamId stream_id =
-      StreamCountToId(stream_id_manager_->incoming_actual_max_streams(),
-                      Perspective::IS_CLIENT);
-  EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0);
-  EXPECT_TRUE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId(stream_id));
+  QuicStreamId stream_id = StreamCountToId(
+      stream_id_manager_.incoming_actual_max_streams(), Perspective::IS_CLIENT);
+  EXPECT_CALL(delegate_, OnError(_, _)).Times(0);
+  EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
 }
 
 // Close the connection if the id exceeds the limit.
 TEST_P(QuicStreamIdManagerTestClient, IsIncomingStreamIdInValidAboveLimit) {
   QuicStreamId stream_id = StreamCountToId(
-      stream_id_manager_->incoming_actual_max_streams() + 1,
+      stream_id_manager_.incoming_actual_max_streams() + 1,
       Perspective::IS_SERVER);  // This node is a client, incoming
                                 // stream ids must be server-originated.
   std::string error_details =
       GetParam() ? "Stream id 401 would exceed stream count limit 100"
                  : "Stream id 403 would exceed stream count limit 100";
-  EXPECT_CALL(*connection_,
-              CloseConnection(QUIC_INVALID_STREAM_ID, error_details, _));
-  EXPECT_FALSE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId(stream_id));
+  EXPECT_CALL(delegate_, OnError(QUIC_INVALID_STREAM_ID, error_details));
+  EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
 }
 
 // Test functionality for reception of a MAX_STREAMS frame. This code is
@@ -365,7 +270,7 @@
       // need to know the number of request/response streams.
       // This is the total number of outgoing streams (which includes both
       // req/resp and statics).
-      stream_id_manager_->outgoing_max_streams();
+      stream_id_manager_.outgoing_max_streams();
 
   QuicMaxStreamsFrame frame;
 
@@ -376,27 +281,29 @@
   frame.stream_count = initial_stream_count - 1;
 
   frame.unidirectional = IsUnidi();
-  EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame));
+  EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidi()));
+  EXPECT_TRUE(stream_id_manager_.OnMaxStreamsFrame(frame));
   EXPECT_EQ(initial_stream_count - 1u,
-            stream_id_manager_->outgoing_max_streams());
+            stream_id_manager_.outgoing_max_streams());
 
   QuicStreamCount save_outgoing_max_streams =
-      stream_id_manager_->outgoing_max_streams();
+      stream_id_manager_.outgoing_max_streams();
   // Now that there has been one MAX STREAMS frame, we should not
   // accept a MAX_STREAMS that reduces the limit...
   frame.stream_count = initial_stream_count - 2;
   frame.unidirectional = IsUnidi();
-  EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame));
+  EXPECT_TRUE(stream_id_manager_.OnMaxStreamsFrame(frame));
   // should not change from previous setting.
   EXPECT_EQ(save_outgoing_max_streams,
-            stream_id_manager_->outgoing_max_streams());
+            stream_id_manager_.outgoing_max_streams());
 
   // A stream count greater than the current limit should increase the limit.
   frame.stream_count = initial_stream_count + 1;
-  EXPECT_TRUE(stream_id_manager_->OnMaxStreamsFrame(frame));
+  EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidi()));
+  EXPECT_TRUE(stream_id_manager_.OnMaxStreamsFrame(frame));
 
   EXPECT_EQ(initial_stream_count + 1u,
-            stream_id_manager_->outgoing_max_streams());
+            stream_id_manager_.outgoing_max_streams());
 }
 
 // Test functionality for reception of a STREAMS_BLOCKED frame.
@@ -404,9 +311,10 @@
 TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerOnStreamsBlockedFrame) {
   // Get the current maximum allowed incoming stream count.
   QuicStreamCount advertised_stream_count =
-      stream_id_manager_->incoming_advertised_max_streams();
-  // Simulate receiving a config to allow frame transmission
-  session_->OnConfigNegotiated();
+      stream_id_manager_.incoming_advertised_max_streams();
+
+  // Set the config negotiated to allow frame transmission.
+  stream_id_manager_.OnConfigNegotiated();
 
   QuicStreamsBlockedFrame frame;
 
@@ -415,14 +323,14 @@
   // If the peer is saying it's blocked on the stream count that
   // we've advertised, it's a noop since the peer has the correct information.
   frame.stream_count = advertised_stream_count;
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
-  EXPECT_TRUE(stream_id_manager_->OnStreamsBlockedFrame(frame));
+  EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
+  EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame));
 
   // If the peer is saying it's blocked on a stream count that is larger
   // than what we've advertised, the connection should get closed.
   frame.stream_count = advertised_stream_count + 1;
-  EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAMS_BLOCKED_ERROR, _, _));
-  EXPECT_FALSE(stream_id_manager_->OnStreamsBlockedFrame(frame));
+  EXPECT_CALL(delegate_, OnError(QUIC_STREAMS_BLOCKED_ERROR, _));
+  EXPECT_FALSE(stream_id_manager_.OnStreamsBlockedFrame(frame));
 
   // If the peer is saying it's blocked on a count that is less than
   // our actual count, we send a MAX_STREAMS frame and update
@@ -430,16 +338,16 @@
   // First, need to bump up the actual max so there is room for the MAX
   // STREAMS frame to send a larger ID.
   QuicStreamCount actual_stream_count =
-      stream_id_manager_->incoming_actual_max_streams();
+      stream_id_manager_.incoming_actual_max_streams();
 
   // Closing a stream will result in the ability to initiate one more
   // stream
-  stream_id_manager_->OnStreamClosed(
-      QuicStreamIdManagerPeer::GetFirstIncomingStreamId(stream_id_manager_));
+  stream_id_manager_.OnStreamClosed(
+      QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_));
   EXPECT_EQ(actual_stream_count + 1u,
-            stream_id_manager_->incoming_actual_max_streams());
-  EXPECT_EQ(stream_id_manager_->incoming_actual_max_streams(),
-            stream_id_manager_->incoming_advertised_max_streams() + 1u);
+            stream_id_manager_.incoming_actual_max_streams());
+  EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
+            stream_id_manager_.incoming_advertised_max_streams() + 1u);
 
   // Now simulate receiving a STREAMS_BLOCKED frame...
   // Changing the actual maximum, above, forces a MAX_STREAMS frame to be
@@ -450,19 +358,14 @@
   // MAX_STREAMS sent earler.
   frame.stream_count = advertised_stream_count;
 
-  EXPECT_CALL(*connection_, SendControlFrame(_))
-      .Times(1)
-      .WillRepeatedly(Invoke(session_.get(), &TestQuicSession::SaveFrame));
+  EXPECT_CALL(delegate_,
+              SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
+                             IsUnidi()));
 
-  EXPECT_TRUE(stream_id_manager_->OnStreamsBlockedFrame(frame));
+  EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame));
   // Check that the saved frame is correct.
-  EXPECT_EQ(stream_id_manager_->incoming_actual_max_streams(),
-            stream_id_manager_->incoming_advertised_max_streams());
-  EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type);
-  EXPECT_EQ(stream_id_manager_->incoming_advertised_max_streams(),
-            session_->save_frame().max_streams_frame.stream_count);
-  // Make sure that this is the only MAX_STREAMS
-  EXPECT_EQ(1u, GetControlFrameId(session_->save_frame()));
+  EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
+            stream_id_manager_.incoming_advertised_max_streams());
 }
 
 // Test GetNextOutgoingStream. This is client/server agnostic.
@@ -471,41 +374,34 @@
   // opening...
   size_t number_of_streams = kDefaultMaxStreamsPerConnection;
 
-  // Set up config to allow the default stream limit and then
-  // simulate receiving a config to allow frame transmission
-  QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
-      session_->config(), kDefaultMaxStreamsPerConnection);
-  QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams(
-      session_->config(), kDefaultMaxStreamsPerConnection);
-  session_->OnConfigNegotiated();
+  EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidi()));
+  stream_id_manager_.SetMaxOpenOutgoingStreams(100);
+
+  stream_id_manager_.OnConfigNegotiated();
 
   QuicStreamId stream_id =
-      IsUnidi() ? session_->next_outgoing_unidirectional_stream_id()
-                : session_->next_outgoing_bidirectional_stream_id();
+      IsUnidi() ? QuicUtils::GetFirstUnidirectionalStreamId(
+                      QUIC_VERSION_99, stream_id_manager_.perspective())
+                : QuicUtils::GetFirstBidirectionalStreamId(
+                      QUIC_VERSION_99, stream_id_manager_.perspective());
 
-  EXPECT_EQ(number_of_streams, stream_id_manager_->outgoing_max_streams());
+  EXPECT_EQ(number_of_streams, stream_id_manager_.outgoing_max_streams());
   while (number_of_streams) {
-    EXPECT_TRUE(stream_id_manager_->CanOpenNextOutgoingStream());
-    EXPECT_EQ(stream_id, stream_id_manager_->GetNextOutgoingStreamId());
+    EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
+    EXPECT_EQ(stream_id, stream_id_manager_.GetNextOutgoingStreamId());
     stream_id += kV99StreamIdIncrement;
     number_of_streams--;
   }
 
   // If we try to check that the next outgoing stream id is available it should
   // A) fail and B) generate a STREAMS_BLOCKED frame.
-  EXPECT_CALL(*connection_, SendControlFrame(_))
-      .Times(1)
-      .WillRepeatedly(Invoke(session_.get(), &TestQuicSession::SaveFrame));
-  EXPECT_FALSE(stream_id_manager_->CanOpenNextOutgoingStream());
-  EXPECT_EQ(STREAMS_BLOCKED_FRAME, session_->save_frame().type);
-  // If bidi, Crypto stream default created  at start up, it is one
-  // more stream to account for since initialization is "number of
-  // request/responses" & crypto is added in to that, not streams.
-  EXPECT_EQ(kDefaultMaxStreamsPerConnection,
-            session_->save_frame().max_streams_frame.stream_count);
+  EXPECT_CALL(delegate_,
+              SendStreamsBlocked(kDefaultMaxStreamsPerConnection, IsUnidi()));
+  EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
+
   // If we try to get the next id (above the limit), it should cause a quic-bug.
   EXPECT_QUIC_BUG(
-      stream_id_manager_->GetNextOutgoingStreamId(),
+      stream_id_manager_.GetNextOutgoingStreamId(),
       "Attempt to allocate a new outgoing stream that would exceed the limit");
 }
 
@@ -513,27 +409,26 @@
 // server/client agnostic.
 TEST_P(QuicStreamIdManagerTestClient,
        StreamIdManagerServerMaybeIncreaseLargestPeerStreamId) {
-  QuicStreamId max_stream_id =
-      StreamCountToId(stream_id_manager_->incoming_actual_max_streams(),
-                      Perspective::IS_SERVER);
+  QuicStreamId max_stream_id = StreamCountToId(
+      stream_id_manager_.incoming_actual_max_streams(), Perspective::IS_SERVER);
   EXPECT_TRUE(
-      stream_id_manager_->MaybeIncreaseLargestPeerStreamId(max_stream_id));
+      stream_id_manager_.MaybeIncreaseLargestPeerStreamId(max_stream_id));
 
   QuicStreamId server_initiated_stream_id =
       StreamCountToId(1u,  // get 1st id
                       Perspective::IS_SERVER);
-  EXPECT_TRUE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId(
+  EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
       server_initiated_stream_id));
   // A bad stream ID results in a closed connection.
-  EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _));
-  EXPECT_FALSE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId(
+  EXPECT_CALL(delegate_, OnError(QUIC_INVALID_STREAM_ID, _));
+  EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
       max_stream_id + kV99StreamIdIncrement));
 }
 
 // Test the MAX STREAMS Window functionality.
 TEST_P(QuicStreamIdManagerTestClient, StreamIdManagerServerMaxStreams) {
-  // Simulate completed config to allow frame transmission
-  session_->OnConfigNegotiated();
+  // Set the config negotiated to allow frame transmission.
+  stream_id_manager_.OnConfigNegotiated();
 
   // Test that a MAX_STREAMS frame is generated when the peer has less than
   // |max_streams_window_| streams left that it can initiate.
@@ -543,96 +438,89 @@
   // should be sent. The -1 is because the check in
   // QuicStreamIdManager::MaybeSendMaxStreamsFrame sends a MAX_STREAMS if the
   // number of available streams at the peer is <= |max_streams_window_|
-  int stream_count = stream_id_manager_->max_streams_window() - 1;
+  int stream_count = stream_id_manager_.max_streams_window() - 1;
 
   // Should not get a control-frame transmission since the peer should have
   // "plenty" of stream IDs to use.
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
+  EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
+  EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
 
   // Get the first incoming stream ID to try and allocate.
   QuicStreamId stream_id = IsBidi() ? GetNthServerInitiatedBidirectionalId(0)
                                     : GetNthServerInitiatedUnidirectionalId(0);
   size_t old_available_incoming_streams =
-      stream_id_manager_->available_incoming_streams();
+      stream_id_manager_.available_incoming_streams();
   while (stream_count) {
-    EXPECT_TRUE(
-        stream_id_manager_->MaybeIncreaseLargestPeerStreamId(stream_id));
+    EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
 
     // This node should think that the peer believes it has one fewer
     // stream it can create.
     old_available_incoming_streams--;
     EXPECT_EQ(old_available_incoming_streams,
-              stream_id_manager_->available_incoming_streams());
+              stream_id_manager_.available_incoming_streams());
 
     stream_count--;
     stream_id += kV99StreamIdIncrement;
   }
 
   // Now close them, still should get no MAX_STREAMS
-  stream_count = stream_id_manager_->max_streams_window();
+  stream_count = stream_id_manager_.max_streams_window();
   stream_id = IsBidi() ? GetNthServerInitiatedBidirectionalId(0)
                        : GetNthServerInitiatedUnidirectionalId(0);
   QuicStreamCount expected_actual_max =
-      stream_id_manager_->incoming_actual_max_streams();
+      stream_id_manager_.incoming_actual_max_streams();
   QuicStreamCount expected_advertised_max_streams =
-      stream_id_manager_->incoming_advertised_max_streams();
+      stream_id_manager_.incoming_advertised_max_streams();
   while (stream_count) {
-    stream_id_manager_->OnStreamClosed(stream_id);
+    stream_id_manager_.OnStreamClosed(stream_id);
     stream_count--;
     stream_id += kV99StreamIdIncrement;
     expected_actual_max++;
     EXPECT_EQ(expected_actual_max,
-              stream_id_manager_->incoming_actual_max_streams());
+              stream_id_manager_.incoming_actual_max_streams());
     // Advertised maximum should remain the same.
     EXPECT_EQ(expected_advertised_max_streams,
-              stream_id_manager_->incoming_advertised_max_streams());
+              stream_id_manager_.incoming_advertised_max_streams());
   }
 
   // This should not change.
   EXPECT_EQ(old_available_incoming_streams,
-            stream_id_manager_->available_incoming_streams());
+            stream_id_manager_.available_incoming_streams());
 
   // Now whenever we close a stream we should get a MAX_STREAMS frame.
   // Above code closed all the open streams, so we have to open/close
-  EXPECT_CALL(*connection_, SendControlFrame(_))
-      .Times(1)
-      .WillRepeatedly(Invoke(session_.get(), &TestQuicSession::SaveFrame));
-  EXPECT_TRUE(stream_id_manager_->MaybeIncreaseLargestPeerStreamId(stream_id));
-  stream_id_manager_->OnStreamClosed(stream_id);
-  stream_id += kV99StreamIdIncrement;
-
-  // Check that the MAX STREAMS was sent and has the correct values.
-  EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type);
-  EXPECT_EQ(stream_id_manager_->incoming_advertised_max_streams(),
-            session_->save_frame().max_streams_frame.stream_count);
+  //  EXPECT_CALL(delegate_,
+  //  SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
+  //  IsUnidi()));
+  EXPECT_CALL(delegate_, SendMaxStreams(_, IsUnidi()));
+  EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
+  stream_id_manager_.OnStreamClosed(stream_id);
 }
 
 // Check that edge conditions of the stream count in a STREAMS_BLOCKED frame
 // are. properly handled.
 TEST_P(QuicStreamIdManagerTestClient, StreamsBlockedEdgeConditions) {
-  // Simulate completed config to allow frame transmission
-  session_->OnConfigNegotiated();
+  // Set the config negotiated to allow frame transmission.
+  stream_id_manager_.OnConfigNegotiated();
 
   QuicStreamsBlockedFrame frame;
   frame.unidirectional = IsUnidi();
 
   // Check that receipt of a STREAMS BLOCKED with stream-count = 0 does nothing
   // when max_allowed_incoming_streams is 0.
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
-  stream_id_manager_->SetMaxOpenIncomingStreams(0);
+  EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
+  EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
+  stream_id_manager_.SetMaxOpenIncomingStreams(0);
   frame.stream_count = 0;
-  stream_id_manager_->OnStreamsBlockedFrame(frame);
+  stream_id_manager_.OnStreamsBlockedFrame(frame);
 
   // Check that receipt of a STREAMS BLOCKED with stream-count = 0 invokes a
   // MAX STREAMS, count = 123, when the MaxOpen... is set to 123.
-  EXPECT_CALL(*connection_, SendControlFrame(_))
-      .Times(1)
-      .WillOnce(Invoke(session_.get(), &TestQuicSession::SaveFrame));
-  stream_id_manager_->SetMaxOpenIncomingStreams(123);
+  EXPECT_CALL(delegate_, SendMaxStreams(123u, IsUnidi()));
+  EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
+  stream_id_manager_.SetMaxOpenIncomingStreams(123);
   frame.stream_count = 0;
-  stream_id_manager_->OnStreamsBlockedFrame(frame);
-  EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type);
-  EXPECT_EQ(123u, session_->save_frame().max_streams_frame.stream_count);
+  stream_id_manager_.OnStreamsBlockedFrame(frame);
 }
 
 TEST_P(QuicStreamIdManagerTestClient, HoldMaxStreamsFrame) {
@@ -640,21 +528,18 @@
     return;
   }
 
-  // The session has not been configured so frame transmission will not be
-  // allowed.
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
+  // The config has not been negotiated so the MAX_STREAMS frame will not be
+  // sent.
+  EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
 
-  QuicStreamsBlockedFrame frame(
-      1u, 0u, QuicStreamIdManagerPeer::get_unidirectional(stream_id_manager_));
+  QuicStreamsBlockedFrame frame(1u, 0u, IsUnidi());
   // Should cause change in pending_max_streams.
-  stream_id_manager_->OnStreamsBlockedFrame(frame);
-  // Will do OnConfig. We should see a control frame pop out now.
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1);
+  stream_id_manager_.OnStreamsBlockedFrame(frame);
 
-  // Now allow frame transmission -- which happens when the QuicSession
-  // receives the configuration and calls
-  // QuicStreamIdManager::OnConfigNegotiated()
-  session_->OnConfigNegotiated();
+  EXPECT_CALL(delegate_, SendMaxStreams(_, IsUnidi()));
+
+  // MAX_STREAMS will be sent now that the config has been negotiated.
+  stream_id_manager_.OnConfigNegotiated();
 }
 
 // Following tests all are server-specific. They depend, in some way, on
@@ -673,25 +558,21 @@
 
   // set outgoing limit to 0, will cause the CanOpenNext... to fail
   // leading to a STREAMS_BLOCKED.
-  QuicStreamIdManagerPeer::set_outgoing_max_streams(stream_id_manager_, 0);
+  EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidi()));
+  stream_id_manager_.SetMaxOpenOutgoingStreams(0);
 
-  // We should not see a STREAMS-BLOCKED frame because we're not configured..
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
+  // We should not see a STREAMS_BLOCKED frame because we're not configured..
+  EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
 
   // Since the stream limit is 0 and no sreams can be created this should return
-  // false and have forced a streams-blocked to be queued up, with the
+  // false and have forced a STREAMS_BLOCKED to be queued up, with the
   // blocked stream id == 0.
-  EXPECT_FALSE(stream_id_manager_->CanOpenNextOutgoingStream());
+  EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
 
-  // Simulate receipt of the configuration; This case does not update the
-  // outgoing stream limit, so the on-config should result in a streams-blocked
-  // being sent.
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1);
-  QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
-      session_->config(), 0);
-  QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams(session_->config(),
-                                                             0);
-  session_->OnConfigNegotiated();
+  // Since the steam limit has not been increased when the config was negotiated
+  // a STREAMS_BLOCKED frame should be sent.
+  EXPECT_CALL(delegate_, SendStreamsBlocked(_, IsUnidi()));
+  stream_id_manager_.OnConfigNegotiated();
 }
 
 TEST_P(QuicStreamIdManagerTestClient, HoldStreamsBlockedFrameNoXmit) {
@@ -700,28 +581,22 @@
   }
   // Set outgoing limit to 0, will cause the CanOpenNext... to fail
   // leading to a STREAMS_BLOCKED.
-  QuicStreamIdManagerPeer::set_outgoing_max_streams(stream_id_manager_, 0);
+  EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidi()));
+  stream_id_manager_.SetMaxOpenOutgoingStreams(0);
 
-  // We should not see a STREAMS-BLOCKED frame because we're not configured..
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
+  // We should not see a STREAMS_BLOCKED frame because we're not configured..
+  EXPECT_CALL(delegate_, SendStreamsBlocked(_, IsUnidi())).Times(0);
 
   // Since the stream limit is 0 and no sreams can be created this should return
-  // false and have forced a streams-blocked to be queued up, with the
+  // false and have forced a STREAMS_BLOCKED to be queued up, with the
   // blocked stream id == 0.
-  EXPECT_FALSE(stream_id_manager_->CanOpenNextOutgoingStream());
+  EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
 
-  // Since the config gives some streams to create, we should not see
-  // a STREAMS-BLOCKED frame.
-  EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0);
-
-  // Do the configuration.  The stream limits are increased, allowing this
-  // node to create more streams, so we should not see the pending
-  // STREAMS-BLOCKED frame get transmitted.
-  QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
-      session_->config(), 10);
-  QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams(session_->config(),
-                                                             10);
-  session_->OnConfigNegotiated();
+  EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidi()));
+  stream_id_manager_.SetMaxOpenOutgoingStreams(10);
+  // Since the stream limit has been increase which allows streams to be created
+  // no STREAMS_BLOCKED should be send.
+  stream_id_manager_.OnConfigNegotiated();
 }
 
 INSTANTIATE_TEST_SUITE_P(Tests,
@@ -733,86 +608,64 @@
 // stream id is correct.
 TEST_P(QuicStreamIdManagerTestServer, CheckMaxAllowedOutgoing) {
   const size_t kIncomingStreamCount = 123;
-  stream_id_manager_->SetMaxOpenOutgoingStreams(kIncomingStreamCount);
-  EXPECT_EQ(kIncomingStreamCount, stream_id_manager_->outgoing_max_streams());
+  EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidi()));
+  stream_id_manager_.SetMaxOpenOutgoingStreams(kIncomingStreamCount);
+  EXPECT_EQ(kIncomingStreamCount, stream_id_manager_.outgoing_max_streams());
 }
 
 // Test that a MAX_STREAMS frame is generated when half the stream ids become
 // available. This has a useful side effect of testing that when streams are
 // closed, the number of available stream ids increases.
 TEST_P(QuicStreamIdManagerTestServer, MaxStreamsSlidingWindow) {
-  // Ignore OnStreamReset calls.
-  EXPECT_CALL(*connection_, OnStreamReset(_, _)).WillRepeatedly(Return());
-  // Capture control frames for analysis.
-  EXPECT_CALL(*connection_, SendControlFrame(_))
-      .WillRepeatedly(Invoke(session_.get(), &TestQuicSession::SaveFrame));
   // Simulate config being negotiated, causing the limits all to be initialized.
-  session_->OnConfigNegotiated();
+  stream_id_manager_.OnConfigNegotiated();
+
   QuicStreamCount first_advert =
-      stream_id_manager_->incoming_advertised_max_streams();
+      stream_id_manager_.incoming_advertised_max_streams();
 
   // Open/close enough streams to shrink the window without causing a MAX
   // STREAMS to be generated. The window will open (and a MAX STREAMS generated)
   // when max_streams_window() stream IDs have been made available. The loop
   // will make that many stream IDs available, so the last CloseStream should
+
   // cause a MAX STREAMS frame to be generated.
-  int i = static_cast<int>(stream_id_manager_->max_streams_window());
+  int i = static_cast<int>(stream_id_manager_.max_streams_window());
   QuicStreamId id =
-      QuicStreamIdManagerPeer::GetFirstIncomingStreamId(stream_id_manager_);
+      QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_);
+  EXPECT_CALL(
+      delegate_,
+      SendMaxStreams(first_advert + stream_id_manager_.max_streams_window(),
+                     IsUnidi()));
   while (i) {
-    QuicStream* stream = session_->GetOrCreateStream(id);
-    EXPECT_NE(nullptr, stream);
-    // have to set the stream's fin-received flag to true so that it
-    // does not go into the has-not-received-byte-offset state, leading
-    // to the stream being added to the locally_closed_streams_highest_offset_
-    // map, and therefore not counting as truly being closed. The test requires
-    // that the stream truly close, so that new streams become available,
-    // causing the MAX_STREAMS to be sent.
-    stream->set_fin_received(true);
-    EXPECT_EQ(id, stream->id());
-    if (IsBidi()) {
-      // Only send reset for incoming bidirectional streams.
-      EXPECT_CALL(*session_, SendRstStream(_, _, _));
-    }
-    CloseStream(stream->id());
+    EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(id));
+    stream_id_manager_.OnStreamClosed(id);
     i--;
     id += kV99StreamIdIncrement;
   }
-  EXPECT_EQ(MAX_STREAMS_FRAME, session_->save_frame().type);
-  QuicStreamCount second_advert =
-      session_->save_frame().max_streams_frame.stream_count;
-  EXPECT_EQ(first_advert + stream_id_manager_->max_streams_window(),
-            second_advert);
 }
 
 // Tast that an attempt to create an outgoing stream does not exceed the limit
 // and that it generates an appropriate STREAMS_BLOCKED frame.
 TEST_P(QuicStreamIdManagerTestServer, NewStreamDoesNotExceedLimit) {
-  // Configure with some number of streams, and allow frame transmission
-  QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams(
-      session_->config(), 100);
-  QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams(session_->config(),
-                                                             100);
-  session_->OnConfigNegotiated();
+  EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidi()));
+  stream_id_manager_.SetMaxOpenOutgoingStreams(100);
+  stream_id_manager_.OnConfigNegotiated();
 
-  size_t stream_count = stream_id_manager_->outgoing_max_streams();
+  size_t stream_count = stream_id_manager_.outgoing_max_streams();
   EXPECT_NE(0u, stream_count);
-  TestQuicStream* stream;
+
   while (stream_count) {
-    stream = IsBidi() ? session_->CreateOutgoingBidirectionalStream()
-                      : session_->CreateOutgoingUnidirectionalStream();
-    EXPECT_NE(stream, nullptr);
+    EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
+    stream_id_manager_.GetNextOutgoingStreamId();
     stream_count--;
   }
 
-  EXPECT_EQ(stream_id_manager_->outgoing_stream_count(),
-            stream_id_manager_->outgoing_max_streams());
+  EXPECT_EQ(stream_id_manager_.outgoing_stream_count(),
+            stream_id_manager_.outgoing_max_streams());
   // Create another, it should fail. Should also send a STREAMS_BLOCKED
   // control frame.
-  EXPECT_CALL(*connection_, SendControlFrame(_));
-  stream = IsBidi() ? session_->CreateOutgoingBidirectionalStream()
-                    : session_->CreateOutgoingUnidirectionalStream();
-  EXPECT_EQ(nullptr, stream);
+  EXPECT_CALL(delegate_, SendStreamsBlocked(_, IsUnidi()));
+  EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
 }
 
 // Check that the parameters used by the stream ID manager are properly
@@ -821,27 +674,27 @@
   // These fields are inited via the QuicSession constructor to default
   // values defined as a constant.
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
-            stream_id_manager_->incoming_initial_max_open_streams());
+            stream_id_manager_.incoming_initial_max_open_streams());
 
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
-            stream_id_manager_->incoming_actual_max_streams());
+            stream_id_manager_.incoming_actual_max_streams());
   EXPECT_EQ(kDefaultMaxStreamsPerConnection,
-            stream_id_manager_->outgoing_max_streams());
+            stream_id_manager_.outgoing_max_streams());
 
   // The window for advertising updates to the MAX STREAM ID is half the number
   // of stream allowed.
   EXPECT_EQ(kDefaultMaxStreamsPerConnection / kMaxStreamsWindowDivisor,
-            stream_id_manager_->max_streams_window());
+            stream_id_manager_.max_streams_window());
 }
 
 TEST_P(QuicStreamIdManagerTestServer, AvailableStreams) {
-  stream_id_manager_->MaybeIncreaseLargestPeerStreamId(
+  stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
       IsBidi() ? GetNthClientInitiatedBidirectionalId(3)
                : GetNthClientInitiatedUnidirectionalId(3));
-  EXPECT_TRUE(stream_id_manager_->IsAvailableStream(
+  EXPECT_TRUE(stream_id_manager_.IsAvailableStream(
       IsBidi() ? GetNthClientInitiatedBidirectionalId(1)
                : GetNthClientInitiatedUnidirectionalId(1)));
-  EXPECT_TRUE(stream_id_manager_->IsAvailableStream(
+  EXPECT_TRUE(stream_id_manager_.IsAvailableStream(
       IsBidi() ? GetNthClientInitiatedBidirectionalId(2)
                : GetNthClientInitiatedUnidirectionalId(2)));
 }
@@ -851,7 +704,7 @@
 // This is a regression for Chromium bugs 909987 and 910040
 TEST_P(QuicStreamIdManagerTestServer, ExtremeMaybeIncreaseLargestPeerStreamId) {
   QuicStreamId too_big_stream_id = StreamCountToId(
-      stream_id_manager_->incoming_actual_max_streams() + 20,
+      stream_id_manager_.incoming_actual_max_streams() + 20,
       Perspective::IS_CLIENT);  // This node is a server, incoming stream
                                 // ids must be client-originated.
   std::string error_details;
@@ -865,10 +718,9 @@
     error_details = "Stream id 478 would exceed stream count limit 100";
   }
 
-  EXPECT_CALL(*connection_,
-              CloseConnection(QUIC_INVALID_STREAM_ID, error_details, _));
+  EXPECT_CALL(delegate_, OnError(QUIC_INVALID_STREAM_ID, error_details));
   EXPECT_FALSE(
-      stream_id_manager_->MaybeIncreaseLargestPeerStreamId(too_big_stream_id));
+      stream_id_manager_.MaybeIncreaseLargestPeerStreamId(too_big_stream_id));
 }
 
 }  // namespace
diff --git a/quic/core/uber_quic_stream_id_manager.cc b/quic/core/uber_quic_stream_id_manager.cc
index fa42643..98c6e8c 100644
--- a/quic/core/uber_quic_stream_id_manager.cc
+++ b/quic/core/uber_quic_stream_id_manager.cc
@@ -11,17 +11,24 @@
 
 UberQuicStreamIdManager::UberQuicStreamIdManager(
     QuicSession* session,
+    QuicStreamCount num_expected_unidirectiona_static_streams,
     QuicStreamCount max_open_outgoing_bidirectional_streams,
     QuicStreamCount max_open_outgoing_unidirectional_streams,
     QuicStreamCount max_open_incoming_bidirectional_streams,
     QuicStreamCount max_open_incoming_unidirectional_streams)
     : bidirectional_stream_id_manager_(session,
                                        /*unidirectional=*/false,
+                                       session->perspective(),
+                                       session->transport_version(),
+                                       0,
                                        max_open_outgoing_bidirectional_streams,
                                        max_open_incoming_bidirectional_streams),
       unidirectional_stream_id_manager_(
           session,
           /*unidirectional=*/true,
+          session->perspective(),
+          session->transport_version(),
+          num_expected_unidirectiona_static_streams,
           max_open_outgoing_unidirectional_streams,
           max_open_incoming_unidirectional_streams) {}
 
diff --git a/quic/core/uber_quic_stream_id_manager.h b/quic/core/uber_quic_stream_id_manager.h
index 5505475..dab571d 100644
--- a/quic/core/uber_quic_stream_id_manager.h
+++ b/quic/core/uber_quic_stream_id_manager.h
@@ -22,6 +22,7 @@
  public:
   UberQuicStreamIdManager(
       QuicSession* session,
+      QuicStreamCount num_expected_unidirectiona_static_streams,
       QuicStreamCount max_open_outgoing_bidirectional_streams,
       QuicStreamCount max_open_outgoing_unidirectional_streams,
       QuicStreamCount max_open_incoming_bidirectional_streams,
diff --git a/quic/core/uber_quic_stream_id_manager_test.cc b/quic/core/uber_quic_stream_id_manager_test.cc
index 7e3cc8c..b4ef1cc 100644
--- a/quic/core/uber_quic_stream_id_manager_test.cc
+++ b/quic/core/uber_quic_stream_id_manager_test.cc
@@ -315,7 +315,7 @@
 
 TEST_P(UberQuicStreamIdManagerTest, OnStreamsBlockedFrame) {
   // Allow MAX_STREAMS frame transmission
-  QuicSessionPeer::set_is_configured(session_.get(), true);
+  manager_->OnConfigNegotiated();
   // Set up to capture calls to SendControlFrame - when a STREAMS_BLOCKED
   // frame is received, it will result in a a new MAX_STREAMS frame being
   // sent (if new streams can be made available).