spdy_websocket_stream_unittest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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
22namespace net {
23
24namespace {
25
26struct 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
50class 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
164class 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
287INSTANTIATE_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.
296const char SpdyWebSocketStreamTest::kMessageFrame[] = "\x81\x05hello";
297const char SpdyWebSocketStreamTest::kClosingFrame[] = "\x88\0";
298const size_t SpdyWebSocketStreamTest::kMessageFrameLength =
299    arraysize(SpdyWebSocketStreamTest::kMessageFrame) - 1;
300const size_t SpdyWebSocketStreamTest::kClosingFrameLength =
301    arraysize(SpdyWebSocketStreamTest::kClosingFrame) - 1;
302
303TEST_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
378TEST_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
439TEST_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
499TEST_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