root/net/websockets/websocket_channel_test.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. OnStartOpeningHandshake
  2. OnFinishOpeningHandshake
  3. OnAddChannelResponse
  4. OnDataFrame
  5. OnFlowControl
  6. OnClosingHandshake
  7. OnFailChannel
  8. OnDropChannel
  9. OnStartOpeningHandshake
  10. OnFinishOpeningHandshake
  11. extensions_
  12. ReadFrames
  13. WriteFrames
  14. Close
  15. GetSubProtocol
  16. GetExtensions
  17. CreateFrameVector
  18. ACTION_P
  19. MatchAndExplain
  20. DescribeTo
  21. DescribeNegationTo
  22. EqualsFrames
  23. closure
  24. WaitForResult
  25. ACTION_P
  26. ACTION_P
  27. read_frames_pending_
  28. PrepareReadFrames
  29. PrepareRawReadFrames
  30. PrepareReadFramesError
  31. ReadFrames
  32. DoCallback
  33. WriteFrames
  34. WriteFrames
  35. done_
  36. WriteFrames
  37. ReadFrames
  38. PostCallback
  39. DoCallback
  40. MoveFrames
  41. weak_ptr_factory_
  42. WriteFrames
  43. ReadFrames
  44. Close
  45. CallCallbackUnlessClosed
  46. AsVector
  47. CreateChannelAndConnect
  48. CreateChannelAndConnectSuccessfully
  49. CreateEventInterface
  50. set_stream
  51. DeleteIfDeleting
  52. OnAddChannelResponse
  53. OnDataFrame
  54. OnFlowControl
  55. OnClosingHandshake
  56. OnFailChannel
  57. OnDropChannel
  58. OnStartOpeningHandshake
  59. OnFinishOpeningHandshake
  60. CreateEventInterface
  61. CreateEventInterface
  62. CreateChannelAndConnectSuccessfully
  63. SetUp
  64. CreateChannelAndConnectWithQuota
  65. CreateChannelAndConnectSuccesfully
  66. SetUp
  67. TEST_F
  68. TEST_F
  69. TEST_F
  70. TEST_F
  71. TEST_F
  72. TEST_F
  73. TEST_F
  74. TEST_F
  75. TEST_F
  76. TEST_F
  77. TEST_F
  78. TEST_F
  79. TEST_F
  80. TEST_F
  81. TEST_F
  82. TEST_F
  83. TEST_F
  84. TEST_F
  85. TEST_F
  86. TEST_F
  87. TEST_F
  88. TEST_F
  89. TEST_F
  90. TEST_F
  91. TEST_F
  92. TEST_F
  93. TEST_F
  94. TEST_F
  95. TEST_F
  96. TEST_F
  97. TEST_F
  98. TEST_F
  99. TEST_F
  100. TEST_F
  101. TEST_F
  102. TEST_F
  103. TEST_F
  104. TEST_F
  105. TEST_F
  106. TEST_F
  107. TEST_F
  108. TEST_F
  109. TEST_F
  110. TEST_F
  111. TEST_F
  112. TEST_F
  113. TEST_F
  114. TEST_F
  115. TEST_F
  116. TEST_F
  117. TEST_F
  118. TEST_F
  119. TEST_F
  120. TEST_F
  121. TEST_F
  122. TEST_F
  123. TEST_F
  124. TEST_F
  125. TEST_F
  126. TEST_F
  127. TEST_F
  128. TEST_F
  129. TEST_F
  130. TEST_F
  131. TEST_F
  132. TEST_F
  133. TEST_F
  134. TEST_F
  135. TEST_F
  136. TEST_F
  137. TEST_F
  138. TEST_F
  139. TEST_F
  140. TEST_F
  141. TEST_F
  142. TEST_F
  143. TEST_F
  144. TEST_F
  145. TEST_F
  146. TEST_F
  147. TEST_F
  148. TEST_F
  149. TEST_F
  150. TEST_F
  151. TEST_F
  152. TEST_F
  153. TEST_F
  154. TEST_F
  155. TEST_F
  156. TEST_F
  157. TEST_F
  158. TEST_F
  159. TEST_F
  160. TEST_F
  161. TEST_F
  162. TEST_F
  163. TEST_F
  164. TEST_F
  165. TEST_F
  166. TEST_F
  167. TEST_F
  168. TEST_F
  169. TEST_F
  170. TEST_F
  171. TEST_F
  172. TEST_F
  173. TEST_F
  174. TEST_F
  175. TEST_F
  176. TEST_F
  177. TEST_F
  178. TEST_F
  179. TEST_F
  180. TEST_F
  181. TEST_F
  182. CreateChannelAndConnectSuccessfully
  183. TEST_F
  184. TEST_F
  185. TEST_F

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/websockets/websocket_channel.h"

#include <limits.h>
#include <string.h>

#include <iostream>
#include <string>
#include <vector>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_piece.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request_context.h"
#include "net/websockets/websocket_errors.h"
#include "net/websockets/websocket_event_interface.h"
#include "net/websockets/websocket_handshake_request_info.h"
#include "net/websockets/websocket_handshake_response_info.h"
#include "net/websockets/websocket_mux.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"

// Hacky macros to construct the body of a Close message from a code and a
// string, while ensuring the result is a compile-time constant string.
// Use like CLOSE_DATA(NORMAL_CLOSURE, "Explanation String")
#define CLOSE_DATA(code, string) WEBSOCKET_CLOSE_CODE_AS_STRING_##code string
#define WEBSOCKET_CLOSE_CODE_AS_STRING_NORMAL_CLOSURE "\x03\xe8"
#define WEBSOCKET_CLOSE_CODE_AS_STRING_GOING_AWAY "\x03\xe9"
#define WEBSOCKET_CLOSE_CODE_AS_STRING_PROTOCOL_ERROR "\x03\xea"
#define WEBSOCKET_CLOSE_CODE_AS_STRING_ABNORMAL_CLOSURE "\x03\xee"
#define WEBSOCKET_CLOSE_CODE_AS_STRING_SERVER_ERROR "\x03\xf3"

namespace net {

// Printing helpers to allow GoogleMock to print frames. These are explicitly
// designed to look like the static initialisation format we use in these
// tests. They have to live in the net namespace in order to be found by
// GoogleMock; a nested anonymous namespace will not work.

std::ostream& operator<<(std::ostream& os, const WebSocketFrameHeader& header) {
  return os << (header.final ? "FINAL_FRAME" : "NOT_FINAL_FRAME") << ", "
            << header.opcode << ", "
            << (header.masked ? "MASKED" : "NOT_MASKED");
}

std::ostream& operator<<(std::ostream& os, const WebSocketFrame& frame) {
  os << "{" << frame.header << ", ";
  if (frame.data) {
    return os << "\"" << base::StringPiece(frame.data->data(),
                                           frame.header.payload_length)
              << "\"}";
  }
  return os << "NULL}";
}

std::ostream& operator<<(std::ostream& os,
                         const ScopedVector<WebSocketFrame>& vector) {
  os << "{";
  bool first = true;
  for (ScopedVector<WebSocketFrame>::const_iterator it = vector.begin();
       it != vector.end();
       ++it) {
    if (!first) {
      os << ",\n";
    } else {
      first = false;
    }
    os << **it;
  }
  return os << "}";
}

std::ostream& operator<<(std::ostream& os,
                         const ScopedVector<WebSocketFrame>* vector) {
  return os << '&' << *vector;
}

namespace {

using ::base::TimeDelta;

using ::testing::AnyNumber;
using ::testing::DefaultValue;
using ::testing::InSequence;
using ::testing::MockFunction;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::StrictMock;
using ::testing::_;

// A selection of characters that have traditionally been mangled in some
// environment or other, for testing 8-bit cleanliness.
const char kBinaryBlob[] = {'\n',   '\r',    // BACKWARDS CRNL
                            '\0',            // nul
                            '\x7F',          // DEL
                            '\x80', '\xFF',  // NOT VALID UTF-8
                            '\x1A',          // Control-Z, EOF on DOS
                            '\x03',          // Control-C
                            '\x04',          // EOT, special for Unix terms
                            '\x1B',          // ESC, often special
                            '\b',            // backspace
                            '\'',            // single-quote, special in PHP
};
const size_t kBinaryBlobSize = arraysize(kBinaryBlob);

// The amount of quota a new connection gets by default.
// TODO(ricea): If kDefaultSendQuotaHighWaterMark changes, then this value will
// need to be updated.
const size_t kDefaultInitialQuota = 1 << 17;
// The amount of bytes we need to send after the initial connection to trigger a
// quota refresh. TODO(ricea): Change this if kDefaultSendQuotaHighWaterMark or
// kDefaultSendQuotaLowWaterMark change.
const size_t kDefaultQuotaRefreshTrigger = (1 << 16) + 1;

// TestTimeouts::tiny_timeout() is 100ms! I could run halfway around the world
// in that time! I would like my tests to run a bit quicker.
const int kVeryTinyTimeoutMillis = 1;

// Enough quota to pass any test.
const int64 kPlentyOfQuota = INT_MAX;

typedef WebSocketEventInterface::ChannelState ChannelState;
const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED;

// This typedef mainly exists to avoid having to repeat the "NOLINT" incantation
// all over the place.
typedef StrictMock< MockFunction<void(int)> > Checkpoint;  // NOLINT

// This mock is for testing expectations about how the EventInterface is used.
class MockWebSocketEventInterface : public WebSocketEventInterface {
 public:
  MockWebSocketEventInterface() {}

  MOCK_METHOD3(OnAddChannelResponse,
               ChannelState(bool,
                            const std::string&,
                            const std::string&));  // NOLINT
  MOCK_METHOD3(OnDataFrame,
               ChannelState(bool,
                            WebSocketMessageType,
                            const std::vector<char>&));  // NOLINT
  MOCK_METHOD1(OnFlowControl, ChannelState(int64));  // NOLINT
  MOCK_METHOD0(OnClosingHandshake, ChannelState(void));  // NOLINT
  MOCK_METHOD1(OnFailChannel, ChannelState(const std::string&));  // NOLINT
  MOCK_METHOD3(OnDropChannel,
               ChannelState(bool, uint16, const std::string&));  // NOLINT

  // We can't use GMock with scoped_ptr.
  ChannelState OnStartOpeningHandshake(
      scoped_ptr<WebSocketHandshakeRequestInfo>) OVERRIDE {
    OnStartOpeningHandshakeCalled();
    return CHANNEL_ALIVE;
  }
  ChannelState OnFinishOpeningHandshake(
      scoped_ptr<WebSocketHandshakeResponseInfo>) OVERRIDE {
    OnFinishOpeningHandshakeCalled();
    return CHANNEL_ALIVE;
  }

  MOCK_METHOD0(OnStartOpeningHandshakeCalled, void());  // NOLINT
  MOCK_METHOD0(OnFinishOpeningHandshakeCalled, void());  // NOLINT
};

// This fake EventInterface is for tests which need a WebSocketEventInterface
// implementation but are not verifying how it is used.
class FakeWebSocketEventInterface : public WebSocketEventInterface {
  virtual ChannelState OnAddChannelResponse(
      bool fail,
      const std::string& selected_protocol,
      const std::string& extensions) OVERRIDE {
    return fail ? CHANNEL_DELETED : CHANNEL_ALIVE;
  }
  virtual ChannelState OnDataFrame(bool fin,
                                   WebSocketMessageType type,
                                   const std::vector<char>& data) OVERRIDE {
    return CHANNEL_ALIVE;
  }
  virtual ChannelState OnFlowControl(int64 quota) OVERRIDE {
    return CHANNEL_ALIVE;
  }
  virtual ChannelState OnClosingHandshake() OVERRIDE { return CHANNEL_ALIVE; }
  virtual ChannelState OnFailChannel(const std::string& message) OVERRIDE {
    return CHANNEL_DELETED;
  }
  virtual ChannelState OnDropChannel(bool was_clean,
                                     uint16 code,
                                     const std::string& reason) OVERRIDE {
    return CHANNEL_DELETED;
  }
  virtual ChannelState OnStartOpeningHandshake(
      scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE {
    return CHANNEL_ALIVE;
  }
  virtual ChannelState OnFinishOpeningHandshake(
      scoped_ptr<WebSocketHandshakeResponseInfo> response) OVERRIDE {
    return CHANNEL_ALIVE;
  }
};

// This fake WebSocketStream is for tests that require a WebSocketStream but are
// not testing the way it is used. It has minimal functionality to return
// the |protocol| and |extensions| that it was constructed with.
class FakeWebSocketStream : public WebSocketStream {
 public:
  // Constructs with empty protocol and extensions.
  FakeWebSocketStream() {}

