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 |