Home | History | Annotate | Download | only in drive
      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.
     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 
     68   int64 received_bytes() const { return received_bytes_; }
     69   void set_received_bytes(int64 received_bytes) {
     70     received_bytes_ = received_bytes;
     71   }
     72 
     73   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.
     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 
     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.
    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.
    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.
    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.
    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 
    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.
    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.
    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 
    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.
    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.
    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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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