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.
4
5 #include "chrome/browser/drive/drive_uploader.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "base/values.h"
16 #include "chrome/browser/drive/dummy_drive_service.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "google_apis/drive/drive_api_parser.h"
19 #include "google_apis/drive/test_util.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 using google_apis::CancelCallback;
23 using google_apis::FileResource;
24 using google_apis::GDataErrorCode;
25 using google_apis::GDATA_NO_CONNECTION;
26 using google_apis::GDATA_OTHER_ERROR;
27 using google_apis::HTTP_CONFLICT;
28 using google_apis::HTTP_CREATED;
29 using google_apis::HTTP_NOT_FOUND;
30 using google_apis::HTTP_PRECONDITION;
31 using google_apis::HTTP_RESUME_INCOMPLETE;
32 using google_apis::HTTP_SUCCESS;
33 using google_apis::InitiateUploadCallback;
34 using google_apis::ProgressCallback;
35 using google_apis::UploadRangeResponse;
36 using google_apis::drive::UploadRangeCallback;
37 namespace test_util = google_apis::test_util;
38
39 namespace drive {
40
41 namespace {
42
43 const char kTestDummyMd5[] = "dummy_md5";
44 const char kTestDocumentTitle[] = "Hello world";
45 const char kTestInitiateUploadParentResourceId[] = "parent_resource_id";
46 const char kTestInitiateUploadResourceId[] = "resource_id";
47 const char kTestMimeType[] = "text/plain";
48 const char kTestUploadNewFileURL[] = "http://test/upload_location/new_file";
49 const char kTestUploadExistingFileURL[] =
50 "http://test/upload_location/existing_file";
51 const int64 kUploadChunkSize = 512 * 1024;
52 const char kTestETag[] = "test_etag";
53
54 // Mock DriveService that verifies if the uploaded content matches the preset
55 // expectation.
56 class MockDriveServiceWithUploadExpectation : public DummyDriveService {
57 public:
58 // Sets up an expected upload content. InitiateUpload and ResumeUpload will
59 // verify that the specified data is correctly uploaded.
MockDriveServiceWithUploadExpectation(const base::FilePath & expected_upload_file,int64 expected_content_length)60 MockDriveServiceWithUploadExpectation(
61 const base::FilePath& expected_upload_file,
62 int64 expected_content_length)
63 : expected_upload_file_(expected_upload_file),
64 expected_content_length_(expected_content_length),
65 received_bytes_(0),
66 resume_upload_call_count_(0) {}
67
received_bytes() const68 int64 received_bytes() const { return received_bytes_; }
set_received_bytes(int64 received_bytes)69 void set_received_bytes(int64 received_bytes) {
70 received_bytes_ = received_bytes;
71 }
72
resume_upload_call_count() const73 int64 resume_upload_call_count() const { return resume_upload_call_count_; }
74
75 private:
76 // DriveServiceInterface overrides.
77 // Handles a request for obtaining an upload location URL.
InitiateUploadNewFile(const std::string & content_type,int64 content_length,const std::string & parent_resource_id,const std::string & title,const InitiateUploadNewFileOptions & options,const InitiateUploadCallback & callback)78 virtual CancelCallback InitiateUploadNewFile(
79 const std::string& content_type,
80 int64 content_length,
81 const std::string& parent_resource_id,
82 const std::string& title,
83 const InitiateUploadNewFileOptions& options,
84 const InitiateUploadCallback& callback) OVERRIDE {
85 EXPECT_EQ(kTestDocumentTitle, title);
86 EXPECT_EQ(kTestMimeType, content_type);
87 EXPECT_EQ(expected_content_length_, content_length);
88 EXPECT_EQ(kTestInitiateUploadParentResourceId, parent_resource_id);
89
90 // Calls back the upload URL for subsequent ResumeUpload requests.
91 // InitiateUpload is an asynchronous function, so don't callback directly.
92 base::MessageLoop::current()->PostTask(FROM_HERE,
93 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadNewFileURL)));
94 return CancelCallback();
95 }
96
InitiateUploadExistingFile(const std::string & content_type,int64 content_length,const std::string & resource_id,const InitiateUploadExistingFileOptions & options,const InitiateUploadCallback & callback)97 virtual CancelCallback InitiateUploadExistingFile(
98 const std::string& content_type,
99 int64 content_length,
100 const std::string& resource_id,
101 const InitiateUploadExistingFileOptions& options,
102 const InitiateUploadCallback& callback) OVERRIDE {
103 EXPECT_EQ(kTestMimeType, content_type);
104 EXPECT_EQ(expected_content_length_, content_length);
105 EXPECT_EQ(kTestInitiateUploadResourceId, resource_id);
106
107 if (!options.etag.empty() && options.etag != kTestETag) {
108 base::MessageLoop::current()->PostTask(FROM_HERE,
109 base::Bind(callback, HTTP_PRECONDITION, GURL()));
110 return CancelCallback();
111 }
112
113 // Calls back the upload URL for subsequent ResumeUpload requests.
114 // InitiateUpload is an asynchronous function, so don't callback directly.
115 base::MessageLoop::current()->PostTask(FROM_HERE,
116 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadExistingFileURL)));
117 return CancelCallback();
118 }
119
120 // Handles a request for uploading a chunk of bytes.
ResumeUpload(const GURL & upload_location,int64 start_position,int64 end_position,int64 content_length,const std::string & content_type,const base::FilePath & local_file_path,const UploadRangeCallback & callback,const ProgressCallback & progress_callback)121 virtual CancelCallback ResumeUpload(
122 const GURL& upload_location,
123 int64 start_position,
124 int64 end_position,
125 int64 content_length,
126 const std::string& content_type,
127 const base::FilePath& local_file_path,
128 const UploadRangeCallback& callback,
129 const ProgressCallback& progress_callback) OVERRIDE {
130 // The upload range should start from the current first unreceived byte.
131 EXPECT_EQ(received_bytes_, start_position);
132 EXPECT_EQ(expected_upload_file_, local_file_path);
133
134 // The upload data must be split into 512KB chunks.
135 const int64 expected_chunk_end =
136 std::min(received_bytes_ + kUploadChunkSize, expected_content_length_);
137 EXPECT_EQ(expected_chunk_end, end_position);
138
139 // The upload URL returned by InitiateUpload() must be used.
140 EXPECT_TRUE(GURL(kTestUploadNewFileURL) == upload_location ||
141 GURL(kTestUploadExistingFileURL) == upload_location);
142
143 // Other parameters should be the exact values passed to DriveUploader.
144 EXPECT_EQ(expected_content_length_, content_length);
145 EXPECT_EQ(kTestMimeType, content_type);
146
147 // Update the internal status of the current upload session.
148 resume_upload_call_count_++;
149 received_bytes_ = end_position;
150
151 // Callback progress
152 if (!progress_callback.is_null()) {
153 // For the testing purpose, it always notifies the progress at the end of
154 // each chunk uploading.
155 int64 chunk_size = end_position - start_position;
156 base::MessageLoop::current()->PostTask(FROM_HERE,
157 base::Bind(progress_callback, chunk_size, chunk_size));
158 }
159
160 SendUploadRangeResponse(upload_location, callback);
161 return CancelCallback();
162 }
163
164 // Handles a request to fetch the current upload status.
GetUploadStatus(const GURL & upload_location,int64 content_length,const UploadRangeCallback & callback)165 virtual CancelCallback GetUploadStatus(
166 const GURL& upload_location,
167 int64 content_length,
168 const UploadRangeCallback& callback) OVERRIDE {
169 EXPECT_EQ(expected_content_length_, content_length);
170 // The upload URL returned by InitiateUpload() must be used.
171 EXPECT_TRUE(GURL(kTestUploadNewFileURL) == upload_location ||
172 GURL(kTestUploadExistingFileURL) == upload_location);
173
174 SendUploadRangeResponse(upload_location, callback);
175 return CancelCallback();
176 }
177
178 // Runs |callback| with the current upload status.
SendUploadRangeResponse(const GURL & upload_location,const UploadRangeCallback & callback)179 void SendUploadRangeResponse(const GURL& upload_location,
180 const UploadRangeCallback& callback) {
181 // Callback with response.
182 UploadRangeResponse response;
183 scoped_ptr<FileResource> entry;
184 if (received_bytes_ == expected_content_length_) {
185 GDataErrorCode response_code =
186 upload_location == GURL(kTestUploadNewFileURL) ?
187 HTTP_CREATED : HTTP_SUCCESS;
188 response = UploadRangeResponse(response_code, -1, -1);
189
190 entry.reset(new FileResource);
191 entry->set_md5_checksum(kTestDummyMd5);
192 } else {
193 response = UploadRangeResponse(
194 HTTP_RESUME_INCOMPLETE, 0, received_bytes_);
195 }
196 // ResumeUpload is an asynchronous function, so don't callback directly.
197 base::MessageLoop::current()->PostTask(FROM_HERE,
198 base::Bind(callback, response, base::Passed(&entry)));
199 }
200
201 const base::FilePath expected_upload_file_;
202 const int64 expected_content_length_;
203 int64 received_bytes_;
204 int64 resume_upload_call_count_;
205 };
206
207 // Mock DriveService that returns a failure at InitiateUpload().
208 class MockDriveServiceNoConnectionAtInitiate : public DummyDriveService {
209 // Returns error.
InitiateUploadNewFile(const std::string & content_type,int64 content_length,const std::string & parent_resource_id,const std::string & title,const InitiateUploadNewFileOptions & options,const InitiateUploadCallback & callback)210 virtual CancelCallback InitiateUploadNewFile(
211 const std::string& content_type,
212 int64 content_length,
213 const std::string& parent_resource_id,
214 const std::string& title,
215 const InitiateUploadNewFileOptions& options,
216 const InitiateUploadCallback& callback) OVERRIDE {
217 base::MessageLoop::current()->PostTask(FROM_HERE,
218 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
219 return CancelCallback();
220 }
221
InitiateUploadExistingFile(const std::string & content_type,int64 content_length,const std::string & resource_id,const InitiateUploadExistingFileOptions & options,const InitiateUploadCallback & callback)222 virtual CancelCallback InitiateUploadExistingFile(
223 const std::string& content_type,
224 int64 content_length,
225 const std::string& resource_id,
226 const InitiateUploadExistingFileOptions& options,
227 const InitiateUploadCallback& callback) OVERRIDE {
228 base::MessageLoop::current()->PostTask(FROM_HERE,
229 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
230 return CancelCallback();
231 }
232
233 // Should not be used.
ResumeUpload(const GURL & upload_url,int64 start_position,int64 end_position,int64 content_length,const std::string & content_type,const base::FilePath & local_file_path,const UploadRangeCallback & callback,const ProgressCallback & progress_callback)234 virtual CancelCallback ResumeUpload(
235 const GURL& upload_url,
236 int64 start_position,
237 int64 end_position,
238 int64 content_length,
239 const std::string& content_type,
240 const base::FilePath& local_file_path,
241 const UploadRangeCallback& callback,
242 const ProgressCallback& progress_callback) OVERRIDE {
243 NOTREACHED();
244 return CancelCallback();
245 }
246 };
247
248 // Mock DriveService that returns a failure at ResumeUpload().
249 class MockDriveServiceNoConnectionAtResume : public DummyDriveService {
250 // Succeeds and returns an upload location URL.
InitiateUploadNewFile(const std::string & content_type,int64 content_length,const std::string & parent_resource_id,const std::string & title,const InitiateUploadNewFileOptions & options,const InitiateUploadCallback & callback)251 virtual CancelCallback InitiateUploadNewFile(
252 const std::string& content_type,
253 int64 content_length,
254 const std::string& parent_resource_id,
255 const std::string& title,
256 const InitiateUploadNewFileOptions& options,
257 const InitiateUploadCallback& callback) OVERRIDE {
258 base::MessageLoop::current()->PostTask(FROM_HERE,
259 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadNewFileURL)));
260 return CancelCallback();
261 }
262
InitiateUploadExistingFile(const std::string & content_type,int64 content_length,const std::string & resource_id,const InitiateUploadExistingFileOptions & options,const InitiateUploadCallback & callback)263 virtual CancelCallback InitiateUploadExistingFile(
264 const std::string& content_type,
265 int64 content_length,
266 const std::string& resource_id,
267 const InitiateUploadExistingFileOptions& options,
268 const InitiateUploadCallback& callback) OVERRIDE {
269 base::MessageLoop::current()->PostTask(FROM_HERE,
270 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadExistingFileURL)));
271 return CancelCallback();
272 }
273
274 // Returns error.
ResumeUpload(const GURL & upload_url,int64 start_position,int64 end_position,int64 content_length,const std::string & content_type,const base::FilePath & local_file_path,const UploadRangeCallback & callback,const ProgressCallback & progress_callback)275 virtual CancelCallback ResumeUpload(
276 const GURL& upload_url,
277 int64 start_position,
278 int64 end_position,
279 int64 content_length,
280 const std::string& content_type,
281 const base::FilePath& local_file_path,
282 const UploadRangeCallback& callback,
283 const ProgressCallback& progress_callback) OVERRIDE {
284 base::MessageLoop::current()->PostTask(FROM_HERE,
285 base::Bind(callback,
286 UploadRangeResponse(GDATA_NO_CONNECTION, -1, -1),
287 base::Passed(scoped_ptr<FileResource>())));
288 return CancelCallback();
289 }
290 };
291
292 // Mock DriveService that returns a failure at GetUploadStatus().
293 class MockDriveServiceNoConnectionAtGetUploadStatus : public DummyDriveService {
294 // Returns error.
GetUploadStatus(const GURL & upload_url,int64 content_length,const UploadRangeCallback & callback)295 virtual CancelCallback GetUploadStatus(
296 const GURL& upload_url,
297 int64 content_length,
298 const UploadRangeCallback& callback) OVERRIDE {
299 base::MessageLoop::current()->PostTask(FROM_HERE,
300 base::Bind(callback,
301 UploadRangeResponse(GDATA_NO_CONNECTION, -1, -1),
302 base::Passed(scoped_ptr<FileResource>())));
303 return CancelCallback();
304 }
305 };
306
307 class DriveUploaderTest : public testing::Test {
308 public:
SetUp()309 virtual void SetUp() OVERRIDE {
310 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
311 }
312
313 protected:
314 content::TestBrowserThreadBundle thread_bundle_;
315 base::ScopedTempDir temp_dir_;
316 };
317
318 } // namespace
319
TEST_F(DriveUploaderTest,UploadExisting0KB)320 TEST_F(DriveUploaderTest, UploadExisting0KB) {
321 base::FilePath local_path;
322 std::string data;
323 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
324 temp_dir_.path(), 0, &local_path, &data));
325
326 GDataErrorCode error = GDATA_OTHER_ERROR;
327 GURL upload_location;
328 scoped_ptr<FileResource> entry;
329
330 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
331 DriveUploader uploader(&mock_service,
332 base::MessageLoopProxy::current().get());
333 std::vector<test_util::ProgressInfo> upload_progress_values;
334 uploader.UploadExistingFile(
335 kTestInitiateUploadResourceId,
336 local_path,
337 kTestMimeType,
338 DriveUploader::UploadExistingFileOptions(),
339 test_util::CreateCopyResultCallback(
340 &error, &upload_location, &entry),
341 base::Bind(&test_util::AppendProgressCallbackResult,
342 &upload_progress_values));
343 base::RunLoop().RunUntilIdle();
344
345 EXPECT_EQ(1, mock_service.resume_upload_call_count());
346 EXPECT_EQ(0, mock_service.received_bytes());
347 EXPECT_EQ(HTTP_SUCCESS, error);
348 EXPECT_TRUE(upload_location.is_empty());
349 ASSERT_TRUE(entry);
350 EXPECT_EQ(kTestDummyMd5, entry->md5_checksum());
351 ASSERT_EQ(1U, upload_progress_values.size());
352 EXPECT_EQ(test_util::ProgressInfo(0, 0), upload_progress_values[0]);
353 }
354
TEST_F(DriveUploaderTest,UploadExisting512KB)355 TEST_F(DriveUploaderTest, UploadExisting512KB) {
356 base::FilePath local_path;
357 std::string data;
358 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
359 temp_dir_.path(), 512 * 1024, &local_path, &data));
360
361 GDataErrorCode error = GDATA_OTHER_ERROR;
362 GURL upload_location;
363 scoped_ptr<FileResource> entry;
364
365 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
366 DriveUploader uploader(&mock_service,
367 base::MessageLoopProxy::current().get());
368 std::vector<test_util::ProgressInfo> upload_progress_values;
369 uploader.UploadExistingFile(
370 kTestInitiateUploadResourceId,
371 local_path,
372 kTestMimeType,
373 DriveUploader::UploadExistingFileOptions(),
374 test_util::CreateCopyResultCallback(
375 &error, &upload_location, &entry),
376 base::Bind(&test_util::AppendProgressCallbackResult,
377 &upload_progress_values));
378 base::RunLoop().RunUntilIdle();
379
380 // 512KB upload should not be split into multiple chunks.
381 EXPECT_EQ(1, mock_service.resume_upload_call_count());
382 EXPECT_EQ(512 * 1024, mock_service.received_bytes());
383 EXPECT_EQ(HTTP_SUCCESS, error);
384 EXPECT_TRUE(upload_location.is_empty());
385 ASSERT_TRUE(entry);
386 EXPECT_EQ(kTestDummyMd5, entry->md5_checksum());
387 ASSERT_EQ(1U, upload_progress_values.size());
388 EXPECT_EQ(test_util::ProgressInfo(512 * 1024, 512 * 1024),
389 upload_progress_values[0]);
390 }
391
TEST_F(DriveUploaderTest,InitiateUploadFail)392 TEST_F(DriveUploaderTest, InitiateUploadFail) {
393 base::FilePath local_path;
394 std::string data;
395 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
396 temp_dir_.path(), 512 * 1024, &local_path, &data));
397
398 GDataErrorCode error = HTTP_SUCCESS;
399 GURL upload_location;
400 scoped_ptr<FileResource> entry;
401
402 MockDriveServiceNoConnectionAtInitiate mock_service;
403 DriveUploader uploader(&mock_service,
404 base::MessageLoopProxy::current().get());
405 uploader.UploadExistingFile(kTestInitiateUploadResourceId,
406 local_path,
407 kTestMimeType,
408 DriveUploader::UploadExistingFileOptions(),
409 test_util::CreateCopyResultCallback(
410 &error, &upload_location, &entry),
411 google_apis::ProgressCallback());
412 base::RunLoop().RunUntilIdle();
413
414 EXPECT_EQ(GDATA_NO_CONNECTION, error);
415 EXPECT_TRUE(upload_location.is_empty());
416 EXPECT_FALSE(entry);
417 }
418
TEST_F(DriveUploaderTest,InitiateUploadNoConflict)419 TEST_F(DriveUploaderTest, InitiateUploadNoConflict) {
420 base::FilePath local_path;
421 std::string data;
422 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
423 temp_dir_.path(), 512 * 1024, &local_path, &data));
424
425 GDataErrorCode error = GDATA_OTHER_ERROR;
426 GURL upload_location;
427 scoped_ptr<FileResource> entry;
428
429 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
430 DriveUploader uploader(&mock_service,
431 base::MessageLoopProxy::current().get());
432 DriveUploader::UploadExistingFileOptions options;
433 options.etag = kTestETag;
434 uploader.UploadExistingFile(kTestInitiateUploadResourceId,
435 local_path,
436 kTestMimeType,
437 options,
438 test_util::CreateCopyResultCallback(
439 &error, &upload_location, &entry),
440 google_apis::ProgressCallback());
441 base::RunLoop().RunUntilIdle();
442
443 EXPECT_EQ(HTTP_SUCCESS, error);
444 EXPECT_TRUE(upload_location.is_empty());
445 }
446
TEST_F(DriveUploaderTest,InitiateUploadConflict)447 TEST_F(DriveUploaderTest, InitiateUploadConflict) {
448 base::FilePath local_path;
449 std::string data;
450 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
451 temp_dir_.path(), 512 * 1024, &local_path, &data));
452 const std::string kDestinationETag("destination_etag");
453
454 GDataErrorCode error = GDATA_OTHER_ERROR;
455 GURL upload_location;
456 scoped_ptr<FileResource> entry;
457
458 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
459 DriveUploader uploader(&mock_service,
460 base::MessageLoopProxy::current().get());
461 DriveUploader::UploadExistingFileOptions options;
462 options.etag = kDestinationETag;
463 uploader.UploadExistingFile(kTestInitiateUploadResourceId,
464 local_path,
465 kTestMimeType,
466 options,
467 test_util::CreateCopyResultCallback(
468 &error, &upload_location, &entry),
469 google_apis::ProgressCallback());
470 base::RunLoop().RunUntilIdle();
471
472 EXPECT_EQ(HTTP_CONFLICT, error);
473 EXPECT_TRUE(upload_location.is_empty());
474 }
475
TEST_F(DriveUploaderTest,ResumeUploadFail)476 TEST_F(DriveUploaderTest, ResumeUploadFail) {
477 base::FilePath local_path;
478 std::string data;
479 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
480 temp_dir_.path(), 512 * 1024, &local_path, &data));
481
482 GDataErrorCode error = HTTP_SUCCESS;
483 GURL upload_location;
484 scoped_ptr<FileResource> entry;
485
486 MockDriveServiceNoConnectionAtResume mock_service;
487 DriveUploader uploader(&mock_service,
488 base::MessageLoopProxy::current().get());
489 uploader.UploadExistingFile(kTestInitiateUploadResourceId,
490 local_path,
491 kTestMimeType,
492 DriveUploader::UploadExistingFileOptions(),
493 test_util::CreateCopyResultCallback(
494 &error, &upload_location, &entry),
495 google_apis::ProgressCallback());
496 base::RunLoop().RunUntilIdle();
497
498 EXPECT_EQ(GDATA_NO_CONNECTION, error);
499 EXPECT_EQ(GURL(kTestUploadExistingFileURL), upload_location);
500 }
501
TEST_F(DriveUploaderTest,GetUploadStatusFail)502 TEST_F(DriveUploaderTest, GetUploadStatusFail) {
503 base::FilePath local_path;
504 std::string data;
505 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
506 temp_dir_.path(), 512 * 1024, &local_path, &data));
507
508 GDataErrorCode error = HTTP_SUCCESS;
509 GURL upload_location;
510 scoped_ptr<FileResource> entry;
511
512 MockDriveServiceNoConnectionAtGetUploadStatus mock_service;
513 DriveUploader uploader(&mock_service,
514 base::MessageLoopProxy::current().get());
515 uploader.ResumeUploadFile(GURL(kTestUploadExistingFileURL),
516 local_path,
517 kTestMimeType,
518 test_util::CreateCopyResultCallback(
519 &error, &upload_location, &entry),
520 google_apis::ProgressCallback());
521 base::RunLoop().RunUntilIdle();
522
523 EXPECT_EQ(GDATA_NO_CONNECTION, error);
524 EXPECT_TRUE(upload_location.is_empty());
525 }
526
TEST_F(DriveUploaderTest,NonExistingSourceFile)527 TEST_F(DriveUploaderTest, NonExistingSourceFile) {
528 GDataErrorCode error = GDATA_OTHER_ERROR;
529 GURL upload_location;
530 scoped_ptr<FileResource> entry;
531
532 DriveUploader uploader(NULL, // NULL, the service won't be used.
533 base::MessageLoopProxy::current().get());
534 uploader.UploadExistingFile(
535 kTestInitiateUploadResourceId,
536 temp_dir_.path().AppendASCII("_this_path_should_not_exist_"),
537 kTestMimeType,
538 DriveUploader::UploadExistingFileOptions(),
539 test_util::CreateCopyResultCallback(
540 &error, &upload_location, &entry),
541 google_apis::ProgressCallback());
542 base::RunLoop().RunUntilIdle();
543
544 // Should return failure without doing any attempt to connect to the server.
545 EXPECT_EQ(HTTP_NOT_FOUND, error);
546 EXPECT_TRUE(upload_location.is_empty());
547 }
548
TEST_F(DriveUploaderTest,ResumeUpload)549 TEST_F(DriveUploaderTest, ResumeUpload) {
550 base::FilePath local_path;
551 std::string data;
552 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
553 temp_dir_.path(), 1024 * 1024, &local_path, &data));
554
555 GDataErrorCode error = GDATA_OTHER_ERROR;
556 GURL upload_location;
557 scoped_ptr<FileResource> entry;
558
559 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
560 DriveUploader uploader(&mock_service,
561 base::MessageLoopProxy::current().get());
562 // Emulate the situation that the only first part is successfully uploaded,
563 // but not the latter half.
564 mock_service.set_received_bytes(512 * 1024);
565
566 std::vector<test_util::ProgressInfo> upload_progress_values;
567 uploader.ResumeUploadFile(
568 GURL(kTestUploadExistingFileURL),
569 local_path,
570 kTestMimeType,
571 test_util::CreateCopyResultCallback(
572 &error, &upload_location, &entry),
573 base::Bind(&test_util::AppendProgressCallbackResult,
574 &upload_progress_values));
575 base::RunLoop().RunUntilIdle();
576
577 EXPECT_EQ(1, mock_service.resume_upload_call_count());
578 EXPECT_EQ(1024 * 1024, mock_service.received_bytes());
579 EXPECT_EQ(HTTP_SUCCESS, error);
580 EXPECT_TRUE(upload_location.is_empty());
581 ASSERT_TRUE(entry);
582 EXPECT_EQ(kTestDummyMd5, entry->md5_checksum());
583 ASSERT_EQ(1U, upload_progress_values.size());
584 EXPECT_EQ(test_util::ProgressInfo(1024 * 1024, 1024 * 1024),
585 upload_progress_values[0]);
586 }
587
588 } // namespace drive
589