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