  // Constructs with specified protocol and extensions.
  FakeWebSocketStream(const std::string& protocol,
                      const std::string& extensions)
      : protocol_(protocol), extensions_(extensions) {}

  virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
                         const CompletionCallback& callback) OVERRIDE {
    return ERR_IO_PENDING;
  }

  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
                          const CompletionCallback& callback) OVERRIDE {
    return ERR_IO_PENDING;
  }

  virtual void Close() OVERRIDE {}

  // Returns the string passed to the constructor.
  virtual std::string GetSubProtocol() const OVERRIDE { return protocol_; }

  // Returns the string passed to the constructor.
  virtual std::string GetExtensions() const OVERRIDE { return extensions_; }

 private:
  // The string to return from GetSubProtocol().
  std::string protocol_;

  // The string to return from GetExtensions().
  std::string extensions_;
};

// To make the static initialisers easier to read, we use enums rather than
// bools.
enum IsFinal { NOT_FINAL_FRAME, FINAL_FRAME };

enum IsMasked { NOT_MASKED, MASKED };

// This is used to initialise a WebSocketFrame but is statically initialisable.
struct InitFrame {
  IsFinal final;
  // Reserved fields omitted for now. Add them if you need them.
  WebSocketFrameHeader::OpCode opcode;
  IsMasked masked;

  // Will be used to create the IOBuffer member. Can be NULL for NULL data. Is a
  // nul-terminated string for ease-of-use. |header.payload_length| is
  // initialised from |strlen(data)|. This means it is not 8-bit clean, but this
  // is not an issue for test data.
  const char* const data;
};

// For GoogleMock
std::ostream& operator<<(std::ostream& os, const InitFrame& frame) {
  os << "{" << (frame.final == FINAL_FRAME ? "FINAL_FRAME" : "NOT_FINAL_FRAME")
     << ", " << frame.opcode << ", "
     << (frame.masked == MASKED ? "MASKED" : "NOT_MASKED") << ", ";
  if (frame.data) {
    return os << "\"" << frame.data << "\"}";
  }
  return os << "NULL}";
}

template <size_t N>
std::ostream& operator<<(std::ostream& os, const InitFrame (&frames)[N]) {
  os << "{";
  bool first = true;
  for (size_t i = 0; i < N; ++i) {
    if (!first) {
      os << ",\n";
    } else {
      first = false;
    }
    os << frames[i];
  }
  return os << "}";
}

// Convert a const array of InitFrame structs to the format used at
// runtime. Templated on the size of the array to save typing.
template <size_t N>
ScopedVector<WebSocketFrame> CreateFrameVector(
    const InitFrame (&source_frames)[N]) {
  ScopedVector<WebSocketFrame> result_frames;
  result_frames.reserve(N);
  for (size_t i = 0; i < N; ++i) {
    const InitFrame& source_frame = source_frames[i];
    scoped_ptr<WebSocketFrame> result_frame(
        new WebSocketFrame(source_frame.opcode));
    size_t frame_length = source_frame.data ? strlen(source_frame.data) : 0;
    WebSocketFrameHeader& result_header = result_frame->header;
    result_header.final = (source_frame.final == FINAL_FRAME);
    result_header.masked = (source_frame.masked == MASKED);
    result_header.payload_length = frame_length;
    if (source_frame.data) {
      result_frame->data = new IOBuffer(frame_length);
      memcpy(result_frame->data->data(), source_frame.data, frame_length);
    }
    result_frames.push_back(result_frame.release());
  }
  return result_frames.Pass();
}

// A GoogleMock action which can be used to respond to call to ReadFrames with
// some frames. Use like ReadFrames(_, _).WillOnce(ReturnFrames(&frames));
// |frames| is an array of InitFrame. |frames| needs to be passed by pointer
// because otherwise it will be treated as a pointer and the array size
// information will be lost.
ACTION_P(ReturnFrames, source_frames) {
  *arg0 = CreateFrameVector(*source_frames);
  return OK;
}

// The implementation of a GoogleMock matcher which can be used to compare a
// ScopedVector<WebSocketFrame>* against an expectation defined as an array of
// InitFrame objects. Although it is possible to compose built-in GoogleMock
// matchers to check the contents of a WebSocketFrame, the results are so
// unreadable that it is better to use this matcher.
template <size_t N>
class EqualsFramesMatcher
    : public ::testing::MatcherInterface<ScopedVector<WebSocketFrame>*> {
 public:
  EqualsFramesMatcher(const InitFrame (*expect_frames)[N])
      : expect_frames_(expect_frames) {}

  virtual bool MatchAndExplain(ScopedVector<WebSocketFrame>* actual_frames,
                               ::testing::MatchResultListener* listener) const {
    if (actual_frames->size() != N) {
      *listener << "the vector size is " << actual_frames->size();
      return false;
    }
    for (size_t i = 0; i < N; ++i) {
      const WebSocketFrame& actual_frame = *(*actual_frames)[i];
      const InitFrame& expected_frame = (*expect_frames_)[i];
      if (actual_frame.header.final != (expected_frame.final == FINAL_FRAME)) {
        *listener << "the frame is marked as "
                  << (actual_frame.header.final ? "" : "not ") << "final";
        return false;
      }
      if (actual_frame.header.opcode != expected_frame.opcode) {
        *listener << "the opcode is " << actual_frame.header.opcode;
        return false;
      }
      if (actual_frame.header.masked != (expected_frame.masked == MASKED)) {
        *listener << "the frame is "
                  << (actual_frame.header.masked ? "masked" : "not masked");
        return false;
      }
      const size_t expected_length =
          expected_frame.data ? strlen(expected_frame.data) : 0;
      if (actual_frame.header.payload_length != expected_length) {
        *listener << "the payload length is "
                  << actual_frame.header.payload_length;
        return false;
      }
      if (expected_length != 0 &&
          memcmp(actual_frame.data->data(),
                 expected_frame.data,
                 actual_frame.header.payload_length) != 0) {
        *listener << "the data content differs";
        return false;
      }
    }
    return true;
  }

  virtual void DescribeTo(std::ostream* os) const {
    *os << "matches " << *expect_frames_;
  }

  virtual void DescribeNegationTo(std::ostream* os) const {
    *os << "does not match " << *expect_frames_;
  }

 private:
  const InitFrame (*expect_frames_)[N];
};

// The definition of EqualsFrames GoogleMock matcher. Unlike the ReturnFrames
// action, this can take the array by reference.
template <size_t N>
::testing::Matcher<ScopedVector<WebSocketFrame>*> EqualsFrames(
    const InitFrame (&frames)[N]) {
  return ::testing::MakeMatcher(new EqualsFramesMatcher<N>(&frames));
}

// TestClosure works like TestCompletionCallback, but doesn't take an argument.
class TestClosure {
 public:
  base::Closure closure() { return base::Bind(callback_.callback(), OK); }

  void WaitForResult() { callback_.WaitForResult(); }

 private:
  // Delegate to TestCompletionCallback for the implementation.
  TestCompletionCallback callback_;
};

// A GoogleMock action to run a Closure.
ACTION_P(InvokeClosure, closure) { closure.Run(); }

// A GoogleMock action to run a Closure and return CHANNEL_DELETED.
ACTION_P(InvokeClosureReturnDeleted, closure) {
  closure.Run();
  return WebSocketEventInterface::CHANNEL_DELETED;
}

// A FakeWebSocketStream whose ReadFrames() function returns data.
class ReadableFakeWebSocketStream : public FakeWebSocketStream {
 public:
  enum IsSync { SYNC, ASYNC };

  // After constructing the object, call PrepareReadFrames() once for each
  // time you wish it to return from the test.
  ReadableFakeWebSocketStream() : index_(0), read_frames_pending_(false) {}

  // Check that all the prepared responses have been consumed.
  virtual ~ReadableFakeWebSocketStream() {
    CHECK(index_ >= responses_.size());
    CHECK(!read_frames_pending_);
  }

  // Prepares a fake response. Fake responses will be returned from ReadFrames()
  // in the same order they were prepared with PrepareReadFrames() and
  // PrepareReadFramesError(). If |async| is ASYNC, then ReadFrames() will
  // return ERR_IO_PENDING and the callback will be scheduled to run on the
  // message loop. This requires the test case to run the message loop. If
  // |async| is SYNC, the response will be returned synchronously. |error| is
  // returned directly from ReadFrames() in the synchronous case, or passed to
  // the callback in the asynchronous case. |frames| will be converted to a
  // ScopedVector<WebSocketFrame> and copied to the pointer that was passed to
  // ReadFrames().
  template <size_t N>
  void PrepareReadFrames(IsSync async,
                         int error,
                         const InitFrame (&frames)[N]) {
    responses_.push_back(new Response(async, error, CreateFrameVector(frames)));
  }

  // An alternate version of PrepareReadFrames for when we need to construct
  // the frames manually.
  void PrepareRawReadFrames(IsSync async,
                            int error,
                            ScopedVector<WebSocketFrame> frames) {
    responses_.push_back(new Response(async, error, frames.Pass()));
  }

  // Prepares a fake error response (ie. there is no data).
  void PrepareReadFramesError(IsSync async, int error) {
    responses_.push_back(
        new Response(async, error, ScopedVector<WebSocketFrame>()));
  }

  virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
                         const CompletionCallback& callback) OVERRIDE {
    CHECK(!read_frames_pending_);
    if (index_ >= responses_.size())
      return ERR_IO_PENDING;
    if (responses_[index_]->async == ASYNC) {
      read_frames_pending_ = true;
      base::MessageLoop::current()->PostTask(
          FROM_HERE,
          base::Bind(&ReadableFakeWebSocketStream::DoCallback,
                     base::Unretained(this),
                     frames,
                     callback));
      return ERR_IO_PENDING;
    } else {
      frames->swap(responses_[index_]->frames);
      return responses_[index_++]->error;
    }
  }

 private:
  void DoCallback(ScopedVector<WebSocketFrame>* frames,
                  const CompletionCallback& callback) {
    read_frames_pending_ = false;
    frames->swap(responses_[index_]->frames);
    callback.Run(responses_[index_++]->error);
    return;
  }

  struct Response {
    Response(IsSync async, int error, ScopedVector<WebSocketFrame> frames)
        : async(async), error(error), frames(frames.Pass()) {}

    IsSync async;
    int error;
    ScopedVector<WebSocketFrame> frames;

   private:
    // Bad things will happen if we attempt to copy or assign |frames|.
    DISALLOW_COPY_AND_ASSIGN(Response);
  };
  ScopedVector<Response> responses_;

  // The index into the responses_ array of the next response to be returned.
  size_t index_;

  // True when an async response from ReadFrames() is pending. This only applies
  // to "real" async responses. Once all the prepared responses have been
  // returned, ReadFrames() returns ERR_IO_PENDING but read_frames_pending_ is
  // not set to true.
  bool read_frames_pending_;
};

// A FakeWebSocketStream where writes always complete successfully and
// synchronously.
class WriteableFakeWebSocketStream : public FakeWebSocketStream {
 public:
  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
                          const CompletionCallback& callback) OVERRIDE {
    return OK;
  }
};

// A FakeWebSocketStream where writes always fail.
class UnWriteableFakeWebSocketStream : public FakeWebSocketStream {
 public:
  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
                          const CompletionCallback& callback) OVERRIDE {
    return ERR_CONNECTION_RESET;
  }
};

