1 // Copyright 2013 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 "chrome/browser/chromeos/drive/drive_url_request_job.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/run_loop.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "base/threading/thread.h"
14 #include "chrome/browser/chromeos/drive/drive_file_stream_reader.h"
15 #include "chrome/browser/chromeos/drive/fake_file_system.h"
16 #include "chrome/browser/chromeos/drive/file_system_util.h"
17 #include "chrome/browser/chromeos/drive/test_util.h"
18 #include "chrome/browser/drive/fake_drive_service.h"
19 #include "chrome/common/url_constants.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/test/test_browser_thread_bundle.h"
22 #include "google_apis/drive/test_util.h"
23 #include "net/base/request_priority.h"
24 #include "net/base/test_completion_callback.h"
25 #include "net/http/http_byte_range.h"
26 #include "net/url_request/url_request_test_util.h"
27 #include "testing/gtest/include/gtest/gtest.h"
33 // A simple URLRequestJobFactory implementation to create DriveURLRequestJob.
34 class TestURLRequestJobFactory
: public net::URLRequestJobFactory
{
36 TestURLRequestJobFactory(
37 const DriveURLRequestJob::FileSystemGetter
& file_system_getter
,
38 base::SequencedTaskRunner
* sequenced_task_runner
)
39 : file_system_getter_(file_system_getter
),
40 sequenced_task_runner_(sequenced_task_runner
) {
43 virtual ~TestURLRequestJobFactory() {}
45 // net::URLRequestJobFactory override:
46 virtual net::URLRequestJob
* MaybeCreateJobWithProtocolHandler(
47 const std::string
& scheme
,
48 net::URLRequest
* request
,
49 net::NetworkDelegate
* network_delegate
) const OVERRIDE
{
50 return new DriveURLRequestJob(file_system_getter_
,
51 sequenced_task_runner_
.get(),
56 virtual bool IsHandledProtocol(const std::string
& scheme
) const OVERRIDE
{
57 return scheme
== chrome::kDriveScheme
;
60 virtual bool IsHandledURL(const GURL
& url
) const OVERRIDE
{
61 return url
.is_valid() && IsHandledProtocol(url
.scheme());
64 virtual bool IsSafeRedirectTarget(const GURL
& location
) const OVERRIDE
{
69 const DriveURLRequestJob::FileSystemGetter file_system_getter_
;
70 scoped_refptr
<base::SequencedTaskRunner
> sequenced_task_runner_
;
72 DISALLOW_COPY_AND_ASSIGN(TestURLRequestJobFactory
);
75 class TestDelegate
: public net::TestDelegate
{
79 const GURL
& redirect_url() const { return redirect_url_
; }
81 // net::TestDelegate override.
82 virtual void OnReceivedRedirect(net::URLRequest
* request
,
84 bool* defer_redirect
) OVERRIDE
{
85 redirect_url_
= new_url
;
86 net::TestDelegate::OnReceivedRedirect(request
, new_url
, defer_redirect
);
92 DISALLOW_COPY_AND_ASSIGN(TestDelegate
);
97 class DriveURLRequestJobTest
: public testing::Test
{
99 DriveURLRequestJobTest()
100 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
) {
103 virtual ~DriveURLRequestJobTest() {
106 virtual void SetUp() OVERRIDE
{
107 // Initialize FakeDriveService.
108 fake_drive_service_
.reset(new FakeDriveService
);
109 ASSERT_TRUE(fake_drive_service_
->LoadResourceListForWapi(
110 "gdata/root_feed.json"));
111 ASSERT_TRUE(fake_drive_service_
->LoadAccountMetadataForWapi(
112 "gdata/account_metadata.json"));
114 // Initialize FakeFileSystem.
115 fake_file_system_
.reset(
116 new test_util::FakeFileSystem(fake_drive_service_
.get()));
118 scoped_refptr
<base::SequencedWorkerPool
> blocking_pool
=
119 content::BrowserThread::GetBlockingPool();
120 test_network_delegate_
.reset(new net::TestNetworkDelegate
);
121 test_url_request_job_factory_
.reset(new TestURLRequestJobFactory(
122 base::Bind(&DriveURLRequestJobTest::GetFileSystem
,
123 base::Unretained(this)),
124 blocking_pool
->GetSequencedTaskRunner(
125 blocking_pool
->GetSequenceToken()).get()));
126 url_request_context_
.reset(new net::URLRequestContext());
127 url_request_context_
->set_job_factory(test_url_request_job_factory_
.get());
128 url_request_context_
->set_network_delegate(test_network_delegate_
.get());
129 test_delegate_
.reset(new TestDelegate
);
132 FileSystemInterface
* GetFileSystem() {
133 return fake_file_system_
.get();
136 bool ReadDriveFileSync(
137 const base::FilePath
& file_path
, std::string
* out_content
) {
138 scoped_ptr
<base::Thread
> worker_thread(
139 new base::Thread("ReadDriveFileSync"));
140 if (!worker_thread
->Start())
143 scoped_ptr
<DriveFileStreamReader
> reader(new DriveFileStreamReader(
144 base::Bind(&DriveURLRequestJobTest::GetFileSystem
,
145 base::Unretained(this)),
146 worker_thread
->message_loop_proxy().get()));
147 int error
= net::ERR_FAILED
;
148 scoped_ptr
<ResourceEntry
> entry
;
150 base::RunLoop run_loop
;
153 net::HttpByteRange(),
154 google_apis::test_util::CreateQuitCallback(
156 google_apis::test_util::CreateCopyResultCallback(
160 if (error
!= net::OK
|| !entry
)
163 // Read data from the reader.
165 if (test_util::ReadAllData(reader
.get(), &content
) != net::OK
)
168 if (static_cast<size_t>(entry
->file_info().size()) != content
.size())
171 *out_content
= content
;
175 content::TestBrowserThreadBundle thread_bundle_
;
177 scoped_ptr
<FakeDriveService
> fake_drive_service_
;
178 scoped_ptr
<test_util::FakeFileSystem
> fake_file_system_
;
180 scoped_ptr
<net::TestNetworkDelegate
> test_network_delegate_
;
181 scoped_ptr
<TestURLRequestJobFactory
> test_url_request_job_factory_
;
182 scoped_ptr
<net::URLRequestContext
> url_request_context_
;
183 scoped_ptr
<TestDelegate
> test_delegate_
;
186 TEST_F(DriveURLRequestJobTest
, NonGetMethod
) {
187 net::URLRequest
request(GURL("drive:drive/root/File 1.txt"),
188 net::DEFAULT_PRIORITY
,
189 test_delegate_
.get(),
190 url_request_context_
.get());
191 request
.set_method("POST"); // Set non "GET" method.
194 base::RunLoop().Run();
196 EXPECT_EQ(net::URLRequestStatus::FAILED
, request
.status().status());
197 EXPECT_EQ(net::ERR_METHOD_NOT_SUPPORTED
, request
.status().error());
200 TEST_F(DriveURLRequestJobTest
, RegularFile
) {
201 const GURL
kTestUrl("drive:drive/root/File 1.txt");
202 const base::FilePath
kTestFilePath("drive/root/File 1.txt");
204 // For the first time, the file should be fetched from the server.
206 net::URLRequest
request(kTestUrl
,
207 net::DEFAULT_PRIORITY
,
208 test_delegate_
.get(),
209 url_request_context_
.get());
212 base::RunLoop().Run();
214 EXPECT_EQ(net::URLRequestStatus::SUCCESS
, request
.status().status());
215 // It looks weird, but the mime type for the "File 1.txt" is "audio/mpeg"
217 std::string mime_type
;
218 request
.GetMimeType(&mime_type
);
219 EXPECT_EQ("audio/mpeg", mime_type
);
221 // Reading file must be done after |request| runs, otherwise
222 // it'll create a local cache file, and we cannot test correctly.
223 std::string expected_data
;
224 ASSERT_TRUE(ReadDriveFileSync(kTestFilePath
, &expected_data
));
225 EXPECT_EQ(expected_data
, test_delegate_
->data_received());
228 // For the second time, the locally cached file should be used.
229 // The caching emulation is done by FakeFileSystem.
231 test_delegate_
.reset(new TestDelegate
);
232 net::URLRequest
request(GURL("drive:drive/root/File 1.txt"),
233 net::DEFAULT_PRIORITY
,
234 test_delegate_
.get(),
235 url_request_context_
.get());
238 base::RunLoop().Run();
240 EXPECT_EQ(net::URLRequestStatus::SUCCESS
, request
.status().status());
241 std::string mime_type
;
242 request
.GetMimeType(&mime_type
);
243 EXPECT_EQ("audio/mpeg", mime_type
);
245 std::string expected_data
;
246 ASSERT_TRUE(ReadDriveFileSync(kTestFilePath
, &expected_data
));
247 EXPECT_EQ(expected_data
, test_delegate_
->data_received());
251 TEST_F(DriveURLRequestJobTest
, HostedDocument
) {
253 test_delegate_
->set_quit_on_redirect(true);
254 net::URLRequest
request(
255 GURL("drive:drive/root/Document 1 excludeDir-test.gdoc"),
256 net::DEFAULT_PRIORITY
,
257 test_delegate_
.get(),
258 url_request_context_
.get());
261 base::RunLoop().Run();
263 EXPECT_EQ(net::URLRequestStatus::SUCCESS
, request
.status().status());
264 // Make sure that a hosted document triggers redirection.
265 EXPECT_TRUE(request
.is_redirecting());
266 EXPECT_EQ(GURL("https://3_document_alternate_link"),
267 test_delegate_
->redirect_url());
270 TEST_F(DriveURLRequestJobTest
, RootDirectory
) {
271 net::URLRequest
request(GURL("drive:drive/root"),
272 net::DEFAULT_PRIORITY
,
273 test_delegate_
.get(),
274 url_request_context_
.get());
277 base::RunLoop().Run();
279 EXPECT_EQ(net::URLRequestStatus::FAILED
, request
.status().status());
280 EXPECT_EQ(net::ERR_FAILED
, request
.status().error());
283 TEST_F(DriveURLRequestJobTest
, Directory
) {
284 net::URLRequest
request(GURL("drive:drive/root/Directory 1"),
285 net::DEFAULT_PRIORITY
,
286 test_delegate_
.get(),
287 url_request_context_
.get());
290 base::RunLoop().Run();
292 EXPECT_EQ(net::URLRequestStatus::FAILED
, request
.status().status());
293 EXPECT_EQ(net::ERR_FAILED
, request
.status().error());
296 TEST_F(DriveURLRequestJobTest
, NonExistingFile
) {
297 net::URLRequest
request(GURL("drive:drive/root/non-existing-file.txt"),
298 net::DEFAULT_PRIORITY
,
299 test_delegate_
.get(),
300 url_request_context_
.get());
303 base::RunLoop().Run();
305 EXPECT_EQ(net::URLRequestStatus::FAILED
, request
.status().status());
306 EXPECT_EQ(net::ERR_FILE_NOT_FOUND
, request
.status().error());
309 TEST_F(DriveURLRequestJobTest
, WrongFormat
) {
310 net::URLRequest
request(GURL("drive:"),
311 net::DEFAULT_PRIORITY
,
312 test_delegate_
.get(),
313 url_request_context_
.get());
316 base::RunLoop().Run();
318 EXPECT_EQ(net::URLRequestStatus::FAILED
, request
.status().status());
319 EXPECT_EQ(net::ERR_INVALID_URL
, request
.status().error());
322 TEST_F(DriveURLRequestJobTest
, Cancel
) {
323 net::URLRequest
request(GURL("drive:drive/root/File 1.txt"),
324 net::DEFAULT_PRIORITY
,
325 test_delegate_
.get(),
326 url_request_context_
.get());
328 // Start the request, and cancel it immediately after it.
332 base::RunLoop().Run();
334 EXPECT_EQ(net::URLRequestStatus::CANCELED
, request
.status().status());
337 TEST_F(DriveURLRequestJobTest
, RangeHeader
) {
338 const GURL
kTestUrl("drive:drive/root/File 1.txt");
339 const base::FilePath
kTestFilePath("drive/root/File 1.txt");
341 net::URLRequest
request(kTestUrl
,
342 net::DEFAULT_PRIORITY
,
343 test_delegate_
.get(),
344 url_request_context_
.get());
347 request
.SetExtraRequestHeaderByName(
348 "Range", "bytes=3-5", false /* overwrite */);
351 base::RunLoop().Run();
353 EXPECT_EQ(net::URLRequestStatus::SUCCESS
, request
.status().status());
355 // Reading file must be done after |request| runs, otherwise
356 // it'll create a local cache file, and we cannot test correctly.
357 std::string expected_data
;
358 ASSERT_TRUE(ReadDriveFileSync(kTestFilePath
, &expected_data
));
359 EXPECT_EQ(expected_data
.substr(3, 3), test_delegate_
->data_received());
362 TEST_F(DriveURLRequestJobTest
, WrongRangeHeader
) {
363 const GURL
kTestUrl("drive:drive/root/File 1.txt");
365 net::URLRequest
request(kTestUrl
,
366 net::DEFAULT_PRIORITY
,
367 test_delegate_
.get(),
368 url_request_context_
.get());
371 request
.SetExtraRequestHeaderByName(
372 "Range", "Wrong Range Header Value", false /* overwrite */);
375 base::RunLoop().Run();
377 EXPECT_EQ(net::URLRequestStatus::FAILED
, request
.status().status());
378 EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE
, request
.status().error());