Home | History | Annotate | Download | only in spdy
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/spdy/spdy_websocket_stream.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/bind_helpers.h"
     12 #include "net/base/completion_callback.h"
     13 #include "net/proxy/proxy_server.h"
     14 #include "net/socket/next_proto.h"
     15 #include "net/socket/ssl_client_socket.h"
     16 #include "net/spdy/spdy_http_utils.h"
     17 #include "net/spdy/spdy_protocol.h"
     18 #include "net/spdy/spdy_session.h"
     19 #include "net/spdy/spdy_websocket_test_util.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 
     22 namespace net {
     23 
     24 namespace {
     25 
     26 struct SpdyWebSocketStreamEvent {
     27   enum EventType {
     28     EVENT_CREATED,
     29     EVENT_SENT_HEADERS,
     30     EVENT_RECEIVED_HEADER,
     31     EVENT_SENT_DATA,
     32     EVENT_RECEIVED_DATA,
     33     EVENT_CLOSE,
     34   };
     35   SpdyWebSocketStreamEvent(EventType type,
     36                            const SpdyHeaderBlock& headers,
     37                            int result,
     38                            const std::string& data)
     39       : event_type(type),
     40         headers(headers),
     41         result(result),
     42         data(data) {}
     43 
     44   EventType event_type;
     45   SpdyHeaderBlock headers;
     46   int result;
     47   std::string data;
     48 };
     49 
     50 class SpdyWebSocketStreamEventRecorder : public SpdyWebSocketStream::Delegate {
     51  public:
     52   explicit SpdyWebSocketStreamEventRecorder(const CompletionCallback& callback)
     53       : callback_(callback) {}
     54   virtual ~SpdyWebSocketStreamEventRecorder() {}
     55 
     56   typedef base::Callback<void(SpdyWebSocketStreamEvent*)> StreamEventCallback;
     57 
     58   void SetOnCreated(const StreamEventCallback& callback) {
     59     on_created_ = callback;
     60   }
     61   void SetOnSentHeaders(const StreamEventCallback& callback) {
     62     on_sent_headers_ = callback;
     63   }
     64   void SetOnReceivedHeader(const StreamEventCallback& callback) {
     65     on_received_header_ = callback;
     66   }
     67   void SetOnSentData(const StreamEventCallback& callback) {
     68     on_sent_data_ = callback;
     69   }
     70   void SetOnReceivedData(const StreamEventCallback& callback) {
     71     on_received_data_ = callback;
     72   }
     73   void SetOnClose(const StreamEventCallback& callback) {
     74     on_close_ = callback;
     75   }
     76 
     77   virtual void OnCreatedSpdyStream(int result) OVERRIDE {
     78     events_.push_back(
     79         SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_CREATED,
     80                                  SpdyHeaderBlock(),
     81                                  result,
     82                                  std::string()));
     83     if (!on_created_.is_null())
     84       on_created_.Run(&events_.back());
     85   }
     86   virtual void OnSentSpdyHeaders() OVERRIDE {
     87     events_.push_back(
     88         SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
     89                                  SpdyHeaderBlock(),
     90                                  OK,
     91                                  std::string()));
     92     if (!on_sent_data_.is_null())
     93       on_sent_data_.Run(&events_.back());
     94   }
     95   virtual void OnSpdyResponseHeadersUpdated(
     96       const SpdyHeaderBlock& response_headers) OVERRIDE {
     97     events_.push_back(
     98         SpdyWebSocketStreamEvent(
     99             SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
    100             response_headers,
    101             OK,
    102             std::string()));
    103     if (!on_received_header_.is_null())
    104       on_received_header_.Run(&events_.back());
    105   }
    106   virtual void OnSentSpdyData(size_t bytes_sent) OVERRIDE {
    107     events_.push_back(
    108         SpdyWebSocketStreamEvent(
    109             SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
    110             SpdyHeaderBlock(),
    111             static_cast<int>(bytes_sent),
    112             std::string()));
    113     if (!on_sent_data_.is_null())
    114       on_sent_data_.Run(&events_.back());
    115   }
    116   virtual void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {
    117     std::string buffer_data;
    118     size_t buffer_len = 0;
    119     if (buffer) {
    120       buffer_len = buffer->GetRemainingSize();
    121       buffer_data.append(buffer->GetRemainingData(), buffer_len);
    122     }
    123     events_.push_back(
    124         SpdyWebSocketStreamEvent(
    125             SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
    126             SpdyHeaderBlock(),
    127             buffer_len,
    128             buffer_data));
    129     if (!on_received_data_.is_null())
    130       on_received_data_.Run(&events_.back());
    131   }
    132   virtual void OnCloseSpdyStream() OVERRIDE {
    133     events_.push_back(
    134         SpdyWebSocketStreamEvent(
    135             SpdyWebSocketStreamEvent::EVENT_CLOSE,
    136             SpdyHeaderBlock(),
    137             OK,
    138             std::string()));
    139     if (!on_close_.is_null())
    140       on_close_.Run(&events_.back());
    141     if (!callback_.is_null())
    142       callback_.Run(OK);
    143   }
    144 
    145   const std::vector<SpdyWebSocketStreamEvent>& GetSeenEvents() const {
    146     return events_;
    147   }
    148 
    149  private:
    150   std::vector<SpdyWebSocketStreamEvent> events_;
    151   StreamEventCallback on_created_;
    152   StreamEventCallback on_sent_headers_;
    153   StreamEventCallback on_received_header_;
    154   StreamEventCallback on_sent_data_;
    155   StreamEventCallback on_received_data_;
    156   StreamEventCallback on_close_;
    157   CompletionCallback callback_;
    158 
    159   DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStreamEventRecorder);
    160 };
    161 
    162 }  // namespace
    163 
    164 class SpdyWebSocketStreamTest
    165     : public ::testing::Test,
    166       public ::testing::WithParamInterface<NextProto> {
    167  public:
    168   OrderedSocketData* data() { return data_.get(); }
    169 
    170   void DoSendHelloFrame(SpdyWebSocketStreamEvent* event) {
    171     // Record the actual stream_id.
    172     created_stream_id_ = websocket_stream_->stream_->stream_id();
    173     websocket_stream_->SendData(kMessageFrame, kMessageFrameLength);
    174   }
    175 
    176   void DoSendClosingFrame(SpdyWebSocketStreamEvent* event) {
    177     websocket_stream_->SendData(kClosingFrame, kClosingFrameLength);
    178   }
    179 
    180   void DoClose(SpdyWebSocketStreamEvent* event) {
    181     websocket_stream_->Close();
    182   }
    183 
    184   void DoSync(SpdyWebSocketStreamEvent* event) {
    185     sync_callback_.callback().Run(OK);
    186   }
    187 
    188  protected:
    189   SpdyWebSocketStreamTest()
    190       : spdy_util_(GetParam()),
    191         spdy_settings_id_to_set_(SETTINGS_MAX_CONCURRENT_STREAMS),
    192         spdy_settings_flags_to_set_(SETTINGS_FLAG_PLEASE_PERSIST),
    193         spdy_settings_value_to_set_(1),
    194         session_deps_(GetParam()),
    195         stream_id_(0),
    196         created_stream_id_(0) {}
    197   virtual ~SpdyWebSocketStreamTest() {}
    198 
    199   virtual void SetUp() {
    200     host_port_pair_.set_host("example.com");
    201     host_port_pair_.set_port(80);
    202     spdy_session_key_ = SpdySessionKey(host_port_pair_,
    203                                        ProxyServer::Direct(),
    204                                        kPrivacyModeDisabled);
    205 
    206     spdy_settings_to_send_[spdy_settings_id_to_set_] =
    207         SettingsFlagsAndValue(
    208             SETTINGS_FLAG_PERSISTED, spdy_settings_value_to_set_);
    209   }
    210 
    211   virtual void TearDown() {
    212     base::MessageLoop::current()->RunUntilIdle();
    213   }
    214 
    215   void Prepare(SpdyStreamId stream_id) {
    216     stream_id_ = stream_id;
    217 
    218     request_frame_.reset(spdy_util_.ConstructSpdyWebSocketSynStream(
    219         stream_id_,
    220         "/echo",
    221         "example.com",
    222         "http://example.com/wsdemo"));
    223 
    224     response_frame_.reset(
    225         spdy_util_.ConstructSpdyWebSocketSynReply(stream_id_));
    226 
    227     message_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
    228         kMessageFrame,
    229         kMessageFrameLength,
    230         stream_id_,
    231         false));
    232 
    233     closing_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
    234         kClosingFrame,
    235         kClosingFrameLength,
    236         stream_id_,
    237         false));
    238   }
    239 
    240   void InitSession(MockRead* reads, size_t reads_count,
    241                    MockWrite* writes, size_t writes_count) {
    242     data_.reset(new OrderedSocketData(reads, reads_count,
    243                                       writes, writes_count));
    244     session_deps_.socket_factory->AddSocketDataProvider(data_.get());
    245     http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
    246     session_ = CreateInsecureSpdySession(
    247         http_session_, spdy_session_key_, BoundNetLog());
    248   }
    249 
    250   void SendRequest() {
    251     scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
    252     spdy_util_.SetHeader("path", "/echo", headers.get());
    253     spdy_util_.SetHeader("host", "example.com", headers.get());
    254     spdy_util_.SetHeader("version", "WebSocket/13", headers.get());
    255     spdy_util_.SetHeader("scheme", "ws", headers.get());
    256     spdy_util_.SetHeader("origin", "http://example.com/wsdemo", headers.get());
    257     websocket_stream_->SendRequest(headers.Pass());
    258   }
    259 
    260   SpdyWebSocketTestUtil spdy_util_;
    261   SpdySettingsIds spdy_settings_id_to_set_;
    262   SpdySettingsFlags spdy_settings_flags_to_set_;
    263   uint32 spdy_settings_value_to_set_;
    264   SettingsMap spdy_settings_to_send_;
    265   SpdySessionDependencies session_deps_;
    266   scoped_ptr<OrderedSocketData> data_;
    267   scoped_refptr<HttpNetworkSession> http_session_;
    268   base::WeakPtr<SpdySession> session_;
    269   scoped_ptr<SpdyWebSocketStream> websocket_stream_;
    270   SpdyStreamId stream_id_;
    271   SpdyStreamId created_stream_id_;
    272   scoped_ptr<SpdyFrame> request_frame_;
    273   scoped_ptr<SpdyFrame> response_frame_;
    274   scoped_ptr<SpdyFrame> message_frame_;
    275   scoped_ptr<SpdyFrame> closing_frame_;
    276   HostPortPair host_port_pair_;
    277   SpdySessionKey spdy_session_key_;
    278   TestCompletionCallback completion_callback_;
    279   TestCompletionCallback sync_callback_;
    280 
    281   static const char kMessageFrame[];
    282   static const char kClosingFrame[];
    283   static const size_t kMessageFrameLength;
    284   static const size_t kClosingFrameLength;
    285 };
    286 
    287 INSTANTIATE_TEST_CASE_P(
    288     NextProto,
    289     SpdyWebSocketStreamTest,
    290     testing::Values(kProtoDeprecatedSPDY2,
    291                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
    292                     kProtoHTTP2Draft04));
    293 
    294 // TODO(toyoshim): Replace old framing data to new one, then use HEADERS and
    295 // data frames.
    296 const char SpdyWebSocketStreamTest::kMessageFrame[] = "\x81\x05hello";
    297 const char SpdyWebSocketStreamTest::kClosingFrame[] = "\x88\0";
    298 const size_t SpdyWebSocketStreamTest::kMessageFrameLength =
    299     arraysize(SpdyWebSocketStreamTest::kMessageFrame) - 1;
    300 const size_t SpdyWebSocketStreamTest::kClosingFrameLength =
    301     arraysize(SpdyWebSocketStreamTest::kClosingFrame) - 1;
    302 
    303 TEST_P(SpdyWebSocketStreamTest, Basic) {
    304   Prepare(1);
    305   MockWrite writes[] = {
    306     CreateMockWrite(*request_frame_.get(), 1),
    307     CreateMockWrite(*message_frame_.get(), 3),
    308     CreateMockWrite(*closing_frame_.get(), 5)
    309   };
    310 
    311   MockRead reads[] = {
    312     CreateMockRead(*response_frame_.get(), 2),
    313     CreateMockRead(*message_frame_.get(), 4),
    314     // Skip sequence 6 to notify closing has been sent.
    315     CreateMockRead(*closing_frame_.get(), 7),
    316     MockRead(SYNCHRONOUS, 0, 8)  // EOF cause OnCloseSpdyStream event.
    317   };
    318 
    319   InitSession(reads, arraysize(reads), writes, arraysize(writes));
    320 
    321   SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
    322   delegate.SetOnReceivedHeader(
    323       base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
    324                  base::Unretained(this)));
    325   delegate.SetOnReceivedData(
    326       base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
    327                  base::Unretained(this)));
    328 
    329   websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
    330 
    331   BoundNetLog net_log;
    332   GURL url("ws://example.com/echo");
    333   ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
    334 
    335   ASSERT_TRUE(websocket_stream_->stream_.get());
    336 
    337   SendRequest();
    338 
    339   completion_callback_.WaitForResult();
    340 
    341   EXPECT_EQ(stream_id_, created_stream_id_);
    342 
    343   websocket_stream_.reset();
    344 
    345   const std::vector<SpdyWebSocketStreamEvent>& events =
    346       delegate.GetSeenEvents();
    347   ASSERT_EQ(7U, events.size());
    348 
    349   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
    350             events[0].event_type);
    351   EXPECT_EQ(OK, events[0].result);
    352   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
    353             events[1].event_type);
    354   EXPECT_EQ(OK, events[1].result);
    355   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
    356             events[2].event_type);
    357   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
    358   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
    359             events[3].event_type);
    360   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
    361   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
    362             events[4].event_type);
    363   EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[4].result);
    364   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
    365             events[5].event_type);
    366   EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
    367   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
    368             events[6].event_type);
    369   EXPECT_EQ(OK, events[6].result);
    370 
    371   // EOF close SPDY session.
    372   EXPECT_FALSE(
    373       HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
    374   EXPECT_TRUE(data()->at_read_eof());
    375   EXPECT_TRUE(data()->at_write_eof());
    376 }
    377 
    378 TEST_P(SpdyWebSocketStreamTest, DestructionBeforeClose) {
    379   Prepare(1);
    380   MockWrite writes[] = {
    381     CreateMockWrite(*request_frame_.get(), 1),
    382     CreateMockWrite(*message_frame_.get(), 3)
    383   };
    384 
    385   MockRead reads[] = {
    386     CreateMockRead(*response_frame_.get(), 2),
    387     CreateMockRead(*message_frame_.get(), 4),
    388     MockRead(ASYNC, ERR_IO_PENDING, 5)
    389   };
    390 
    391   InitSession(reads, arraysize(reads), writes, arraysize(writes));
    392 
    393   SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
    394   delegate.SetOnReceivedHeader(
    395       base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
    396                  base::Unretained(this)));
    397   delegate.SetOnReceivedData(
    398       base::Bind(&SpdyWebSocketStreamTest::DoSync,
    399                  base::Unretained(this)));
    400 
    401   websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
    402 
    403   BoundNetLog net_log;
    404   GURL url("ws://example.com/echo");
    405   ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
    406 
    407   SendRequest();
    408 
    409   sync_callback_.WaitForResult();
    410 
    411   // WebSocketStream destruction remove its SPDY stream from the session.
    412   EXPECT_TRUE(session_->IsStreamActive(stream_id_));
    413   websocket_stream_.reset();
    414   EXPECT_FALSE(session_->IsStreamActive(stream_id_));
    415 
    416   const std::vector<SpdyWebSocketStreamEvent>& events =
    417       delegate.GetSeenEvents();
    418   ASSERT_GE(4U, events.size());
    419 
    420   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
    421             events[0].event_type);
    422   EXPECT_EQ(OK, events[0].result);
    423   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
    424             events[1].event_type);
    425   EXPECT_EQ(OK, events[1].result);
    426   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
    427             events[2].event_type);
    428   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
    429   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
    430             events[3].event_type);
    431   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
    432 
    433   EXPECT_TRUE(
    434       HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
    435   EXPECT_TRUE(data()->at_read_eof());
    436   EXPECT_TRUE(data()->at_write_eof());
    437 }
    438 
    439 TEST_P(SpdyWebSocketStreamTest, DestructionAfterExplicitClose) {
    440   Prepare(1);
    441   MockWrite writes[] = {
    442     CreateMockWrite(*request_frame_.get(), 1),
    443     CreateMockWrite(*message_frame_.get(), 3),
    444     CreateMockWrite(*closing_frame_.get(), 5)
    445   };
    446 
    447   MockRead reads[] = {
    448     CreateMockRead(*response_frame_.get(), 2),
    449     CreateMockRead(*message_frame_.get(), 4),
    450     MockRead(ASYNC, ERR_IO_PENDING, 6)
    451   };
    452 
    453   InitSession(reads, arraysize(reads), writes, arraysize(writes));
    454 
    455   SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
    456   delegate.SetOnReceivedHeader(
    457       base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
    458                  base::Unretained(this)));
    459   delegate.SetOnReceivedData(
    460       base::Bind(&SpdyWebSocketStreamTest::DoClose,
    461                  base::Unretained(this)));
    462 
    463   websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
    464 
    465   BoundNetLog net_log;
    466   GURL url("ws://example.com/echo");
    467   ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
    468 
    469   SendRequest();
    470 
    471   completion_callback_.WaitForResult();
    472 
    473   // SPDY stream has already been removed from the session by Close().
    474   EXPECT_FALSE(session_->IsStreamActive(stream_id_));
    475   websocket_stream_.reset();
    476 
    477   const std::vector<SpdyWebSocketStreamEvent>& events =
    478       delegate.GetSeenEvents();
    479   ASSERT_EQ(5U, events.size());
    480 
    481   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
    482             events[0].event_type);
    483   EXPECT_EQ(OK, events[0].result);
    484   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
    485             events[1].event_type);
    486   EXPECT_EQ(OK, events[1].result);
    487   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
    488             events[2].event_type);
    489   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
    490   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
    491             events[3].event_type);
    492   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
    493   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE, events[4].event_type);
    494 
    495   EXPECT_TRUE(
    496       HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
    497 }
    498 
    499 TEST_P(SpdyWebSocketStreamTest, IOPending) {
    500   Prepare(1);
    501   scoped_ptr<SpdyFrame> settings_frame(
    502       spdy_util_.ConstructSpdySettings(spdy_settings_to_send_));
    503   MockWrite writes[] = {
    504     CreateMockWrite(*request_frame_.get(), 1),
    505     CreateMockWrite(*message_frame_.get(), 3),
    506     CreateMockWrite(*closing_frame_.get(), 5)
    507   };
    508 
    509   MockRead reads[] = {
    510     CreateMockRead(*settings_frame.get(), 0),
    511     CreateMockRead(*response_frame_.get(), 2),
    512     CreateMockRead(*message_frame_.get(), 4),
    513     CreateMockRead(*closing_frame_.get(), 6),
    514     MockRead(SYNCHRONOUS, 0, 7)  // EOF cause OnCloseSpdyStream event.
    515   };
    516 
    517   DeterministicSocketData data(reads, arraysize(reads),
    518                                writes, arraysize(writes));
    519   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
    520   http_session_ =
    521       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
    522 
    523   session_ = CreateInsecureSpdySession(
    524       http_session_, spdy_session_key_, BoundNetLog());
    525 
    526   // Create a dummy WebSocketStream which cause ERR_IO_PENDING to another
    527   // WebSocketStream under test.
    528   SpdyWebSocketStreamEventRecorder block_delegate((CompletionCallback()));
    529 
    530   scoped_ptr<SpdyWebSocketStream> block_stream(
    531       new SpdyWebSocketStream(session_, &block_delegate));
    532   BoundNetLog block_net_log;
    533   GURL block_url("ws://example.com/block");
    534   ASSERT_EQ(OK,
    535             block_stream->InitializeStream(block_url, HIGHEST, block_net_log));
    536 
    537   data.RunFor(1);
    538 
    539   // Create a WebSocketStream under test.
    540   SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
    541   delegate.SetOnCreated(
    542       base::Bind(&SpdyWebSocketStreamTest::DoSync,
    543                  base::Unretained(this)));
    544   delegate.SetOnReceivedHeader(
    545       base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
    546                  base::Unretained(this)));
    547   delegate.SetOnReceivedData(
    548       base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
    549                  base::Unretained(this)));
    550 
    551   websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
    552   BoundNetLog net_log;
    553   GURL url("ws://example.com/echo");
    554   ASSERT_EQ(ERR_IO_PENDING, websocket_stream_->InitializeStream(
    555       url, HIGHEST, net_log));
    556 
    557   // Delete the fist stream to allow create the second stream.
    558   block_stream.reset();
    559   ASSERT_EQ(OK, sync_callback_.WaitForResult());
    560 
    561   SendRequest();
    562 
    563   data.RunFor(7);
    564   completion_callback_.WaitForResult();
    565 
    566   websocket_stream_.reset();
    567 
    568   const std::vector<SpdyWebSocketStreamEvent>& block_events =
    569       block_delegate.GetSeenEvents();
    570   ASSERT_EQ(0U, block_events.size());
    571 
    572   const std::vector<SpdyWebSocketStreamEvent>& events =
    573       delegate.GetSeenEvents();
    574   ASSERT_EQ(8U, events.size());
    575   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CREATED,
    576             events[0].event_type);
    577   EXPECT_EQ(0, events[0].result);
    578   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
    579             events[1].event_type);
    580   EXPECT_EQ(OK, events[1].result);
    581   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
    582             events[2].event_type);
    583   EXPECT_EQ(OK, events[2].result);
    584   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
    585             events[3].event_type);
    586   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
    587   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
    588             events[4].event_type);
    589   EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[4].result);
    590   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
    591             events[5].event_type);
    592   EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
    593   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
    594             events[6].event_type);
    595   EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[6].result);
    596   EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
    597             events[7].event_type);
    598   EXPECT_EQ(OK, events[7].result);
    599 
    600   // EOF close SPDY session.
    601   EXPECT_FALSE(
    602       HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
    603   EXPECT_TRUE(data.at_read_eof());
    604   EXPECT_TRUE(data.at_write_eof());
    605 }
    606 
    607 }  // namespace net
    608