// A FakeWebSocketStream which echoes any frames written back. Clears the
// "masked" header bit, but makes no other checks for validity. Tests using this
// must run the MessageLoop to receive the callback(s). If a message with opcode
// Close is echoed, then an ERR_CONNECTION_CLOSED is returned in the next
// callback. The test must do something to cause WriteFrames() to be called,
// otherwise the ReadFrames() callback will never be called.
class EchoeyFakeWebSocketStream : public FakeWebSocketStream {
 public:
  EchoeyFakeWebSocketStream() : read_frames_(NULL), done_(false) {}

  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
                          const CompletionCallback& callback) OVERRIDE {
    // Users of WebSocketStream will not expect the ReadFrames() callback to be
    // called from within WriteFrames(), so post it to the message loop instead.
    stored_frames_.insert(stored_frames_.end(), frames->begin(), frames->end());
    frames->weak_clear();
    PostCallback();
    return OK;
  }

  virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
                         const CompletionCallback& callback) OVERRIDE {
    read_callback_ = callback;
    read_frames_ = frames;
    if (done_)
      PostCallback();
    return ERR_IO_PENDING;
  }

 private:
  void PostCallback() {
    base::MessageLoop::current()->PostTask(
        FROM_HERE,
        base::Bind(&EchoeyFakeWebSocketStream::DoCallback,
                   base::Unretained(this)));
  }

  void DoCallback() {
    if (done_) {
      read_callback_.Run(ERR_CONNECTION_CLOSED);
    } else if (!stored_frames_.empty()) {
      done_ = MoveFrames(read_frames_);
      read_frames_ = NULL;
      read_callback_.Run(OK);
    }
  }

  // Copy the frames stored in stored_frames_ to |out|, while clearing the
  // "masked" header bit. Returns true if a Close Frame was seen, false
  // otherwise.
  bool MoveFrames(ScopedVector<WebSocketFrame>* out) {
    bool seen_close = false;
    *out = stored_frames_.Pass();
    for (ScopedVector<WebSocketFrame>::iterator it = out->begin();
         it != out->end();
         ++it) {
      WebSocketFrameHeader& header = (*it)->header;
      header.masked = false;
      if (header.opcode == WebSocketFrameHeader::kOpCodeClose)
        seen_close = true;
    }
    return seen_close;
  }

  ScopedVector<WebSocketFrame> stored_frames_;
  CompletionCallback read_callback_;
  // Owned by the caller of ReadFrames().
  ScopedVector<WebSocketFrame>* read_frames_;
  // True if we should close the connection.
  bool done_;
};

// A FakeWebSocketStream where writes trigger a connection reset.
// This differs from UnWriteableFakeWebSocketStream in that it is asynchronous
// and triggers ReadFrames to return a reset as well. Tests using this need to
// run the message loop. There are two tricky parts here:
// 1. Calling the write callback may call Close(), after which the read callback
//    should not be called.
// 2. Calling either callback may delete the stream altogether.
class ResetOnWriteFakeWebSocketStream : public FakeWebSocketStream {
 public:
  ResetOnWriteFakeWebSocketStream() : closed_(false), weak_ptr_factory_(this) {}

  virtual int WriteFrames(ScopedVector<WebSocketFrame>* frames,
                          const CompletionCallback& callback) OVERRIDE {
    base::MessageLoop::current()->PostTask(
        FROM_HERE,
        base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
                   weak_ptr_factory_.GetWeakPtr(),
                   callback,
                   ERR_CONNECTION_RESET));
    base::MessageLoop::current()->PostTask(
        FROM_HERE,
        base::Bind(&ResetOnWriteFakeWebSocketStream::CallCallbackUnlessClosed,
                   weak_ptr_factory_.GetWeakPtr(),
                   read_callback_,
                   ERR_CONNECTION_RESET));
    return ERR_IO_PENDING;
  }

  virtual int ReadFrames(ScopedVector<WebSocketFrame>* frames,
                         const CompletionCallback& callback) OVERRIDE {
    read_callback_ = callback;
    return ERR_IO_PENDING;
  }

  virtual void Close() OVERRIDE { closed_ = true; }

 private:
  void CallCallbackUnlessClosed(const CompletionCallback& callback, int value) {
    if (!closed_)
      callback.Run(value);
  }

  CompletionCallback read_callback_;
  bool closed_;
  // An IO error can result in the socket being deleted, so we use weak pointers
  // to ensure correct behaviour in that case.
  base::WeakPtrFactory<ResetOnWriteFakeWebSocketStream> weak_ptr_factory_;
};

// This mock is for verifying that WebSocket protocol semantics are obeyed (to
// the extent that they are implemented in WebSocketCommon).
class MockWebSocketStream : public WebSocketStream {
 public:
  MOCK_METHOD2(ReadFrames,
               int(ScopedVector<WebSocketFrame>* frames,
                   const CompletionCallback& callback));
  MOCK_METHOD2(WriteFrames,
               int(ScopedVector<WebSocketFrame>* frames,
                   const CompletionCallback& callback));
  MOCK_METHOD0(Close, void());
  MOCK_CONST_METHOD0(GetSubProtocol, std::string());
  MOCK_CONST_METHOD0(GetExtensions, std::string());
  MOCK_METHOD0(AsWebSocketStream, WebSocketStream*());
};

struct ArgumentCopyingWebSocketStreamCreator {
  scoped_ptr<WebSocketStreamRequest> Create(
      const GURL& socket_url,
      const std::vector<std::string>& requested_subprotocols,
      const url::Origin& origin,
      URLRequestContext* url_request_context,
      const BoundNetLog& net_log,
      scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate) {
    this->socket_url = socket_url;
    this->requested_subprotocols = requested_subprotocols;
    this->origin = origin;
    this->url_request_context = url_request_context;
    this->net_log = net_log;
    this->connect_delegate = connect_delegate.Pass();
    return make_scoped_ptr(new WebSocketStreamRequest);
  }

  GURL socket_url;
  url::Origin origin;
  std::vector<std::string> requested_subprotocols;
  URLRequestContext* url_request_context;
  BoundNetLog net_log;
  scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate;
};

// Converts a std::string to a std::vector<char>. For test purposes, it is
// convenient to be able to specify data as a string, but the
// WebSocketEventInterface requires the vector<char> type.
std::vector<char> AsVector(const std::string& s) {
  return std::vector<char>(s.begin(), s.end());
}

// Base class for all test fixtures.
class WebSocketChannelTest : public ::testing::Test {
 protected:
  WebSocketChannelTest() : stream_(new FakeWebSocketStream) {}

  // Creates a new WebSocketChannel and connects it, using the settings stored
  // in |connect_data_|.
  void CreateChannelAndConnect() {
    channel_.reset(new WebSocketChannel(CreateEventInterface(),
                                        &connect_data_.url_request_context));
    channel_->SendAddChannelRequestForTesting(
        connect_data_.socket_url,
        connect_data_.requested_subprotocols,
        connect_data_.origin,
        base::Bind(&ArgumentCopyingWebSocketStreamCreator::Create,
                   base::Unretained(&connect_data_.creator)));
  }

  // Same as CreateChannelAndConnect(), but calls the on_success callback as
  // well. This method is virtual so that subclasses can also set the stream.
  virtual void CreateChannelAndConnectSuccessfully() {
    CreateChannelAndConnect();
    // Most tests aren't concerned with flow control from the renderer, so allow
    // MAX_INT quota units.
    channel_->SendFlowControl(kPlentyOfQuota);
    connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
  }

  // Returns a WebSocketEventInterface to be passed to the WebSocketChannel.
  // This implementation returns a newly-created fake. Subclasses may return a
  // mock instead.
  virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() {
    return scoped_ptr<WebSocketEventInterface>(new FakeWebSocketEventInterface);
  }

  // This method serves no other purpose than to provide a nice syntax for
  // assigning to stream_. class T must be a subclass of WebSocketStream or you
  // will have unpleasant compile errors.
  template <class T>
  void set_stream(scoped_ptr<T> stream) {
    // Since the definition of "PassAs" depends on the type T, the C++ standard
    // requires the "template" keyword to indicate that "PassAs" should be
    // parsed as a template method.
    stream_ = stream.template PassAs<WebSocketStream>();
  }

  // A struct containing the data that will be used to connect the channel.
  // Grouped for readability.
  struct ConnectData {
    ConnectData() : socket_url("ws://ws/"), origin("http://ws") {}

    // URLRequestContext object.
    URLRequestContext url_request_context;

    // URL to (pretend to) connect to.
    GURL socket_url;
    // Requested protocols for the request.
    std::vector<std::string> requested_subprotocols;
    // Origin of the request
    url::Origin origin;

    // A fake WebSocketStreamCreator that just records its arguments.
    ArgumentCopyingWebSocketStreamCreator creator;
  };
  ConnectData connect_data_;

  // The channel we are testing. Not initialised until SetChannel() is called.
  scoped_ptr<WebSocketChannel> channel_;

  // A mock or fake stream for tests that need one.
  scoped_ptr<WebSocketStream> stream_;
};

// enum of WebSocketEventInterface calls. These are intended to be or'd together
// in order to instruct WebSocketChannelDeletingTest when it should fail.
enum EventInterfaceCall {
  EVENT_ON_ADD_CHANNEL_RESPONSE = 0x1,
  EVENT_ON_DATA_FRAME = 0x2,
  EVENT_ON_FLOW_CONTROL = 0x4,
  EVENT_ON_CLOSING_HANDSHAKE = 0x8,
  EVENT_ON_FAIL_CHANNEL = 0x10,
  EVENT_ON_DROP_CHANNEL = 0x20,
  EVENT_ON_START_OPENING_HANDSHAKE = 0x40,
  EVENT_ON_FINISH_OPENING_HANDSHAKE = 0x80,
};

class WebSocketChannelDeletingTest : public WebSocketChannelTest {
 public:
  ChannelState DeleteIfDeleting(EventInterfaceCall call) {
    if (deleting_ & call) {
      channel_.reset();
      return CHANNEL_DELETED;
    } else {
      return CHANNEL_ALIVE;
    }
  }

 protected:
  WebSocketChannelDeletingTest()
      : deleting_(EVENT_ON_ADD_CHANNEL_RESPONSE | EVENT_ON_DATA_FRAME |
                  EVENT_ON_FLOW_CONTROL |
                  EVENT_ON_CLOSING_HANDSHAKE |
                  EVENT_ON_FAIL_CHANNEL |
                  EVENT_ON_DROP_CHANNEL |
                  EVENT_ON_START_OPENING_HANDSHAKE |
                  EVENT_ON_FINISH_OPENING_HANDSHAKE) {}
  // Create a ChannelDeletingFakeWebSocketEventInterface. Defined out-of-line to
  // avoid circular dependency.
  virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() OVERRIDE;

  // Tests can set deleting_ to a bitmap of EventInterfaceCall members that they
  // want to cause Channel deletion. The default is for all calls to cause
  // deletion.
  int deleting_;
};

