blob: ab90f4777225e3f09ee41433689f8f1c2449a3aa [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 <atlbase.h>
#include <atlcom.h>
#include "base/win/scoped_com_initializer.h"
#include "chrome/common/automation_messages.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
#include "chrome_frame/test/test_server.h"
#include "chrome_frame/test/test_with_web_server.h"
#include "chrome_frame/urlmon_url_request.h"
#include "chrome_frame/urlmon_url_request_private.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::CreateFunctor;
const int kChromeFrameLongNavigationTimeoutInSeconds = 10;
static void AppendToStream(IStream* s, void* buffer, ULONG cb) {
ULONG bytes_written;
LARGE_INTEGER current_pos;
LARGE_INTEGER zero = {0};
// Remember current position.
ASSERT_HRESULT_SUCCEEDED(s->Seek(zero, STREAM_SEEK_CUR,
reinterpret_cast<ULARGE_INTEGER*>(&current_pos)));
// Seek to the end.
ASSERT_HRESULT_SUCCEEDED(s->Seek(zero, STREAM_SEEK_END, NULL));
ASSERT_HRESULT_SUCCEEDED(s->Write(buffer, cb, &bytes_written));
ASSERT_EQ(cb, bytes_written);
// Seek to original position.
ASSERT_HRESULT_SUCCEEDED(s->Seek(current_pos, STREAM_SEEK_SET, NULL));
}
class MockUrlDelegate : public PluginUrlRequestDelegate {
public:
MOCK_METHOD8(OnResponseStarted, void(int request_id, const char* mime_type,
const char* headers, int size, base::Time last_modified,
const std::string& redirect_url, int redirect_status,
const net::HostPortPair& socket_address));
MOCK_METHOD2(OnReadComplete, void(int request_id, const std::string& data));
MOCK_METHOD2(OnResponseEnd, void(int request_id,
const net::URLRequestStatus& status));
MOCK_METHOD4(OnCookiesRetrieved, void(bool success, const GURL& url,
const std::string& cookie, int cookie_id));
static bool ImplementsThreadSafeReferenceCounting() {
return false;
}
void AddRef() {}
void Release() {}
void PostponeReadRequest(chrome_frame_test::TimedMsgLoop* loop,
UrlmonUrlRequest* request, int bytes_to_read) {
loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(this,
&MockUrlDelegate::RequestRead, request, bytes_to_read), 0);
}
private:
void RequestRead(UrlmonUrlRequest* request, int bytes_to_read) {
request->Read(bytes_to_read);
}
};
// Simplest UrlmonUrlRequest. Retrieve a file from local web server.
TEST(UrlmonUrlRequestTest, Simple1) {
MockUrlDelegate mock;
chrome_frame_test::TimedMsgLoop loop;
testing::StrictMock<MockWebServer> mock_server(1337, L"127.0.0.1",
chrome_frame_test::GetTestDataFolder());
mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE));
base::win::ScopedCOMInitializer init_com;
CComObjectStackEx<UrlmonUrlRequest> request;
request.AddRef();
request.Initialize(&mock, 1, // request_id
WideToUTF8(mock_server.Resolve(L"chrome_frame_window_open.html")),
"get",
"", // referrer
"", // extra request
NULL, // upload data
ResourceType::MAIN_FRAME, // resource type
true,
0); // frame busting
testing::InSequence s;
EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_,
testing::_, testing::_, testing::_,
testing::_))
.Times(1)
.WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor(
&request, &UrlmonUrlRequest::Read, 512))));
EXPECT_CALL(mock, OnReadComplete(1, testing::Property(&std::string::size,
testing::Gt(0u))))
.Times(testing::AtLeast(1))
.WillRepeatedly(testing::InvokeWithoutArgs(CreateFunctor(&mock,
&MockUrlDelegate::PostponeReadRequest, &loop, &request, 64)));
EXPECT_CALL(mock, OnResponseEnd(1, testing::_))
.Times(1)
.WillOnce(QUIT_LOOP_SOON(loop, 2));
request.Start();
loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
request.Release();
}
// Same as Simple1 except we use the HEAD verb to fetch only the headers
// from the server.
TEST(UrlmonUrlRequestTest, Head) {
MockUrlDelegate mock;
chrome_frame_test::TimedMsgLoop loop;
// Use SimpleWebServer instead of the python server to support HEAD
// requests.
test_server::SimpleWebServer server(13337);
test_server::SimpleResponse head_response("/head", "");
server.AddResponse(&head_response);
base::win::ScopedCOMInitializer init_com;
CComObjectStackEx<UrlmonUrlRequest> request;
request.AddRef();
request.Initialize(&mock, 1, // request_id
"http://localhost:13337/head",
"head",
"", // referrer
"", // extra request
NULL, // upload data
ResourceType::MAIN_FRAME, // resource type
true,
0); // frame busting
testing::InSequence s;
EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_,
testing::_, testing::_, testing::_,
testing::_))
.Times(1)
.WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs(CreateFunctor(
&request, &UrlmonUrlRequest::Read, 512))));
// For HEAD requests we don't expect content reads.
EXPECT_CALL(mock, OnReadComplete(1, testing::_)).Times(0);
EXPECT_CALL(mock, OnResponseEnd(1, testing::_))
.Times(1)
.WillOnce(QUIT_LOOP_SOON(loop, 2));
request.Start();
loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
request.Release();
}
TEST(UrlmonUrlRequestTest, UnreachableUrl) {
MockUrlDelegate mock;
chrome_frame_test::TimedMsgLoop loop;
base::win::ScopedCOMInitializer init_com;
CComObjectStackEx<UrlmonUrlRequest> request;
testing::StrictMock<MockWebServer> mock_server(1337, L"127.0.0.1",
chrome_frame_test::GetTestDataFolder());
mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE));
GURL unreachable(WideToUTF8(mock_server.Resolve(
L"non_existing.html")));
request.AddRef();
request.Initialize(&mock, 1, // request_id
unreachable.spec(), "get",
"", // referrer
"", // extra request
NULL, // upload data
ResourceType::MAIN_FRAME, // resource type
true,
0); // frame busting
// Expect headers
EXPECT_CALL(mock, OnResponseStarted(1, testing::_,
testing::StartsWith("HTTP/1.1 404"),
testing::_, testing::_, testing::_,
testing::_, testing::_))
.Times(1)
.WillOnce(QUIT_LOOP_SOON(loop, 2));
EXPECT_CALL(mock, OnResponseEnd(1, testing::Property(
&net::URLRequestStatus::os_error,
net::ERR_TUNNEL_CONNECTION_FAILED)))
.Times(testing::AtMost(1));
request.Start();
loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
request.Release();
}
TEST(UrlmonUrlRequestTest, ZeroLengthResponse) {
MockUrlDelegate mock;
chrome_frame_test::TimedMsgLoop loop;
testing::StrictMock<MockWebServer> mock_server(1337, L"127.0.0.1",
chrome_frame_test::GetTestDataFolder());
mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE));
base::win::ScopedCOMInitializer init_com;
CComObjectStackEx<UrlmonUrlRequest> request;
request.AddRef();
request.Initialize(&mock, 1, // request_id
WideToUTF8(mock_server.Resolve(L"empty.html")), "get",
"", // referrer
"", // extra request
NULL, // upload data
ResourceType::MAIN_FRAME, // resource type
true,
0); // frame busting
// Expect headers
EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_,
testing::_, testing::_, testing::_,
testing::_))
.Times(1)
.WillOnce(QUIT_LOOP(loop));
request.Start();
loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
EXPECT_FALSE(loop.WasTimedOut());
// Should stay quiet, since we do not ask for anything for awhile.
EXPECT_CALL(mock, OnResponseEnd(1, testing::_)).Times(0);
loop.RunFor(3);
// Invoke read. Only now the response end ("server closed the connection")
// is supposed to be delivered.
EXPECT_CALL(mock, OnResponseEnd(1, testing::Property(
&net::URLRequestStatus::is_success, true))).Times(1);
request.Read(512);
request.Release();
}
ACTION_P4(ManagerRead, loop, mgr, request_id, bytes_to_read) {
loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(mgr,
&UrlmonUrlRequestManager::ReadUrlRequest, request_id,
bytes_to_read), 0);
}
ACTION_P3(ManagerEndRequest, loop, mgr, request_id) {
loop->PostDelayedTask(FROM_HERE, NewRunnableMethod(mgr,
&UrlmonUrlRequestManager::EndUrlRequest, request_id,
net::URLRequestStatus()), 0);
}
// Simplest test - retrieve file from local web server.
TEST(UrlmonUrlRequestManagerTest, Simple1) {
MockUrlDelegate mock;
chrome_frame_test::TimedMsgLoop loop;
testing::StrictMock<MockWebServer> mock_server(1337, L"127.0.0.1",
chrome_frame_test::GetTestDataFolder());
mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE));
scoped_ptr<UrlmonUrlRequestManager> mgr(new UrlmonUrlRequestManager());
mgr->set_delegate(&mock);
AutomationURLRequest r1(
WideToUTF8(mock_server.Resolve(L"chrome_frame_window_open.html")),
"get", "", "", NULL, 0, 0);
EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_,
testing::_, testing::_, testing::_, testing::_))
.Times(1)
.WillOnce(ManagerRead(&loop, mgr.get(), 1, 512));
EXPECT_CALL(mock, OnReadComplete(1, testing::Property(&std::string::size,
testing::Gt(0u))))
.Times(testing::AtLeast(1))
.WillRepeatedly(ManagerRead(&loop, mgr.get(), 1, 2));
EXPECT_CALL(mock, OnResponseEnd(1, testing::_))
.Times(1)
.WillOnce(QUIT_LOOP_SOON(loop, 2));
mgr->StartUrlRequest(1, r1);
loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
mgr.reset();
}
TEST(UrlmonUrlRequestManagerTest, Abort1) {
MockUrlDelegate mock;
chrome_frame_test::TimedMsgLoop loop;
testing::StrictMock<MockWebServer> mock_server(1337, L"127.0.0.1",
chrome_frame_test::GetTestDataFolder());
mock_server.ExpectAndServeAnyRequests(CFInvocation(CFInvocation::NONE));
scoped_ptr<UrlmonUrlRequestManager> mgr(new UrlmonUrlRequestManager());
mgr->set_delegate(&mock);
AutomationURLRequest r1(
WideToUTF8(mock_server.Resolve(L"chrome_frame_window_open.html")),
"get", "", "", NULL, 0, 0);
EXPECT_CALL(mock, OnResponseStarted(1, testing::_, testing::_, testing::_,
testing::_, testing::_, testing::_, testing::_))
.Times(1)
.WillOnce(testing::DoAll(
ManagerEndRequest(&loop, mgr.get(), 1),
QUIT_LOOP_SOON(loop, 3)));
EXPECT_CALL(mock, OnReadComplete(1, testing::_))
.Times(0);
EXPECT_CALL(mock, OnResponseEnd(1, testing::_))
.Times(0);
mgr->StartUrlRequest(1, r1);
loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
mgr.reset();
}