Chromium Code Reviews| Index: net/websockets/websocket_basic_stream_test.cc |
| diff --git a/net/websockets/websocket_basic_stream_test.cc b/net/websockets/websocket_basic_stream_test.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5eaf126e7e0ac183475bd6e2d0b569e1cd747e6d |
| --- /dev/null |
| +++ b/net/websockets/websocket_basic_stream_test.cc |
| @@ -0,0 +1,482 @@ |
| +// 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. |
| +// |
| +// Tests for WebSocketBasicStream. Note that we do not attempt to verify that |
| +// frame parsing itself functions correctly, as that is covered by the |
| +// WebSocketFrameParser tests. |
| + |
| +#include "net/websockets/websocket_basic_stream.h" |
| + |
| +#include "base/basictypes.h" |
| +#include "net/base/capturing_net_log.h" |
| +#include "net/base/test_completion_callback.h" |
| +#include "net/socket/socket_test_util.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace net { |
| +namespace { |
| + |
| +const char kSampleFrame[] = "\x81\x06Sample"; |
| +const size_t kSampleFrameSize = arraysize(kSampleFrame) - 1; |
| +const char kPartialLargeFrame[] = |
| + "\x81\x7F\x00\x00\x00\x00\x7F\xFF\xFF\xFF" |
| + "chromiunum ad pasco per loca insanis pullum manducat frumenti"; |
| +const size_t kPartialLargeFrameSize = arraysize(kPartialLargeFrame) - 1; |
| +const size_t kLargeFrameHeaderSize = 10; |
| +const size_t kLargeFrameDeclaredPayloadSize = 0x7FFFFFFF; |
| +const char kMultipleFrames[] = "\x81\x01X\x81\x01Y\x81\x01Z"; |
| +const size_t kMultipleFramesSize = arraysize(kMultipleFrames) - 1; |
| +// This frame encodes a payload length of 7 in two bytes, which is always |
| +// invalid. |
| +const char kInvalidFrame[] = "\x81\x7E\x00\x07Invalid"; |
| +const size_t kInvalidFrameSize = arraysize(kInvalidFrame) - 1; |
| +const char kWriteFrame[] = "\x81\x85\x00\x00\x00\x00Write"; |
| +const size_t kWriteFrameSize = arraysize(kWriteFrame) - 1; |
| +const WebSocketMaskingKey kNulMaskingKey = {{'\0', '\0', '\0', '\0'}}; |
| + |
| +// Generates a ScopedVector<WebSocketFrameChunk> which will have a wire format |
| +// matching kWriteFrame. |
| +ScopedVector<WebSocketFrameChunk> GenerateWriteFrame() { |
| + scoped_ptr<WebSocketFrameChunk> chunk(new WebSocketFrameChunk); |
| + const size_t payload_size = |
| + kWriteFrameSize - (WebSocketFrameHeader::kBaseHeaderSize + |
| + WebSocketFrameHeader::kMaskingKeyLength); |
| + chunk->data = new IOBufferWithSize(payload_size); |
| + memcpy(chunk->data->data(), |
| + kWriteFrame + kWriteFrameSize - payload_size, |
| + payload_size); |
| + chunk->final_chunk = true; |
| + scoped_ptr<WebSocketFrameHeader> header( |
| + new WebSocketFrameHeader(WebSocketFrameHeader::kOpCodeText)); |
| + header->final = true; |
| + header->masked = true; |
| + header->payload_length = payload_size; |
| + chunk->header = header.Pass(); |
| + ScopedVector<WebSocketFrameChunk> chunks; |
| + chunks.push_back(chunk.release()); |
| + return chunks.Pass(); |
| +} |
| + |
| +// A masking key generator function which generates the identity mask, |
| +// ie. "\0\0\0\0". |
| +WebSocketMaskingKey GenerateNulMaskingKey() { return kNulMaskingKey; } |
| + |
| +// Base class for WebSocketBasicStream test fixtures. |
| +class WebSocketBasicStreamTest : public ::testing::Test { |
| + protected: |
| + scoped_ptr<WebSocketBasicStream> stream_; |
| + CapturingNetLog net_log_; |
| +}; |
| + |
| +// A fixture for tests which only perform normal socket operations. |
| +class WebSocketBasicStreamSocketTest : public WebSocketBasicStreamTest { |
| + protected: |
| + virtual ~WebSocketBasicStreamSocketTest() { |
| + // stream_ has a reference to socket_data_ (via MockTCPClientSocket) and so |
| + // should be destroyed first. |
| + stream_.reset(); |
| + } |
| + |
| + scoped_ptr<StreamSocket> MakeMockTCPClientSocket(MockRead reads[], |
| + size_t reads_count, |
| + MockWrite writes[], |
| + size_t writes_count) { |
| + // Nothing in WebSocketBasicStream should be caring about what the address |
| + // is. Set it to 8.8.8.8:80. |
| + AddressList address_list(IPEndPoint(IPAddressNumber(4, 8), 80)); |
| + socket_data_.reset( |
| + new StaticSocketDataProvider(reads, reads_count, writes, writes_count)); |
| + socket_data_->set_connect_data(MockConnect(SYNCHRONOUS, OK)); |
| + scoped_ptr<MockTCPClientSocket> socket( |
| + new MockTCPClientSocket(address_list, &net_log_, socket_data_.get())); |
| + CHECK_EQ(OK, socket->Connect(cb_.callback())); |
| + return socket.PassAs<StreamSocket>(); |
| + } |
| + |
| + scoped_ptr<ClientSocketHandle> MakeTransportSocket( |
| + scoped_ptr<StreamSocket> socket) { |
| + scoped_ptr<ClientSocketHandle> transport_socket(new ClientSocketHandle); |
| + transport_socket->SetSocket(socket.Pass()); |
| + return transport_socket.Pass(); |
| + } |
| + |
| + void SetHttpReadBuffer(const char* data, size_t size) { |
| + http_read_buffer_ = new GrowableIOBuffer; |
| + http_read_buffer_->SetCapacity(size); |
| + memcpy(http_read_buffer_->data(), data, size); |
| + http_read_buffer_->set_offset(size); |
| + } |
| + |
| + void CreateStream(MockRead reads[], |
| + size_t reads_count, |
| + MockWrite writes[], |
| + size_t writes_count) { |
| + stream_ = WebSocketBasicStream::CreateWebSocketBasicStreamForTesting( |
| + MakeTransportSocket( |
| + MakeMockTCPClientSocket(reads, reads_count, writes, writes_count)), |
| + http_read_buffer_, |
| + sub_protocol_, |
| + extensions_, |
| + &GenerateNulMaskingKey); |
| + } |
| + |
| + template <size_t N> |
| + void CreateReadOnly(MockRead (&reads)[N]) { |
| + CreateStream(reads, N, NULL, 0); |
| + } |
| + |
| + template <size_t N> |
| + void CreateWriteOnly(MockWrite (&writes)[N]) { |
| + CreateStream(NULL, 0, writes, N); |
| + } |
| + |
| + void CreateNullStream() { CreateStream(NULL, 0, NULL, 0); } |
| + |
| + scoped_ptr<SocketDataProvider> socket_data_; |
| + ScopedVector<WebSocketFrameChunk> frame_chunks_; |
| + TestCompletionCallback cb_; |
| + scoped_refptr<GrowableIOBuffer> http_read_buffer_; |
| + std::string sub_protocol_; |
| + std::string extensions_; |
| +}; |
| + |
| +TEST_F(WebSocketBasicStreamSocketTest, ConstructionWorks) { |
| + CreateNullStream(); |
| +} |
| + |
| +TEST_F(WebSocketBasicStreamSocketTest, SyncReadWorks) { |
| + MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize)}; |
| + CreateReadOnly(reads); |
| + int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); |
| + EXPECT_EQ(OK, result); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->header); |
| + EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); |
| + EXPECT_TRUE(frame_chunks_[0]->header->final); |
| + EXPECT_TRUE(frame_chunks_[0]->final_chunk); |
| +} |
| + |
| +TEST_F(WebSocketBasicStreamSocketTest, ASyncReadWorks) { |
| + MockRead reads[] = {MockRead(ASYNC, kSampleFrame, kSampleFrameSize)}; |
| + CreateReadOnly(reads); |
| + int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); |
| + ASSERT_EQ(ERR_IO_PENDING, result); |
| + EXPECT_EQ(OK, cb_.WaitForResult()); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->header); |
| + EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); |
| + // Don't repeat all the tests from SyncReadWorks; just enough to be sure the |
| + // frame was really read. |
| +} |
| + |
| +// ReadFrames will not return a frame whose header has not been wholly received. |
| +TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSync) { |
| + MockRead reads[] = { |
| + MockRead(SYNCHRONOUS, kSampleFrame, 1), |
| + MockRead(SYNCHRONOUS, kSampleFrame + 1, kSampleFrameSize - 1)}; |
| + CreateReadOnly(reads); |
| + int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); |
| + ASSERT_EQ(OK, result); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->header); |
| + EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); |
| +} |
| + |
| +// The same behaviour applies to asynchronous reads. |
| +TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedAsync) { |
| + MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1), |
| + MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; |
| + CreateReadOnly(reads); |
| + int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); |
| + ASSERT_EQ(ERR_IO_PENDING, result); |
| + EXPECT_EQ(OK, cb_.WaitForResult()); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->header); |
| + EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); |
| +} |
| + |
| +// If it receives an incomplete header in a synchronous call, then has to wait |
| +// for the rest of the frame, ReadFrames will return ERR_IO_PENDING. |
| +TEST_F(WebSocketBasicStreamSocketTest, HeaderFragmentedSyncAsync) { |
| + MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, 1), |
| + MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; |
| + CreateReadOnly(reads); |
| + int result = stream_->ReadFrames(&frame_chunks_, cb_.callback()); |
| + ASSERT_EQ(ERR_IO_PENDING, result); |
| + EXPECT_EQ(OK, cb_.WaitForResult()); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->header); |
| + EXPECT_EQ(GG_UINT64_C(6), frame_chunks_[0]->header->payload_length); |
| +} |
| + |
| +// An extended header should also return ERR_IO_PENDING if it is not completely |
| +// received. |
| +TEST_F(WebSocketBasicStreamSocketTest, FragmentedLargeHeader) { |
| + MockRead reads[] = { |
| + MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize - 1), |
| + MockRead(SYNCHRONOUS, ERR_IO_PENDING)}; |
| + CreateReadOnly(reads); |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| +} |
| + |
| +// A frame that does not arrive in a single read should arrive in chunks. |
| +TEST_F(WebSocketBasicStreamSocketTest, LargeFrameFirstChunk) { |
| + MockRead reads[] = { |
| + MockRead(SYNCHRONOUS, kPartialLargeFrame, kPartialLargeFrameSize)}; |
| + CreateReadOnly(reads); |
| + EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->header); |
| + EXPECT_EQ(kLargeFrameDeclaredPayloadSize, |
| + frame_chunks_[0]->header->payload_length); |
| + EXPECT_TRUE(frame_chunks_[0]->header->final); |
| + EXPECT_FALSE(frame_chunks_[0]->final_chunk); |
| + EXPECT_EQ(kPartialLargeFrameSize - kLargeFrameHeaderSize, |
| + static_cast<size_t>(frame_chunks_[0]->data->size())); |
| +} |
| + |
| +// If only the header arrives, we should get a zero-byte chunk. |
| +TEST_F(WebSocketBasicStreamSocketTest, HeaderOnlyChunk) { |
| + MockRead reads[] = { |
| + MockRead(SYNCHRONOUS, kPartialLargeFrame, kLargeFrameHeaderSize)}; |
| + CreateReadOnly(reads); |
| + EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + EXPECT_FALSE(frame_chunks_[0]->final_chunk); |
| + EXPECT_TRUE(frame_chunks_[0]->data.get() == NULL); |
| +} |
| + |
| +// The second and subsequent chunks of a frame have no header. |
| +TEST_F(WebSocketBasicStreamSocketTest, LargeFrameTwoChunks) { |
| + static const size_t kChunkSize = 16; |
| + MockRead reads[] = { |
| + MockRead(ASYNC, kPartialLargeFrame, kChunkSize), |
| + MockRead(ASYNC, kPartialLargeFrame + kChunkSize, kChunkSize)}; |
| + CreateReadOnly(reads); |
| + TestCompletionCallback cb[2]; |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb[0].callback())); |
| + EXPECT_EQ(OK, cb[0].WaitForResult()); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->header); |
| + |
| + frame_chunks_.clear(); |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb[1].callback())); |
| + EXPECT_EQ(OK, cb[1].WaitForResult()); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_FALSE(frame_chunks_[0]->header); |
| +} |
| + |
| +// Only the final chunk of a frame has final_chunk set. |
| +TEST_F(WebSocketBasicStreamSocketTest, OnlyFinalChunkIsFinal) { |
| + static const size_t kFirstChunkSize = 4; |
| + MockRead reads[] = {MockRead(ASYNC, kSampleFrame, kFirstChunkSize), |
| + MockRead(ASYNC, |
| + kSampleFrame + kFirstChunkSize, |
| + kSampleFrameSize - kFirstChunkSize)}; |
| + CreateReadOnly(reads); |
| + TestCompletionCallback cb[2]; |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb[0].callback())); |
| + EXPECT_EQ(OK, cb[0].WaitForResult()); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_FALSE(frame_chunks_[0]->final_chunk); |
| + |
| + frame_chunks_.clear(); |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb[1].callback())); |
| + EXPECT_EQ(OK, cb[1].WaitForResult()); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->final_chunk); |
| +} |
| + |
| +// Multiple frames that arrive together should be parsed correctly. |
| +TEST_F(WebSocketBasicStreamSocketTest, ThreeFramesTogether) { |
| + MockRead reads[] = { |
| + MockRead(SYNCHRONOUS, kMultipleFrames, kMultipleFramesSize)}; |
| + CreateReadOnly(reads); |
| + |
| + ASSERT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + ASSERT_EQ(3U, frame_chunks_.size()); |
| + EXPECT_TRUE(frame_chunks_[0]->final_chunk); |
| + EXPECT_TRUE(frame_chunks_[1]->final_chunk); |
| + EXPECT_TRUE(frame_chunks_[2]->final_chunk); |
| +} |
| + |
| +// ERR_CONNECTION_CLOSED must be returned on close. |
| +TEST_F(WebSocketBasicStreamSocketTest, SyncClose) { |
| + MockRead reads[] = {MockRead(SYNCHRONOUS, "", 0)}; |
| + CreateReadOnly(reads); |
| + |
| + EXPECT_EQ(ERR_CONNECTION_CLOSED, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| +} |
| + |
| +TEST_F(WebSocketBasicStreamSocketTest, ASyncClose) { |
| + MockRead reads[] = {MockRead(ASYNC, "", 0)}; |
| + CreateReadOnly(reads); |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
| +} |
| + |
| +// The result should be the same if the socket returns ERR_CONNECTION_CLOSED |
| +TEST_F(WebSocketBasicStreamSocketTest, SyncCloseWithErr) { |
| + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)}; |
| + CreateReadOnly(reads); |
| + |
| + EXPECT_EQ(ERR_CONNECTION_CLOSED, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| +} |
| + |
| +TEST_F(WebSocketBasicStreamSocketTest, ASyncCloseWithErr) { |
|
tyoshino (SeeGerritForStatus)
2013/08/22 07:56:10
ASync -> Async
Adam Rice
2013/08/22 08:13:04
Done (and the other places).
|
| + MockRead reads[] = {MockRead(ASYNC, ERR_CONNECTION_CLOSED)}; |
| + CreateReadOnly(reads); |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + EXPECT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
| +} |
| + |
| +// If we get a frame followed by a close, we should receive them separately. |
| +TEST_F(WebSocketBasicStreamSocketTest, CloseAfterFrame) { |
| + MockRead reads[] = {MockRead(SYNCHRONOUS, kSampleFrame, kSampleFrameSize), |
| + MockRead(SYNCHRONOUS, "", 0)}; |
| + CreateReadOnly(reads); |
| + |
| + EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + EXPECT_EQ(1U, frame_chunks_.size()); |
| + frame_chunks_.clear(); |
| + EXPECT_EQ(ERR_CONNECTION_CLOSED, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| +} |
| + |
| +// Synchronous close after an async frame header is handled by a different code |
| +// path. |
| +TEST_F(WebSocketBasicStreamSocketTest, AsyncCloseAfterIncompleteHeader) { |
| + MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), |
| + MockRead(SYNCHRONOUS, "", 0)}; |
| + CreateReadOnly(reads); |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + ASSERT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
| +} |
| + |
| +// When Stream::Read returns ERR_CONNECTION_CLOSED we get the same result via a |
| +// slightly different code path. |
| +TEST_F(WebSocketBasicStreamSocketTest, AsyncErrCloseAfterIncompleteHeader) { |
| + MockRead reads[] = {MockRead(ASYNC, kSampleFrame, 1U), |
| + MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED)}; |
| + CreateReadOnly(reads); |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + ASSERT_EQ(ERR_CONNECTION_CLOSED, cb_.WaitForResult()); |
| +} |
| + |
| +// If there was a frame read at the same time as the response headers (and the |
| +// handshake succeeded), then we should parse it. |
| +TEST_F(WebSocketBasicStreamSocketTest, HttpReadBufferIsUsed) { |
| + SetHttpReadBuffer(kSampleFrame, kSampleFrameSize); |
| + CreateNullStream(); |
| + |
| + EXPECT_EQ(OK, stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->data); |
| + EXPECT_EQ(6, frame_chunks_[0]->data->size()); |
| +} |
| + |
| +// Check that a frame whose header partially arrived at the end of the response |
| +// headers works correctly. |
| +TEST_F(WebSocketBasicStreamSocketTest, PartialFrameHeaderInHttpResponse) { |
| + SetHttpReadBuffer(kSampleFrame, 1); |
| + MockRead reads[] = {MockRead(ASYNC, kSampleFrame + 1, kSampleFrameSize - 1)}; |
| + CreateReadOnly(reads); |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + EXPECT_EQ(OK, cb_.WaitForResult()); |
| + ASSERT_EQ(1U, frame_chunks_.size()); |
| + ASSERT_TRUE(frame_chunks_[0]->data); |
| + EXPECT_EQ(6, frame_chunks_[0]->data->size()); |
| + ASSERT_TRUE(frame_chunks_[0]->header); |
| + EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, |
| + frame_chunks_[0]->header->opcode); |
| +} |
| + |
| +// Check that an invalid frame results in an error. |
| +TEST_F(WebSocketBasicStreamSocketTest, SyncInvalidFrame) { |
| + MockRead reads[] = {MockRead(SYNCHRONOUS, kInvalidFrame, kInvalidFrameSize)}; |
| + CreateReadOnly(reads); |
| + |
| + EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| +} |
| + |
| +TEST_F(WebSocketBasicStreamSocketTest, ASyncInvalidFrame) { |
| + MockRead reads[] = {MockRead(ASYNC, kInvalidFrame, kInvalidFrameSize)}; |
| + CreateReadOnly(reads); |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->ReadFrames(&frame_chunks_, cb_.callback())); |
| + EXPECT_EQ(ERR_WS_PROTOCOL_ERROR, cb_.WaitForResult()); |
| +} |
| + |
| +// Check that writing a frame all at once works. |
| +TEST_F(WebSocketBasicStreamSocketTest, WriteAtOnce) { |
| + MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, kWriteFrameSize)}; |
| + CreateWriteOnly(writes); |
| + frame_chunks_ = GenerateWriteFrame(); |
| + |
| + EXPECT_EQ(OK, stream_->WriteFrames(&frame_chunks_, cb_.callback())); |
| +} |
| + |
| +// Check that completely async writing works. |
| +TEST_F(WebSocketBasicStreamSocketTest, AsyncWriteAtOnce) { |
| + MockWrite writes[] = {MockWrite(ASYNC, kWriteFrame, kWriteFrameSize)}; |
| + CreateWriteOnly(writes); |
| + frame_chunks_ = GenerateWriteFrame(); |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->WriteFrames(&frame_chunks_, cb_.callback())); |
| + EXPECT_EQ(OK, cb_.WaitForResult()); |
| +} |
| + |
| +// Check that writing a frame to an extremely full kernel buffer (so that it |
| +// ends up being sent in bits) works. The WriteFrames() callback should not be |
| +// called until all parts have been written. |
| +TEST_F(WebSocketBasicStreamSocketTest, WriteInBits) { |
| + MockWrite writes[] = {MockWrite(SYNCHRONOUS, kWriteFrame, 4), |
| + MockWrite(ASYNC, kWriteFrame + 4, 4), |
| + MockWrite(ASYNC, kWriteFrame + 8, kWriteFrameSize - 8)}; |
| + CreateWriteOnly(writes); |
| + frame_chunks_ = GenerateWriteFrame(); |
| + |
| + ASSERT_EQ(ERR_IO_PENDING, |
| + stream_->WriteFrames(&frame_chunks_, cb_.callback())); |
| + EXPECT_EQ(OK, cb_.WaitForResult()); |
| +} |
| + |
| +TEST_F(WebSocketBasicStreamSocketTest, GetExtensionsWorks) { |
| + extensions_ = "inflate-uuencode"; |
| + CreateNullStream(); |
| + |
| + EXPECT_EQ("inflate-uuencode", stream_->GetExtensions()); |
| +} |
| + |
| +TEST_F(WebSocketBasicStreamSocketTest, GetSubProtocolWorks) { |
| + sub_protocol_ = "cyberchat"; |
| + CreateNullStream(); |
| + |
| + EXPECT_EQ("cyberchat", stream_->GetSubProtocol()); |
| +} |
| + |
| +} // namespace |
| +} // namespace net |