Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Unified Diff: net/websockets/websocket_basic_stream_test.cc

Issue 18792002: WebSocketBasicStream framing logic (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Remove "We" from comment. Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/websockets/websocket_basic_stream.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..ec2e51a6d0ffb7e7a71897b260ad86bee26d1f84
--- /dev/null
+++ b/net/websockets/websocket_basic_stream_test.cc
@@ -0,0 +1,513 @@
+// 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 "base/port.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 {
+
+// TODO(ricea): Add tests for
+// - Empty frames (data & control)
+// - Non-NULL masking key
+// - A frame larger than kReadBufferSize;
+
+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:
+ WebSocketBasicStreamSocketTest()
+ : histograms_("a"), pool_(1, 1, &histograms_, &factory_) {}
+
+ virtual ~WebSocketBasicStreamSocketTest() {
+ // stream_ has a reference to socket_data_ (via MockTCPClientSocket) and so
+ // should be destroyed first.
+ stream_.reset();
+ }
+
+ scoped_ptr<ClientSocketHandle> MakeTransportSocket(MockRead reads[],
+ size_t reads_count,
+ MockWrite writes[],
+ size_t writes_count) {
+ socket_data_.reset(
+ new StaticSocketDataProvider(reads, reads_count, writes, writes_count));
+ socket_data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
+ factory_.AddSocketDataProvider(socket_data_.get());
+
+ scoped_ptr<ClientSocketHandle> transport_socket(new ClientSocketHandle);
+ scoped_refptr<MockTransportSocketParams> params;
+ transport_socket->Init("a",
+ params,
+ MEDIUM,
+ CompletionCallback(),
+ &pool_,
+ bound_net_log_.bound());
+ 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(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_;
+ MockClientSocketFactory factory_;
+ ClientSocketPoolHistograms histograms_;
+ MockTransportClientSocketPool pool_;
+ CapturingBoundNetLog(bound_net_log_);
+ 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. This is not expected to happen on an established
+// connection; a Read of size 0 is the expected behaviour. The key point of this
+// test is to confirm that ReadFrames() behaviour is identical in both cases.
+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) {
+ 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());
+}
+
+TEST_F(WebSocketBasicStreamSocketTest, SyncErrorsPassedThrough) {
+ // ERR_INSUFFICIENT_RESOURCES here represents an arbitrary error that
+ // WebSocketBasicStream gives no special handling to.
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_INSUFFICIENT_RESOURCES)};
+ CreateReadOnly(reads);
+
+ EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES,
+ stream_->ReadFrames(&frame_chunks_, cb_.callback()));
+}
+
+TEST_F(WebSocketBasicStreamSocketTest, AsyncErrorsPassedThrough) {
+ MockRead reads[] = {MockRead(ASYNC, ERR_INSUFFICIENT_RESOURCES)};
+ CreateReadOnly(reads);
+
+ ASSERT_EQ(ERR_IO_PENDING,
+ stream_->ReadFrames(&frame_chunks_, cb_.callback()));
+ EXPECT_EQ(ERR_INSUFFICIENT_RESOURCES, 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
« no previous file with comments | « net/websockets/websocket_basic_stream.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698