// A FakeWebSocketEventInterface that deletes the WebSocketChannel on failure to
// connect.
class ChannelDeletingFakeWebSocketEventInterface
    : public FakeWebSocketEventInterface {
 public:
  ChannelDeletingFakeWebSocketEventInterface(
      WebSocketChannelDeletingTest* fixture)
      : fixture_(fixture) {}

  virtual ChannelState OnAddChannelResponse(
      bool fail,
      const std::string& selected_protocol,
      const std::string& extensions) OVERRIDE {
    return fixture_->DeleteIfDeleting(EVENT_ON_ADD_CHANNEL_RESPONSE);
  }

  virtual ChannelState OnDataFrame(bool fin,
                                   WebSocketMessageType type,
                                   const std::vector<char>& data) OVERRIDE {
    return fixture_->DeleteIfDeleting(EVENT_ON_DATA_FRAME);
  }

  virtual ChannelState OnFlowControl(int64 quota) OVERRIDE {
    return fixture_->DeleteIfDeleting(EVENT_ON_FLOW_CONTROL);
  }

  virtual ChannelState OnClosingHandshake() OVERRIDE {
    return fixture_->DeleteIfDeleting(EVENT_ON_CLOSING_HANDSHAKE);
  }

  virtual ChannelState OnFailChannel(const std::string& message) OVERRIDE {
    return fixture_->DeleteIfDeleting(EVENT_ON_FAIL_CHANNEL);
  }

  virtual ChannelState OnDropChannel(bool was_clean,
                                     uint16 code,
                                     const std::string& reason) OVERRIDE {
    return fixture_->DeleteIfDeleting(EVENT_ON_DROP_CHANNEL);
  }

  virtual ChannelState OnStartOpeningHandshake(
      scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE {
    return fixture_->DeleteIfDeleting(EVENT_ON_START_OPENING_HANDSHAKE);
  }
  virtual ChannelState OnFinishOpeningHandshake(
      scoped_ptr<WebSocketHandshakeResponseInfo> response) OVERRIDE {
    return fixture_->DeleteIfDeleting(EVENT_ON_FINISH_OPENING_HANDSHAKE);
  }

 private:
  // A pointer to the test fixture. Owned by the test harness; this object will
  // be deleted before it is.
  WebSocketChannelDeletingTest* fixture_;
};

scoped_ptr<WebSocketEventInterface>
WebSocketChannelDeletingTest::CreateEventInterface() {
  return scoped_ptr<WebSocketEventInterface>(
      new ChannelDeletingFakeWebSocketEventInterface(this));
}

// Base class for tests which verify that EventInterface methods are called
// appropriately.
class WebSocketChannelEventInterfaceTest : public WebSocketChannelTest {
 protected:
  WebSocketChannelEventInterfaceTest()
      : event_interface_(new StrictMock<MockWebSocketEventInterface>) {
    DefaultValue<ChannelState>::Set(CHANNEL_ALIVE);
    ON_CALL(*event_interface_, OnAddChannelResponse(true, _, _))
        .WillByDefault(Return(CHANNEL_DELETED));
    ON_CALL(*event_interface_, OnDropChannel(_, _, _))
        .WillByDefault(Return(CHANNEL_DELETED));
    ON_CALL(*event_interface_, OnFailChannel(_))
        .WillByDefault(Return(CHANNEL_DELETED));
  }

  virtual ~WebSocketChannelEventInterfaceTest() {
    DefaultValue<ChannelState>::Clear();
  }

  // Tests using this fixture must set expectations on the event_interface_ mock
  // object before calling CreateChannelAndConnect() or
  // CreateChannelAndConnectSuccessfully(). This will only work once per test
  // case, but once should be enough.
  virtual scoped_ptr<WebSocketEventInterface> CreateEventInterface() OVERRIDE {
    return scoped_ptr<WebSocketEventInterface>(event_interface_.release());
  }

  scoped_ptr<MockWebSocketEventInterface> event_interface_;
};

// Base class for tests which verify that WebSocketStream methods are called
// appropriately by using a MockWebSocketStream.
class WebSocketChannelStreamTest : public WebSocketChannelTest {
 protected:
  WebSocketChannelStreamTest()
      : mock_stream_(new StrictMock<MockWebSocketStream>) {}

  virtual void CreateChannelAndConnectSuccessfully() OVERRIDE {
    set_stream(mock_stream_.Pass());
    WebSocketChannelTest::CreateChannelAndConnectSuccessfully();
  }

  scoped_ptr<MockWebSocketStream> mock_stream_;
};

// Fixture for tests which test UTF-8 validation of sent Text frames via the
// EventInterface.
class WebSocketChannelSendUtf8Test
    : public WebSocketChannelEventInterfaceTest {
 public:
  virtual void SetUp() {
    set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
    // For the purpose of the tests using this fixture, it doesn't matter
    // whether these methods are called or not.
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(_, _, _))
        .Times(AnyNumber());
    EXPECT_CALL(*event_interface_, OnFlowControl(_))
        .Times(AnyNumber());
  }
};

// Fixture for tests which test use of receive quota from the renderer.
class WebSocketChannelFlowControlTest
    : public WebSocketChannelEventInterfaceTest {
 protected:
  // Tests using this fixture should use CreateChannelAndConnectWithQuota()
  // instead of CreateChannelAndConnectSuccessfully().
  void CreateChannelAndConnectWithQuota(int64 quota) {
    CreateChannelAndConnect();
    channel_->SendFlowControl(quota);
    connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
  }

  virtual void CreateChannelAndConnectSuccesfully() { NOTREACHED(); }
};

// Fixture for tests which test UTF-8 validation of received Text frames using a
// mock WebSocketStream.
class WebSocketChannelReceiveUtf8Test : public WebSocketChannelStreamTest {
 public:
  virtual void SetUp() {
    // For the purpose of the tests using this fixture, it doesn't matter
    // whether these methods are called or not.
    EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
    EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  }
};

// Simple test that everything that should be passed to the creator function is
// passed to the creator function.
TEST_F(WebSocketChannelTest, EverythingIsPassedToTheCreatorFunction) {
  connect_data_.socket_url = GURL("ws://example.com/test");
  connect_data_.origin = url::Origin("http://example.com");
  connect_data_.requested_subprotocols.push_back("Sinbad");

  CreateChannelAndConnect();

  const ArgumentCopyingWebSocketStreamCreator& actual = connect_data_.creator;

  EXPECT_EQ(&connect_data_.url_request_context, actual.url_request_context);

  EXPECT_EQ(connect_data_.socket_url, actual.socket_url);
  EXPECT_EQ(connect_data_.requested_subprotocols,
            actual.requested_subprotocols);
  EXPECT_EQ(connect_data_.origin.string(), actual.origin.string());
}

// Verify that calling SendFlowControl before the connection is established does
// not cause a crash.
TEST_F(WebSocketChannelTest, SendFlowControlDuringHandshakeOkay) {
  CreateChannelAndConnect();
  ASSERT_TRUE(channel_);
  channel_->SendFlowControl(65536);
}

// Any WebSocketEventInterface methods can delete the WebSocketChannel and
// return CHANNEL_DELETED. The WebSocketChannelDeletingTests are intended to
// verify that there are no use-after-free bugs when this happens. Problems will
// probably only be found when running under Address Sanitizer or a similar
// tool.
TEST_F(WebSocketChannelDeletingTest, OnAddChannelResponseFail) {
  CreateChannelAndConnect();
  EXPECT_TRUE(channel_);
  connect_data_.creator.connect_delegate->OnFailure("bye");
  EXPECT_EQ(NULL, channel_.get());
}

// Deletion is possible (due to IPC failure) even if the connect succeeds.
TEST_F(WebSocketChannelDeletingTest, OnAddChannelResponseSuccess) {
  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnDataFrameSync) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_DATA_FRAME;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnDataFrameAsync) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_DATA_FRAME;

  CreateChannelAndConnectSuccessfully();
  EXPECT_TRUE(channel_);
  base::MessageLoop::current()->RunUntilIdle();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnFlowControlAfterConnect) {
  deleting_ = EVENT_ON_FLOW_CONTROL;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnFlowControlAfterSend) {
  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
  // Avoid deleting the channel yet.
  deleting_ = EVENT_ON_FAIL_CHANNEL | EVENT_ON_DROP_CHANNEL;
  CreateChannelAndConnectSuccessfully();
  ASSERT_TRUE(channel_);
  deleting_ = EVENT_ON_FLOW_CONTROL;
  channel_->SendFrame(true,
                      WebSocketFrameHeader::kOpCodeText,
                      std::vector<char>(kDefaultInitialQuota, 'B'));
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnClosingHandshakeSync) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_CLOSING_HANDSHAKE;
  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnClosingHandshakeAsync) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_CLOSING_HANDSHAKE;
  CreateChannelAndConnectSuccessfully();
  ASSERT_TRUE(channel_);
  base::MessageLoop::current()->RunUntilIdle();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnDropChannelWriteError) {
  set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
  deleting_ = EVENT_ON_DROP_CHANNEL;
  CreateChannelAndConnectSuccessfully();
  ASSERT_TRUE(channel_);
  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeText, AsVector("this will fail"));
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnDropChannelReadError) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
                                 ERR_FAILED);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_DROP_CHANNEL;
  CreateChannelAndConnectSuccessfully();
  ASSERT_TRUE(channel_);
  base::MessageLoop::current()->RunUntilIdle();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnNotifyStartOpeningHandshakeError) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_START_OPENING_HANDSHAKE;

  CreateChannelAndConnectSuccessfully();
  ASSERT_TRUE(channel_);
  channel_->OnStartOpeningHandshake(scoped_ptr<WebSocketHandshakeRequestInfo>(
      new WebSocketHandshakeRequestInfo(GURL("http://www.example.com/"),
                                        base::Time())));
  base::MessageLoop::current()->RunUntilIdle();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, OnNotifyFinishOpeningHandshakeError) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FINISH_OPENING_HANDSHAKE;

  CreateChannelAndConnectSuccessfully();
  ASSERT_TRUE(channel_);
  scoped_refptr<HttpResponseHeaders> response_headers(
      new HttpResponseHeaders(""));
  channel_->OnFinishOpeningHandshake(scoped_ptr<WebSocketHandshakeResponseInfo>(
      new WebSocketHandshakeResponseInfo(GURL("http://www.example.com/"),
                                         200,
                                         "OK",
                                         response_headers,
                                         base::Time())));
  base::MessageLoop::current()->RunUntilIdle();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, FailChannelInSendFrame) {
  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
  deleting_ = EVENT_ON_FAIL_CHANNEL;
  CreateChannelAndConnectSuccessfully();
  ASSERT_TRUE(channel_);
  channel_->SendFrame(true,
                      WebSocketFrameHeader::kOpCodeText,
                      std::vector<char>(kDefaultInitialQuota * 2, 'T'));
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, FailChannelInOnReadDone) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
                                 ERR_WS_PROTOCOL_ERROR);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FAIL_CHANNEL;
  CreateChannelAndConnectSuccessfully();
  ASSERT_TRUE(channel_);
  base::MessageLoop::current()->RunUntilIdle();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, FailChannelDueToMaskedFrame) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FAIL_CHANNEL;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, FailChannelDueToBadControlFrame) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, 0xF, NOT_MASKED, ""}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FAIL_CHANNEL;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

// Version of above test with NULL data.
TEST_F(WebSocketChannelDeletingTest, FailChannelDueToBadControlFrameNull) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, 0xF, NOT_MASKED, NULL}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FAIL_CHANNEL;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, FailChannelDueToPongAfterClose) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED,
       CLOSE_DATA(NORMAL_CLOSURE, "Success")},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, ""}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FAIL_CHANNEL;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, FailChannelDueToPongAfterCloseNull) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED,
       CLOSE_DATA(NORMAL_CLOSURE, "Success")},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, NULL}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FAIL_CHANNEL;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, FailChannelDueToUnknownOpCode) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {{FINAL_FRAME, 0x7, NOT_MASKED, ""}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FAIL_CHANNEL;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, FailChannelDueToUnknownOpCodeNull) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {{FINAL_FRAME, 0x7, NOT_MASKED, NULL}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FAIL_CHANNEL;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelDeletingTest, FailChannelDueInvalidCloseReason) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "\xFF")}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  deleting_ = EVENT_ON_FAIL_CHANNEL;

  CreateChannelAndConnectSuccessfully();
  EXPECT_EQ(NULL, channel_.get());
}

TEST_F(WebSocketChannelEventInterfaceTest, ConnectSuccessReported) {
  // false means success.
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, "", ""));
  // OnFlowControl is always called immediately after connect to provide initial
  // quota to the renderer.
  EXPECT_CALL(*event_interface_, OnFlowControl(_));

  CreateChannelAndConnect();

  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
}

TEST_F(WebSocketChannelEventInterfaceTest, ConnectFailureReported) {
  EXPECT_CALL(*event_interface_, OnFailChannel("hello"));

  CreateChannelAndConnect();

  connect_data_.creator.connect_delegate->OnFailure("hello");
}

TEST_F(WebSocketChannelEventInterfaceTest, NonWebSocketSchemeRejected) {
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(true, "", ""));
  connect_data_.socket_url = GURL("http://www.google.com/");
  CreateChannelAndConnect();
}

TEST_F(WebSocketChannelEventInterfaceTest, ProtocolPassed) {
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, "Bob", ""));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));

  CreateChannelAndConnect();

  connect_data_.creator.connect_delegate->OnSuccess(
      scoped_ptr<WebSocketStream>(new FakeWebSocketStream("Bob", "")));
}

TEST_F(WebSocketChannelEventInterfaceTest, ExtensionsPassed) {
  EXPECT_CALL(*event_interface_,
              OnAddChannelResponse(false, "", "extension1, extension2"));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));

  CreateChannelAndConnect();

  connect_data_.creator.connect_delegate->OnSuccess(scoped_ptr<WebSocketStream>(
      new FakeWebSocketStream("", "extension1, extension2")));
}

// The first frames from the server can arrive together with the handshake, in
// which case they will be available as soon as ReadFrames() is called the first
// time.
TEST_F(WebSocketChannelEventInterfaceTest, DataLeftFromHandshake) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
  }

  CreateChannelAndConnectSuccessfully();
}

// A remote server could accept the handshake, but then immediately send a
// Close frame.
TEST_F(WebSocketChannelEventInterfaceTest, CloseAfterHandshake) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(SERVER_ERROR, "Internal Server Error")}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
                                 ERR_CONNECTION_CLOSED);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_, OnClosingHandshake());
    EXPECT_CALL(
        *event_interface_,
        OnDropChannel(
            true, kWebSocketErrorInternalServerError, "Internal Server Error"));
  }

  CreateChannelAndConnectSuccessfully();
}

