| Index: extensions/browser/api/cast_channel/cast_socket_unittest.cc
|
| diff --git a/extensions/browser/api/cast_channel/cast_socket_unittest.cc b/extensions/browser/api/cast_channel/cast_socket_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bbd47674826a99dd24f0d33787ed300dfb7a6bf1
|
| --- /dev/null
|
| +++ b/extensions/browser/api/cast_channel/cast_socket_unittest.cc
|
| @@ -0,0 +1,794 @@
|
| +// 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_socket.h"
|
| +
|
| +#include <stdint.h>
|
| +
|
| +#include <utility>
|
| +#include <vector>
|
| +
|
| +#include "base/location.h"
|
| +#include "base/macros.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/memory/weak_ptr.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/single_thread_task_runner.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/sys_byteorder.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| +#include "base/timer/mock_timer.h"
|
| +#include "extensions/browser/api/cast_channel/cast_auth_util.h"
|
| +#include "extensions/browser/api/cast_channel/cast_framer.h"
|
| +#include "extensions/browser/api/cast_channel/cast_message_util.h"
|
| +#include "extensions/browser/api/cast_channel/cast_test_util.h"
|
| +#include "extensions/browser/api/cast_channel/cast_transport.h"
|
| +#include "extensions/browser/api/cast_channel/logger.h"
|
| +#include "extensions/common/api/cast_channel/cast_channel.pb.h"
|
| +#include "extensions/common/api/cast_channel/logging.pb.h"
|
| +#include "net/base/address_list.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/log/test_net_log.h"
|
| +#include "net/socket/socket_test_util.h"
|
| +#include "net/socket/ssl_client_socket.h"
|
| +#include "net/socket/tcp_client_socket.h"
|
| +#include "net/ssl/ssl_info.h"
|
| +#include "net/test/cert_test_util.h"
|
| +#include "net/test/test_data_directory.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +const int64_t kDistantTimeoutMillis = 100000; // 100 seconds (never hit).
|
| +
|
| +using ::cast_channel::ChannelError;
|
| +using ::cast_channel::ChannelAuthType;
|
| +using ::cast_channel::ReadyState;
|
| +using ::testing::_;
|
| +using ::testing::A;
|
| +using ::testing::DoAll;
|
| +using ::testing::Invoke;
|
| +using ::testing::InvokeArgument;
|
| +using ::testing::NotNull;
|
| +using ::testing::Return;
|
| +using ::testing::SaveArg;
|
| +
|
| +namespace extensions {
|
| +namespace api {
|
| +namespace cast_channel {
|
| +const char kAuthNamespace[] = "urn:x-cast:com.google.cast.tp.deviceauth";
|
| +
|
| +// Returns an auth challenge message inline.
|
| +CastMessage CreateAuthChallenge() {
|
| + CastMessage output;
|
| + CreateAuthChallengeMessage(&output, AuthContext::Create());
|
| + return output;
|
| +}
|
| +
|
| +// Returns an auth challenge response message inline.
|
| +CastMessage CreateAuthReply() {
|
| + CastMessage output;
|
| + output.set_protocol_version(CastMessage::CASTV2_1_0);
|
| + output.set_source_id("sender-0");
|
| + output.set_destination_id("receiver-0");
|
| + output.set_payload_type(CastMessage::BINARY);
|
| + output.set_payload_binary("abcd");
|
| + output.set_namespace_(kAuthNamespace);
|
| + return output;
|
| +}
|
| +
|
| +CastMessage CreateTestMessage() {
|
| + CastMessage test_message;
|
| + test_message.set_protocol_version(CastMessage::CASTV2_1_0);
|
| + test_message.set_namespace_("ns");
|
| + test_message.set_source_id("source");
|
| + test_message.set_destination_id("dest");
|
| + test_message.set_payload_type(CastMessage::STRING);
|
| + test_message.set_payload_utf8("payload");
|
| + return test_message;
|
| +}
|
| +
|
| +class MockTCPSocket : public net::TCPClientSocket {
|
| + public:
|
| + explicit MockTCPSocket(const net::MockConnect& connect_data)
|
| + : TCPClientSocket(net::AddressList(),
|
| + nullptr,
|
| + nullptr,
|
| + net::NetLogSource()),
|
| + connect_data_(connect_data),
|
| + do_nothing_(false) {}
|
| +
|
| + explicit MockTCPSocket(bool do_nothing)
|
| + : TCPClientSocket(net::AddressList(),
|
| + nullptr,
|
| + nullptr,
|
| + net::NetLogSource()) {
|
| + CHECK(do_nothing);
|
| + do_nothing_ = do_nothing;
|
| + }
|
| +
|
| + virtual int Connect(const net::CompletionCallback& callback) {
|
| + if (do_nothing_) {
|
| + // Stall the I/O event loop.
|
| + return net::ERR_IO_PENDING;
|
| + }
|
| +
|
| + if (connect_data_.mode == net::ASYNC) {
|
| + CHECK_NE(connect_data_.result, net::ERR_IO_PENDING);
|
| + base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| + FROM_HERE, base::Bind(callback, connect_data_.result));
|
| + return net::ERR_IO_PENDING;
|
| + } else {
|
| + return connect_data_.result;
|
| + }
|
| + }
|
| +
|
| + virtual bool SetKeepAlive(bool enable, int delay) {
|
| + // Always return true in tests
|
| + return true;
|
| + }
|
| +
|
| + virtual bool SetNoDelay(bool no_delay) {
|
| + // Always return true in tests
|
| + return true;
|
| + }
|
| +
|
| + MOCK_METHOD3(Read,
|
| + int(net::IOBuffer*, int, const net::CompletionCallback&));
|
| + MOCK_METHOD3(Write,
|
| + int(net::IOBuffer*, int, const net::CompletionCallback&));
|
| +
|
| + virtual void Disconnect() {
|
| + // Do nothing in tests
|
| + }
|
| +
|
| + private:
|
| + net::MockConnect connect_data_;
|
| + bool do_nothing_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MockTCPSocket);
|
| +};
|
| +
|
| +class MockDelegate : public CastTransport::Delegate {
|
| + public:
|
| + MockDelegate() {}
|
| + virtual ~MockDelegate() {}
|
| + MOCK_METHOD1(OnError, void(ChannelError error_state));
|
| + MOCK_METHOD1(OnMessage, void(const CastMessage& message));
|
| + MOCK_METHOD0(Start, void());
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(MockDelegate);
|
| +};
|
| +
|
| +class CompleteHandler {
|
| + public:
|
| + CompleteHandler() {}
|
| + MOCK_METHOD1(OnCloseComplete, void(int result));
|
| + MOCK_METHOD1(OnConnectComplete, void(ChannelError error_state));
|
| + MOCK_METHOD1(OnWriteComplete, void(int result));
|
| + MOCK_METHOD1(OnReadComplete, void(int result));
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(CompleteHandler);
|
| +};
|
| +
|
| +class TestCastSocket : public CastSocketImpl {
|
| + public:
|
| + static std::unique_ptr<TestCastSocket> CreateSecure(
|
| + Logger* logger,
|
| + uint64_t device_capabilities = cast_channel::CastDeviceCapability::NONE) {
|
| + return std::unique_ptr<TestCastSocket>(new TestCastSocket(
|
| + CreateIPEndPointForTest(), ChannelAuthType::SSL_VERIFIED,
|
| + kDistantTimeoutMillis, logger, device_capabilities));
|
| + }
|
| +
|
| + TestCastSocket(const net::IPEndPoint& ip_endpoint,
|
| + ChannelAuthType channel_auth,
|
| + int64_t timeout_ms,
|
| + Logger* logger,
|
| + uint64_t device_capabilities)
|
| + : TestCastSocket(ip_endpoint,
|
| + channel_auth,
|
| + timeout_ms,
|
| + logger,
|
| + new net::TestNetLog(),
|
| + device_capabilities) {}
|
| +
|
| + TestCastSocket(const net::IPEndPoint& ip_endpoint,
|
| + ChannelAuthType channel_auth,
|
| + int64_t timeout_ms,
|
| + Logger* logger,
|
| + net::TestNetLog* capturing_net_log,
|
| + uint64_t device_capabilities)
|
| + : CastSocketImpl("some_extension_id",
|
| + ip_endpoint,
|
| + channel_auth,
|
| + capturing_net_log,
|
| + base::TimeDelta::FromMilliseconds(timeout_ms),
|
| + false,
|
| + logger,
|
| + device_capabilities,
|
| + AuthContext::Create()),
|
| + capturing_net_log_(capturing_net_log),
|
| + ip_(ip_endpoint),
|
| + extract_cert_result_(true),
|
| + verify_challenge_result_(true),
|
| + verify_challenge_disallow_(false),
|
| + tcp_unresponsive_(false),
|
| + mock_timer_(new base::MockTimer(false, false)),
|
| + mock_transport_(nullptr) {}
|
| +
|
| + ~TestCastSocket() override {}
|
| +
|
| + void SetupMockTransport() {
|
| + mock_transport_ = new MockCastTransport;
|
| + SetTransportForTesting(base::WrapUnique(mock_transport_));
|
| + }
|
| +
|
| + // Socket connection helpers.
|
| + void SetupTcpConnect(net::IoMode mode, int result) {
|
| + tcp_connect_data_.reset(new net::MockConnect(mode, result));
|
| + }
|
| + void SetupSslConnect(net::IoMode mode, int result) {
|
| + ssl_connect_data_.reset(new net::MockConnect(mode, result));
|
| + }
|
| +
|
| + // Socket I/O helpers.
|
| + void AddWriteResult(const net::MockWrite& write) {
|
| + writes_.push_back(write);
|
| + }
|
| + void AddWriteResult(net::IoMode mode, int result) {
|
| + AddWriteResult(net::MockWrite(mode, result));
|
| + }
|
| + void AddWriteResultForData(net::IoMode mode, const std::string& msg) {
|
| + AddWriteResult(mode, msg.size());
|
| + }
|
| + void AddReadResult(const net::MockRead& read) {
|
| + reads_.push_back(read);
|
| + }
|
| + void AddReadResult(net::IoMode mode, int result) {
|
| + AddReadResult(net::MockRead(mode, result));
|
| + }
|
| + void AddReadResultForData(net::IoMode mode, const std::string& data) {
|
| + AddReadResult(net::MockRead(mode, data.c_str(), data.size()));
|
| + }
|
| +
|
| + // Helpers for modifying other connection-related behaviors.
|
| + void SetupTcpConnectUnresponsive() { tcp_unresponsive_ = true; }
|
| +
|
| + void SetExtractCertResult(bool value) {
|
| + extract_cert_result_ = value;
|
| + }
|
| +
|
| + void SetVerifyChallengeResult(bool value) {
|
| + verify_challenge_result_ = value;
|
| + }
|
| +
|
| + void TriggerTimeout() {
|
| + mock_timer_->Fire();
|
| + }
|
| +
|
| + bool TestVerifyChannelPolicyNone() {
|
| + AuthResult authResult;
|
| + return VerifyChannelPolicy(authResult);
|
| + }
|
| +
|
| + bool TestVerifyChannelPolicyAudioOnly() {
|
| + AuthResult authResult;
|
| + authResult.channel_policies |= AuthResult::POLICY_AUDIO_ONLY;
|
| + return VerifyChannelPolicy(authResult);
|
| + }
|
| +
|
| + void DisallowVerifyChallengeResult() { verify_challenge_disallow_ = true; }
|
| +
|
| + MockCastTransport* GetMockTransport() {
|
| + CHECK(mock_transport_);
|
| + return mock_transport_;
|
| + }
|
| +
|
| + private:
|
| + std::unique_ptr<net::TCPClientSocket> CreateTcpSocket() override {
|
| + if (tcp_unresponsive_) {
|
| + return std::unique_ptr<net::TCPClientSocket>(new MockTCPSocket(true));
|
| + } else {
|
| + net::MockConnect* connect_data = tcp_connect_data_.get();
|
| + connect_data->peer_addr = ip_;
|
| + return std::unique_ptr<net::TCPClientSocket>(
|
| + new MockTCPSocket(*connect_data));
|
| + }
|
| + }
|
| +
|
| + std::unique_ptr<net::SSLClientSocket> CreateSslSocket(
|
| + std::unique_ptr<net::StreamSocket> socket) override {
|
| + net::MockConnect* connect_data = ssl_connect_data_.get();
|
| + connect_data->peer_addr = ip_;
|
| +
|
| + ssl_data_.reset(new net::StaticSocketDataProvider(
|
| + reads_.data(), reads_.size(), writes_.data(), writes_.size()));
|
| + ssl_data_->set_connect_data(*connect_data);
|
| + // NOTE: net::MockTCPClientSocket inherits from net::SSLClientSocket !!
|
| + return std::unique_ptr<net::SSLClientSocket>(new net::MockTCPClientSocket(
|
| + net::AddressList(), capturing_net_log_.get(), ssl_data_.get()));
|
| + }
|
| +
|
| + scoped_refptr<net::X509Certificate> ExtractPeerCert() override {
|
| + return extract_cert_result_
|
| + ? net::ImportCertFromFile(net::GetTestCertsDirectory(),
|
| + "ok_cert.pem")
|
| + : nullptr;
|
| + }
|
| +
|
| + bool VerifyChallengeReply() override {
|
| + EXPECT_FALSE(verify_challenge_disallow_);
|
| + return verify_challenge_result_;
|
| + }
|
| +
|
| + base::Timer* GetTimer() override { return mock_timer_.get(); }
|
| +
|
| + std::unique_ptr<net::TestNetLog> capturing_net_log_;
|
| + net::IPEndPoint ip_;
|
| + // Simulated connect data
|
| + std::unique_ptr<net::MockConnect> tcp_connect_data_;
|
| + std::unique_ptr<net::MockConnect> ssl_connect_data_;
|
| + // Simulated read / write data
|
| + std::vector<net::MockWrite> writes_;
|
| + std::vector<net::MockRead> reads_;
|
| + std::unique_ptr<net::SocketDataProvider> ssl_data_;
|
| + // Simulated result of peer cert extraction.
|
| + bool extract_cert_result_;
|
| + // Simulated result of verifying challenge reply.
|
| + bool verify_challenge_result_;
|
| + bool verify_challenge_disallow_;
|
| + // If true, makes TCP connection process stall. For timeout testing.
|
| + bool tcp_unresponsive_;
|
| + std::unique_ptr<base::MockTimer> mock_timer_;
|
| + MockCastTransport* mock_transport_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestCastSocket);
|
| +};
|
| +
|
| +class CastSocketTest : public testing::Test {
|
| + public:
|
| + CastSocketTest() : logger_(new Logger()), delegate_(new MockDelegate) {}
|
| + ~CastSocketTest() override {}
|
| +
|
| + void SetUp() override { EXPECT_CALL(*delegate_, OnMessage(_)).Times(0); }
|
| +
|
| + void TearDown() override {
|
| + if (socket_.get()) {
|
| + EXPECT_CALL(handler_, OnCloseComplete(net::OK));
|
| + socket_->Close(base::Bind(&CompleteHandler::OnCloseComplete,
|
| + base::Unretained(&handler_)));
|
| + }
|
| + }
|
| +
|
| + void CreateCastSocketSecure() {
|
| + socket_ = TestCastSocket::CreateSecure(logger_);
|
| + }
|
| +
|
| + void HandleAuthHandshake() {
|
| + socket_->SetupMockTransport();
|
| + CastMessage challenge_proto = CreateAuthChallenge();
|
| + EXPECT_CALL(*socket_->GetMockTransport(),
|
| + SendMessage(EqualsProto(challenge_proto), _))
|
| + .WillOnce(PostCompletionCallbackTask<1>(net::OK));
|
| + EXPECT_CALL(*socket_->GetMockTransport(), Start());
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::NONE));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| + socket_->GetMockTransport()->current_delegate()->OnMessage(
|
| + CreateAuthReply());
|
| + RunPendingTasks();
|
| + }
|
| +
|
| + protected:
|
| + // Runs all pending tasks in the message loop.
|
| + void RunPendingTasks() {
|
| + base::RunLoop run_loop;
|
| + run_loop.RunUntilIdle();
|
| + }
|
| +
|
| + base::MessageLoop message_loop_;
|
| + Logger* logger_;
|
| + std::unique_ptr<TestCastSocket> socket_;
|
| + CompleteHandler handler_;
|
| + std::unique_ptr<MockDelegate> delegate_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(CastSocketTest);
|
| +};
|
| +
|
| +// Tests that the following connection flow works:
|
| +// - TCP connection succeeds (async)
|
| +// - SSL connection succeeds (async)
|
| +// - Cert is extracted successfully
|
| +// - Challenge request is sent (async)
|
| +// - Challenge response is received (async)
|
| +// - Credentials are verified successfuly
|
| +TEST_F(CastSocketTest, TestConnectFullSecureFlowAsync) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupTcpConnect(net::ASYNC, net::OK);
|
| + socket_->SetupSslConnect(net::ASYNC, net::OK);
|
| +
|
| + HandleAuthHandshake();
|
| +
|
| + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::NONE, socket_->error_state());
|
| +}
|
| +
|
| +// Tests that the following connection flow works:
|
| +// - TCP connection succeeds (sync)
|
| +// - SSL connection succeeds (sync)
|
| +// - Cert is extracted successfully
|
| +// - Challenge request is sent (sync)
|
| +// - Challenge response is received (sync)
|
| +// - Credentials are verified successfuly
|
| +TEST_F(CastSocketTest, TestConnectFullSecureFlowSync) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
|
| + socket_->SetupSslConnect(net::SYNCHRONOUS, net::OK);
|
| +
|
| + HandleAuthHandshake();
|
| +
|
| + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::NONE, socket_->error_state());
|
| +}
|
| +
|
| +// Test that an AuthMessage with a mangled namespace triggers cancelation
|
| +// of the connection event loop.
|
| +TEST_F(CastSocketTest, TestConnectAuthMessageCorrupted) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupMockTransport();
|
| +
|
| + socket_->SetupTcpConnect(net::ASYNC, net::OK);
|
| + socket_->SetupSslConnect(net::ASYNC, net::OK);
|
| +
|
| + CastMessage challenge_proto = CreateAuthChallenge();
|
| + EXPECT_CALL(*socket_->GetMockTransport(),
|
| + SendMessage(EqualsProto(challenge_proto), _))
|
| + .WillOnce(PostCompletionCallbackTask<1>(net::OK));
|
| + EXPECT_CALL(*socket_->GetMockTransport(), Start());
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::TRANSPORT_ERROR));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| + CastMessage mangled_auth_reply = CreateAuthReply();
|
| + mangled_auth_reply.set_namespace_("BOGUS_NAMESPACE");
|
| +
|
| + socket_->GetMockTransport()->current_delegate()->OnMessage(
|
| + mangled_auth_reply);
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::TRANSPORT_ERROR, socket_->error_state());
|
| +
|
| + // Verifies that the CastSocket's resources were torn down during channel
|
| + // close. (see http://crbug.com/504078)
|
| + EXPECT_EQ(nullptr, socket_->transport());
|
| +}
|
| +
|
| +// Test connection error - TCP connect fails (async)
|
| +TEST_F(CastSocketTest, TestConnectTcpConnectErrorAsync) {
|
| + CreateCastSocketSecure();
|
| +
|
| + socket_->SetupTcpConnect(net::ASYNC, net::ERR_FAILED);
|
| +
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_ERROR));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::CONNECT_ERROR, socket_->error_state());
|
| +}
|
| +
|
| +// Test connection error - TCP connect fails (sync)
|
| +TEST_F(CastSocketTest, TestConnectTcpConnectErrorSync) {
|
| + CreateCastSocketSecure();
|
| +
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::ERR_FAILED);
|
| +
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_ERROR));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::CONNECT_ERROR, socket_->error_state());
|
| +}
|
| +
|
| +// Test connection error - timeout
|
| +TEST_F(CastSocketTest, TestConnectTcpTimeoutError) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupTcpConnectUnresponsive();
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_TIMEOUT));
|
| + EXPECT_CALL(*delegate_, OnError(ChannelError::CONNECT_TIMEOUT));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CONNECTING, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::NONE, socket_->error_state());
|
| + socket_->TriggerTimeout();
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::CONNECT_TIMEOUT, socket_->error_state());
|
| +}
|
| +
|
| +// Test connection error - TCP socket returns timeout
|
| +TEST_F(CastSocketTest, TestConnectTcpSocketTimeoutError) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::ERR_CONNECTION_TIMED_OUT);
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_TIMEOUT));
|
| + EXPECT_CALL(*delegate_, OnError(ChannelError::CONNECT_TIMEOUT));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::CONNECT_TIMEOUT, socket_->error_state());
|
| + EXPECT_EQ(net::ERR_CONNECTION_TIMED_OUT,
|
| + logger_->GetLastErrors(socket_->id()).net_return_value);
|
| +}
|
| +
|
| +// Test connection error - SSL connect fails (async)
|
| +TEST_F(CastSocketTest, TestConnectSslConnectErrorAsync) {
|
| + CreateCastSocketSecure();
|
| +
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
|
| + socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_FAILED);
|
| +
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::AUTHENTICATION_ERROR));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::AUTHENTICATION_ERROR, socket_->error_state());
|
| +}
|
| +
|
| +// Test connection error - SSL connect fails (sync)
|
| +TEST_F(CastSocketTest, TestConnectSslConnectErrorSync) {
|
| + CreateCastSocketSecure();
|
| +
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
|
| + socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_FAILED);
|
| +
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::AUTHENTICATION_ERROR));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::AUTHENTICATION_ERROR, socket_->error_state());
|
| + EXPECT_EQ(net::ERR_FAILED,
|
| + logger_->GetLastErrors(socket_->id()).net_return_value);
|
| +}
|
| +
|
| +// Test connection error - SSL connect times out (sync)
|
| +TEST_F(CastSocketTest, TestConnectSslConnectTimeoutSync) {
|
| + CreateCastSocketSecure();
|
| +
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
|
| + socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_CONNECTION_TIMED_OUT);
|
| +
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_TIMEOUT));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::CONNECT_TIMEOUT, socket_->error_state());
|
| + EXPECT_EQ(net::ERR_CONNECTION_TIMED_OUT,
|
| + logger_->GetLastErrors(socket_->id()).net_return_value);
|
| +}
|
| +
|
| +// Test connection error - SSL connect times out (async)
|
| +TEST_F(CastSocketTest, TestConnectSslConnectTimeoutAsync) {
|
| + CreateCastSocketSecure();
|
| +
|
| + socket_->SetupTcpConnect(net::ASYNC, net::OK);
|
| + socket_->SetupSslConnect(net::ASYNC, net::ERR_CONNECTION_TIMED_OUT);
|
| +
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CONNECT_TIMEOUT));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::CONNECT_TIMEOUT, socket_->error_state());
|
| +}
|
| +
|
| +// Test connection error - challenge send fails
|
| +TEST_F(CastSocketTest, TestConnectChallengeSendError) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupMockTransport();
|
| +
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
|
| + socket_->SetupSslConnect(net::SYNCHRONOUS, net::OK);
|
| + EXPECT_CALL(*socket_->GetMockTransport(),
|
| + SendMessage(EqualsProto(CreateAuthChallenge()), _))
|
| + .WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET));
|
| +
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CAST_SOCKET_ERROR));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::CAST_SOCKET_ERROR, socket_->error_state());
|
| +}
|
| +
|
| +// Test connection error - connection is destroyed after the challenge is
|
| +// sent, with the async result still lurking in the task queue.
|
| +TEST_F(CastSocketTest, TestConnectDestroyedAfterChallengeSent) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupMockTransport();
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
|
| + socket_->SetupSslConnect(net::SYNCHRONOUS, net::OK);
|
| + EXPECT_CALL(*socket_->GetMockTransport(),
|
| + SendMessage(EqualsProto(CreateAuthChallenge()), _))
|
| + .WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + socket_.reset();
|
| + RunPendingTasks();
|
| +}
|
| +
|
| +// Test connection error - challenge reply receive fails
|
| +TEST_F(CastSocketTest, TestConnectChallengeReplyReceiveError) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupMockTransport();
|
| +
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
|
| + socket_->SetupSslConnect(net::SYNCHRONOUS, net::OK);
|
| + EXPECT_CALL(*socket_->GetMockTransport(),
|
| + SendMessage(EqualsProto(CreateAuthChallenge()), _))
|
| + .WillOnce(PostCompletionCallbackTask<1>(net::OK));
|
| + socket_->AddReadResult(net::SYNCHRONOUS, net::ERR_FAILED);
|
| + EXPECT_CALL(*delegate_, OnError(ChannelError::CAST_SOCKET_ERROR));
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::CAST_SOCKET_ERROR));
|
| + EXPECT_CALL(*socket_->GetMockTransport(), Start());
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| + socket_->GetMockTransport()->current_delegate()->OnError(
|
| + ChannelError::CAST_SOCKET_ERROR);
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::CAST_SOCKET_ERROR, socket_->error_state());
|
| +}
|
| +
|
| +TEST_F(CastSocketTest, TestConnectChallengeVerificationFails) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupMockTransport();
|
| + socket_->SetupTcpConnect(net::ASYNC, net::OK);
|
| + socket_->SetupSslConnect(net::ASYNC, net::OK);
|
| + socket_->SetVerifyChallengeResult(false);
|
| +
|
| + EXPECT_CALL(*delegate_, OnError(ChannelError::AUTHENTICATION_ERROR));
|
| + CastMessage challenge_proto = CreateAuthChallenge();
|
| + EXPECT_CALL(*socket_->GetMockTransport(),
|
| + SendMessage(EqualsProto(challenge_proto), _))
|
| + .WillOnce(PostCompletionCallbackTask<1>(net::OK));
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::AUTHENTICATION_ERROR));
|
| + EXPECT_CALL(*socket_->GetMockTransport(), Start());
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| + socket_->GetMockTransport()->current_delegate()->OnMessage(CreateAuthReply());
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::CLOSED, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::AUTHENTICATION_ERROR, socket_->error_state());
|
| +}
|
| +
|
| +// Sends message data through an actual non-mocked CastTransport object,
|
| +// testing the two components in integration.
|
| +TEST_F(CastSocketTest, TestConnectEndToEndWithRealTransportAsync) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupTcpConnect(net::ASYNC, net::OK);
|
| + socket_->SetupSslConnect(net::ASYNC, net::OK);
|
| +
|
| + // Set low-level auth challenge expectations.
|
| + CastMessage challenge = CreateAuthChallenge();
|
| + std::string challenge_str;
|
| + EXPECT_TRUE(MessageFramer::Serialize(challenge, &challenge_str));
|
| + socket_->AddWriteResultForData(net::ASYNC, challenge_str);
|
| +
|
| + // Set low-level auth reply expectations.
|
| + CastMessage reply = CreateAuthReply();
|
| + std::string reply_str;
|
| + EXPECT_TRUE(MessageFramer::Serialize(reply, &reply_str));
|
| + socket_->AddReadResultForData(net::ASYNC, reply_str);
|
| + socket_->AddReadResult(net::ASYNC, net::ERR_IO_PENDING);
|
| +
|
| + CastMessage test_message = CreateTestMessage();
|
| + std::string test_message_str;
|
| + EXPECT_TRUE(MessageFramer::Serialize(test_message, &test_message_str));
|
| + socket_->AddWriteResultForData(net::ASYNC, test_message_str);
|
| +
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::NONE));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::NONE, socket_->error_state());
|
| +
|
| + // Send the test message through a real transport object.
|
| + EXPECT_CALL(handler_, OnWriteComplete(net::OK));
|
| + socket_->transport()->SendMessage(
|
| + test_message, base::Bind(&CompleteHandler::OnWriteComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::NONE, socket_->error_state());
|
| +}
|
| +
|
| +// Same as TestConnectEndToEndWithRealTransportAsync, except synchronous.
|
| +TEST_F(CastSocketTest, TestConnectEndToEndWithRealTransportSync) {
|
| + CreateCastSocketSecure();
|
| + socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
|
| + socket_->SetupSslConnect(net::SYNCHRONOUS, net::OK);
|
| +
|
| + // Set low-level auth challenge expectations.
|
| + CastMessage challenge = CreateAuthChallenge();
|
| + std::string challenge_str;
|
| + EXPECT_TRUE(MessageFramer::Serialize(challenge, &challenge_str));
|
| + socket_->AddWriteResultForData(net::SYNCHRONOUS, challenge_str);
|
| +
|
| + // Set low-level auth reply expectations.
|
| + CastMessage reply = CreateAuthReply();
|
| + std::string reply_str;
|
| + EXPECT_TRUE(MessageFramer::Serialize(reply, &reply_str));
|
| + socket_->AddReadResultForData(net::SYNCHRONOUS, reply_str);
|
| + socket_->AddReadResult(net::ASYNC, net::ERR_IO_PENDING);
|
| +
|
| + CastMessage test_message = CreateTestMessage();
|
| + std::string test_message_str;
|
| + EXPECT_TRUE(MessageFramer::Serialize(test_message, &test_message_str));
|
| + socket_->AddWriteResultForData(net::SYNCHRONOUS, test_message_str);
|
| +
|
| + EXPECT_CALL(handler_, OnConnectComplete(ChannelError::NONE));
|
| + socket_->Connect(std::move(delegate_),
|
| + base::Bind(&CompleteHandler::OnConnectComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::NONE, socket_->error_state());
|
| +
|
| + // Send the test message through a real transport object.
|
| + EXPECT_CALL(handler_, OnWriteComplete(net::OK));
|
| + socket_->transport()->SendMessage(
|
| + test_message, base::Bind(&CompleteHandler::OnWriteComplete,
|
| + base::Unretained(&handler_)));
|
| + RunPendingTasks();
|
| +
|
| + EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
|
| + EXPECT_EQ(ChannelError::NONE, socket_->error_state());
|
| +}
|
| +
|
| +} // namespace cast_channel
|
| +} // namespace api
|
| +} // namespace extensions
|
|
|