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.
5 #include "components/drive/drive_uploader.h"
11 #include "base/bind.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "base/values.h"
18 #include "components/drive/service/dummy_drive_service.h"
19 #include "google_apis/drive/drive_api_parser.h"
20 #include "google_apis/drive/test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using google_apis::CancelCallback
;
24 using google_apis::FileResource
;
25 using google_apis::DriveApiErrorCode
;
26 using google_apis::DRIVE_NO_CONNECTION
;
27 using google_apis::DRIVE_OTHER_ERROR
;
28 using google_apis::HTTP_CONFLICT
;
29 using google_apis::HTTP_CREATED
;
30 using google_apis::HTTP_NOT_FOUND
;
31 using google_apis::HTTP_PRECONDITION
;
32 using google_apis::HTTP_RESUME_INCOMPLETE
;
33 using google_apis::HTTP_SUCCESS
;
34 using google_apis::InitiateUploadCallback
;
35 using google_apis::ProgressCallback
;
36 using google_apis::UploadRangeResponse
;
37 using google_apis::drive::UploadRangeCallback
;
38 namespace test_util
= google_apis::test_util
;
44 const char kTestDummyMd5
[] = "dummy_md5";
45 const char kTestDocumentTitle
[] = "Hello world";
46 const char kTestInitiateUploadParentResourceId
[] = "parent_resource_id";
47 const char kTestInitiateUploadResourceId
[] = "resource_id";
48 const char kTestMimeType
[] = "text/plain";
49 const char kTestUploadNewFileURL
[] = "http://test/upload_location/new_file";
50 const char kTestUploadExistingFileURL
[] =
51 "http://test/upload_location/existing_file";
52 const int64 kUploadChunkSize
= 1024 * 1024 * 1024;
53 const char kTestETag
[] = "test_etag";
55 CancelCallback
SendMultipartUploadResult(
56 DriveApiErrorCode response_code
,
58 const google_apis::FileResourceCallback
& callback
,
59 const google_apis::ProgressCallback
& progress_callback
) {
61 if (!progress_callback
.is_null()) {
62 // For the testing purpose, it always notifies the progress at the end of
63 // whole file uploading.
64 base::ThreadTaskRunnerHandle::Get()->PostTask(
66 base::Bind(progress_callback
, content_length
, content_length
));
69 // MultipartUploadXXXFile is an asynchronous function, so don't callback
71 scoped_ptr
<FileResource
> entry
;
72 entry
.reset(new FileResource
);
73 entry
->set_md5_checksum(kTestDummyMd5
);
74 base::ThreadTaskRunnerHandle::Get()->PostTask(
75 FROM_HERE
, base::Bind(callback
, response_code
, base::Passed(&entry
)));
76 return CancelCallback();
79 // Mock DriveService that verifies if the uploaded content matches the preset
81 class MockDriveServiceWithUploadExpectation
: public DummyDriveService
{
83 // Sets up an expected upload content. InitiateUpload and ResumeUpload will
84 // verify that the specified data is correctly uploaded.
85 MockDriveServiceWithUploadExpectation(
86 const base::FilePath
& expected_upload_file
,
87 int64 expected_content_length
)
88 : expected_upload_file_(expected_upload_file
),
89 expected_content_length_(expected_content_length
),
91 resume_upload_call_count_(0),
92 multipart_upload_call_count_(0) {}
94 int64
received_bytes() const { return received_bytes_
; }
95 void set_received_bytes(int64 received_bytes
) {
96 received_bytes_
= received_bytes
;
99 int64
resume_upload_call_count() const { return resume_upload_call_count_
; }
100 int64
multipart_upload_call_count() const {
101 return multipart_upload_call_count_
;
105 // DriveServiceInterface overrides.
106 // Handles a request for obtaining an upload location URL.
107 CancelCallback
InitiateUploadNewFile(
108 const std::string
& content_type
,
109 int64 content_length
,
110 const std::string
& parent_resource_id
,
111 const std::string
& title
,
112 const UploadNewFileOptions
& options
,
113 const InitiateUploadCallback
& callback
) override
{
114 EXPECT_EQ(kTestDocumentTitle
, title
);
115 EXPECT_EQ(kTestMimeType
, content_type
);
116 EXPECT_EQ(expected_content_length_
, content_length
);
117 EXPECT_EQ(kTestInitiateUploadParentResourceId
, parent_resource_id
);
119 // Calls back the upload URL for subsequent ResumeUpload requests.
120 // InitiateUpload is an asynchronous function, so don't callback directly.
121 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
122 base::Bind(callback
, HTTP_SUCCESS
, GURL(kTestUploadNewFileURL
)));
123 return CancelCallback();
126 CancelCallback
InitiateUploadExistingFile(
127 const std::string
& content_type
,
128 int64 content_length
,
129 const std::string
& resource_id
,
130 const UploadExistingFileOptions
& options
,
131 const InitiateUploadCallback
& callback
) override
{
132 EXPECT_EQ(kTestMimeType
, content_type
);
133 EXPECT_EQ(expected_content_length_
, content_length
);
134 EXPECT_EQ(kTestInitiateUploadResourceId
, resource_id
);
136 if (!options
.etag
.empty() && options
.etag
!= kTestETag
) {
137 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
138 base::Bind(callback
, HTTP_PRECONDITION
, GURL()));
139 return CancelCallback();
142 // Calls back the upload URL for subsequent ResumeUpload requests.
143 // InitiateUpload is an asynchronous function, so don't callback directly.
144 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
145 base::Bind(callback
, HTTP_SUCCESS
, GURL(kTestUploadExistingFileURL
)));
146 return CancelCallback();
149 // Handles a request for uploading a chunk of bytes.
150 CancelCallback
ResumeUpload(
151 const GURL
& upload_location
,
152 int64 start_position
,
154 int64 content_length
,
155 const std::string
& content_type
,
156 const base::FilePath
& local_file_path
,
157 const UploadRangeCallback
& callback
,
158 const ProgressCallback
& progress_callback
) override
{
159 // The upload range should start from the current first unreceived byte.
160 EXPECT_EQ(received_bytes_
, start_position
);
161 EXPECT_EQ(expected_upload_file_
, local_file_path
);
163 // The upload data must be split into 512KB chunks.
164 const int64 expected_chunk_end
=
165 std::min(received_bytes_
+ kUploadChunkSize
, expected_content_length_
);
166 EXPECT_EQ(expected_chunk_end
, end_position
);
168 // The upload URL returned by InitiateUpload() must be used.
169 EXPECT_TRUE(GURL(kTestUploadNewFileURL
) == upload_location
||
170 GURL(kTestUploadExistingFileURL
) == upload_location
);
172 // Other parameters should be the exact values passed to DriveUploader.
173 EXPECT_EQ(expected_content_length_
, content_length
);
174 EXPECT_EQ(kTestMimeType
, content_type
);
176 // Update the internal status of the current upload session.
177 resume_upload_call_count_
++;
178 received_bytes_
= end_position
;
181 if (!progress_callback
.is_null()) {
182 // For the testing purpose, it always notifies the progress at the end of
183 // each chunk uploading.
184 int64 chunk_size
= end_position
- start_position
;
185 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
186 base::Bind(progress_callback
, chunk_size
, chunk_size
));
189 SendUploadRangeResponse(upload_location
, callback
);
190 return CancelCallback();
193 // Handles a request to fetch the current upload status.
194 CancelCallback
GetUploadStatus(const GURL
& upload_location
,
195 int64 content_length
,
196 const UploadRangeCallback
& callback
) override
{
197 EXPECT_EQ(expected_content_length_
, content_length
);
198 // The upload URL returned by InitiateUpload() must be used.
199 EXPECT_TRUE(GURL(kTestUploadNewFileURL
) == upload_location
||
200 GURL(kTestUploadExistingFileURL
) == upload_location
);
202 SendUploadRangeResponse(upload_location
, callback
);
203 return CancelCallback();
206 // Runs |callback| with the current upload status.
207 void SendUploadRangeResponse(const GURL
& upload_location
,
208 const UploadRangeCallback
& callback
) {
209 // Callback with response.
210 UploadRangeResponse response
;
211 scoped_ptr
<FileResource
> entry
;
212 if (received_bytes_
== expected_content_length_
) {
213 DriveApiErrorCode response_code
=
214 upload_location
== GURL(kTestUploadNewFileURL
) ?
215 HTTP_CREATED
: HTTP_SUCCESS
;
216 response
= UploadRangeResponse(response_code
, -1, -1);
218 entry
.reset(new FileResource
);
219 entry
->set_md5_checksum(kTestDummyMd5
);
221 response
= UploadRangeResponse(
222 HTTP_RESUME_INCOMPLETE
, 0, received_bytes_
);
224 // ResumeUpload is an asynchronous function, so don't callback directly.
225 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
226 base::Bind(callback
, response
, base::Passed(&entry
)));
229 CancelCallback
MultipartUploadNewFile(
230 const std::string
& content_type
,
231 int64 content_length
,
232 const std::string
& parent_resource_id
,
233 const std::string
& title
,
234 const base::FilePath
& local_file_path
,
235 const UploadNewFileOptions
& options
,
236 const google_apis::FileResourceCallback
& callback
,
237 const google_apis::ProgressCallback
& progress_callback
) override
{
238 EXPECT_EQ(kTestMimeType
, content_type
);
239 EXPECT_EQ(expected_content_length_
, content_length
);
240 EXPECT_EQ(kTestInitiateUploadParentResourceId
, parent_resource_id
);
241 EXPECT_EQ(kTestDocumentTitle
, title
);
242 EXPECT_EQ(expected_upload_file_
, local_file_path
);
244 received_bytes_
= content_length
;
245 multipart_upload_call_count_
++;
246 return SendMultipartUploadResult(HTTP_CREATED
, content_length
, callback
,
250 CancelCallback
MultipartUploadExistingFile(
251 const std::string
& content_type
,
252 int64 content_length
,
253 const std::string
& resource_id
,
254 const base::FilePath
& local_file_path
,
255 const UploadExistingFileOptions
& options
,
256 const google_apis::FileResourceCallback
& callback
,
257 const google_apis::ProgressCallback
& progress_callback
) override
{
258 EXPECT_EQ(kTestMimeType
, content_type
);
259 EXPECT_EQ(expected_content_length_
, content_length
);
260 EXPECT_EQ(kTestInitiateUploadResourceId
, resource_id
);
261 EXPECT_EQ(expected_upload_file_
, local_file_path
);
263 if (!options
.etag
.empty() && options
.etag
!= kTestETag
) {
264 base::ThreadTaskRunnerHandle::Get()->PostTask(
266 base::Bind(callback
, HTTP_PRECONDITION
,
267 base::Passed(make_scoped_ptr
<FileResource
>(NULL
))));
268 return CancelCallback();
271 received_bytes_
= content_length
;
272 multipart_upload_call_count_
++;
273 return SendMultipartUploadResult(HTTP_SUCCESS
, content_length
, callback
,
277 const base::FilePath expected_upload_file_
;
278 const int64 expected_content_length_
;
279 int64 received_bytes_
;
280 int64 resume_upload_call_count_
;
281 int64 multipart_upload_call_count_
;
284 // Mock DriveService that returns a failure at InitiateUpload().
285 class MockDriveServiceNoConnectionAtInitiate
: public DummyDriveService
{
287 CancelCallback
InitiateUploadNewFile(
288 const std::string
& content_type
,
289 int64 content_length
,
290 const std::string
& parent_resource_id
,
291 const std::string
& title
,
292 const UploadNewFileOptions
& options
,
293 const InitiateUploadCallback
& callback
) override
{
294 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
295 base::Bind(callback
, DRIVE_NO_CONNECTION
, GURL()));
296 return CancelCallback();
299 CancelCallback
InitiateUploadExistingFile(
300 const std::string
& content_type
,
301 int64 content_length
,
302 const std::string
& resource_id
,
303 const UploadExistingFileOptions
& options
,
304 const InitiateUploadCallback
& callback
) override
{
305 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
306 base::Bind(callback
, DRIVE_NO_CONNECTION
, GURL()));
307 return CancelCallback();
310 // Should not be used.
311 CancelCallback
ResumeUpload(
312 const GURL
& upload_url
,
313 int64 start_position
,
315 int64 content_length
,
316 const std::string
& content_type
,
317 const base::FilePath
& local_file_path
,
318 const UploadRangeCallback
& callback
,
319 const ProgressCallback
& progress_callback
) override
{
321 return CancelCallback();
324 CancelCallback
MultipartUploadNewFile(
325 const std::string
& content_type
,
326 int64 content_length
,
327 const std::string
& parent_resource_id
,
328 const std::string
& title
,
329 const base::FilePath
& local_file_path
,
330 const UploadNewFileOptions
& options
,
331 const google_apis::FileResourceCallback
& callback
,
332 const google_apis::ProgressCallback
& progress_callback
) override
{
333 base::ThreadTaskRunnerHandle::Get()->PostTask(
335 base::Bind(callback
, DRIVE_NO_CONNECTION
,
336 base::Passed(make_scoped_ptr
<FileResource
>(NULL
))));
337 return CancelCallback();
340 CancelCallback
MultipartUploadExistingFile(
341 const std::string
& content_type
,
342 int64 content_length
,
343 const std::string
& resource_id
,
344 const base::FilePath
& local_file_path
,
345 const UploadExistingFileOptions
& options
,
346 const google_apis::FileResourceCallback
& callback
,
347 const google_apis::ProgressCallback
& progress_callback
) override
{
348 base::ThreadTaskRunnerHandle::Get()->PostTask(
350 base::Bind(callback
, DRIVE_NO_CONNECTION
,
351 base::Passed(make_scoped_ptr
<FileResource
>(NULL
))));
352 return CancelCallback();
356 // Mock DriveService that returns a failure at ResumeUpload().
357 class MockDriveServiceNoConnectionAtResume
: public DummyDriveService
{
358 // Succeeds and returns an upload location URL.
359 CancelCallback
InitiateUploadNewFile(
360 const std::string
& content_type
,
361 int64 content_length
,
362 const std::string
& parent_resource_id
,
363 const std::string
& title
,
364 const UploadNewFileOptions
& options
,
365 const InitiateUploadCallback
& callback
) override
{
366 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
367 base::Bind(callback
, HTTP_SUCCESS
, GURL(kTestUploadNewFileURL
)));
368 return CancelCallback();
371 CancelCallback
InitiateUploadExistingFile(
372 const std::string
& content_type
,
373 int64 content_length
,
374 const std::string
& resource_id
,
375 const UploadExistingFileOptions
& options
,
376 const InitiateUploadCallback
& callback
) override
{
377 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
378 base::Bind(callback
, HTTP_SUCCESS
, GURL(kTestUploadExistingFileURL
)));
379 return CancelCallback();
383 CancelCallback
ResumeUpload(
384 const GURL
& upload_url
,
385 int64 start_position
,
387 int64 content_length
,
388 const std::string
& content_type
,
389 const base::FilePath
& local_file_path
,
390 const UploadRangeCallback
& callback
,
391 const ProgressCallback
& progress_callback
) override
{
392 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
394 UploadRangeResponse(DRIVE_NO_CONNECTION
, -1, -1),
395 base::Passed(scoped_ptr
<FileResource
>())));
396 return CancelCallback();
400 // Mock DriveService that returns a failure at GetUploadStatus().
401 class MockDriveServiceNoConnectionAtGetUploadStatus
: public DummyDriveService
{
403 CancelCallback
GetUploadStatus(const GURL
& upload_url
,
404 int64 content_length
,
405 const UploadRangeCallback
& callback
) override
{
406 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
,
408 UploadRangeResponse(DRIVE_NO_CONNECTION
, -1, -1),
409 base::Passed(scoped_ptr
<FileResource
>())));
410 return CancelCallback();
414 class DriveUploaderTest
: public testing::Test
{
416 void SetUp() override
{ ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir()); }
419 base::MessageLoop message_loop_
;
420 base::ScopedTempDir temp_dir_
;
425 TEST_F(DriveUploaderTest
, UploadExisting0KB
) {
426 base::FilePath local_path
;
428 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
429 temp_dir_
.path(), 0, &local_path
, &data
));
431 DriveApiErrorCode error
= DRIVE_OTHER_ERROR
;
432 GURL upload_location
;
433 scoped_ptr
<FileResource
> entry
;
435 MockDriveServiceWithUploadExpectation
mock_service(local_path
, data
.size());
436 DriveUploader
uploader(&mock_service
,
437 base::ThreadTaskRunnerHandle::Get().get());
438 std::vector
<test_util::ProgressInfo
> upload_progress_values
;
439 uploader
.UploadExistingFile(
440 kTestInitiateUploadResourceId
, local_path
, kTestMimeType
,
441 UploadExistingFileOptions(),
442 test_util::CreateCopyResultCallback(&error
, &upload_location
, &entry
),
443 base::Bind(&test_util::AppendProgressCallbackResult
,
444 &upload_progress_values
));
445 base::RunLoop().RunUntilIdle();
447 EXPECT_EQ(0, mock_service
.resume_upload_call_count());
448 EXPECT_EQ(1, mock_service
.multipart_upload_call_count());
449 EXPECT_EQ(0, mock_service
.received_bytes());
450 EXPECT_EQ(HTTP_SUCCESS
, error
);
451 EXPECT_TRUE(upload_location
.is_empty());
453 EXPECT_EQ(kTestDummyMd5
, entry
->md5_checksum());
454 ASSERT_EQ(1U, upload_progress_values
.size());
455 EXPECT_EQ(test_util::ProgressInfo(0, 0), upload_progress_values
[0]);
458 TEST_F(DriveUploaderTest
, UploadExisting512KB
) {
459 base::FilePath local_path
;
461 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
462 temp_dir_
.path(), 512 * 1024, &local_path
, &data
));
464 DriveApiErrorCode error
= DRIVE_OTHER_ERROR
;
465 GURL upload_location
;
466 scoped_ptr
<FileResource
> entry
;
468 MockDriveServiceWithUploadExpectation
mock_service(local_path
, data
.size());
469 DriveUploader
uploader(&mock_service
,
470 base::ThreadTaskRunnerHandle::Get().get());
471 std::vector
<test_util::ProgressInfo
> upload_progress_values
;
472 uploader
.UploadExistingFile(
473 kTestInitiateUploadResourceId
, local_path
, kTestMimeType
,
474 UploadExistingFileOptions(),
475 test_util::CreateCopyResultCallback(&error
, &upload_location
, &entry
),
476 base::Bind(&test_util::AppendProgressCallbackResult
,
477 &upload_progress_values
));
478 base::RunLoop().RunUntilIdle();
480 // 512KB upload should be uploaded as multipart body.
481 EXPECT_EQ(0, mock_service
.resume_upload_call_count());
482 EXPECT_EQ(1, mock_service
.multipart_upload_call_count());
483 EXPECT_EQ(512 * 1024, mock_service
.received_bytes());
484 EXPECT_EQ(HTTP_SUCCESS
, error
);
485 EXPECT_TRUE(upload_location
.is_empty());
487 EXPECT_EQ(kTestDummyMd5
, entry
->md5_checksum());
488 ASSERT_EQ(1U, upload_progress_values
.size());
489 EXPECT_EQ(test_util::ProgressInfo(512 * 1024, 512 * 1024),
490 upload_progress_values
[0]);
493 TEST_F(DriveUploaderTest
, UploadExisting2MB
) {
494 base::FilePath local_path
;
496 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
497 temp_dir_
.path(), 2 * 1024 * 1024, &local_path
, &data
));
499 DriveApiErrorCode error
= DRIVE_OTHER_ERROR
;
500 GURL upload_location
;
501 scoped_ptr
<FileResource
> entry
;
503 MockDriveServiceWithUploadExpectation
mock_service(local_path
, data
.size());
504 DriveUploader
uploader(&mock_service
,
505 base::ThreadTaskRunnerHandle::Get().get());
506 std::vector
<test_util::ProgressInfo
> upload_progress_values
;
507 uploader
.UploadExistingFile(
508 kTestInitiateUploadResourceId
, local_path
, kTestMimeType
,
509 UploadExistingFileOptions(),
510 test_util::CreateCopyResultCallback(&error
, &upload_location
, &entry
),
511 base::Bind(&test_util::AppendProgressCallbackResult
,
512 &upload_progress_values
));
513 base::RunLoop().RunUntilIdle();
515 // 2MB upload should not be split into multiple chunks.
516 EXPECT_EQ(1, mock_service
.resume_upload_call_count());
517 EXPECT_EQ(0, mock_service
.multipart_upload_call_count());
518 EXPECT_EQ(2 * 1024 * 1024, mock_service
.received_bytes());
519 EXPECT_EQ(HTTP_SUCCESS
, error
);
520 EXPECT_TRUE(upload_location
.is_empty());
522 EXPECT_EQ(kTestDummyMd5
, entry
->md5_checksum());
523 ASSERT_EQ(1U, upload_progress_values
.size());
524 EXPECT_EQ(test_util::ProgressInfo(2 * 1024 * 1024, 2 * 1024 * 1024),
525 upload_progress_values
[0]);
528 TEST_F(DriveUploaderTest
, InitiateUploadFail
) {
529 base::FilePath local_path
;
531 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
532 temp_dir_
.path(), 2 * 1024 * 1024, &local_path
, &data
));
534 DriveApiErrorCode error
= HTTP_SUCCESS
;
535 GURL upload_location
;
536 scoped_ptr
<FileResource
> entry
;
538 MockDriveServiceNoConnectionAtInitiate mock_service
;
539 DriveUploader
uploader(&mock_service
,
540 base::ThreadTaskRunnerHandle::Get().get());
541 uploader
.UploadExistingFile(
542 kTestInitiateUploadResourceId
, local_path
, kTestMimeType
,
543 UploadExistingFileOptions(),
544 test_util::CreateCopyResultCallback(&error
, &upload_location
, &entry
),
545 google_apis::ProgressCallback());
546 base::RunLoop().RunUntilIdle();
548 EXPECT_EQ(DRIVE_NO_CONNECTION
, error
);
549 EXPECT_TRUE(upload_location
.is_empty());
553 TEST_F(DriveUploaderTest
, MultipartUploadFail
) {
554 base::FilePath local_path
;
556 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(temp_dir_
.path(), 512 * 1024,
557 &local_path
, &data
));
559 DriveApiErrorCode error
= HTTP_SUCCESS
;
560 GURL upload_location
;
561 scoped_ptr
<FileResource
> entry
;
563 MockDriveServiceNoConnectionAtInitiate mock_service
;
564 DriveUploader
uploader(&mock_service
,
565 base::ThreadTaskRunnerHandle::Get().get());
566 uploader
.UploadExistingFile(
567 kTestInitiateUploadResourceId
, local_path
, kTestMimeType
,
568 UploadExistingFileOptions(),
569 test_util::CreateCopyResultCallback(&error
, &upload_location
, &entry
),
570 google_apis::ProgressCallback());
571 base::RunLoop().RunUntilIdle();
573 EXPECT_EQ(DRIVE_NO_CONNECTION
, error
);
574 EXPECT_TRUE(upload_location
.is_empty());
578 TEST_F(DriveUploaderTest
, InitiateUploadNoConflict
) {
579 base::FilePath local_path
;
581 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
582 temp_dir_
.path(), 512 * 1024, &local_path
, &data
));
584 DriveApiErrorCode error
= DRIVE_OTHER_ERROR
;
585 GURL upload_location
;
586 scoped_ptr
<FileResource
> entry
;
588 MockDriveServiceWithUploadExpectation
mock_service(local_path
, data
.size());
589 DriveUploader
uploader(&mock_service
,
590 base::ThreadTaskRunnerHandle::Get().get());
591 UploadExistingFileOptions options
;
592 options
.etag
= kTestETag
;
593 uploader
.UploadExistingFile(kTestInitiateUploadResourceId
,
597 test_util::CreateCopyResultCallback(
598 &error
, &upload_location
, &entry
),
599 google_apis::ProgressCallback());
600 base::RunLoop().RunUntilIdle();
602 EXPECT_EQ(HTTP_SUCCESS
, error
);
603 EXPECT_TRUE(upload_location
.is_empty());
606 TEST_F(DriveUploaderTest
, MultipartUploadConflict
) {
607 base::FilePath local_path
;
609 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
610 temp_dir_
.path(), 512 * 1024, &local_path
, &data
));
611 const std::string
kDestinationETag("destination_etag");
613 DriveApiErrorCode error
= DRIVE_OTHER_ERROR
;
614 GURL upload_location
;
615 scoped_ptr
<FileResource
> entry
;
617 MockDriveServiceWithUploadExpectation
mock_service(local_path
, data
.size());
618 DriveUploader
uploader(&mock_service
,
619 base::ThreadTaskRunnerHandle::Get().get());
620 UploadExistingFileOptions options
;
621 options
.etag
= kDestinationETag
;
622 uploader
.UploadExistingFile(kTestInitiateUploadResourceId
,
626 test_util::CreateCopyResultCallback(
627 &error
, &upload_location
, &entry
),
628 google_apis::ProgressCallback());
629 base::RunLoop().RunUntilIdle();
631 EXPECT_EQ(HTTP_CONFLICT
, error
);
632 EXPECT_TRUE(upload_location
.is_empty());
635 TEST_F(DriveUploaderTest
, InitiateUploadConflict
) {
636 base::FilePath local_path
;
638 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
639 temp_dir_
.path(), 2 * 1024 * 1024, &local_path
, &data
));
640 const std::string
kDestinationETag("destination_etag");
642 DriveApiErrorCode error
= DRIVE_OTHER_ERROR
;
643 GURL upload_location
;
644 scoped_ptr
<FileResource
> entry
;
646 MockDriveServiceWithUploadExpectation
mock_service(local_path
, data
.size());
647 DriveUploader
uploader(&mock_service
,
648 base::ThreadTaskRunnerHandle::Get().get());
649 UploadExistingFileOptions options
;
650 options
.etag
= kDestinationETag
;
651 uploader
.UploadExistingFile(
652 kTestInitiateUploadResourceId
, local_path
, kTestMimeType
, options
,
653 test_util::CreateCopyResultCallback(&error
, &upload_location
, &entry
),
654 google_apis::ProgressCallback());
655 base::RunLoop().RunUntilIdle();
657 EXPECT_EQ(HTTP_CONFLICT
, error
);
658 EXPECT_TRUE(upload_location
.is_empty());
661 TEST_F(DriveUploaderTest
, ResumeUploadFail
) {
662 base::FilePath local_path
;
664 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
665 temp_dir_
.path(), 2 * 1024 * 1024, &local_path
, &data
));
667 DriveApiErrorCode error
= HTTP_SUCCESS
;
668 GURL upload_location
;
669 scoped_ptr
<FileResource
> entry
;
671 MockDriveServiceNoConnectionAtResume mock_service
;
672 DriveUploader
uploader(&mock_service
,
673 base::ThreadTaskRunnerHandle::Get().get());
674 uploader
.UploadExistingFile(
675 kTestInitiateUploadResourceId
, local_path
, kTestMimeType
,
676 UploadExistingFileOptions(),
677 test_util::CreateCopyResultCallback(&error
, &upload_location
, &entry
),
678 google_apis::ProgressCallback());
679 base::RunLoop().RunUntilIdle();
681 EXPECT_EQ(DRIVE_NO_CONNECTION
, error
);
682 EXPECT_EQ(GURL(kTestUploadExistingFileURL
), upload_location
);
685 TEST_F(DriveUploaderTest
, GetUploadStatusFail
) {
686 base::FilePath local_path
;
688 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
689 temp_dir_
.path(), 2 * 1024 * 1024, &local_path
, &data
));
691 DriveApiErrorCode error
= HTTP_SUCCESS
;
692 GURL upload_location
;
693 scoped_ptr
<FileResource
> entry
;
695 MockDriveServiceNoConnectionAtGetUploadStatus mock_service
;
696 DriveUploader
uploader(&mock_service
,
697 base::ThreadTaskRunnerHandle::Get().get());
698 uploader
.ResumeUploadFile(GURL(kTestUploadExistingFileURL
),
701 test_util::CreateCopyResultCallback(
702 &error
, &upload_location
, &entry
),
703 google_apis::ProgressCallback());
704 base::RunLoop().RunUntilIdle();
706 EXPECT_EQ(DRIVE_NO_CONNECTION
, error
);
707 EXPECT_TRUE(upload_location
.is_empty());
710 TEST_F(DriveUploaderTest
, NonExistingSourceFile
) {
711 DriveApiErrorCode error
= DRIVE_OTHER_ERROR
;
712 GURL upload_location
;
713 scoped_ptr
<FileResource
> entry
;
715 DriveUploader
uploader(NULL
, // NULL, the service won't be used.
716 base::ThreadTaskRunnerHandle::Get().get());
717 uploader
.UploadExistingFile(
718 kTestInitiateUploadResourceId
,
719 temp_dir_
.path().AppendASCII("_this_path_should_not_exist_"),
720 kTestMimeType
, UploadExistingFileOptions(),
721 test_util::CreateCopyResultCallback(&error
, &upload_location
, &entry
),
722 google_apis::ProgressCallback());
723 base::RunLoop().RunUntilIdle();
725 // Should return failure without doing any attempt to connect to the server.
726 EXPECT_EQ(HTTP_NOT_FOUND
, error
);
727 EXPECT_TRUE(upload_location
.is_empty());
730 TEST_F(DriveUploaderTest
, ResumeUpload
) {
731 base::FilePath local_path
;
733 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
734 temp_dir_
.path(), 1024 * 1024, &local_path
, &data
));
736 DriveApiErrorCode error
= DRIVE_OTHER_ERROR
;
737 GURL upload_location
;
738 scoped_ptr
<FileResource
> entry
;
740 MockDriveServiceWithUploadExpectation
mock_service(local_path
, data
.size());
741 DriveUploader
uploader(&mock_service
,
742 base::ThreadTaskRunnerHandle::Get().get());
743 // Emulate the situation that the only first part is successfully uploaded,
744 // but not the latter half.
745 mock_service
.set_received_bytes(512 * 1024);
747 std::vector
<test_util::ProgressInfo
> upload_progress_values
;
748 uploader
.ResumeUploadFile(
749 GURL(kTestUploadExistingFileURL
),
752 test_util::CreateCopyResultCallback(
753 &error
, &upload_location
, &entry
),
754 base::Bind(&test_util::AppendProgressCallbackResult
,
755 &upload_progress_values
));
756 base::RunLoop().RunUntilIdle();
758 EXPECT_EQ(1, mock_service
.resume_upload_call_count());
759 EXPECT_EQ(1024 * 1024, mock_service
.received_bytes());
760 EXPECT_EQ(HTTP_SUCCESS
, error
);
761 EXPECT_TRUE(upload_location
.is_empty());
763 EXPECT_EQ(kTestDummyMd5
, entry
->md5_checksum());
764 ASSERT_EQ(1U, upload_progress_values
.size());
765 EXPECT_EQ(test_util::ProgressInfo(1024 * 1024, 1024 * 1024),
766 upload_progress_values
[0]);
769 class MockDriveServiceForBatchProcessing
: public DummyDriveService
{
771 struct UploadFileInfo
{
772 enum { NEW_FILE
, EXISTING_FILE
} type
;
773 std::string content_type
;
774 uint64 content_length
;
775 std::string parent_resource_id
;
776 std::string resource_id
;
778 base::FilePath local_file_path
;
779 google_apis::FileResourceCallback callback
;
780 google_apis::ProgressCallback progress_callback
;
783 class BatchRequestConfigurator
: public BatchRequestConfiguratorInterface
{
785 explicit BatchRequestConfigurator(
786 MockDriveServiceForBatchProcessing
* service
)
787 : service(service
) {}
789 CancelCallback
MultipartUploadNewFile(
790 const std::string
& content_type
,
791 int64 content_length
,
792 const std::string
& parent_resource_id
,
793 const std::string
& title
,
794 const base::FilePath
& local_file_path
,
795 const UploadNewFileOptions
& options
,
796 const google_apis::FileResourceCallback
& callback
,
797 const google_apis::ProgressCallback
& progress_callback
) override
{
799 info
.type
= UploadFileInfo::NEW_FILE
;
800 info
.content_type
= content_type
;
801 info
.content_length
= content_length
;
802 info
.parent_resource_id
= parent_resource_id
;
804 info
.local_file_path
= local_file_path
;
805 info
.callback
= callback
;
806 info
.progress_callback
= progress_callback
;
807 service
->files
.push_back(info
);
808 return CancelCallback();
811 CancelCallback
MultipartUploadExistingFile(
812 const std::string
& content_type
,
813 int64 content_length
,
814 const std::string
& resource_id
,
815 const base::FilePath
& local_file_path
,
816 const UploadExistingFileOptions
& options
,
817 const google_apis::FileResourceCallback
& callback
,
818 const google_apis::ProgressCallback
& progress_callback
) override
{
820 info
.type
= UploadFileInfo::EXISTING_FILE
;
821 info
.content_type
= content_type
;
822 info
.content_length
= content_length
;
823 info
.resource_id
= resource_id
;
824 info
.local_file_path
= local_file_path
;
825 info
.callback
= callback
;
826 info
.progress_callback
= progress_callback
;
827 service
->files
.push_back(info
);
828 return CancelCallback();
831 void Commit() override
{
832 ASSERT_FALSE(service
->committed
);
833 service
->committed
= true;
834 for (const auto& file
: service
->files
) {
835 SendMultipartUploadResult(HTTP_SUCCESS
, file
.content_length
,
836 file
.callback
, file
.progress_callback
);
841 MockDriveServiceForBatchProcessing
* service
;
845 scoped_ptr
<BatchRequestConfiguratorInterface
> StartBatchRequest() override
{
847 return scoped_ptr
<BatchRequestConfiguratorInterface
>(
848 new BatchRequestConfigurator(this));
851 std::vector
<UploadFileInfo
> files
;
855 TEST_F(DriveUploaderTest
, BatchProcessing
) {
856 // Preapre test file.
857 const size_t kTestFileSize
= 1024 * 512;
858 base::FilePath local_path
;
860 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
861 temp_dir_
.path(), kTestFileSize
, &local_path
, &data
));
863 // Prepare test target.
864 MockDriveServiceForBatchProcessing service
;
865 DriveUploader
uploader(&service
, base::ThreadTaskRunnerHandle::Get().get());
868 DriveApiErrorCode error
;
870 scoped_ptr
<FileResource
> file
;
871 UploadCompletionCallback
callback() {
872 return test_util::CreateCopyResultCallback(&error
, &resume_url
, &file
);
876 uploader
.StartBatchProcessing();
877 uploader
.UploadNewFile("parent_resource_id", local_path
, "title",
878 kTestMimeType
, UploadNewFileOptions(),
879 results
[0].callback(),
880 google_apis::ProgressCallback());
881 uploader
.UploadExistingFile(
882 "resource_id", local_path
, kTestMimeType
, UploadExistingFileOptions(),
883 results
[1].callback(), google_apis::ProgressCallback());
884 uploader
.StopBatchProcessing();
885 base::RunLoop().RunUntilIdle();
887 ASSERT_EQ(2u, service
.files
.size());
888 EXPECT_TRUE(service
.committed
);
890 EXPECT_EQ(MockDriveServiceForBatchProcessing::UploadFileInfo::NEW_FILE
,
891 service
.files
[0].type
);
892 EXPECT_EQ(kTestMimeType
, service
.files
[0].content_type
);
893 EXPECT_EQ(kTestFileSize
, service
.files
[0].content_length
);
894 EXPECT_EQ("parent_resource_id", service
.files
[0].parent_resource_id
);
895 EXPECT_EQ("", service
.files
[0].resource_id
);
896 EXPECT_EQ("title", service
.files
[0].title
);
897 EXPECT_EQ(local_path
.value(), service
.files
[0].local_file_path
.value());
899 EXPECT_EQ(MockDriveServiceForBatchProcessing::UploadFileInfo::EXISTING_FILE
,
900 service
.files
[1].type
);
901 EXPECT_EQ(kTestMimeType
, service
.files
[1].content_type
);
902 EXPECT_EQ(kTestFileSize
, service
.files
[1].content_length
);
903 EXPECT_EQ("", service
.files
[1].parent_resource_id
);
904 EXPECT_EQ("resource_id", service
.files
[1].resource_id
);
905 EXPECT_EQ("", service
.files
[1].title
);
906 EXPECT_EQ(local_path
.value(), service
.files
[1].local_file_path
.value());
908 EXPECT_EQ(HTTP_SUCCESS
, results
[0].error
);
909 EXPECT_TRUE(results
[0].resume_url
.is_empty());
910 EXPECT_TRUE(results
[0].file
);
912 EXPECT_EQ(HTTP_SUCCESS
, results
[1].error
);
913 EXPECT_TRUE(results
[1].resume_url
.is_empty());
914 EXPECT_TRUE(results
[1].file
);
917 TEST_F(DriveUploaderTest
, BatchProcessingWithError
) {
918 // Prepare test target.
919 MockDriveServiceForBatchProcessing service
;
920 DriveUploader
uploader(&service
, base::ThreadTaskRunnerHandle::Get().get());
923 DriveApiErrorCode error
;
925 scoped_ptr
<FileResource
> file
;
926 UploadCompletionCallback
callback() {
927 return test_util::CreateCopyResultCallback(&error
, &resume_url
, &file
);
931 uploader
.StartBatchProcessing();
932 uploader
.UploadNewFile("parent_resource_id",
933 base::FilePath(FILE_PATH_LITERAL("/path/non_exists")),
934 "title", kTestMimeType
, UploadNewFileOptions(),
935 results
[0].callback(),
936 google_apis::ProgressCallback());
937 uploader
.UploadExistingFile(
938 "resource_id", base::FilePath(FILE_PATH_LITERAL("/path/non_exists")),
939 kTestMimeType
, UploadExistingFileOptions(), results
[1].callback(),
940 google_apis::ProgressCallback());
941 uploader
.StopBatchProcessing();
942 base::RunLoop().RunUntilIdle();
944 EXPECT_EQ(0u, service
.files
.size());
945 EXPECT_TRUE(service
.committed
);
947 EXPECT_EQ(HTTP_NOT_FOUND
, results
[0].error
);
948 EXPECT_TRUE(results
[0].resume_url
.is_empty());
949 EXPECT_FALSE(results
[0].file
);
951 EXPECT_EQ(HTTP_NOT_FOUND
, results
[1].error
);
952 EXPECT_TRUE(results
[1].resume_url
.is_empty());
953 EXPECT_FALSE(results
[1].file
);