// A remote server could close the connection immediately after sending the
// handshake response (most likely a bug in the server).
TEST_F(WebSocketChannelEventInterfaceTest, ConnectionCloseAfterHandshake) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
                                 ERR_CONNECTION_CLOSED);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_,
                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _));
  }

  CreateChannelAndConnectSuccessfully();
}

TEST_F(WebSocketChannelEventInterfaceTest, NormalAsyncRead) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
  // We use this checkpoint object to verify that the callback isn't called
  // until we expect it to be.
  Checkpoint checkpoint;
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
    EXPECT_CALL(checkpoint, Call(2));
  }

  CreateChannelAndConnectSuccessfully();
  checkpoint.Call(1);
  base::MessageLoop::current()->RunUntilIdle();
  checkpoint.Call(2);
}

// Extra data can arrive while a read is being processed, resulting in the next
// read completing synchronously.
TEST_F(WebSocketChannelEventInterfaceTest, AsyncThenSyncRead) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames1[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "HELLO"}};
  static const InitFrame frames2[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "WORLD"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames1);
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames2);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            true, WebSocketFrameHeader::kOpCodeText, AsVector("HELLO")));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            true, WebSocketFrameHeader::kOpCodeText, AsVector("WORLD")));
  }

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// Data frames are delivered the same regardless of how many reads they arrive
// as.
TEST_F(WebSocketChannelEventInterfaceTest, FragmentedMessage) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  // Here we have one message which arrived in five frames split across three
  // reads. It may have been reframed on arrival, but this class doesn't care
  // about that.
  static const InitFrame frames1[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "THREE"},
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,      " "}};
  static const InitFrame frames2[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,      "SMALL"}};
  static const InitFrame frames3[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,      " "},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,  "FRAMES"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames1);
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames2);
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames3);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            false, WebSocketFrameHeader::kOpCodeText, AsVector("THREE")));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(false,
                            WebSocketFrameHeader::kOpCodeContinuation,
                            AsVector("SMALL")));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            false, WebSocketFrameHeader::kOpCodeContinuation, AsVector(" ")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(true,
                            WebSocketFrameHeader::kOpCodeContinuation,
                            AsVector("FRAMES")));
  }

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// A message can consist of one frame with NULL payload.
TEST_F(WebSocketChannelEventInterfaceTest, NullMessage) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, NULL}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  EXPECT_CALL(
      *event_interface_,
      OnDataFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("")));
  CreateChannelAndConnectSuccessfully();
}

// Connection closed by the remote host without a closing handshake.
TEST_F(WebSocketChannelEventInterfaceTest, AsyncAbnormalClosure) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
                                 ERR_CONNECTION_CLOSED);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_,
                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _));
  }

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// A connection reset should produce the same event as an unexpected closure.
TEST_F(WebSocketChannelEventInterfaceTest, ConnectionReset) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
                                 ERR_CONNECTION_RESET);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_,
                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _));
  }

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// RFC6455 5.1 "A client MUST close a connection if it detects a masked frame."
TEST_F(WebSocketChannelEventInterfaceTest, MaskedFramesAreRejected) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"}};

  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(
        *event_interface_,
        OnFailChannel(
            "A server must not mask any frames that it sends to the client."));
  }

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// RFC6455 5.2 "If an unknown opcode is received, the receiving endpoint MUST
// _Fail the WebSocket Connection_."
TEST_F(WebSocketChannelEventInterfaceTest, UnknownOpCodeIsRejected) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {{FINAL_FRAME, 4, NOT_MASKED, "HELLO"}};

  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_,
                OnFailChannel("Unrecognized frame opcode: 4"));
  }

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// RFC6455 5.4 "Control frames ... MAY be injected in the middle of a
// fragmented message."
TEST_F(WebSocketChannelEventInterfaceTest, ControlFrameInDataMessage) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  // We have one message of type Text split into two frames. In the middle is a
  // control message of type Pong.
  static const InitFrame frames1[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
       NOT_MASKED,      "SPLIT "}};
  static const InitFrame frames2[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, ""}};
  static const InitFrame frames3[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,  "MESSAGE"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames1);
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames2);
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames3);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            false, WebSocketFrameHeader::kOpCodeText, AsVector("SPLIT ")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(true,
                            WebSocketFrameHeader::kOpCodeContinuation,
                            AsVector("MESSAGE")));
  }

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// It seems redundant to repeat the entirety of the above test, so just test a
// Pong with NULL data.
TEST_F(WebSocketChannelEventInterfaceTest, PongWithNullData) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, NOT_MASKED, NULL}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// If a frame has an invalid header, then the connection is closed and
// subsequent frames must not trigger events.
TEST_F(WebSocketChannelEventInterfaceTest, FrameAfterInvalidFrame) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "HELLO"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, " WORLD"}};

  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(
        *event_interface_,
        OnFailChannel(
            "A server must not mask any frames that it sends to the client."));
  }

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// If the renderer sends lots of small writes, we don't want to update the quota
// for each one.
TEST_F(WebSocketChannelEventInterfaceTest, SmallWriteDoesntUpdateQuota) {
  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
  }

  CreateChannelAndConnectSuccessfully();
  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("B"));
}

// If we send enough to go below send_quota_low_water_mask_ we should get our
// quota refreshed.
TEST_F(WebSocketChannelEventInterfaceTest, LargeWriteUpdatesQuota) {
  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
  // We use this checkpoint object to verify that the quota update comes after
  // the write.
  Checkpoint checkpoint;
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(checkpoint, Call(2));
  }

  CreateChannelAndConnectSuccessfully();
  checkpoint.Call(1);
  channel_->SendFrame(true,
                      WebSocketFrameHeader::kOpCodeText,
                      std::vector<char>(kDefaultInitialQuota, 'B'));
  checkpoint.Call(2);
}

// Verify that our quota actually is refreshed when we are told it is.
TEST_F(WebSocketChannelEventInterfaceTest, QuotaReallyIsRefreshed) {
  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
  Checkpoint checkpoint;
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(checkpoint, Call(2));
    // If quota was not really refreshed, we would get an OnDropChannel()
    // message.
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(checkpoint, Call(3));
  }

  CreateChannelAndConnectSuccessfully();
  checkpoint.Call(1);
  channel_->SendFrame(true,
                      WebSocketFrameHeader::kOpCodeText,
                      std::vector<char>(kDefaultQuotaRefreshTrigger, 'D'));
  checkpoint.Call(2);
  // We should have received more quota at this point.
  channel_->SendFrame(true,
                      WebSocketFrameHeader::kOpCodeText,
                      std::vector<char>(kDefaultQuotaRefreshTrigger, 'E'));
  checkpoint.Call(3);
}

// If we send more than the available quota then the connection will be closed
// with an error.
TEST_F(WebSocketChannelEventInterfaceTest, WriteOverQuotaIsRejected) {
  set_stream(make_scoped_ptr(new WriteableFakeWebSocketStream));
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
    EXPECT_CALL(*event_interface_, OnFailChannel("Send quota exceeded"));
  }

  CreateChannelAndConnectSuccessfully();
  channel_->SendFrame(true,
                      WebSocketFrameHeader::kOpCodeText,
                      std::vector<char>(kDefaultInitialQuota + 1, 'C'));
}

// If a write fails, the channel is dropped.
TEST_F(WebSocketChannelEventInterfaceTest, FailedWrite) {
  set_stream(make_scoped_ptr(new UnWriteableFakeWebSocketStream));
  Checkpoint checkpoint;
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*event_interface_,
                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _));
    EXPECT_CALL(checkpoint, Call(2));
  }

  CreateChannelAndConnectSuccessfully();
  checkpoint.Call(1);

  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("H"));
  checkpoint.Call(2);
}

// OnDropChannel() is called exactly once when StartClosingHandshake() is used.
TEST_F(WebSocketChannelEventInterfaceTest, SendCloseDropsChannel) {
  set_stream(make_scoped_ptr(new EchoeyFakeWebSocketStream));
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_,
                OnDropChannel(true, kWebSocketNormalClosure, "Fred"));
  }

  CreateChannelAndConnectSuccessfully();

  channel_->StartClosingHandshake(kWebSocketNormalClosure, "Fred");
  base::MessageLoop::current()->RunUntilIdle();
}

// StartClosingHandshake() also works before connection completes, and calls
// OnDropChannel.
TEST_F(WebSocketChannelEventInterfaceTest, CloseDuringConnection) {
  EXPECT_CALL(*event_interface_,
              OnDropChannel(false, kWebSocketErrorAbnormalClosure, ""));

  CreateChannelAndConnect();
  channel_->StartClosingHandshake(kWebSocketNormalClosure, "Joe");
}

// OnDropChannel() is only called once when a write() on the socket triggers a
// connection reset.
TEST_F(WebSocketChannelEventInterfaceTest, OnDropChannelCalledOnce) {
  set_stream(make_scoped_ptr(new ResetOnWriteFakeWebSocketStream));
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));

  EXPECT_CALL(*event_interface_,
              OnDropChannel(false, kWebSocketErrorAbnormalClosure, ""))
      .Times(1);

  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("yt?"));
  base::MessageLoop::current()->RunUntilIdle();
}

// When the remote server sends a Close frame with an empty payload,
// WebSocketChannel should report code 1005, kWebSocketErrorNoStatusReceived.
TEST_F(WebSocketChannelEventInterfaceTest, CloseWithNoPayloadGivesStatus1005) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, ""}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
                                 ERR_CONNECTION_CLOSED);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  EXPECT_CALL(*event_interface_, OnClosingHandshake());
  EXPECT_CALL(*event_interface_,
              OnDropChannel(true, kWebSocketErrorNoStatusReceived, _));

  CreateChannelAndConnectSuccessfully();
}

// A version of the above test with NULL payload.
TEST_F(WebSocketChannelEventInterfaceTest,
       CloseWithNullPayloadGivesStatus1005) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, NULL}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
                                 ERR_CONNECTION_CLOSED);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  EXPECT_CALL(*event_interface_, OnClosingHandshake());
  EXPECT_CALL(*event_interface_,
              OnDropChannel(true, kWebSocketErrorNoStatusReceived, _));

  CreateChannelAndConnectSuccessfully();
}

// If ReadFrames() returns ERR_WS_PROTOCOL_ERROR, then the connection must be
// failed.
TEST_F(WebSocketChannelEventInterfaceTest, SyncProtocolErrorGivesStatus1002) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
                                 ERR_WS_PROTOCOL_ERROR);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));

  EXPECT_CALL(*event_interface_, OnFailChannel("Invalid frame header"));

  CreateChannelAndConnectSuccessfully();
}

// Async version of above test.
TEST_F(WebSocketChannelEventInterfaceTest, AsyncProtocolErrorGivesStatus1002) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::ASYNC,
                                 ERR_WS_PROTOCOL_ERROR);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));

  EXPECT_CALL(*event_interface_, OnFailChannel("Invalid frame header"));

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

TEST_F(WebSocketChannelEventInterfaceTest, StartHandshakeRequest) {
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_, OnStartOpeningHandshakeCalled());
  }

  CreateChannelAndConnectSuccessfully();

  scoped_ptr<WebSocketHandshakeRequestInfo> request_info(
      new WebSocketHandshakeRequestInfo(GURL("ws://www.example.com/"),
                                        base::Time()));
  connect_data_.creator.connect_delegate->OnStartOpeningHandshake(
      request_info.Pass());

  base::MessageLoop::current()->RunUntilIdle();
}

TEST_F(WebSocketChannelEventInterfaceTest, FinishHandshakeRequest) {
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_, OnFinishOpeningHandshakeCalled());
  }

  CreateChannelAndConnectSuccessfully();

  scoped_refptr<HttpResponseHeaders> response_headers(
      new HttpResponseHeaders(""));
  scoped_ptr<WebSocketHandshakeResponseInfo> response_info(
      new WebSocketHandshakeResponseInfo(GURL("ws://www.example.com/"),
                                         200,
                                         "OK",
                                         response_headers,
                                         base::Time()));
  connect_data_.creator.connect_delegate->OnFinishOpeningHandshake(
      response_info.Pass());
  base::MessageLoop::current()->RunUntilIdle();
}

