Chromium Code Reviews| Index: extensions/browser/api/cast_channel/cast_transport_unittest.cc |
| diff --git a/extensions/browser/api/cast_channel/cast_transport_unittest.cc b/extensions/browser/api/cast_channel/cast_transport_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..c1a86cbdc2131229e01b34c8de0e0d5a90735e59 |
| --- /dev/null |
| +++ b/extensions/browser/api/cast_channel/cast_transport_unittest.cc |
| @@ -0,0 +1,654 @@ |
| +// Copyright 2014 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 "extensions/browser/api/cast_channel/cast_transport.h" |
| + |
| +#include <stddef.h> |
| +#include <queue> |
| + |
| +#include "base/test/simple_test_tick_clock.h" |
| +#include "extensions/browser/api/cast_channel/cast_channel.pb.h" |
| +#include "extensions/browser/api/cast_channel/cast_framer.h" |
| +#include "extensions/browser/api/cast_channel/cast_transport.h" |
| +#include "extensions/browser/api/cast_channel/logger.h" |
| +#include "extensions/browser/api/cast_channel/logger_util.h" |
| +#include "net/base/capturing_net_log.h" |
| +#include "net/base/completion_callback.h" |
| +#include "net/base/net_errors.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +using testing::_; |
| +using testing::DoAll; |
| +using testing::InSequence; |
| +using testing::Invoke; |
| +using testing::NotNull; |
| +using testing::Return; |
| +using testing::WithArg; |
| + |
| +namespace extensions { |
| +namespace core_api { |
| +namespace cast_channel { |
| +namespace { |
| +// Mockable placeholder for write completion events. |
| +class CompleteHandler { |
| + public: |
| + CompleteHandler() {} |
| + MOCK_METHOD1(Complete, void(int result)); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(CompleteHandler); |
| +}; |
| + |
| +// Creates a CastMessage proto with the bare minimum required fields set. |
| +CastMessage CreateCastMessage() { |
| + CastMessage output; |
| + output.set_protocol_version(CastMessage::CASTV2_1_0); |
| + output.set_namespace_("x"); |
| + output.set_source_id("source"); |
| + output.set_destination_id("destination"); |
| + output.set_payload_type(CastMessage::STRING); |
| + output.set_payload_utf8("payload"); |
| + return output; |
| +} |
| + |
| +// FIFO queue of completion callbacks. Outstanding write operations are |
| +// Push()ed into the queue. Callback completion is simulated by invoking |
| +// Pop() in the same order as Push(). |
| +class CompletionQueue { |
| + public: |
| + CompletionQueue() {} |
| + ~CompletionQueue() { CHECK_EQ(0u, cb_queue_.size()); } |
| + |
| + // Enqueues a pending completion callback. |
| + void Push(const net::CompletionCallback& cb) { cb_queue_.push(cb); } |
| + // Runs the next callback and removes it from the queue. |
| + void Pop(int rv) { |
| + CHECK_GT(cb_queue_.size(), 0u); |
| + cb_queue_.front().Run(rv); |
| + cb_queue_.pop(); |
| + } |
| + |
| + private: |
| + std::queue<net::CompletionCallback> cb_queue_; |
| + DISALLOW_COPY_AND_ASSIGN(CompletionQueue); |
| +}; |
| + |
| +// GMock action that reads data from an IOBuffer and writes it to a string |
| +// variable. |
| +// |
| +// buf_idx (template parameter 0): 0-based index of the net::IOBuffer |
| +// in the function mock arg list. |
| +// size_idx (template parameter 1): 0-based index of the byte count arg. |
| +// str: pointer to the string which will receive data from the buffer. |
| +ACTION_TEMPLATE(ReadBufferToString, |
| + HAS_2_TEMPLATE_PARAMS(int, buf_idx, int, size_idx), |
| + AND_1_VALUE_PARAMS(str)) { |
| + str->assign(testing::get<buf_idx>(args)->data(), |
| + testing::get<size_idx>(args)); |
| +} |
| + |
| +// GMock action that writes data from a string to an IOBuffer. |
| +// |
| +// buf_idx (template parameter 0): 0-based index of the IOBuffer arg. |
| +// str: the string containing data to be written to the IOBuffer. |
| +ACTION_TEMPLATE(FillBufferFromString, |
| + HAS_1_TEMPLATE_PARAMS(int, buf_idx), |
| + AND_1_VALUE_PARAMS(str)) { |
| + memcpy(testing::get<buf_idx>(args)->data(), str.data(), str.size()); |
| +} |
| + |
| +// Checks if two proto messages are the same. |
| +// From |
| +// third_party/cacheinvalidation/overrides/google/cacheinvalidation/deps/gmock.h |
| +MATCHER_P(EqualsProto, message, "") { |
| + std::string expected_serialized, actual_serialized; |
| + message.SerializeToString(&expected_serialized); |
| + arg.SerializeToString(&actual_serialized); |
| + return expected_serialized == actual_serialized; |
| +} |
| +} // namespace |
| + |
| +class MockCastTransportDelegate : public CastTransport::Delegate { |
| + public: |
| + MOCK_METHOD3(OnError, |
| + void(const CastSocketPlaceholder* socket, |
| + ChannelError error, |
| + const LastErrors& last_errors)); |
| + MOCK_METHOD2(OnMessage, |
| + void(const CastSocketPlaceholder* socket, |
| + const CastMessage& message)); |
| +}; |
| + |
| +class MockCastSocket : public CastSocketPlaceholder { |
| + public: |
| + MockCastSocket() { |
| + net::IPAddressNumber number; |
| + number.push_back(192); |
| + number.push_back(0); |
| + number.push_back(0); |
| + number.push_back(1); |
| + ip_ = net::IPEndPoint(number, 8009); |
| + } |
| + |
| + virtual ~MockCastSocket() {} |
| + |
| + // The IP endpoint for the destination of the channel. |
| + virtual const net::IPEndPoint& ip_endpoint() const OVERRIDE { return ip_; } |
| + |
| + // The authentication level requested for the channel. |
| + virtual ChannelAuthType channel_auth() const OVERRIDE { |
| + return CHANNEL_AUTH_TYPE_SSL_VERIFIED; |
| + } |
| + |
| + virtual int id() const OVERRIDE { return 1; } |
| + |
| + MOCK_METHOD3(Write, |
| + int(net::IOBuffer* buffer, |
| + size_t size, |
| + const net::CompletionCallback& callback)); |
| + MOCK_METHOD3(Read, |
| + int(net::IOBuffer* buf, |
| + int buf_len, |
| + const net::CompletionCallback& callback)); |
| + MOCK_METHOD1(CloseWithError, void(ChannelError error)); |
| + |
| + protected: |
| + virtual void CloseInternal() {} |
| + |
| + private: |
| + net::IPEndPoint ip_; |
| + net::CapturingNetLog capturing_net_log_; |
| +}; |
| + |
| +class CastTransportTest : public testing::Test { |
| + public: |
| + CastTransportTest() |
| + : logger_(new Logger( |
| + scoped_ptr<base::TickClock>(new base::SimpleTestTickClock), |
| + base::TimeTicks())) { |
| + transport_.reset(new CastTransport(&mock_socket_, &delegate_, logger_)); |
| + } |
| + virtual ~CastTransportTest() {} |
| + |
| + protected: |
| + MockCastTransportDelegate delegate_; |
| + MockCastSocket mock_socket_; |
| + scoped_refptr<Logger> logger_; |
| + scoped_ptr<CastTransport> transport_; |
| +}; |
| + |
| +// ---------------------------------------------------------------------------- |
| +// Asynchronous write tests |
| +TEST_F(CastTransportTest, TestFullWriteAsync) { |
| + CompletionQueue socket_cbs; |
| + CompleteHandler write_handler; |
| + std::string output; |
| + |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + EXPECT_CALL(mock_socket_, Write(NotNull(), serialized_message.size(), _)) |
| + .WillOnce(DoAll(ReadBufferToString<0, 1>(&output), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
|
mark a. foltz
2014/09/12 19:41:01
The pattern of pushing a completion callback on th
Kevin M
2014/09/12 20:22:25
Done.
|
| + Return(net::ERR_IO_PENDING))); |
| + EXPECT_CALL(write_handler, Complete(net::OK)); |
| + transport_->SendMessage( |
| + message, |
| + base::Bind(&CompleteHandler::Complete, base::Unretained(&write_handler))); |
| + socket_cbs.Pop(serialized_message.size()); |
| + EXPECT_EQ(serialized_message, output); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestPartialWritesAsync) { |
| + InSequence seq; |
| + CompletionQueue socket_cbs; |
| + CompleteHandler write_handler; |
| + std::string output; |
| + |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Only one byte is written. |
| + EXPECT_CALL(mock_socket_, Write(NotNull(), serialized_message.size(), _)) |
| + .WillOnce(DoAll(ReadBufferToString<0, 1>(&output), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))); |
| + // Remainder of bytes are written. |
| + EXPECT_CALL(mock_socket_, Write(NotNull(), serialized_message.size() - 1, _)) |
| + .WillOnce(DoAll(ReadBufferToString<0, 1>(&output), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))); |
| + |
| + transport_->SendMessage( |
| + message, |
| + base::Bind(&CompleteHandler::Complete, base::Unretained(&write_handler))); |
| + EXPECT_EQ(serialized_message, output); |
| + socket_cbs.Pop(1); |
| + |
| + EXPECT_CALL(write_handler, Complete(net::OK)); |
| + socket_cbs.Pop(serialized_message.size() - 1); |
| + EXPECT_EQ(serialized_message.substr(1, serialized_message.size() - 1), |
| + output); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestWriteFailureAsync) { |
| + CompletionQueue socket_cbs; |
| + CompleteHandler write_handler; |
| + CastMessage message = CreateCastMessage(); |
| + EXPECT_CALL(mock_socket_, Write(NotNull(), _, _)) |
| + .WillOnce(DoAll(WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))); |
| + EXPECT_CALL(write_handler, Complete(net::ERR_FAILED)); |
| + transport_->SendMessage( |
| + message, |
| + base::Bind(&CompleteHandler::Complete, base::Unretained(&write_handler))); |
| + socket_cbs.Pop(net::ERR_CONNECTION_RESET); |
| +} |
| + |
| +// ---------------------------------------------------------------------------- |
| +// Synchronous write tests |
| +TEST_F(CastTransportTest, TestFullWriteSync) { |
| + CompleteHandler write_handler; |
| + std::string output; |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + EXPECT_CALL(mock_socket_, Write(NotNull(), serialized_message.size(), _)) |
| + .WillOnce(DoAll(ReadBufferToString<0, 1>(&output), |
| + Return(serialized_message.size()))); |
| + EXPECT_CALL(write_handler, Complete(net::OK)); |
| + transport_->SendMessage( |
| + message, |
| + base::Bind(&CompleteHandler::Complete, base::Unretained(&write_handler))); |
| + EXPECT_EQ(serialized_message, output); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestPartialWritesSync) { |
| + InSequence seq; |
| + CompleteHandler write_handler; |
| + std::string output; |
| + |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Only one byte is written. |
| + EXPECT_CALL(mock_socket_, Write(NotNull(), serialized_message.size(), _)) |
| + .WillOnce(DoAll(ReadBufferToString<0, 1>(&output), Return(1))); |
| + // Remainder of bytes are written. |
| + EXPECT_CALL(mock_socket_, Write(NotNull(), serialized_message.size() - 1, _)) |
| + .WillOnce(DoAll(ReadBufferToString<0, 1>(&output), |
| + Return(serialized_message.size() - 1))); |
| + |
| + EXPECT_CALL(write_handler, Complete(net::OK)); |
| + transport_->SendMessage( |
| + message, |
| + base::Bind(&CompleteHandler::Complete, base::Unretained(&write_handler))); |
| + EXPECT_EQ(serialized_message.substr(1, serialized_message.size() - 1), |
| + output); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestWriteFailureSync) { |
| + CompleteHandler write_handler; |
| + CastMessage message = CreateCastMessage(); |
| + EXPECT_CALL(mock_socket_, Write(NotNull(), _, _)) |
| + .WillOnce(Return(net::ERR_CONNECTION_RESET)); |
| + EXPECT_CALL(write_handler, Complete(net::ERR_FAILED)); |
| + transport_->SendMessage( |
| + message, |
| + base::Bind(&CompleteHandler::Complete, base::Unretained(&write_handler))); |
| +} |
| + |
| +// ---------------------------------------------------------------------------- |
| +// Asynchronous read tests |
| +TEST_F(CastTransportTest, TestFullReadAsync) { |
| + CompletionQueue socket_cbs; |
| + |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
|
mark a. foltz
2014/09/12 19:41:01
What does this call do? Not familiar with it.
Kevin M
2014/09/12 20:22:25
It makes Gmock respect cardinality limits when eva
|
| + // Read bytes [4, n]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size(), |
| + _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + MessageFramer::MessageHeader::header_size(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size())), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
| + |
| + EXPECT_CALL(delegate_, OnMessage(&mock_socket_, EqualsProto(message))); |
| + transport_->StartReadLoop(); |
| + socket_cbs.Pop(MessageFramer::MessageHeader::header_size()); |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(Return(net::ERR_IO_PENDING)); |
| + socket_cbs.Pop(serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size()); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestPartialReadAsync) { |
| + CompletionQueue socket_cbs; |
| + |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
| + // Read bytes [4, n-1]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size(), |
| + _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + MessageFramer::MessageHeader::header_size(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size() - 1)), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
| + // Read final byte. |
| + EXPECT_CALL(mock_socket_, Read(NotNull(), 1, _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + serialized_message.size() - 1, 1)), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
| + |
| + EXPECT_CALL(delegate_, OnMessage(&mock_socket_, EqualsProto(message))); |
| + transport_->StartReadLoop(); |
| + socket_cbs.Pop(MessageFramer::MessageHeader::header_size()); |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(Return(net::ERR_IO_PENDING)); |
| + socket_cbs.Pop(serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size() - 1); |
| + socket_cbs.Pop(1); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestReadErrorInHeaderAsync) { |
| + CompletionQueue socket_cbs; |
| + |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
| + |
| + EXPECT_CALL(delegate_, |
| + OnError(&mock_socket_, CHANNEL_ERROR_TRANSPORT_ERROR, _)); |
| + EXPECT_CALL(mock_socket_, CloseWithError(CHANNEL_ERROR_TRANSPORT_ERROR)); |
| + transport_->StartReadLoop(); |
| + // Header read failure. |
| + socket_cbs.Pop(net::ERR_CONNECTION_RESET); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestReadErrorInBodyAsync) { |
| + CompletionQueue socket_cbs; |
| + |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
| + // Read bytes [4, n-1]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size(), |
| + _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + MessageFramer::MessageHeader::header_size(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size() - 1)), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
| + |
| + EXPECT_CALL(delegate_, |
| + OnError(&mock_socket_, CHANNEL_ERROR_TRANSPORT_ERROR, _)); |
| + transport_->StartReadLoop(); |
| + // Header read is OK. |
| + socket_cbs.Pop(MessageFramer::MessageHeader::header_size()); |
| + EXPECT_CALL(mock_socket_, CloseWithError(CHANNEL_ERROR_TRANSPORT_ERROR)); |
| + // Body read fails. |
| + socket_cbs.Pop(net::ERR_CONNECTION_RESET); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestReadCorruptedMessageAsync) { |
| + CompletionQueue socket_cbs; |
| + |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Corrupt the serialized message body(set it to X's). |
| + for (size_t i = MessageFramer::MessageHeader::header_size(); |
| + i < serialized_message.size(); |
| + ++i) { |
| + serialized_message[i] = 'x'; |
| + } |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
| + // Read bytes [4, n]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size(), |
| + _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + MessageFramer::MessageHeader::header_size(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size() - 1)), |
| + WithArg<2>(Invoke(&socket_cbs, &CompletionQueue::Push)), |
| + Return(net::ERR_IO_PENDING))) |
| + .RetiresOnSaturation(); |
| + |
| + EXPECT_CALL(delegate_, |
| + OnError(&mock_socket_, CHANNEL_ERROR_INVALID_MESSAGE, _)); |
| + transport_->StartReadLoop(); |
| + socket_cbs.Pop(MessageFramer::MessageHeader::header_size()); |
| + EXPECT_CALL(mock_socket_, CloseWithError(CHANNEL_ERROR_INVALID_MESSAGE)); |
| + socket_cbs.Pop(serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size()); |
| +} |
| + |
| +// ---------------------------------------------------------------------------- |
| +// Synchronous read tests |
| +TEST_F(CastTransportTest, TestFullReadSync) { |
| + InSequence s; |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + Return(MessageFramer::MessageHeader::header_size()))) |
| + .RetiresOnSaturation(); |
| + // Read bytes [4, n]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size(), |
| + _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + MessageFramer::MessageHeader::header_size(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size())), |
| + Return(serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size()))) |
| + .RetiresOnSaturation(); |
| + EXPECT_CALL(delegate_, OnMessage(&mock_socket_, EqualsProto(message))); |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(Return(net::ERR_IO_PENDING)); |
| + transport_->StartReadLoop(); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestPartialReadSync) { |
| + InSequence s; |
| + |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + Return(MessageFramer::MessageHeader::header_size()))) |
| + .RetiresOnSaturation(); |
| + // Read bytes [4, n-1]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size(), |
| + _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + MessageFramer::MessageHeader::header_size(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size() - 1)), |
| + Return(serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size() - 1))) |
| + .RetiresOnSaturation(); |
| + // Read final byte. |
| + EXPECT_CALL(mock_socket_, Read(NotNull(), 1, _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + serialized_message.size() - 1, 1)), |
| + Return(1))) |
| + .RetiresOnSaturation(); |
| + EXPECT_CALL(delegate_, OnMessage(&mock_socket_, EqualsProto(message))); |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(Return(net::ERR_IO_PENDING)); |
| + transport_->StartReadLoop(); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestReadErrorInHeaderSync) { |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + Return(net::ERR_CONNECTION_RESET))) |
| + .RetiresOnSaturation(); |
| + EXPECT_CALL(delegate_, |
| + OnError(&mock_socket_, CHANNEL_ERROR_TRANSPORT_ERROR, _)); |
| + EXPECT_CALL(mock_socket_, CloseWithError(CHANNEL_ERROR_TRANSPORT_ERROR)); |
| + transport_->StartReadLoop(); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestReadErrorInBodySync) { |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + Return(MessageFramer::MessageHeader::header_size()))) |
| + .RetiresOnSaturation(); |
| + // Read bytes [4, n-1]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size(), |
| + _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + MessageFramer::MessageHeader::header_size(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size() - 1)), |
| + Return(net::ERR_CONNECTION_RESET))) |
| + .RetiresOnSaturation(); |
| + EXPECT_CALL(delegate_, |
| + OnError(&mock_socket_, CHANNEL_ERROR_TRANSPORT_ERROR, _)); |
| + EXPECT_CALL(mock_socket_, CloseWithError(CHANNEL_ERROR_TRANSPORT_ERROR)); |
| + transport_->StartReadLoop(); |
| +} |
| + |
| +TEST_F(CastTransportTest, TestReadCorruptedMessageSync) { |
| + CastMessage message = CreateCastMessage(); |
| + std::string serialized_message; |
| + EXPECT_TRUE(MessageFramer::Serialize(message, &serialized_message)); |
| + |
| + // Corrupt the serialized message body(set it to X's). |
| + for (size_t i = MessageFramer::MessageHeader::header_size(); |
| + i < serialized_message.size(); |
| + ++i) { |
| + serialized_message[i] = 'x'; |
| + } |
| + |
| + // Read bytes [0, 3]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), MessageFramer::MessageHeader::header_size(), _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message), |
| + Return(MessageFramer::MessageHeader::header_size()))) |
| + .RetiresOnSaturation(); |
| + // Read bytes [4, n]. |
| + EXPECT_CALL(mock_socket_, |
| + Read(NotNull(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size(), |
| + _)) |
| + .WillOnce(DoAll(FillBufferFromString<0>(serialized_message.substr( |
| + MessageFramer::MessageHeader::header_size(), |
| + serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size() - 1)), |
| + Return(serialized_message.size() - |
| + MessageFramer::MessageHeader::header_size()))) |
| + .RetiresOnSaturation(); |
| + EXPECT_CALL(delegate_, |
| + OnError(&mock_socket_, CHANNEL_ERROR_INVALID_MESSAGE, _)); |
| + EXPECT_CALL(mock_socket_, CloseWithError(CHANNEL_ERROR_INVALID_MESSAGE)); |
| + transport_->StartReadLoop(); |
| +} |
| +} // namespace cast_channel |
| +} // namespace core_api |
| +} // namespace extensions |