Updating trunk VERSION from 993.0 to 994.0
[chromium-blink-merge.git] / chrome_frame / cfproxy_test.cc
blob417413322176f41777e2e9be1643d9c83a5e5439
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <string>
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/file_path.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "chrome/common/automation_messages.h"
13 #include "chrome_frame/cfproxy_private.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gmock_mutant.h"
18 using testing::_;
19 using testing::DoAll;
20 using testing::NotNull;
21 using testing::Return;
22 using testing::StrictMock;
23 using testing::InvokeWithoutArgs;
24 using testing::WithoutArgs;
25 using testing::CreateFunctor;
26 using testing::StrEq;
27 using testing::Eq;
29 // There is not much to test here since CFProxy is pretty dumb.
30 struct MockFactory : public ChromeProxyFactory {
31 MOCK_METHOD0(CreateProxy, ChromeProxy*());
34 struct MockChromeProxyDelegate : public ChromeProxyDelegate {
35 MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message& message));
36 MOCK_METHOD1(Connected, void(ChromeProxy* proxy));
37 MOCK_METHOD2(PeerLost, void(ChromeProxy*, enum DisconnectReason reason));
38 MOCK_METHOD0(Disconnected, void());
39 MOCK_METHOD0(tab_handle, int());
41 MOCK_METHOD5(Completed_CreateTab, void(bool success, HWND chrome_wnd,
42 HWND tab_window, int tab_handle, int session_id));
43 MOCK_METHOD5(Completed_ConnectToTab, void(bool success, HWND chrome_window,
44 HWND tab_window, int tab_handle, int session_id));
45 MOCK_METHOD2(Completed_Navigate, void(bool success,
46 enum AutomationMsg_NavigationResponseValues res));
48 // Network requests from Chrome.
49 MOCK_METHOD2(Network_Start, void(int request_id,
50 const AutomationURLRequest& request_info));
51 MOCK_METHOD2(Network_Read, void(int request_id, int bytes_to_read));
52 MOCK_METHOD2(Network_End, void(int request_id,
53 const net::URLRequestStatus& s));
54 MOCK_METHOD1(Network_DownloadInHost, void(int request_id));
55 MOCK_METHOD2(GetCookies, void(const GURL& url, int cookie_id));
56 MOCK_METHOD2(SetCookie, void(const GURL& url, const std::string& cookie));
58 // Navigation progress notifications.
59 MOCK_METHOD2(NavigationStateChanged, void(int flags,
60 const NavigationInfo& nav_info));
61 MOCK_METHOD1(UpdateTargetUrl, void(const std::wstring& url));
62 MOCK_METHOD2(NavigationFailed, void(int error_code, const GURL& gurl));
63 MOCK_METHOD1(DidNavigate, void(const NavigationInfo& navigation_info));
64 MOCK_METHOD1(TabLoaded, void(const GURL& url));
67 MOCK_METHOD3(OpenURL, void(const GURL& url_to_open, const GURL& referrer,
68 int open_disposition));
69 MOCK_METHOD1(GoToHistoryOffset, void(int offset));
70 MOCK_METHOD3(MessageToHost, void(const std::string& message,
71 const std::string& origin, const std::string& target));
73 // Misc. UI.
74 MOCK_METHOD1(HandleAccelerator, void(const MSG& accel_message));
75 MOCK_METHOD3(HandleContextMenu, void(HANDLE menu_handle, int align_flags,
76 const MiniContextMenuParams& params));
77 MOCK_METHOD1(TabbedOut, void(bool reverse));
80 MOCK_METHOD0(TabClosed, void());
81 MOCK_METHOD1(AttachTab, void(const AttachExternalTabParams& attach_params));
84 struct MockSender : public IPC::Message::Sender {
85 MOCK_METHOD1(Send, bool(IPC::Message* m));
88 struct MockCFProxyTraits : public CFProxyTraits {
89 MOCK_METHOD2(DoCreateChannel, IPC::Message::Sender*(const std::string& id,
90 IPC::Channel::Listener* l));
91 MOCK_METHOD1(CloseChannel, void(IPC::Message::Sender* s));
92 MOCK_METHOD1(LaunchApp, bool(const std::wstring& cmd_line));
94 // Forward the CreateChannel to DoCreateChannel, but save the ipc_thread
95 // and the listener (i.e. proxy implementation of Channel::Listener)
96 virtual IPC::Message::Sender* CreateChannel(const std::string& id,
97 IPC::Channel::Listener* l) {
98 ipc_loop = MessageLoop::current();
99 listener = l;
100 return this->DoCreateChannel(id, l);
103 // Simulate some activity in the IPC thread.
104 // You may find API_FIRE_XXXX macros (see below) handy instead.
105 void FireConnect(base::TimeDelta t) {
106 ASSERT_TRUE(ipc_loop != NULL);
107 ipc_loop->PostDelayedTask(
108 FROM_HERE, base::Bind(&IPC::Channel::Listener::OnChannelConnected,
109 base::Unretained(listener), 0),
110 t.InMilliseconds());
113 void FireError(base::TimeDelta t) {
114 ASSERT_TRUE(ipc_loop != NULL);
115 ipc_loop->PostDelayedTask(
116 FROM_HERE, base::Bind(&IPC::Channel::Listener::OnChannelError,
117 base::Unretained(listener)),
118 t.InMilliseconds());
121 void FireMessage(const IPC::Message& m, base::TimeDelta t) {
122 ASSERT_TRUE(ipc_loop != NULL);
123 ipc_loop->PostDelayedTask(
124 FROM_HERE,
125 base::IgnoreReturn<bool>(
126 base::Bind(&IPC::Channel::Listener::OnMessageReceived,
127 base::Unretained(listener), m)),
128 t.InMilliseconds());
131 MockCFProxyTraits() : ipc_loop(NULL) {}
132 MockSender sender;
133 private:
134 MessageLoop* ipc_loop;
135 IPC::Channel::Listener* listener;
138 // Handy macros when we want so simulate something on the IPC thread.
139 #define API_FIRE_CONNECT(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
140 &MockCFProxyTraits::FireConnect, t))
141 #define API_FIRE_ERROR(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
142 &MockCFProxyTraits::FireError, t))
143 #define API_FIRE_MESSAGE(api, t) InvokeWithoutArgs(CreateFunctor(&api, \
144 &MockCFProxyTraits::FireMessage, t))
146 TEST(ChromeProxy, DelegateAddRemove) {
147 StrictMock<MockCFProxyTraits> api;
148 StrictMock<MockChromeProxyDelegate> delegate;
149 StrictMock<MockFactory> factory; // to be destroyed before other mocks
150 CFProxy* proxy = new CFProxy(&api);
152 EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
153 EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
154 EXPECT_CALL(api, LaunchApp(_)).WillOnce(Return(true));
155 EXPECT_CALL(api, CloseChannel(&api.sender));
157 EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
158 EXPECT_CALL(delegate, Disconnected());
160 ProxyParams params;
161 params.profile = "Adam N. Epilinter";
162 params.timeout = base::TimeDelta::FromSeconds(4);
163 factory.GetProxy(&delegate, params);
164 factory.ReleaseProxy(&delegate, params.profile);
167 // Not very useful test. Just for illustration. :)
168 TEST(ChromeProxy, SharedProxy) {
169 base::WaitableEvent done1(false, false);
170 base::WaitableEvent done2(false, false);
171 StrictMock<MockCFProxyTraits> api;
172 StrictMock<MockChromeProxyDelegate> delegate1;
173 StrictMock<MockChromeProxyDelegate> delegate2;
174 StrictMock<MockFactory> factory;
175 CFProxy* proxy = new CFProxy(&api);
177 EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
178 EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
179 EXPECT_CALL(api, LaunchApp(_)).WillOnce(DoAll(
180 API_FIRE_CONNECT(api, base::TimeDelta::FromMilliseconds(150)),
181 Return(true)));
182 EXPECT_CALL(api, CloseChannel(&api.sender));
184 EXPECT_CALL(delegate1, tab_handle()).WillRepeatedly(Return(0));
185 EXPECT_CALL(delegate2, tab_handle()).WillRepeatedly(Return(0));
187 EXPECT_CALL(delegate1, Connected(proxy))
188 .WillOnce(InvokeWithoutArgs(&done1, &base::WaitableEvent::Signal));
189 EXPECT_CALL(delegate2, Connected(proxy))
190 .WillOnce(InvokeWithoutArgs(&done2, &base::WaitableEvent::Signal));
192 ProxyParams params;
193 params.profile = "Adam N. Epilinter";
194 params.timeout = base::TimeDelta::FromSeconds(4);
196 factory.GetProxy(&delegate1, params);
197 params.timeout = base::TimeDelta::FromSeconds(2);
198 factory.GetProxy(&delegate2, params);
200 EXPECT_TRUE(done1.TimedWait(base::TimeDelta::FromSeconds(1)));
201 EXPECT_TRUE(done2.TimedWait(base::TimeDelta::FromSeconds(1)));
203 EXPECT_CALL(delegate2, Disconnected());
204 EXPECT_CALL(delegate1, Disconnected());
206 factory.ReleaseProxy(&delegate2, params.profile);
207 factory.ReleaseProxy(&delegate1, params.profile);
210 TEST(ChromeProxy, LaunchTimeout) {
211 base::WaitableEvent done(true, false);
212 StrictMock<MockCFProxyTraits> api;
213 StrictMock<MockChromeProxyDelegate> delegate;
214 StrictMock<MockFactory> factory;
215 CFProxy* proxy = new CFProxy(&api);
217 EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
218 EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
219 EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
220 EXPECT_CALL(api, LaunchApp(_)).WillOnce(Return(true));
221 EXPECT_CALL(api, CloseChannel(&api.sender));
223 EXPECT_CALL(delegate, PeerLost(_,
224 ChromeProxyDelegate::CHROME_EXE_LAUNCH_TIMEOUT))
225 .WillOnce(InvokeWithoutArgs(&done, &base::WaitableEvent::Signal));
226 ProxyParams params;
227 params.profile = "Adam N. Epilinter";
228 params.timeout = base::TimeDelta::FromMilliseconds(300);
229 factory.GetProxy(&delegate, params);
230 EXPECT_TRUE(done.TimedWait(base::TimeDelta::FromSeconds(1)));
232 EXPECT_CALL(delegate, Disconnected());
233 factory.ReleaseProxy(&delegate, params.profile);
236 TEST(ChromeProxy, LaunchChrome) {
237 base::WaitableEvent connected(false, false);
238 StrictMock<MockChromeProxyDelegate> delegate;
239 ChromeProxyFactory factory;
241 ProxyParams params;
242 params.profile = "Adam N. Epilinter";
243 params.timeout = base::TimeDelta::FromSeconds(10);
245 EXPECT_CALL(delegate, tab_handle()).WillRepeatedly(Return(0));
246 EXPECT_CALL(delegate, Connected(NotNull()))
247 .WillOnce(InvokeWithoutArgs(&connected, &base::WaitableEvent::Signal));
249 factory.GetProxy(&delegate, params);
250 EXPECT_TRUE(connected.TimedWait(base::TimeDelta::FromSeconds(15)));
252 EXPECT_CALL(delegate, Disconnected());
253 factory.ReleaseProxy(&delegate, params.profile);
256 // Test that a channel error results in Completed_XYZ(false, ) called if
257 // the synchronious XYZ message has been sent.
258 TEST(ChromeProxy, ChannelError) {
259 base::WaitableEvent connected(false, false);
260 StrictMock<MockCFProxyTraits> api;
261 StrictMock<MockChromeProxyDelegate> delegate;
262 StrictMock<MockFactory> factory;
263 CFProxy* proxy = new CFProxy(&api);
265 ProxyParams params;
266 params.profile = "Adam N. Epilinter";
267 params.timeout = base::TimeDelta::FromMilliseconds(300);
269 testing::InSequence s;
271 EXPECT_CALL(factory, CreateProxy()).WillOnce(Return(proxy));
272 EXPECT_CALL(api, DoCreateChannel(_, proxy)).WillOnce(Return(&api.sender));
273 EXPECT_CALL(api, LaunchApp(_)).WillOnce(DoAll(
274 API_FIRE_CONNECT(api, base::TimeDelta::FromMilliseconds(10)),
275 Return(true)));
276 EXPECT_CALL(delegate, Connected(proxy))
277 .WillOnce(DoAll(
278 InvokeWithoutArgs(CreateFunctor(proxy, &ChromeProxy::ConnectTab,
279 &delegate, HWND(6), 512)),
280 InvokeWithoutArgs(&connected, &base::WaitableEvent::Signal)));
282 EXPECT_CALL(api.sender, Send(_));
283 EXPECT_CALL(delegate, Completed_ConnectToTab(false, _, _, _, _));
284 EXPECT_CALL(api, CloseChannel(&api.sender));
285 EXPECT_CALL(delegate, PeerLost(_, ChromeProxyDelegate::CHANNEL_ERROR));
287 factory.GetProxy(&delegate, params);
288 EXPECT_TRUE(connected.TimedWait(base::TimeDelta::FromSeconds(15)));
289 // Simulate a channel error.
290 api.FireError(base::TimeDelta::FromMilliseconds(0));
292 // Expectations when the Proxy is destroyed.
293 EXPECT_CALL(delegate, tab_handle()).WillOnce(Return(0));
294 EXPECT_CALL(delegate, Disconnected());
295 factory.ReleaseProxy(&delegate, params.profile);
297 ///////////////////////////////////////////////////////////////////////////////
298 namespace {
299 template <typename M, typename A>
300 inline IPC::Message* CreateReply(M* m, const A& a) {
301 IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
302 if (r) {
303 M::WriteReplyParams(r, a);
305 return r;
308 template <typename M, typename A, typename B>
309 inline IPC::Message* CreateReply(M* m, const A& a, const B& b) {
310 IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
311 if (r) {
312 M::WriteReplyParams(r, a, b);
314 return r;
317 template <typename M, typename A, typename B, typename C>
318 inline IPC::Message* CreateReply(M* m, const A& a, const B& b, const C& c) {
319 IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
320 if (r) {
321 M::WriteReplyParams(r, a, b, c);
323 return r;
326 template <typename M, typename A, typename B, typename C, typename D>
327 inline IPC::Message* CreateReply(M* m, const A& a, const B& b, const C& c,
328 const D& d) {
329 IPC::Message* r = IPC::SyncMessage::GenerateReply(m);
330 if (r) {
331 M::WriteReplyParams(r, a, b, c, d);
333 return r;
334 }} // namespace
336 TEST(SyncMsgSender, Deserialize) {
337 // Note the ipc thread is not actually needed, but we try to be close
338 // to real-world conditions - that SyncMsgSender works from multiple threads.
339 base::Thread ipc("ipc");
340 ipc.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
342 StrictMock<MockChromeProxyDelegate> d1;
343 TabsMap tab2delegate;
344 SyncMsgSender queue(&tab2delegate);
346 const int kTabHandle = 6;
347 const int kSessionId = 8;
349 // Create a sync message and its reply.
350 AutomationMsg_CreateExternalTab m(ExternalTabSettings(), 0, 0, 0, 0);
351 scoped_ptr<IPC::Message> r(CreateReply(&m, (HWND)1, (HWND)2, kTabHandle,
352 kSessionId));
354 queue.QueueSyncMessage(&m, &d1, NULL);
356 testing::InSequence s;
357 EXPECT_CALL(d1, Completed_CreateTab(true, (HWND)1, (HWND)2, kTabHandle,
358 kSessionId));
360 // Execute replies in a worker thread.
361 ipc.message_loop()->PostTask(
362 FROM_HERE,
363 base::IgnoreReturn<bool>(base::Bind(&SyncMsgSender::OnReplyReceived,
364 base::Unretained(&queue), r.get())));
365 ipc.Stop();
367 // Expect that tab 6 has been associated with the delegate.
368 EXPECT_EQ(&d1, tab2delegate[6]);
371 TEST(SyncMsgSender, OnChannelClosed) {
372 // TODO(stoyan): implement.