TEST_F(WebSocketChannelEventInterfaceTest, FailJustAfterHandshake) {
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnStartOpeningHandshakeCalled());
    EXPECT_CALL(*event_interface_, OnFinishOpeningHandshakeCalled());
    EXPECT_CALL(*event_interface_, OnFailChannel("bye"));
  }

  CreateChannelAndConnect();

  WebSocketStream::ConnectDelegate* connect_delegate =
      connect_data_.creator.connect_delegate.get();
  GURL url("ws://www.example.com/");
  scoped_ptr<WebSocketHandshakeRequestInfo> request_info(
      new WebSocketHandshakeRequestInfo(url, base::Time()));
  scoped_refptr<HttpResponseHeaders> response_headers(
      new HttpResponseHeaders(""));
  scoped_ptr<WebSocketHandshakeResponseInfo> response_info(
      new WebSocketHandshakeResponseInfo(url,
                                         200,
                                         "OK",
                                         response_headers,
                                         base::Time()));
  connect_delegate->OnStartOpeningHandshake(request_info.Pass());
  connect_delegate->OnFinishOpeningHandshake(response_info.Pass());

  connect_delegate->OnFailure("bye");
  base::MessageLoop::current()->RunUntilIdle();
}

// Any frame after close is invalid. This test uses a Text frame. See also
// test "PingAfterCloseIfRejected".
TEST_F(WebSocketChannelEventInterfaceTest, DataAfterCloseIsRejected) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED,
       CLOSE_DATA(NORMAL_CLOSURE, "OK")},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "Payload"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));

  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnClosingHandshake());
    EXPECT_CALL(*event_interface_,
                OnFailChannel("Data frame received after close"));
  }

  CreateChannelAndConnectSuccessfully();
}

// A Close frame with a one-byte payload elicits a specific console error
// message.
TEST_F(WebSocketChannelEventInterfaceTest, OneByteClosePayloadMessage) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, "\x03"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  EXPECT_CALL(
      *event_interface_,
      OnFailChannel(
          "Received a broken close frame containing an invalid size body."));

  CreateChannelAndConnectSuccessfully();
}

// A Close frame with a reserved status code also elicits a specific console
// error message.
TEST_F(WebSocketChannelEventInterfaceTest, ClosePayloadReservedStatusMessage) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(ABNORMAL_CLOSURE, "Not valid on wire")}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  EXPECT_CALL(
      *event_interface_,
      OnFailChannel(
          "Received a broken close frame containing a reserved status code."));

  CreateChannelAndConnectSuccessfully();
}

// A Close frame with invalid UTF-8 also elicits a specific console error
// message.
TEST_F(WebSocketChannelEventInterfaceTest, ClosePayloadInvalidReason) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "\xFF")}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  EXPECT_CALL(
      *event_interface_,
      OnFailChannel(
          "Received a broken close frame containing invalid UTF-8."));

  CreateChannelAndConnectSuccessfully();
}

// The reserved bits must all be clear on received frames. Extensions should
// clear the bits when they are set correctly before passing on the frame.
TEST_F(WebSocketChannelEventInterfaceTest, ReservedBitsMustNotBeSet) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
       NOT_MASKED,  "sakana"}};
  // It is not worth adding support for reserved bits to InitFrame just for this
  // one test, so set the bit manually.
  ScopedVector<WebSocketFrame> raw_frames = CreateFrameVector(frames);
  raw_frames[0]->header.reserved1 = true;
  stream->PrepareRawReadFrames(
      ReadableFakeWebSocketStream::SYNC, OK, raw_frames.Pass());
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  EXPECT_CALL(*event_interface_,
              OnFailChannel(
                  "One or more reserved bits are on: reserved1 = 1, "
                  "reserved2 = 0, reserved3 = 0"));

  CreateChannelAndConnectSuccessfully();
}

// The closing handshake times out and sends an OnDropChannel event if no
// response to the client Close message is received.
TEST_F(WebSocketChannelEventInterfaceTest,
       ClientInitiatedClosingHandshakeTimesOut) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  stream->PrepareReadFramesError(ReadableFakeWebSocketStream::SYNC,
                                 ERR_IO_PENDING);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  // This checkpoint object verifies that the OnDropChannel message comes after
  // the timeout.
  Checkpoint checkpoint;
  TestClosure completion;
  {
    InSequence s;
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*event_interface_,
                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _))
        .WillOnce(InvokeClosureReturnDeleted(completion.closure()));
  }
  CreateChannelAndConnectSuccessfully();
  // OneShotTimer is not very friendly to testing; there is no apparent way to
  // set an expectation on it. Instead the tests need to infer that the timeout
  // was fired by the behaviour of the WebSocketChannel object.
  channel_->SetClosingHandshakeTimeoutForTesting(
      TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
  channel_->StartClosingHandshake(kWebSocketNormalClosure, "");
  checkpoint.Call(1);
  completion.WaitForResult();
}

// The closing handshake times out and sends an OnDropChannel event if a Close
// message is received but the connection isn't closed by the remote host.
TEST_F(WebSocketChannelEventInterfaceTest,
       ServerInitiatedClosingHandshakeTimesOut) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  Checkpoint checkpoint;
  TestClosure completion;
  {
    InSequence s;
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*event_interface_, OnClosingHandshake());
    EXPECT_CALL(*event_interface_,
                OnDropChannel(false, kWebSocketErrorAbnormalClosure, _))
        .WillOnce(InvokeClosureReturnDeleted(completion.closure()));
  }
  CreateChannelAndConnectSuccessfully();
  channel_->SetClosingHandshakeTimeoutForTesting(
      TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
  checkpoint.Call(1);
  completion.WaitForResult();
}

// The renderer should provide us with some quota immediately, and then
// WebSocketChannel calls ReadFrames as soon as the stream is available.
TEST_F(WebSocketChannelStreamTest, FlowControlEarly) {
  Checkpoint checkpoint;
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  {
    InSequence s;
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(Return(ERR_IO_PENDING));
    EXPECT_CALL(checkpoint, Call(2));
  }

  set_stream(mock_stream_.Pass());
  CreateChannelAndConnect();
  channel_->SendFlowControl(kPlentyOfQuota);
  checkpoint.Call(1);
  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
  checkpoint.Call(2);
}

// If for some reason the connect succeeds before the renderer sends us quota,
// we shouldn't call ReadFrames() immediately.
// TODO(ricea): Actually we should call ReadFrames() with a small limit so we
// can still handle control frames. This should be done once we have any API to
// expose quota to the lower levels.
TEST_F(WebSocketChannelStreamTest, FlowControlLate) {
  Checkpoint checkpoint;
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  {
    InSequence s;
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(Return(ERR_IO_PENDING));
    EXPECT_CALL(checkpoint, Call(2));
  }

  set_stream(mock_stream_.Pass());
  CreateChannelAndConnect();
  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
  checkpoint.Call(1);
  channel_->SendFlowControl(kPlentyOfQuota);
  checkpoint.Call(2);
}

// We should stop calling ReadFrames() when all quota is used.
TEST_F(WebSocketChannelStreamTest, FlowControlStopsReadFrames) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};

  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames));

  set_stream(mock_stream_.Pass());
  CreateChannelAndConnect();
  channel_->SendFlowControl(4);
  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
}

// Providing extra quota causes ReadFrames() to be called again.
TEST_F(WebSocketChannelStreamTest, FlowControlStartsWithMoreQuota) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};
  Checkpoint checkpoint;

  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  {
    InSequence s;
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(ReturnFrames(&frames));
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(Return(ERR_IO_PENDING));
  }

  set_stream(mock_stream_.Pass());
  CreateChannelAndConnect();
  channel_->SendFlowControl(4);
  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
  checkpoint.Call(1);
  channel_->SendFlowControl(4);
}

// ReadFrames() isn't called again until all pending data has been passed to
// the renderer.
TEST_F(WebSocketChannelStreamTest, ReadFramesNotCalledUntilQuotaAvailable) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};
  Checkpoint checkpoint;

  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  {
    InSequence s;
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(ReturnFrames(&frames));
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(checkpoint, Call(2));
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(Return(ERR_IO_PENDING));
  }

  set_stream(mock_stream_.Pass());
  CreateChannelAndConnect();
  channel_->SendFlowControl(2);
  connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
  checkpoint.Call(1);
  channel_->SendFlowControl(2);
  checkpoint.Call(2);
  channel_->SendFlowControl(2);
}

// A message that needs to be split into frames to fit within quota should
// maintain correct semantics.
TEST_F(WebSocketChannelFlowControlTest, SingleFrameMessageSplitSync) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(false, WebSocketFrameHeader::kOpCodeText, AsVector("FO")));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("U")));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("R")));
  }

  CreateChannelAndConnectWithQuota(2);
  channel_->SendFlowControl(1);
  channel_->SendFlowControl(1);
}

// The code path for async messages is slightly different, so test it
// separately.
TEST_F(WebSocketChannelFlowControlTest, SingleFrameMessageSplitAsync) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "FOUR"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::ASYNC, OK, frames);
  set_stream(stream.Pass());
  Checkpoint checkpoint;
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(false, WebSocketFrameHeader::kOpCodeText, AsVector("FO")));
    EXPECT_CALL(checkpoint, Call(2));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("U")));
    EXPECT_CALL(checkpoint, Call(3));
    EXPECT_CALL(
        *event_interface_,
        OnDataFrame(
            true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("R")));
  }

  CreateChannelAndConnectWithQuota(2);
  checkpoint.Call(1);
  base::MessageLoop::current()->RunUntilIdle();
  checkpoint.Call(2);
  channel_->SendFlowControl(1);
  checkpoint.Call(3);
  channel_->SendFlowControl(1);
}

// A message split into multiple frames which is further split due to quota
// restrictions should stil be correct.
// TODO(ricea): The message ends up split into more frames than are strictly
// necessary. The complexity/performance tradeoffs here need further
// examination.
TEST_F(WebSocketChannelFlowControlTest, MultipleFrameSplit) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
       NOT_MASKED,      "FIRST FRAME IS 25 BYTES. "},
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,      "SECOND FRAME IS 26 BYTES. "},
      {FINAL_FRAME,     WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,      "FINAL FRAME IS 24 BYTES."}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(false,
                            WebSocketFrameHeader::kOpCodeText,
                            AsVector("FIRST FRAME IS")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(false,
                            WebSocketFrameHeader::kOpCodeContinuation,
                            AsVector(" 25 BYTES. ")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(false,
                            WebSocketFrameHeader::kOpCodeContinuation,
                            AsVector("SECOND FRAME IS 26 BYTES. ")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(false,
                            WebSocketFrameHeader::kOpCodeContinuation,
                            AsVector("FINAL ")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(true,
                            WebSocketFrameHeader::kOpCodeContinuation,
                            AsVector("FRAME IS 24 BYTES.")));
  }
  CreateChannelAndConnectWithQuota(14);
  channel_->SendFlowControl(43);
  channel_->SendFlowControl(32);
}

// An empty message handled when we are out of quota must not be delivered
// out-of-order with respect to other messages.
TEST_F(WebSocketChannelFlowControlTest, EmptyMessageNoQuota) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
       NOT_MASKED,  "FIRST MESSAGE"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
       NOT_MASKED,  ""},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
       NOT_MASKED,  "THIRD MESSAGE"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());
  {
    InSequence s;
    EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
    EXPECT_CALL(*event_interface_, OnFlowControl(_));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(false,
                            WebSocketFrameHeader::kOpCodeText,
                            AsVector("FIRST ")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(true,
                            WebSocketFrameHeader::kOpCodeContinuation,
                            AsVector("MESSAGE")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(true,
                            WebSocketFrameHeader::kOpCodeText,
                            AsVector("")));
    EXPECT_CALL(*event_interface_,
                OnDataFrame(true,
                            WebSocketFrameHeader::kOpCodeText,
                            AsVector("THIRD MESSAGE")));
  }

  CreateChannelAndConnectWithQuota(6);
  channel_->SendFlowControl(128);
}

// RFC6455 5.1 "a client MUST mask all frames that it sends to the server".
// WebSocketChannel actually only sets the mask bit in the header, it doesn't
// perform masking itself (not all transports actually use masking).
TEST_F(WebSocketChannelStreamTest, SentFramesAreMasked) {
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
       MASKED,      "NEEDS MASKING"}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));

  CreateChannelAndConnectSuccessfully();
  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeText, AsVector("NEEDS MASKING"));
}

// RFC6455 5.5.1 "The application MUST NOT send any more data frames after
// sending a Close frame."
TEST_F(WebSocketChannelStreamTest, NothingIsSentAfterClose) {
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "Success")}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));

  CreateChannelAndConnectSuccessfully();
  channel_->StartClosingHandshake(1000, "Success");
  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeText, AsVector("SHOULD  BE IGNORED"));
}

