blob: fe478bff1af849582925fb56fd6f4828e68290c3 [file] [log] [blame]
// 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.
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "chrome/browser/extensions/api/cast_channel/cast_channel_api.h"
#include "chrome/browser/extensions/api/cast_channel/cast_socket.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/extensions/api/cast_channel.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/common/switches.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/gmock_mutant.h"
namespace cast_channel = extensions::api::cast_channel;
using cast_channel::CastSocket;
using cast_channel::ChannelError;
using cast_channel::MessageInfo;
using cast_channel::ReadyState;
using ::testing::_;
using ::testing::A;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::InSequence;
using ::testing::Return;
namespace {
const char kTestExtensionId[] = "ddchlicdkolnonkihahngkmmmjnjlkkf";
static void FillMessageInfo(MessageInfo* message_info,
const std::string& message) {
message_info->namespace_ = "foo";
message_info->source_id = "src";
message_info->destination_id = "dest";
message_info->data.reset(new base::StringValue(message));
}
ACTION_TEMPLATE(InvokeCompletionCallback,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(result)) {
::std::tr1::get<k>(args).Run(result);
}
ACTION_P2(InvokeDelegateOnError, api_test, api) {
api_test->CallOnError(api);
}
class MockCastSocket : public CastSocket {
public:
explicit MockCastSocket(CastSocket::Delegate* delegate,
net::IPEndPoint ip_endpoint,
net::NetLog* net_log)
: CastSocket(kTestExtensionId, ip_endpoint,
cast_channel::CHANNEL_AUTH_TYPE_SSL, delegate, net_log) {}
virtual ~MockCastSocket() {}
virtual bool CalledOnValidThread() const OVERRIDE {
// Always return true in testing.
return true;
}
MOCK_METHOD1(Connect, void(const net::CompletionCallback& callback));
MOCK_METHOD2(SendMessage, void(const MessageInfo& message,
const net::CompletionCallback& callback));
MOCK_METHOD1(Close, void(const net::CompletionCallback& callback));
MOCK_CONST_METHOD0(ready_state, cast_channel::ReadyState());
MOCK_CONST_METHOD0(error_state, cast_channel::ChannelError());
};
} // namespace
class CastChannelAPITest : public ExtensionApiTest {
public:
CastChannelAPITest() {}
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
ExtensionApiTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(
extensions::switches::kWhitelistedExtensionID,
kTestExtensionId);
}
void SetUpMockCastSocket() {
extensions::CastChannelAPI* api = GetApi();
net::IPAddressNumber ip_number;
net::ParseIPLiteralToNumber("192.168.1.1", &ip_number);
net::IPEndPoint ip_endpoint(ip_number, 8009);
mock_cast_socket_ = new MockCastSocket(api, ip_endpoint,
&capturing_net_log_);
// Transfers ownership of the socket.
api->SetSocketForTest(
make_scoped_ptr<CastSocket>(mock_cast_socket_).Pass());
// Set expectations on error_state().
EXPECT_CALL(*mock_cast_socket_, error_state())
.WillRepeatedly(Return(cast_channel::CHANNEL_ERROR_NONE));
}
extensions::CastChannelAPI* GetApi() {
return extensions::CastChannelAPI::Get(profile());
}
void CallOnError(extensions::CastChannelAPI* api) {
api->OnError(mock_cast_socket_,
cast_channel::CHANNEL_ERROR_CONNECT_ERROR);
}
protected:
void CallOnMessage(const std::string& message) {
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&CastChannelAPITest::DoCallOnMessage, this,
GetApi(), mock_cast_socket_, message));
}
void DoCallOnMessage(extensions::CastChannelAPI* api,
MockCastSocket* cast_socket,
const std::string& message) {
MessageInfo message_info;
FillMessageInfo(&message_info, message);
api->OnMessage(cast_socket, message_info);
}
MockCastSocket* mock_cast_socket_;
net::CapturingNetLog capturing_net_log_;
};
// TODO(munjal): Win Dbg has a workaround that makes RunExtensionSubtest
// always return true without actually running the test. Remove when fixed.
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_TestOpenSendClose DISABLED_TestOpenSendClose
#else
#define MAYBE_TestOpenSendClose TestOpenSendClose
#endif
// Test loading extension, opening a channel with ConnectInfo, adding a
// listener, writing, reading, and closing.
IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenSendClose) {
SetUpMockCastSocket();
{
InSequence dummy;
EXPECT_CALL(*mock_cast_socket_, Connect(_))
.WillOnce(InvokeCompletionCallback<0>(net::OK));
EXPECT_CALL(*mock_cast_socket_, ready_state())
.WillOnce(Return(cast_channel::READY_STATE_OPEN));
EXPECT_CALL(*mock_cast_socket_, SendMessage(A<const MessageInfo&>(), _))
.WillOnce(InvokeCompletionCallback<1>(net::OK));
EXPECT_CALL(*mock_cast_socket_, ready_state())
.WillOnce(Return(cast_channel::READY_STATE_OPEN));
EXPECT_CALL(*mock_cast_socket_, Close(_))
.WillOnce(InvokeCompletionCallback<0>(net::OK));
EXPECT_CALL(*mock_cast_socket_, ready_state())
.WillOnce(Return(cast_channel::READY_STATE_CLOSED));
}
EXPECT_TRUE(RunExtensionSubtest("cast_channel/api",
"test_open_send_close.html"));
}
// TODO(munjal): Win Dbg has a workaround that makes RunExtensionSubtest
// always return true without actually running the test. Remove when fixed.
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_TestOpenSendCloseWithUrl DISABLED_TestOpenSendCloseWithUrl
#else
#define MAYBE_TestOpenSendCloseWithUrl TestOpenSendCloseWithUrl
#endif
// Test loading extension, opening a channel with a URL, adding a listener,
// writing, reading, and closing.
IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenSendCloseWithUrl) {
SetUpMockCastSocket();
{
InSequence dummy;
EXPECT_CALL(*mock_cast_socket_, Connect(_))
.WillOnce(InvokeCompletionCallback<0>(net::OK));
EXPECT_CALL(*mock_cast_socket_, ready_state())
.WillOnce(Return(cast_channel::READY_STATE_OPEN));
EXPECT_CALL(*mock_cast_socket_, SendMessage(A<const MessageInfo&>(), _))
.WillOnce(InvokeCompletionCallback<1>(net::OK));
EXPECT_CALL(*mock_cast_socket_, ready_state())
.WillOnce(Return(cast_channel::READY_STATE_OPEN));
EXPECT_CALL(*mock_cast_socket_, Close(_))
.WillOnce(InvokeCompletionCallback<0>(net::OK));
EXPECT_CALL(*mock_cast_socket_, ready_state())
.WillOnce(Return(cast_channel::READY_STATE_CLOSED));
}
EXPECT_TRUE(RunExtensionSubtest("cast_channel/api",
"test_open_send_close_url.html"));
}
// TODO(munjal): Win Dbg has a workaround that makes RunExtensionSubtest
// always return true without actually running the test. Remove when fixed.
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_TestOpenReceiveClose DISABLED_TestOpenReceiveClose
#else
#define MAYBE_TestOpenReceiveClose TestOpenReceiveClose
#endif
// Test loading extension, opening a channel, adding a listener,
// writing, reading, and closing.
IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenReceiveClose) {
SetUpMockCastSocket();
{
InSequence dummy;
EXPECT_CALL(*mock_cast_socket_, Connect(_))
.WillOnce(InvokeCompletionCallback<0>(net::OK));
EXPECT_CALL(*mock_cast_socket_, ready_state())
.Times(3)
.WillRepeatedly(Return(cast_channel::READY_STATE_OPEN));
EXPECT_CALL(*mock_cast_socket_, Close(_))
.WillOnce(InvokeCompletionCallback<0>(net::OK));
EXPECT_CALL(*mock_cast_socket_, ready_state())
.WillOnce(Return(cast_channel::READY_STATE_CLOSED));
}
EXPECT_TRUE(RunExtensionSubtest("cast_channel/api",
"test_open_receive_close.html"));
ResultCatcher catcher;
CallOnMessage("some-message");
CallOnMessage("some-message");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
// TODO(munjal): Win Dbg has a workaround that makes RunExtensionSubtest
// always return true without actually running the test. Remove when fixed.
#if defined(OS_WIN) && !defined(NDEBUG)
#define MAYBE_TestOpenError DISABLED_TestOpenError
#else
#define MAYBE_TestOpenError TestOpenError
#endif
// Test the case when socket open results in an error.
IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenError) {
SetUpMockCastSocket();
EXPECT_CALL(*mock_cast_socket_, Connect(_))
.WillOnce(DoAll(
InvokeDelegateOnError(this, GetApi()),
InvokeCompletionCallback<0>(net::ERR_FAILED)));
EXPECT_CALL(*mock_cast_socket_, ready_state())
.WillRepeatedly(Return(cast_channel::READY_STATE_CLOSED));
EXPECT_CALL(*mock_cast_socket_, Close(_));
EXPECT_TRUE(RunExtensionSubtest("cast_channel/api",
"test_open_error.html"));
ResultCatcher catcher;
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}