blob: 30ce3393d577aa4fbdc79f65efa84a504a22805b [file] [log] [blame]
[email protected]f90bf0d92011-01-13 02:12:441// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]5a8db802010-10-06 17:34:432// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6#include "base/file_path.h"
[email protected]3b63f8f42011-03-28 01:54:157#include "base/memory/scoped_ptr.h"
[email protected]44f9c952011-01-02 06:05:398#include "base/synchronization/waitable_event.h"
[email protected]a8ba6362010-11-10 20:02:259#include "chrome/common/automation_messages.h"
[email protected]5a8db802010-10-06 17:34:4310#include "chrome_frame/cfproxy_private.h"
[email protected]5a8db802010-10-06 17:34:4311#include "testing/gtest/include/gtest/gtest.h"
12#include "testing/gmock/include/gmock/gmock.h"
13#include "testing/gmock_mutant.h"
14
15using testing::_;
16using testing::DoAll;
17using testing::NotNull;
18using testing::Return;
19using testing::StrictMock;
20using testing::InvokeWithoutArgs;
21using testing::WithoutArgs;
22using testing::CreateFunctor;
[email protected]ccdf73e2010-10-07 20:15:1923using testing::StrEq;
24using testing::Eq;
[email protected]5a8db802010-10-06 17:34:4325
26// There is not much to test here since CFProxy is pretty dumb.
27struct MockFactory : public ChromeProxyFactory {
28 MOCK_METHOD0(CreateProxy, ChromeProxy*());
29};
30
31struct MockChromeProxyDelegate : public ChromeProxyDelegate {
[email protected]a95986a82010-12-24 06:19:2832 MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message& message));
[email protected]5a8db802010-10-06 17:34:4333 MOCK_METHOD1(Connected, void(ChromeProxy* proxy));
34 MOCK_METHOD2(PeerLost, void(ChromeProxy*, enum DisconnectReason reason));
35 MOCK_METHOD0(Disconnected, void());
36 MOCK_METHOD0(tab_handle, int());
37
[email protected]751bf4b2010-11-05 22:06:3138 MOCK_METHOD5(Completed_CreateTab, void(bool success, HWND chrome_wnd,
39 HWND tab_window, int tab_handle, int session_id));
40 MOCK_METHOD5(Completed_ConnectToTab, void(bool success, HWND chrome_window,
41 HWND tab_window, int tab_handle, int session_id));
[email protected]5a8db802010-10-06 17:34:4342 MOCK_METHOD2(Completed_Navigate, void(bool success,
43 enum AutomationMsg_NavigationResponseValues res));
44 MOCK_METHOD3(Completed_InstallExtension, void(bool success,
45 enum AutomationMsg_ExtensionResponseValues res, SyncMessageContext* ctx));
46 MOCK_METHOD3(Completed_LoadExpandedExtension, void(bool success,
47 enum AutomationMsg_ExtensionResponseValues res, SyncMessageContext* ctx));
48 MOCK_METHOD2(Completed_GetEnabledExtensions, void(bool success,
49 const std::vector<FilePath>* v));
50
51 // Network requests from Chrome.
52 MOCK_METHOD2(Network_Start, void(int request_id,
[email protected]f5494d42010-12-23 22:15:3453 const AutomationURLRequest& request_info));
[email protected]5a8db802010-10-06 17:34:4354 MOCK_METHOD2(Network_Read, void(int request_id, int bytes_to_read));
[email protected]f90bf0d92011-01-13 02:12:4455 MOCK_METHOD2(Network_End, void(int request_id,
56 const net::URLRequestStatus& s));
[email protected]5a8db802010-10-06 17:34:4357 MOCK_METHOD1(Network_DownloadInHost, void(int request_id));
58 MOCK_METHOD2(GetCookies, void(const GURL& url, int cookie_id));
59 MOCK_METHOD2(SetCookie, void(const GURL& url, const std::string& cookie));
60
61 // Navigation progress notifications.
62 MOCK_METHOD2(NavigationStateChanged, void(int flags,
[email protected]f5494d42010-12-23 22:15:3463 const NavigationInfo& nav_info));
[email protected]5a8db802010-10-06 17:34:4364 MOCK_METHOD1(UpdateTargetUrl, void(const std::wstring& url));
65 MOCK_METHOD2(NavigationFailed, void(int error_code, const GURL& gurl));
[email protected]f5494d42010-12-23 22:15:3466 MOCK_METHOD1(DidNavigate, void(const NavigationInfo& navigation_info));
[email protected]5a8db802010-10-06 17:34:4367 MOCK_METHOD1(TabLoaded, void(const GURL& url));
68
69 //
70 MOCK_METHOD3(OpenURL, void(const GURL& url_to_open, const GURL& referrer,
71 int open_disposition));
72 MOCK_METHOD1(GoToHistoryOffset, void(int offset));
73 MOCK_METHOD3(MessageToHost, void(const std::string& message,
74 const std::string& origin, const std::string& target));
75
76 // Misc. UI.
77 MOCK_METHOD1(HandleAccelerator, void(const MSG& accel_message));
[email protected]ccdf73e2010-10-07 20:15:1978 MOCK_METHOD3(HandleContextMenu, void(HANDLE menu_handle, int align_flags,
[email protected]f5494d42010-12-23 22:15:3479 const MiniContextMenuParams& params));
[email protected]5a8db802010-10-06 17:34:4380 MOCK_METHOD1(TabbedOut, void(bool reverse));
81
82 //
83 MOCK_METHOD0(TabClosed, void());
[email protected]f5494d42010-12-23 22:15:3484 MOCK_METHOD1(AttachTab, void(const AttachExternalTabParams& attach_params));
[email protected]5a8db802010-10-06 17:34:4385};
86
87struct MockSender : public IPC::Message::Sender {
88 MOCK_METHOD1(Send, bool(IPC::Message* m));
89};
90
91struct MockCFProxyTraits : public CFProxyTraits {
92 MOCK_METHOD2(DoCreateChannel, IPC::Message::Sender*(const std::string& id,
93 IPC::Channel::Listener* l));
94 MOCK_METHOD1(CloseChannel, void(IPC::Message::Sender* s));
95 MOCK_METHOD1(LaunchApp, bool(const std::wstring& cmd_line));
96
97 // Forward the CreateChannel to DoCreateChannel, but save the ipc_thread
98 // and the listener (i.e. proxy implementation of Channel::Listener)
99 virtual IPC::Message::Sender* CreateChannel(const std::string& id,
100 IPC::Channel::Listener* l) {
101 ipc_loop = MessageLoop::current();
102 listener = l;
103 return this->DoCreateChannel(id, l);
104 }
105
106 // Simulate some activity in the IPC thread.
107 // You may find API_FIRE_XXXX macros (see below) handy instead.
108 void FireConnect(base::TimeDelta t) {
109 ASSERT_TRUE(ipc_loop != NULL);
110 ipc_loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(listener,
111 &IPC::Channel::Listener::OnChannelConnected, 0), t.InMilliseconds());
112 }
113
114 void FireError(base::TimeDelta t) {
115 ASSERT_TRUE(ipc_loop != NULL);
116 ipc_loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(listener,
117 &IPC::Channel::Listener::OnChannelError), t.InMilliseconds());
118 }
119
120 void FireMessage(const IPC::Message& m, base::TimeDelta t) {
121 ASSERT_TRUE(ipc_loop != NULL);
122 ipc_loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(listener,
123 &IPC::Channel::Listener::OnMessageReceived, m), t.InMilliseconds());
124 }
125
126 MockCFProxyTraits() : ipc_loop(NULL) {}
127 MockSender sender;
128 private:
129 MessageLoop* ipc_loop;
130 IPC::Channel::Listener* listener;
131};
132
133// Handy macros when we want so similate something on the IPC thread.
134#define API_FIRE_CONNECT(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
135 &MockCFProxyTraits::FireConnect, t))
136#define API_FIRE_ERROR(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
137 &MockCFProxyTraits::FireError, t))
138#define API_FIRE_MESSAGE(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
139 &MockCFProxyTraits::FireMessage, t))
140DISABLE_RUNNABLE_METHOD_REFCOUNT(IPC::Channel::Listener);
141
142TEST(ChromeProxy, DelegateAddRemove) {
143 StrictMock<MockCFProxyTraits> api;
144 StrictMock<MockChromeProxyDelegate> delegate;
145 StrictMock<MockFactory> factory; // to be destroyed before other mocks
146 CFProxy* proxy = new CFProxy(&api);
147
148 EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
149 EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
150 EXPECT_CALL(api, LaunchApp(_)).WillOnce(Return(true));
151 EXPECT_CALL(api, CloseChannel(&api.sender));
152
153 EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
154 EXPECT_CALL(delegate, Disconnected());
155
156 ProxyParams params;
157 params.profile = "Adam N. Epilinter";
158 params.timeout = base::TimeDelta::FromSeconds(4);
159 factory.GetProxy(&delegate, params);
160 factory.ReleaseProxy(&delegate, params.profile);
161}
162
163// Not very useful test. Just for illustration. :)
164TEST(ChromeProxy, SharedProxy) {
165 base::WaitableEvent done1(false, false);
166 base::WaitableEvent done2(false, false);
167 StrictMock<MockCFProxyTraits> api;
168 StrictMock<MockChromeProxyDelegate> delegate1;
169 StrictMock<MockChromeProxyDelegate> delegate2;
170 StrictMock<MockFactory> factory;
171 CFProxy* proxy = new CFProxy(&api);
172
173 EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
174 EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
175 EXPECT_CALL(api, LaunchApp(_)).WillOnce(DoAll(
176 API_FIRE_CONNECT(api, base::TimeDelta::FromMilliseconds(150)),
177 Return(true)));
178 EXPECT_CALL(api, CloseChannel(&api.sender));
179
180 EXPECT_CALL(delegate1, tab_handle()).WillRepeatedly(Return(0));
181 EXPECT_CALL(delegate2, tab_handle()).WillRepeatedly(Return(0));
182
183 EXPECT_CALL(delegate1, Connected(proxy))
184 .WillOnce(InvokeWithoutArgs(&done1, &base::WaitableEvent::Signal));
185 EXPECT_CALL(delegate2, Connected(proxy))
186 .WillOnce(InvokeWithoutArgs(&done2, &base::WaitableEvent::Signal));
187
188 ProxyParams params;
189 params.profile = "Adam N. Epilinter";
190 params.timeout = base::TimeDelta::FromSeconds(4);
191
192 factory.GetProxy(&delegate1, params);
193 params.timeout = base::TimeDelta::FromSeconds(2);
194 factory.GetProxy(&delegate2, params);
195
196 EXPECT_TRUE(done1.TimedWait(base::TimeDelta::FromSeconds(1)));
197 EXPECT_TRUE(done2.TimedWait(base::TimeDelta::FromSeconds(1)));
198
199 EXPECT_CALL(delegate2, Disconnected());
200 EXPECT_CALL(delegate1, Disconnected());
201
202 factory.ReleaseProxy(&delegate2, params.profile);
203 factory.ReleaseProxy(&delegate1, params.profile);
204}
205
206TEST(ChromeProxy, LaunchTimeout) {
207 base::WaitableEvent done(true, false);
[email protected]5a8db802010-10-06 17:34:43208 StrictMock<MockCFProxyTraits> api;
209 StrictMock<MockChromeProxyDelegate> delegate;
[email protected]68a66062010-10-06 18:11:26210 StrictMock<MockFactory> factory;
[email protected]5a8db802010-10-06 17:34:43211 CFProxy* proxy = new CFProxy(&api);
212
213 EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
214 EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
215 EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
216 EXPECT_CALL(api, LaunchApp(_)).WillOnce(Return(true));
217 EXPECT_CALL(api, CloseChannel(&api.sender));
218
219 EXPECT_CALL(delegate, PeerLost(_,
220 ChromeProxyDelegate::CHROME_EXE_LAUNCH_TIMEOUT))
221 .WillOnce(InvokeWithoutArgs(&done, &base::WaitableEvent::Signal));
222 ProxyParams params;
223 params.profile = "Adam N. Epilinter";
224 params.timeout = base::TimeDelta::FromMilliseconds(300);
225 factory.GetProxy(&delegate, params);
226 EXPECT_TRUE(done.TimedWait(base::TimeDelta::FromSeconds(1)));
227
228 EXPECT_CALL(delegate, Disconnected());
229 factory.ReleaseProxy(&delegate, params.profile);
230}
231
232TEST(ChromeProxy, LaunchChrome) {
233 base::WaitableEvent connected(false, false);
234 StrictMock<MockChromeProxyDelegate> delegate;
235 ChromeProxyFactory factory;
236
237 ProxyParams params;
238 params.profile = "Adam N. Epilinter";
239 params.timeout = base::TimeDelta::FromSeconds(10);
240
241 EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
242 EXPECT_CALL(delegate, Connected(NotNull()))
243 .WillOnce(InvokeWithoutArgs(&connected, &base::WaitableEvent::Signal));
244
245 factory.GetProxy(&delegate, params);
246 EXPECT_TRUE(connected.TimedWait(base::TimeDelta::FromSeconds(15)));
247
248 EXPECT_CALL(delegate, Disconnected());
249 factory.ReleaseProxy(&delegate, params.profile);
250}
251
[email protected]138dc7d2010-10-12 19:47:18252// Test that a channel error results in Completed_XYZ(false, ) called if
253// the synchronious XYZ message has been sent.
254TEST(ChromeProxy, ChannelError) {
255 base::WaitableEvent connected(false, false);
256 StrictMock<MockCFProxyTraits> api;
257 StrictMock<MockChromeProxyDelegate> delegate;
258 StrictMock<MockFactory> factory;
259 CFProxy* proxy = new CFProxy(&api);
260
261 ProxyParams params;
262 params.profile = "Adam N. Epilinter";
263 params.timeout = base::TimeDelta::FromMilliseconds(300);
264
265 testing::InSequence s;
266
267 EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
268 EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
269 EXPECT_CALL(api, LaunchApp(_)).WillOnce(DoAll(
270 API_FIRE_CONNECT(api, base::TimeDelta::FromMilliseconds(10)),
271 Return(true)));
272 EXPECT_CALL(delegate, Connected(proxy))
273 .WillOnce(DoAll(
274 InvokeWithoutArgs(CreateFunctor(proxy, &ChromeProxy::ConnectTab,
275 &delegate, HWND(6), 512)),
276 InvokeWithoutArgs(&connected, &base::WaitableEvent::Signal)));
277
278 EXPECT_CALL(api.sender, Send(_));
[email protected]751bf4b2010-11-05 22:06:31279 EXPECT_CALL(delegate, Completed_ConnectToTab(false, _, _, _, _));
[email protected]138dc7d2010-10-12 19:47:18280 EXPECT_CALL(api, CloseChannel(&api.sender));
281 EXPECT_CALL(delegate, PeerLost(_, ChromeProxyDelegate::CHANNEL_ERROR));
282
283 factory.GetProxy(&delegate, params);
284 EXPECT_TRUE(connected.TimedWait(base::TimeDelta::FromSeconds(15)));
285 // Simulate a channel error.
286 api.FireError(base::TimeDelta::FromMilliseconds(0));
287
288 // Expectations when the Proxy is destroyed.
289 EXPECT_CALL(delegate, tab_handle()).WillOnce(Return(0));
290 EXPECT_CALL(delegate, Disconnected());
291 factory.ReleaseProxy(&delegate, params.profile);
292}
[email protected]5a8db802010-10-06 17:34:43293///////////////////////////////////////////////////////////////////////////////
294namespace {
295template <typename M, typename A>
296inline IPC::Message* CreateReply(M* m, const A& a) {
297 IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
298 if (r) {
299 M::WriteReplyParams(r, a);
300 }
301 return r;
302}
303
304template <typename M, typename A, typename B>
305inline IPC::Message* CreateReply(M* m, const A& a, const B& b) {
306 IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
307 if (r) {
308 M::WriteReplyParams(r, a, b);
309 }
310 return r;
311}
312
313template <typename M, typename A, typename B, typename C>
314inline IPC::Message* CreateReply(M* m, const A& a, const B& b, const C& c) {
315 IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
316 if (r) {
317 M::WriteReplyParams(r, a, b, c);
318 }
319 return r;
320}
[email protected]751bf4b2010-11-05 22:06:31321
322template <typename M, typename A, typename B, typename C, typename D>
323inline IPC::Message* CreateReply(M* m, const A& a, const B& b, const C& c,
324 const D& d) {
325 IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
326 if (r) {
327 M::WriteReplyParams(r, a, b, c, d);
328 }
329 return r;
330}} // namespace
[email protected]5a8db802010-10-06 17:34:43331
332DISABLE_RUNNABLE_METHOD_REFCOUNT(SyncMsgSender);
333TEST(SyncMsgSender, Deserialize) {
334 // Note the ipc thread is not actually needed, but we try to be close
335 // to real-world conditions - that SyncMsgSender works from multiple threads.
336 base::Thread ipc("ipc");
337 ipc.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
338
339 StrictMock<MockChromeProxyDelegate> d1;
340 TabsMap tab2delegate;
341 SyncMsgSender queue(&tab2delegate);
342
[email protected]751bf4b2010-11-05 22:06:31343 const int kTabHandle = 6;
344 const int kSessionId = 8;
345
[email protected]5a8db802010-10-06 17:34:43346 // Create some sync messages and their replies.
[email protected]f5494d42010-12-23 22:15:34347 AutomationMsg_InstallExtension m1(FilePath(L"c:\\awesome.x"), 0);
348 AutomationMsg_CreateExternalTab m2(ExternalTabSettings(), 0, 0, 0, 0);
[email protected]5a8db802010-10-06 17:34:43349 scoped_ptr<IPC::Message> r1(CreateReply(&m1,
350 AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED));
[email protected]751bf4b2010-11-05 22:06:31351 scoped_ptr<IPC::Message> r2(CreateReply(&m2, (HWND)1, (HWND)2, kTabHandle,
352 kSessionId));
[email protected]5a8db802010-10-06 17:34:43353
354 queue.QueueSyncMessage(&m1, &d1, NULL);
355 queue.QueueSyncMessage(&m2, &d1, NULL);
356
357 testing::InSequence s;
358 EXPECT_CALL(d1, Completed_InstallExtension(true,
359 AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED, NULL));
[email protected]751bf4b2010-11-05 22:06:31360 EXPECT_CALL(d1, Completed_CreateTab(true, (HWND)1, (HWND)2, kTabHandle,
361 kSessionId));
[email protected]5a8db802010-10-06 17:34:43362
363 // Execute replies in a worker thread.
364 ipc.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(&queue,
365 &SyncMsgSender::OnReplyReceived, r1.get()));
366 ipc.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(&queue,
367 &SyncMsgSender::OnReplyReceived, r2.get()));
368 ipc.Stop();
369
370 // Expect that tab 6 has been associated with the delegate.
371 EXPECT_EQ(&d1, tab2delegate[6]);
372}
373
374TEST(SyncMsgSender, OnChannelClosed) {
375 // TODO(stoyan): implement.
376}