// RFC6455 5.5.1 "If an endpoint receives a Close frame and did not previously
// send a Close frame, the endpoint MUST send a Close frame in response."
TEST_F(WebSocketChannelStreamTest, CloseIsEchoedBack) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));

  CreateChannelAndConnectSuccessfully();
}

// The converse of the above case; after sending a Close frame, we should not
// send another one.
TEST_F(WebSocketChannelStreamTest, CloseOnlySentOnce) {
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "Close")}};
  static const InitFrame frames_init[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "Close")}};

  // We store the parameters that were passed to ReadFrames() so that we can
  // call them explicitly later.
  CompletionCallback read_callback;
  ScopedVector<WebSocketFrame>* frames = NULL;

  // These are not interesting.
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());

  // Use a checkpoint to make the ordering of events clearer.
  Checkpoint checkpoint;
  {
    InSequence s;
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(DoAll(SaveArg<0>(&frames),
                        SaveArg<1>(&read_callback),
                        Return(ERR_IO_PENDING)));
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
        .WillOnce(Return(OK));
    EXPECT_CALL(checkpoint, Call(2));
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(Return(ERR_IO_PENDING));
    EXPECT_CALL(checkpoint, Call(3));
    // WriteFrames() must not be called again. GoogleMock will ensure that the
    // test fails if it is.
  }

  CreateChannelAndConnectSuccessfully();
  checkpoint.Call(1);
  channel_->StartClosingHandshake(kWebSocketNormalClosure, "Close");
  checkpoint.Call(2);

  *frames = CreateFrameVector(frames_init);
  read_callback.Run(OK);
  checkpoint.Call(3);
}

// Invalid close status codes should not be sent on the network.
TEST_F(WebSocketChannelStreamTest, InvalidCloseStatusCodeNotSent) {
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(SERVER_ERROR, "")}};

  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(Return(ERR_IO_PENDING));

  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _));

  CreateChannelAndConnectSuccessfully();
  channel_->StartClosingHandshake(999, "");
}

// A Close frame with a reason longer than 123 bytes cannot be sent on the
// network.
TEST_F(WebSocketChannelStreamTest, LongCloseReasonNotSent) {
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(SERVER_ERROR, "")}};

  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(Return(ERR_IO_PENDING));

  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _));

  CreateChannelAndConnectSuccessfully();
  channel_->StartClosingHandshake(1000, std::string(124, 'A'));
}

// We generate code 1005, kWebSocketErrorNoStatusReceived, when there is no
// status in the Close message from the other side. Code 1005 is not allowed to
// appear on the wire, so we should not echo it back. See test
// CloseWithNoPayloadGivesStatus1005, above, for confirmation that code 1005 is
// correctly generated internally.
TEST_F(WebSocketChannelStreamTest, Code1005IsNotEchoed) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, ""}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, ""}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));

  CreateChannelAndConnectSuccessfully();
}

TEST_F(WebSocketChannelStreamTest, Code1005IsNotEchoedNull) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, NOT_MASKED, NULL}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED, ""}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));

  CreateChannelAndConnectSuccessfully();
}

// Receiving an invalid UTF-8 payload in a Close frame causes us to fail the
// connection.
TEST_F(WebSocketChannelStreamTest, CloseFrameInvalidUtf8) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED, CLOSE_DATA(NORMAL_CLOSURE, "\xFF")}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED, CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in Close frame")}};

  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));
  EXPECT_CALL(*mock_stream_, Close());

  CreateChannelAndConnectSuccessfully();
}

// RFC6455 5.5.2 "Upon receipt of a Ping frame, an endpoint MUST send a Pong
// frame in response"
// 5.5.3 "A Pong frame sent in response to a Ping frame must have identical
// "Application data" as found in the message body of the Ping frame being
// replied to."
TEST_F(WebSocketChannelStreamTest, PingRepliedWithPong) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing,
       NOT_MASKED,  "Application data"}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong,
       MASKED,      "Application data"}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));

  CreateChannelAndConnectSuccessfully();
}

// A ping with a NULL payload should be responded to with a Pong with a NULL
// payload.
TEST_F(WebSocketChannelStreamTest, NullPingRepliedWithNullPong) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing, NOT_MASKED, NULL}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong, MASKED, NULL}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));

  CreateChannelAndConnectSuccessfully();
}

TEST_F(WebSocketChannelStreamTest, PongInTheMiddleOfDataMessage) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing,
       NOT_MASKED,  "Application data"}};
  static const InitFrame expected1[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "Hello "}};
  static const InitFrame expected2[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePong,
       MASKED,      "Application data"}};
  static const InitFrame expected3[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       MASKED,      "World"}};
  ScopedVector<WebSocketFrame>* read_frames;
  CompletionCallback read_callback;
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(DoAll(SaveArg<0>(&read_frames),
                      SaveArg<1>(&read_callback),
                      Return(ERR_IO_PENDING)))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  {
    InSequence s;

    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
        .WillOnce(Return(OK));
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
        .WillOnce(Return(OK));
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected3), _))
        .WillOnce(Return(OK));
  }

  CreateChannelAndConnectSuccessfully();
  channel_->SendFrame(
      false, WebSocketFrameHeader::kOpCodeText, AsVector("Hello "));
  *read_frames = CreateFrameVector(frames);
  read_callback.Run(OK);
  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("World"));
}

// WriteFrames() may not be called until the previous write has completed.
// WebSocketChannel must buffer writes that happen in the meantime.
TEST_F(WebSocketChannelStreamTest, WriteFramesOneAtATime) {
  static const InitFrame expected1[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "Hello "}};
  static const InitFrame expected2[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "World"}};
  CompletionCallback write_callback;
  Checkpoint checkpoint;

  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
  {
    InSequence s;
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
        .WillOnce(DoAll(SaveArg<1>(&write_callback), Return(ERR_IO_PENDING)));
    EXPECT_CALL(checkpoint, Call(2));
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
        .WillOnce(Return(ERR_IO_PENDING));
    EXPECT_CALL(checkpoint, Call(3));
  }

  CreateChannelAndConnectSuccessfully();
  checkpoint.Call(1);
  channel_->SendFrame(
      false, WebSocketFrameHeader::kOpCodeText, AsVector("Hello "));
  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeText, AsVector("World"));
  checkpoint.Call(2);
  write_callback.Run(OK);
  checkpoint.Call(3);
}

// WebSocketChannel must buffer frames while it is waiting for a write to
// complete, and then send them in a single batch. The batching behaviour is
// important to get good throughput in the "many small messages" case.
TEST_F(WebSocketChannelStreamTest, WaitingMessagesAreBatched) {
  static const char input_letters[] = "Hello";
  static const InitFrame expected1[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "H"}};
  static const InitFrame expected2[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "e"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "l"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "l"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, MASKED, "o"}};
  CompletionCallback write_callback;

  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
  {
    InSequence s;
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected1), _))
        .WillOnce(DoAll(SaveArg<1>(&write_callback), Return(ERR_IO_PENDING)));
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected2), _))
        .WillOnce(Return(ERR_IO_PENDING));
  }

  CreateChannelAndConnectSuccessfully();
  for (size_t i = 0; i < strlen(input_letters); ++i) {
    channel_->SendFrame(true,
                        WebSocketFrameHeader::kOpCodeText,
                        std::vector<char>(1, input_letters[i]));
  }
  write_callback.Run(OK);
}

// When the renderer sends more on a channel than it has quota for, we send the
// remote server a kWebSocketErrorGoingAway error code.
TEST_F(WebSocketChannelStreamTest, SendGoingAwayOnRendererQuotaExceeded) {
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(GOING_AWAY, "")}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));
  EXPECT_CALL(*mock_stream_, Close());

  CreateChannelAndConnectSuccessfully();
  channel_->SendFrame(true,
                      WebSocketFrameHeader::kOpCodeText,
                      std::vector<char>(kDefaultInitialQuota + 1, 'C'));
}

// For convenience, most of these tests use Text frames. However, the WebSocket
// protocol also has Binary frames and those need to be 8-bit clean. For the
// sake of completeness, this test verifies that they are.
TEST_F(WebSocketChannelStreamTest, WrittenBinaryFramesAre8BitClean) {
  ScopedVector<WebSocketFrame>* frames = NULL;

  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _)).WillOnce(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(_, _))
      .WillOnce(DoAll(SaveArg<0>(&frames), Return(ERR_IO_PENDING)));

  CreateChannelAndConnectSuccessfully();
  channel_->SendFrame(
      true,
      WebSocketFrameHeader::kOpCodeBinary,
      std::vector<char>(kBinaryBlob, kBinaryBlob + kBinaryBlobSize));
  ASSERT_TRUE(frames != NULL);
  ASSERT_EQ(1U, frames->size());
  const WebSocketFrame* out_frame = (*frames)[0];
  EXPECT_EQ(kBinaryBlobSize, out_frame->header.payload_length);
  ASSERT_TRUE(out_frame->data);
  EXPECT_EQ(0, memcmp(kBinaryBlob, out_frame->data->data(), kBinaryBlobSize));
}

// Test the read path for 8-bit cleanliness as well.
TEST_F(WebSocketChannelEventInterfaceTest, ReadBinaryFramesAre8BitClean) {
  scoped_ptr<WebSocketFrame> frame(
      new WebSocketFrame(WebSocketFrameHeader::kOpCodeBinary));
  WebSocketFrameHeader& frame_header = frame->header;
  frame_header.final = true;
  frame_header.payload_length = kBinaryBlobSize;
  frame->data = new IOBuffer(kBinaryBlobSize);
  memcpy(frame->data->data(), kBinaryBlob, kBinaryBlobSize);
  ScopedVector<WebSocketFrame> frames;
  frames.push_back(frame.release());
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  stream->PrepareRawReadFrames(
      ReadableFakeWebSocketStream::SYNC, OK, frames.Pass());
  set_stream(stream.Pass());
  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(_));
  EXPECT_CALL(*event_interface_,
              OnDataFrame(true,
                          WebSocketFrameHeader::kOpCodeBinary,
                          std::vector<char>(kBinaryBlob,
                                            kBinaryBlob + kBinaryBlobSize)));

  CreateChannelAndConnectSuccessfully();
}

// Invalid UTF-8 is not permitted in Text frames.
TEST_F(WebSocketChannelSendUtf8Test, InvalidUtf8Rejected) {
  EXPECT_CALL(
      *event_interface_,
      OnFailChannel("Browser sent a text frame containing invalid UTF-8"));

  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeText, AsVector("\xff"));
}

// A Text message cannot end with a partial UTF-8 character.
TEST_F(WebSocketChannelSendUtf8Test, IncompleteCharacterInFinalFrame) {
  EXPECT_CALL(
      *event_interface_,
      OnFailChannel("Browser sent a text frame containing invalid UTF-8"));

  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeText, AsVector("\xc2"));
}

// A non-final Text frame may end with a partial UTF-8 character (compare to
// previous test).
TEST_F(WebSocketChannelSendUtf8Test, IncompleteCharacterInNonFinalFrame) {
  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(
      false, WebSocketFrameHeader::kOpCodeText, AsVector("\xc2"));
}

// UTF-8 parsing context must be retained between frames.
TEST_F(WebSocketChannelSendUtf8Test, ValidCharacterSplitBetweenFrames) {
  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(
      false, WebSocketFrameHeader::kOpCodeText, AsVector("\xf1"));
  channel_->SendFrame(true,
                      WebSocketFrameHeader::kOpCodeContinuation,
                      AsVector("\x80\xa0\xbf"));
}

// Similarly, an invalid character should be detected even if split.
TEST_F(WebSocketChannelSendUtf8Test, InvalidCharacterSplit) {
  EXPECT_CALL(
      *event_interface_,
      OnFailChannel("Browser sent a text frame containing invalid UTF-8"));

  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(
      false, WebSocketFrameHeader::kOpCodeText, AsVector("\xe1"));
  channel_->SendFrame(true,
                      WebSocketFrameHeader::kOpCodeContinuation,
                      AsVector("\x80\xa0\xbf"));
}

// An invalid character must be detected in continuation frames.
TEST_F(WebSocketChannelSendUtf8Test, InvalidByteInContinuation) {
  EXPECT_CALL(
      *event_interface_,
      OnFailChannel("Browser sent a text frame containing invalid UTF-8"));

  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(
      false, WebSocketFrameHeader::kOpCodeText, AsVector("foo"));
  channel_->SendFrame(
      false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("bar"));
  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("\xff"));
}

