1 // Copyright (c) 2012 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.
9 #include "base/bind_helpers.h"
10 #include "chrome/common/automation_messages.h"
11 #include "chrome_frame/test/chrome_frame_test_utils.h"
12 #include "chrome_frame/test/test_server.h"
13 #include "chrome_frame/test/test_with_web_server.h"
14 #include "chrome_frame/urlmon_url_request.h"
15 #include "chrome_frame/urlmon_url_request_private.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gmock_mutant.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using testing::CreateFunctor
;
22 using chrome_frame_test::kChromeFrameLongNavigationTimeout
;
24 static void AppendToStream(IStream
* s
, void* buffer
, ULONG cb
) {
26 LARGE_INTEGER current_pos
;
27 LARGE_INTEGER zero
= {0};
28 // Remember current position.
29 ASSERT_HRESULT_SUCCEEDED(s
->Seek(zero
, STREAM_SEEK_CUR
,
30 reinterpret_cast<ULARGE_INTEGER
*>(¤t_pos
)));
32 ASSERT_HRESULT_SUCCEEDED(s
->Seek(zero
, STREAM_SEEK_END
, NULL
));
33 ASSERT_HRESULT_SUCCEEDED(s
->Write(buffer
, cb
, &bytes_written
));
34 ASSERT_EQ(cb
, bytes_written
);
35 // Seek to original position.
36 ASSERT_HRESULT_SUCCEEDED(s
->Seek(current_pos
, STREAM_SEEK_SET
, NULL
));
39 class MockUrlDelegate
: public PluginUrlRequestDelegate
{
41 MOCK_METHOD9(OnResponseStarted
, void(int request_id
, const char* mime_type
,
42 const char* headers
, int size
, base::Time last_modified
,
43 const std::string
& redirect_url
, int redirect_status
,
44 const net::HostPortPair
& socket_address
, uint64 upload_size
));
45 MOCK_METHOD2(OnReadComplete
, void(int request_id
, const std::string
& data
));
46 MOCK_METHOD2(OnResponseEnd
, void(int request_id
,
47 const net::URLRequestStatus
& status
));
48 MOCK_METHOD4(OnCookiesRetrieved
, void(bool success
, const GURL
& url
,
49 const std::string
& cookie
, int cookie_id
));
51 void PostponeReadRequest(chrome_frame_test::TimedMsgLoop
* loop
,
52 UrlmonUrlRequest
* request
, int bytes_to_read
) {
53 loop
->PostTask(FROM_HERE
,
54 base::Bind(&MockUrlDelegate::RequestRead
,
55 base::Unretained(this), request
, bytes_to_read
));
59 void RequestRead(UrlmonUrlRequest
* request
, int bytes_to_read
) {
60 request
->Read(bytes_to_read
);
64 // Simplest UrlmonUrlRequest. Retrieve a file from local web server.
65 TEST(UrlmonUrlRequestTest
, Simple1
) {
67 chrome_frame_test::TimedMsgLoop loop
;
69 testing::StrictMock
<MockWebServer
> mock_server(1337,
70 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()),
71 chrome_frame_test::GetTestDataFolder());
72 mock_server
.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE
));
74 CComObjectStackEx
<UrlmonUrlRequest
> request
;
77 request
.Initialize(&mock
, 1, // request_id
78 WideToUTF8(mock_server
.Resolve(L
"chrome_frame_window_open.html")),
83 ResourceType::MAIN_FRAME
, // resource type
87 testing::InSequence s
;
88 EXPECT_CALL(mock
, OnResponseStarted(1, testing::_
, testing::_
, testing::_
,
89 testing::_
, testing::_
, testing::_
,
90 testing::_
, testing::_
))
92 .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor(
93 &request
, &UrlmonUrlRequest::Read
, 512))));
96 EXPECT_CALL(mock
, OnReadComplete(1, testing::Property(&std::string::size
,
98 .Times(testing::AtLeast(1))
99 .WillRepeatedly(testing::InvokeWithoutArgs(CreateFunctor(&mock
,
100 &MockUrlDelegate::PostponeReadRequest
, &loop
, &request
, 64)));
102 EXPECT_CALL(mock
, OnResponseEnd(1, testing::_
))
104 .WillOnce(QUIT_LOOP_SOON(loop
, base::TimeDelta::FromSeconds(2)));
107 loop
.RunFor(kChromeFrameLongNavigationTimeout
);
111 // Same as Simple1 except we use the HEAD verb to fetch only the headers
113 TEST(UrlmonUrlRequestTest
, Head
) {
114 MockUrlDelegate mock
;
115 chrome_frame_test::TimedMsgLoop loop
;
116 // Use SimpleWebServer instead of the python server to support HEAD
118 test_server::SimpleWebServer
server(13337);
119 test_server::SimpleResponse
head_response("/head", "");
120 server
.AddResponse(&head_response
);
122 CComObjectStackEx
<UrlmonUrlRequest
> request
;
125 request
.Initialize(&mock
, 1, // request_id
126 base::StringPrintf("http://%s:13337/head", server
.host().c_str()),
131 ResourceType::MAIN_FRAME
, // resource type
135 testing::InSequence s
;
136 EXPECT_CALL(mock
, OnResponseStarted(1, testing::_
, testing::_
, testing::_
,
137 testing::_
, testing::_
, testing::_
,
138 testing::_
, testing::_
))
140 .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor(
141 &request
, &UrlmonUrlRequest::Read
, 512))));
143 // For HEAD requests we don't expect content reads.
144 EXPECT_CALL(mock
, OnReadComplete(1, testing::_
)).Times(0);
146 EXPECT_CALL(mock
, OnResponseEnd(1, testing::_
))
148 .WillOnce(QUIT_LOOP_SOON(loop
, base::TimeDelta::FromSeconds(2)));
151 loop
.RunFor(kChromeFrameLongNavigationTimeout
);
155 TEST(UrlmonUrlRequestTest
, UnreachableUrl
) {
156 MockUrlDelegate mock
;
157 chrome_frame_test::TimedMsgLoop loop
;
158 CComObjectStackEx
<UrlmonUrlRequest
> request
;
160 testing::StrictMock
<MockWebServer
> mock_server(1337,
161 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()),
162 chrome_frame_test::GetTestDataFolder());
163 mock_server
.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE
));
165 GURL
unreachable(WideToUTF8(mock_server
.Resolve(
166 L
"non_existing.html")));
169 request
.Initialize(&mock
, 1, // request_id
170 unreachable
.spec(), "get",
174 ResourceType::MAIN_FRAME
, // resource type
179 EXPECT_CALL(mock
, OnResponseStarted(1, testing::_
,
180 testing::StartsWith("HTTP/1.1 404"),
181 testing::_
, testing::_
, testing::_
,
182 testing::_
, testing::_
, testing::_
))
184 .WillOnce(QUIT_LOOP_SOON(loop
, base::TimeDelta::FromSeconds(2)));
186 EXPECT_CALL(mock
, OnResponseEnd(1, testing::Property(
187 &net::URLRequestStatus::error
,
188 net::ERR_TUNNEL_CONNECTION_FAILED
)))
189 .Times(testing::AtMost(1));
192 loop
.RunFor(kChromeFrameLongNavigationTimeout
);
196 TEST(UrlmonUrlRequestTest
, ZeroLengthResponse
) {
197 MockUrlDelegate mock
;
198 chrome_frame_test::TimedMsgLoop loop
;
200 testing::StrictMock
<MockWebServer
> mock_server(1337,
201 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()),
202 chrome_frame_test::GetTestDataFolder());
203 mock_server
.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE
));
205 CComObjectStackEx
<UrlmonUrlRequest
> request
;
208 request
.Initialize(&mock
, 1, // request_id
209 WideToUTF8(mock_server
.Resolve(L
"empty.html")), "get",
213 ResourceType::MAIN_FRAME
, // resource type
218 EXPECT_CALL(mock
, OnResponseStarted(1, testing::_
, testing::_
, testing::_
,
219 testing::_
, testing::_
, testing::_
,
220 testing::_
, testing::_
))
222 .WillOnce(QUIT_LOOP(loop
));
225 loop
.RunFor(kChromeFrameLongNavigationTimeout
);
226 EXPECT_FALSE(loop
.WasTimedOut());
228 // Should stay quiet, since we do not ask for anything for awhile.
229 EXPECT_CALL(mock
, OnResponseEnd(1, testing::_
)).Times(0);
230 loop
.RunFor(base::TimeDelta::FromSeconds(3));
232 // Invoke read. Only now the response end ("server closed the connection")
233 // is supposed to be delivered.
234 EXPECT_CALL(mock
, OnResponseEnd(1, testing::Property(
235 &net::URLRequestStatus::is_success
, true))).Times(1);
240 ACTION_P4(ManagerRead
, loop
, mgr
, request_id
, bytes_to_read
) {
241 loop
->PostTask(FROM_HERE
,
242 base::Bind(&UrlmonUrlRequestManager::ReadUrlRequest
,
243 base::Unretained(mgr
), request_id
, bytes_to_read
));
245 ACTION_P3(ManagerEndRequest
, loop
, mgr
, request_id
) {
246 loop
->PostTask(FROM_HERE
, base::Bind(&UrlmonUrlRequestManager::EndUrlRequest
,
247 base::Unretained(mgr
), request_id
,
248 net::URLRequestStatus()));
251 // Simplest test - retrieve file from local web server.
252 TEST(UrlmonUrlRequestManagerTest
, Simple1
) {
253 MockUrlDelegate mock
;
254 chrome_frame_test::TimedMsgLoop loop
;
256 testing::StrictMock
<MockWebServer
> mock_server(1337,
257 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()),
258 chrome_frame_test::GetTestDataFolder());
259 mock_server
.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE
));
261 scoped_ptr
<UrlmonUrlRequestManager
> mgr(new UrlmonUrlRequestManager());
262 mgr
->set_delegate(&mock
);
263 AutomationURLRequest r1
;
264 r1
.url
= WideToUTF8(mock_server
.Resolve(L
"chrome_frame_window_open.html"));
266 r1
.resource_type
= 0;
269 EXPECT_CALL(mock
, OnResponseStarted(1, testing::_
, testing::_
, testing::_
,
270 testing::_
, testing::_
, testing::_
, testing::_
,
273 .WillOnce(ManagerRead(&loop
, mgr
.get(), 1, 512));
275 EXPECT_CALL(mock
, OnReadComplete(1, testing::Property(&std::string::size
,
277 .Times(testing::AtLeast(1))
278 .WillRepeatedly(ManagerRead(&loop
, mgr
.get(), 1, 2));
280 EXPECT_CALL(mock
, OnResponseEnd(1, testing::_
))
282 .WillOnce(QUIT_LOOP_SOON(loop
, base::TimeDelta::FromSeconds(2)));
284 mgr
->StartUrlRequest(1, r1
);
285 loop
.RunFor(kChromeFrameLongNavigationTimeout
);
289 TEST(UrlmonUrlRequestManagerTest
, Abort1
) {
290 MockUrlDelegate mock
;
291 chrome_frame_test::TimedMsgLoop loop
;
293 testing::StrictMock
<MockWebServer
> mock_server(1337,
294 ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()),
295 chrome_frame_test::GetTestDataFolder());
296 mock_server
.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE
));
298 scoped_ptr
<UrlmonUrlRequestManager
> mgr(new UrlmonUrlRequestManager());
299 mgr
->set_delegate(&mock
);
300 AutomationURLRequest r1
;
301 r1
.url
= WideToUTF8(mock_server
.Resolve(L
"chrome_frame_window_open.html"));
303 r1
.resource_type
= 0;
306 EXPECT_CALL(mock
, OnResponseStarted(1, testing::_
, testing::_
, testing::_
,
307 testing::_
, testing::_
, testing::_
, testing::_
,
310 .WillOnce(testing::DoAll(
311 ManagerEndRequest(&loop
, mgr
.get(), 1),
312 QUIT_LOOP_SOON(loop
, base::TimeDelta::FromSeconds(3))));
314 EXPECT_CALL(mock
, OnReadComplete(1, testing::_
))
317 EXPECT_CALL(mock
, OnResponseEnd(1, testing::_
))
320 mgr
->StartUrlRequest(1, r1
);
321 loop
.RunFor(kChromeFrameLongNavigationTimeout
);