blob: 9ff5b61acb88469ae518b37dd6f9e7ae1448bb3f [file] [log] [blame]
// Copyright (c) 2011 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 "chrome_frame/test/automation_client_mock.h"
#include "base/callback.h"
#include "chrome/common/automation_messages.h"
#include "chrome_frame/custom_sync_call_context.h"
#include "chrome_frame/navigation_constraints.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
#include "net/base/net_errors.h"
#define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
#include "testing/gmock_mutant.h"
using testing::_;
using testing::CreateFunctor;
using testing::Return;
DISABLE_RUNNABLE_METHOD_REFCOUNT(LaunchDelegate);
DISABLE_RUNNABLE_METHOD_REFCOUNT(ChromeFrameAutomationClient);
DISABLE_RUNNABLE_METHOD_REFCOUNT(chrome_frame_test::TimedMsgLoop);
MATCHER_P(LaunchParamProfileEq, profile_name, "Check for profile name") {
return arg->profile_name().compare(profile_name) == 0;
}
void MockProxyFactory::GetServerImpl(ChromeFrameAutomationProxy* pxy,
void* proxy_id,
AutomationLaunchResult result,
LaunchDelegate* d,
ChromeFrameLaunchParams* params,
void** automation_server_id) {
*automation_server_id = proxy_id;
Task* task = NewRunnableMethod(d,
&LaunchDelegate::LaunchComplete, pxy, result);
loop_->PostDelayedTask(FROM_HERE, task,
params->launch_timeout() / 2);
}
void CFACMockTest::SetAutomationServerOk(int times) {
EXPECT_CALL(factory_, GetAutomationServer(testing::NotNull(),
LaunchParamProfileEq(profile_path_.BaseName().value()),
testing::NotNull()))
.Times(times)
.WillRepeatedly(testing::Invoke(CreateFunctor(&factory_,
&MockProxyFactory::GetServerImpl, get_proxy(), id_,
AUTOMATION_SUCCESS)));
EXPECT_CALL(factory_,
ReleaseAutomationServer(testing::Eq(id_), testing::NotNull()))
.Times(times);
}
void CFACMockTest::Set_CFD_LaunchFailed(AutomationLaunchResult result) {
EXPECT_CALL(cfd_, OnAutomationServerLaunchFailed(testing::Eq(result),
testing::_))
.Times(1)
.WillOnce(QUIT_LOOP(loop_));
}
MATCHER_P(MsgType, msg_type, "IPC::Message::type()") {
const IPC::Message& m = arg;
return (m.type() == msg_type);
}
MATCHER_P(EqNavigationInfoUrl, url, "IPC::NavigationInfo matcher") {
if (url.is_valid() && url != arg.url)
return false;
// TODO(stevet): other members
return true;
}
// Could be implemented as MockAutomationProxy member (we have WithArgs<>!)
ACTION_P4(HandleCreateTab, tab_handle, external_tab_container, tab_wnd,
session_id) {
// arg0 - message
// arg1 - callback
// arg2 - key
CreateExternalTabContext::output_type input_args(tab_wnd,
external_tab_container,
tab_handle,
session_id);
CreateExternalTabContext* context =
reinterpret_cast<CreateExternalTabContext*>(arg1);
DispatchToMethod(context, &CreateExternalTabContext::Completed, input_args);
delete context;
}
ACTION_P4(InitiateNavigation, client, url, referrer, constraints) {
client->InitiateNavigation(url, referrer, constraints);
}
// We mock ChromeFrameDelegate only. The rest is with real AutomationProxy
TEST(CFACWithChrome, CreateTooFast) {
MockCFDelegate cfd;
chrome_frame_test::TimedMsgLoop loop;
int timeout = 0; // Chrome cannot send Hello message so fast.
const FilePath profile_path(
chrome_frame_test::GetProfilePath(L"Adam.N.Epilinter"));
scoped_refptr<ChromeFrameAutomationClient> client;
client = new ChromeFrameAutomationClient();
EXPECT_CALL(cfd, OnAutomationServerLaunchFailed(AUTOMATION_TIMEOUT, _))
.Times(1)
.WillOnce(QUIT_LOOP(loop));
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
empty, empty, profile_path, profile_path.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout);
clp->set_version_check(false);
EXPECT_TRUE(client->Initialize(&cfd, clp));
loop.RunFor(10);
client->Uninitialize();
}
// This test may fail if Chrome take more that 10 seconds (timeout var) to
// launch. In this case GMock shall print something like "unexpected call to
// OnAutomationServerLaunchFailed". I'm yet to find out how to specify
// that this is an unexpected call, and still to execute an action.
TEST(CFACWithChrome, CreateNotSoFast) {
MockCFDelegate cfd;
chrome_frame_test::TimedMsgLoop loop;
const FilePath profile_path(
chrome_frame_test::GetProfilePath(L"Adam.N.Epilinter"));
int timeout = 10000;
scoped_refptr<ChromeFrameAutomationClient> client;
client = new ChromeFrameAutomationClient;
EXPECT_CALL(cfd, OnAutomationServerReady())
.Times(1)
.WillOnce(QUIT_LOOP(loop));
EXPECT_CALL(cfd, OnAutomationServerLaunchFailed(_, _))
.Times(0);
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
empty, empty, profile_path, profile_path.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout);
clp->set_version_check(false);
EXPECT_TRUE(client->Initialize(&cfd, clp));
loop.RunFor(11);
client->Uninitialize();
client = NULL;
}
TEST(CFACWithChrome, NavigateOk) {
MockCFDelegate cfd;
NavigationConstraintsImpl navigation_constraints;
chrome_frame_test::TimedMsgLoop loop;
const std::string url = "about:version";
const FilePath profile_path(
chrome_frame_test::GetProfilePath(L"Adam.N.Epilinter"));
int timeout = 10000;
scoped_refptr<ChromeFrameAutomationClient> client;
client = new ChromeFrameAutomationClient;
EXPECT_CALL(cfd, OnAutomationServerReady())
.WillOnce(InitiateNavigation(client.get(),
url, std::string(),
&navigation_constraints));
EXPECT_CALL(cfd, GetBounds(_)).Times(testing::AnyNumber());
EXPECT_CALL(cfd, OnNavigationStateChanged(_))
.Times(testing::AnyNumber());
{
testing::InSequence s;
EXPECT_CALL(cfd, OnDidNavigate(EqNavigationInfoUrl(GURL())))
.Times(1);
EXPECT_CALL(cfd, OnUpdateTargetUrl(_)).Times(testing::AtMost(1));
EXPECT_CALL(cfd, OnLoad(_))
.Times(1)
.WillOnce(QUIT_LOOP(loop));
}
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
empty, empty, profile_path, profile_path.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout);
clp->set_version_check(false);
EXPECT_TRUE(client->Initialize(&cfd, clp));
loop.RunFor(10);
client->Uninitialize();
client = NULL;
}
TEST(CFACWithChrome, NavigateFailed) {
MockCFDelegate cfd;
NavigationConstraintsImpl navigation_constraints;
chrome_frame_test::TimedMsgLoop loop;
const FilePath profile_path(
chrome_frame_test::GetProfilePath(L"Adam.N.Epilinter"));
const std::string url = "http://127.0.0.3:65412/";
const net::URLRequestStatus connection_failed(net::URLRequestStatus::FAILED,
net::ERR_INVALID_URL);
scoped_refptr<ChromeFrameAutomationClient> client;
client = new ChromeFrameAutomationClient;
cfd.SetRequestDelegate(client);
EXPECT_CALL(cfd, OnAutomationServerReady())
.WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor(
client.get(), &ChromeFrameAutomationClient::InitiateNavigation,
url, std::string(), &navigation_constraints))));
EXPECT_CALL(cfd, GetBounds(_)).Times(testing::AnyNumber());
EXPECT_CALL(cfd, OnNavigationStateChanged(_)).Times(testing::AnyNumber());
EXPECT_CALL(cfd, OnRequestStart(_, _))
// Often there's another request for the error page
.Times(testing::Between(1, 2))
.WillRepeatedly(testing::WithArgs<0>(testing::Invoke(CreateFunctor(&cfd,
&MockCFDelegate::Reply, connection_failed))));
EXPECT_CALL(cfd, OnUpdateTargetUrl(_)).Times(testing::AnyNumber());
EXPECT_CALL(cfd, OnLoad(_)).Times(testing::AtMost(1));
EXPECT_CALL(cfd, OnNavigationFailed(_, GURL(url)))
.Times(1)
.WillOnce(QUIT_LOOP_SOON(loop, 2));
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
empty, empty, profile_path, profile_path.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(10000);
clp->set_version_check(false);
EXPECT_TRUE(client->Initialize(&cfd, clp));
loop.RunFor(10);
client->Uninitialize();
client = NULL;
}
TEST_F(CFACMockTest, MockedCreateTabOk) {
int timeout = 500;
CreateTab();
SetAutomationServerOk(1);
EXPECT_CALL(mock_proxy_, server_version()).Times(testing::AnyNumber())
.WillRepeatedly(Return(""));
// We need some valid HWNDs, when responding to CreateExternalTab
HWND h1 = ::GetDesktopWindow();
HWND h2 = ::GetDesktopWindow();
EXPECT_CALL(mock_proxy_, SendAsAsync(testing::Property(
&IPC::SyncMessage::type, AutomationMsg_CreateExternalTab::ID),
testing::NotNull(), _))
.Times(1).WillOnce(HandleCreateTab(tab_handle_, h1, h2, 99));
EXPECT_CALL(mock_proxy_, CreateTabProxy(testing::Eq(tab_handle_)))
.WillOnce(Return(tab_));
EXPECT_CALL(cfd_, OnAutomationServerReady())
.WillOnce(QUIT_LOOP(loop_));
EXPECT_CALL(mock_proxy_, CancelAsync(_)).Times(testing::AnyNumber());
// Here we go!
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
empty, empty, profile_path_, profile_path_.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout);
clp->set_version_check(false);
EXPECT_TRUE(client_->Initialize(&cfd_, clp));
loop_.RunFor(10);
EXPECT_CALL(mock_proxy_, ReleaseTabProxy(testing::Eq(tab_handle_))).Times(1);
client_->Uninitialize();
}
TEST_F(CFACMockTest, MockedCreateTabFailed) {
HWND null_wnd = NULL;
SetAutomationServerOk(1);
EXPECT_CALL(mock_proxy_, server_version()).Times(testing::AnyNumber())
.WillRepeatedly(Return(""));
EXPECT_CALL(mock_proxy_, SendAsAsync(testing::Property(
&IPC::SyncMessage::type, AutomationMsg_CreateExternalTab::ID),
testing::NotNull(), _))
.Times(1).WillOnce(HandleCreateTab(tab_handle_, null_wnd, null_wnd,
99));
EXPECT_CALL(mock_proxy_, CreateTabProxy(_)).Times(0);
EXPECT_CALL(mock_proxy_, CancelAsync(_)).Times(testing::AnyNumber());
Set_CFD_LaunchFailed(AUTOMATION_CREATE_TAB_FAILED);
// Here we go!
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
empty, empty, profile_path_, profile_path_.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout_);
clp->set_version_check(false);
EXPECT_TRUE(client_->Initialize(&cfd_, clp));
loop_.RunFor(4);
client_->Uninitialize();
}
class TestChromeFrameAutomationProxyImpl
: public ChromeFrameAutomationProxyImpl {
public:
TestChromeFrameAutomationProxyImpl()
// 1 is an unneeded timeout.
: ChromeFrameAutomationProxyImpl(
NULL, AutomationProxy::GenerateChannelID(), 1) {
}
MOCK_METHOD3(
SendAsAsync,
void(IPC::SyncMessage* msg,
SyncMessageReplyDispatcher::SyncMessageCallContext* context,
void* key));
void FakeChannelError() {
reinterpret_cast<IPC::ChannelProxy::MessageFilter*>(message_filter_.get())->
OnChannelError();
}
};
TEST_F(CFACMockTest, OnChannelErrorEmpty) {
TestChromeFrameAutomationProxyImpl proxy;
// No tabs should do nothing yet still not fail either.
proxy.FakeChannelError();
}
TEST_F(CFACMockTest, OnChannelError) {
TestChromeFrameAutomationProxyImpl proxy;
returned_proxy_ = &proxy;
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
empty, empty, profile_path_, profile_path_.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(1); // Unneeded timeout, but can't be 0.
clp->set_version_check(false);
HWND h1 = ::GetDesktopWindow();
HWND h2 = ::GetDesktopWindow();
EXPECT_CALL(proxy, SendAsAsync(testing::Property(
&IPC::SyncMessage::type, AutomationMsg_CreateExternalTab::ID),
testing::NotNull(), _)).Times(3)
.WillOnce(HandleCreateTab(tab_handle_, h1, h2, 99))
.WillOnce(HandleCreateTab(tab_handle_ * 2, h1, h2, 100))
.WillOnce(HandleCreateTab(tab_handle_ * 3, h1, h2, 101));
SetAutomationServerOk(3);
// First, try a single tab and make sure the notification find its way to the
// Chrome Frame Delegate.
StrictMock<MockCFDelegate> cfd1;
scoped_refptr<ChromeFrameAutomationClient> client1;
client1 = new ChromeFrameAutomationClient;
client1->set_proxy_factory(&factory_);
EXPECT_CALL(cfd1, OnAutomationServerReady()).WillOnce(QUIT_LOOP(loop_));
EXPECT_TRUE(client1->Initialize(&cfd1, clp));
// Wait for OnAutomationServerReady to be called in the UI thread.
loop_.RunFor(11);
proxy.FakeChannelError();
EXPECT_CALL(cfd1, OnChannelError()).WillOnce(QUIT_LOOP(loop_));
// Wait for OnChannelError to be propagated to delegate from the UI thread.
loop_.RunFor(11);
// Add a second tab using a different delegate.
StrictMock<MockCFDelegate> cfd2;
scoped_refptr<ChromeFrameAutomationClient> client2;
client2 = new ChromeFrameAutomationClient;
client2->set_proxy_factory(&factory_);
EXPECT_CALL(cfd2, OnAutomationServerReady()).WillOnce(QUIT_LOOP(loop_));
EXPECT_TRUE(client2->Initialize(&cfd2, clp));
// Wait for OnAutomationServerReady to be called in the UI thread.
loop_.RunFor(11);
EXPECT_CALL(cfd1, OnChannelError()).Times(1);
EXPECT_CALL(cfd2, OnChannelError()).WillOnce(QUIT_LOOP(loop_));
proxy.FakeChannelError();
// Wait for OnChannelError to be propagated to delegate from the UI thread.
loop_.RunFor(11);
// And now a 3rd tab using the first delegate.
scoped_refptr<ChromeFrameAutomationClient> client3;
client3 = new ChromeFrameAutomationClient;
client3->set_proxy_factory(&factory_);
EXPECT_CALL(cfd1, OnAutomationServerReady()).WillOnce(QUIT_LOOP(loop_));
EXPECT_TRUE(client3->Initialize(&cfd1, clp));
// Wait for OnAutomationServerReady to be called in the UI thread.
loop_.RunFor(11);
EXPECT_CALL(cfd2, OnChannelError()).Times(1);
EXPECT_CALL(cfd1, OnChannelError()).Times(2).WillOnce(Return())
.WillOnce(QUIT_LOOP(loop_));
proxy.FakeChannelError();
// Wait for OnChannelError to be propagated to delegate from the UI thread.
loop_.RunFor(11);
// Cleanup.
client1->Uninitialize();
client2->Uninitialize();
client3->Uninitialize();
client1 = NULL;
client2 = NULL;
client3 = NULL;
}
TEST_F(CFACMockTest, NavigateTwiceAfterInitToSameUrl) {
int timeout = 500;
NavigationConstraintsImpl navigation_constraints;
CreateTab();
SetAutomationServerOk(1);
EXPECT_CALL(mock_proxy_, server_version()).Times(testing::AnyNumber())
.WillRepeatedly(Return(""));
// We need some valid HWNDs, when responding to CreateExternalTab
HWND h1 = ::GetDesktopWindow();
HWND h2 = ::GetDesktopWindow();
EXPECT_CALL(mock_proxy_, SendAsAsync(testing::Property(
&IPC::SyncMessage::type, AutomationMsg_CreateExternalTab::ID),
testing::NotNull(), _))
.Times(1).WillOnce(HandleCreateTab(tab_handle_, h1, h2, 99));
EXPECT_CALL(mock_proxy_, CreateTabProxy(testing::Eq(tab_handle_)))
.WillOnce(Return(tab_));
EXPECT_CALL(cfd_, OnAutomationServerReady())
.WillOnce(InitiateNavigation(client_.get(),
std::string("http://www.nonexistent.com"),
std::string(), &navigation_constraints));
EXPECT_CALL(mock_proxy_, SendAsAsync(testing::Property(
&IPC::SyncMessage::type, AutomationMsg_NavigateInExternalTab::ID),
testing::NotNull(), _))
.Times(1).WillOnce(QUIT_LOOP(loop_));
EXPECT_CALL(mock_proxy_, CancelAsync(_)).Times(testing::AnyNumber());
EXPECT_CALL(mock_proxy_, Send(
testing::Property(&IPC::Message::type, AutomationMsg_TabReposition::ID)))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(cfd_, GetBounds(_)).Times(1);
// Here we go!
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> launch_params(
new ChromeFrameLaunchParams(
GURL("http://www.nonexistent.com"), empty, profile_path_,
profile_path_.BaseName().value(), L"", L"", false, false, false));
launch_params->set_launch_timeout(timeout);
launch_params->set_version_check(false);
EXPECT_TRUE(client_->Initialize(&cfd_, launch_params));
loop_.RunFor(10);
EXPECT_CALL(mock_proxy_, ReleaseTabProxy(testing::Eq(tab_handle_))).Times(1);
client_->Uninitialize();
}