// However, continuation frames of a Binary frame will not be tested for UTF-8
// validity.
TEST_F(WebSocketChannelSendUtf8Test, BinaryContinuationNotChecked) {
  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(
      false, WebSocketFrameHeader::kOpCodeBinary, AsVector("foo"));
  channel_->SendFrame(
      false, WebSocketFrameHeader::kOpCodeContinuation, AsVector("bar"));
  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeContinuation, AsVector("\xff"));
}

// Multiple text messages can be validated without the validation state getting
// confused.
TEST_F(WebSocketChannelSendUtf8Test, ValidateMultipleTextMessages) {
  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("foo"));
  channel_->SendFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("bar"));
}

// UTF-8 validation is enforced on received Text frames.
TEST_F(WebSocketChannelEventInterfaceTest, ReceivedInvalidUtf8) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xff"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());

  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
  EXPECT_CALL(*event_interface_,
              OnFailChannel("Could not decode a text frame as UTF-8."));

  CreateChannelAndConnectSuccessfully();
  base::MessageLoop::current()->RunUntilIdle();
}

// Invalid UTF-8 is not sent over the network.
TEST_F(WebSocketChannelStreamTest, InvalidUtf8TextFrameNotSent) {
  static const InitFrame expected[] = {{FINAL_FRAME,
                                        WebSocketFrameHeader::kOpCodeClose,
                                        MASKED, CLOSE_DATA(GOING_AWAY, "")}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));
  EXPECT_CALL(*mock_stream_, Close()).Times(1);

  CreateChannelAndConnectSuccessfully();

  channel_->SendFrame(
      true, WebSocketFrameHeader::kOpCodeText, AsVector("\xff"));
}

// The rest of the tests for receiving invalid UTF-8 test the communication with
// the server. Since there is only one code path, it would be redundant to
// perform the same tests on the EventInterface as well.

// If invalid UTF-8 is received in a Text frame, the connection is failed.
TEST_F(WebSocketChannelReceiveUtf8Test, InvalidTextFrameRejected) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xff"}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
  {
    InSequence s;
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(ReturnFrames(&frames))
        .WillRepeatedly(Return(ERR_IO_PENDING));
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
        .WillOnce(Return(OK));
    EXPECT_CALL(*mock_stream_, Close()).Times(1);
  }

  CreateChannelAndConnectSuccessfully();
}

// A received Text message is not permitted to end with a partial UTF-8
// character.
TEST_F(WebSocketChannelReceiveUtf8Test, IncompleteCharacterReceived) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xc2"}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));
  EXPECT_CALL(*mock_stream_, Close()).Times(1);

  CreateChannelAndConnectSuccessfully();
}

// However, a non-final Text frame may end with a partial UTF-8 character.
TEST_F(WebSocketChannelReceiveUtf8Test, IncompleteCharacterIncompleteMessage) {
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xc2"}};
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));

  CreateChannelAndConnectSuccessfully();
}

// However, it will become an error if it is followed by an empty final frame.
TEST_F(WebSocketChannelReceiveUtf8Test, TricksyIncompleteCharacter) {
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xc2"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, ""}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));
  EXPECT_CALL(*mock_stream_, Close()).Times(1);

  CreateChannelAndConnectSuccessfully();
}

// UTF-8 parsing context must be retained between received frames of the same
// message.
TEST_F(WebSocketChannelReceiveUtf8Test, ReceivedParsingContextRetained) {
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xf1"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,  "\x80\xa0\xbf"}};
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));

  CreateChannelAndConnectSuccessfully();
}

// An invalid character must be detected even if split between frames.
TEST_F(WebSocketChannelReceiveUtf8Test, SplitInvalidCharacterReceived) {
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "\xe1"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,  "\x80\xa0\xbf"}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));
  EXPECT_CALL(*mock_stream_, Close()).Times(1);

  CreateChannelAndConnectSuccessfully();
}

// An invalid character received in a continuation frame must be detected.
TEST_F(WebSocketChannelReceiveUtf8Test, InvalidReceivedIncontinuation) {
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "foo"},
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,      "bar"},
      {FINAL_FRAME,     WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,      "\xff"}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose, MASKED,
       CLOSE_DATA(PROTOCOL_ERROR, "Invalid UTF-8 in text frame")}};
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));
  EXPECT_CALL(*mock_stream_, Close()).Times(1);

  CreateChannelAndConnectSuccessfully();
}

// Continuations of binary frames must not be tested for UTF-8 validity.
TEST_F(WebSocketChannelReceiveUtf8Test, ReceivedBinaryNotUtf8Tested) {
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeBinary, NOT_MASKED, "foo"},
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,      "bar"},
      {FINAL_FRAME,     WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED,      "\xff"}};
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));

  CreateChannelAndConnectSuccessfully();
}

// Multiple Text messages can be validated.
TEST_F(WebSocketChannelReceiveUtf8Test, ValidateMultipleReceived) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "foo"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, "bar"}};
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));

  CreateChannelAndConnectSuccessfully();
}

// A new data message cannot start in the middle of another data message.
TEST_F(WebSocketChannelEventInterfaceTest, BogusContinuation) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeBinary,
       NOT_MASKED, "frame1"},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeText,
       NOT_MASKED, "frame2"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());

  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
  EXPECT_CALL(
      *event_interface_,
      OnDataFrame(
          false, WebSocketFrameHeader::kOpCodeBinary, AsVector("frame1")));
  EXPECT_CALL(
      *event_interface_,
      OnFailChannel(
          "Received start of new message but previous message is unfinished."));

  CreateChannelAndConnectSuccessfully();
}

// A new message cannot start with a Continuation frame.
TEST_F(WebSocketChannelEventInterfaceTest, MessageStartingWithContinuation) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED, "continuation"}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());

  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
  EXPECT_CALL(*event_interface_,
              OnFailChannel("Received unexpected continuation frame."));

  CreateChannelAndConnectSuccessfully();
}

// A frame passed to the renderer must be either non-empty or have the final bit
// set.
TEST_F(WebSocketChannelEventInterfaceTest, DataFramesNonEmptyOrFinal) {
  scoped_ptr<ReadableFakeWebSocketStream> stream(
      new ReadableFakeWebSocketStream);
  static const InitFrame frames[] = {
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeText, NOT_MASKED, ""},
      {NOT_FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation,
       NOT_MASKED, ""},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeContinuation, NOT_MASKED, ""}};
  stream->PrepareReadFrames(ReadableFakeWebSocketStream::SYNC, OK, frames);
  set_stream(stream.Pass());

  EXPECT_CALL(*event_interface_, OnAddChannelResponse(false, _, _));
  EXPECT_CALL(*event_interface_, OnFlowControl(kDefaultInitialQuota));
  EXPECT_CALL(
      *event_interface_,
      OnDataFrame(true, WebSocketFrameHeader::kOpCodeText, AsVector("")));

  CreateChannelAndConnectSuccessfully();
}

// If we receive another frame after Close, it is not valid. It is not
// completely clear what behaviour is required from the standard in this case,
// but the current implementation fails the connection. Since a Close has
// already been sent, this just means closing the connection.
TEST_F(WebSocketChannelStreamTest, PingAfterCloseIsRejected) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")},
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodePing,
       NOT_MASKED,  "Ping body"}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  {
    // We only need to verify the relative order of WriteFrames() and
    // Close(). The current implementation calls WriteFrames() for the Close
    // frame before calling ReadFrames() again, but that is an implementation
    // detail and better not to consider required behaviour.
    InSequence s;
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
        .WillOnce(Return(OK));
    EXPECT_CALL(*mock_stream_, Close()).Times(1);
  }

  CreateChannelAndConnectSuccessfully();
}

// A protocol error from the remote server should result in a close frame with
// status 1002, followed by the connection closing.
TEST_F(WebSocketChannelStreamTest, ProtocolError) {
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(PROTOCOL_ERROR, "WebSocket Protocol Error")}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(Return(ERR_WS_PROTOCOL_ERROR));
  EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
      .WillOnce(Return(OK));
  EXPECT_CALL(*mock_stream_, Close());

  CreateChannelAndConnectSuccessfully();
}

// Set the closing handshake timeout to a very tiny value before connecting.
class WebSocketChannelStreamTimeoutTest : public WebSocketChannelStreamTest {
 protected:
  WebSocketChannelStreamTimeoutTest() {}

  virtual void CreateChannelAndConnectSuccessfully() OVERRIDE {
    set_stream(mock_stream_.Pass());
    CreateChannelAndConnect();
    channel_->SendFlowControl(kPlentyOfQuota);
    channel_->SetClosingHandshakeTimeoutForTesting(
        TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
    connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
  }
};

// In this case the server initiates the closing handshake with a Close
// message. WebSocketChannel responds with a matching Close message, and waits
// for the server to close the TCP/IP connection. The server never closes the
// connection, so the closing handshake times out and WebSocketChannel closes
// the connection itself.
TEST_F(WebSocketChannelStreamTimeoutTest, ServerInitiatedCloseTimesOut) {
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillOnce(ReturnFrames(&frames))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  Checkpoint checkpoint;
  TestClosure completion;
  {
    InSequence s;
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
        .WillOnce(Return(OK));
    EXPECT_CALL(checkpoint, Call(1));
    EXPECT_CALL(*mock_stream_, Close())
        .WillOnce(InvokeClosure(completion.closure()));
  }

  CreateChannelAndConnectSuccessfully();
  checkpoint.Call(1);
  completion.WaitForResult();
}

// In this case the client initiates the closing handshake by sending a Close
// message. WebSocketChannel waits for a Close message in response from the
// server. The server never responds to the Close message, so the closing
// handshake times out and WebSocketChannel closes the connection.
TEST_F(WebSocketChannelStreamTimeoutTest, ClientInitiatedCloseTimesOut) {
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
      .WillRepeatedly(Return(ERR_IO_PENDING));
  TestClosure completion;
  {
    InSequence s;
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
        .WillOnce(Return(OK));
    EXPECT_CALL(*mock_stream_, Close())
        .WillOnce(InvokeClosure(completion.closure()));
  }

  CreateChannelAndConnectSuccessfully();
  channel_->StartClosingHandshake(kWebSocketNormalClosure, "OK");
  completion.WaitForResult();
}

// In this case the client initiates the closing handshake and the server
// responds with a matching Close message. WebSocketChannel waits for the server
// to close the TCP/IP connection, but it never does. The closing handshake
// times out and WebSocketChannel closes the connection.
TEST_F(WebSocketChannelStreamTimeoutTest, ConnectionCloseTimesOut) {
  static const InitFrame expected[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       MASKED,      CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
  static const InitFrame frames[] = {
      {FINAL_FRAME, WebSocketFrameHeader::kOpCodeClose,
       NOT_MASKED,  CLOSE_DATA(NORMAL_CLOSURE, "OK")}};
  EXPECT_CALL(*mock_stream_, GetSubProtocol()).Times(AnyNumber());
  EXPECT_CALL(*mock_stream_, GetExtensions()).Times(AnyNumber());
  TestClosure completion;
  ScopedVector<WebSocketFrame>* read_frames = NULL;
  CompletionCallback read_callback;
  {
    InSequence s;
    // Copy the arguments to ReadFrames so that the test can call the callback
    // after it has send the close message.
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(DoAll(SaveArg<0>(&read_frames),
                        SaveArg<1>(&read_callback),
                        Return(ERR_IO_PENDING)));
    // The first real event that happens is the client sending the Close
    // message.
    EXPECT_CALL(*mock_stream_, WriteFrames(EqualsFrames(expected), _))
        .WillOnce(Return(OK));
    // The |read_frames| callback is called (from this test case) at this
    // point. ReadFrames is called again by WebSocketChannel, waiting for
    // ERR_CONNECTION_CLOSED.
    EXPECT_CALL(*mock_stream_, ReadFrames(_, _))
        .WillOnce(Return(ERR_IO_PENDING));
    // The timeout happens and so WebSocketChannel closes the stream.
    EXPECT_CALL(*mock_stream_, Close())
        .WillOnce(InvokeClosure(completion.closure()));
  }

  CreateChannelAndConnectSuccessfully();
  channel_->StartClosingHandshake(kWebSocketNormalClosure, "OK");
  ASSERT_TRUE(read_frames);
  // Provide the "Close" message from the server.
  *read_frames = CreateFrameVector(frames);
  read_callback.Run(OK);
  completion.WaitForResult();
}

}  // namespace
}  // namespace net

/* [<][>][^][v][top][bottom][index][help] */