• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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