123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/drive/drive_uploader.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <algorithm>
- #include <memory>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/bind.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/memory/raw_ptr.h"
- #include "base/run_loop.h"
- #include "base/test/task_environment.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/values.h"
- #include "components/drive/service/dummy_drive_service.h"
- #include "google_apis/common/test_util.h"
- #include "google_apis/drive/drive_api_parser.h"
- #include "testing/gtest/include/gtest/gtest.h"
- using google_apis::ApiErrorCode;
- using google_apis::CancelCallbackOnce;
- using google_apis::FileResource;
- using google_apis::HTTP_CONFLICT;
- using google_apis::HTTP_CREATED;
- using google_apis::HTTP_NOT_FOUND;
- using google_apis::HTTP_PRECONDITION;
- using google_apis::HTTP_RESUME_INCOMPLETE;
- using google_apis::HTTP_SUCCESS;
- using google_apis::InitiateUploadCallback;
- using google_apis::NO_CONNECTION;
- using google_apis::OTHER_ERROR;
- using google_apis::ProgressCallback;
- using google_apis::UploadRangeResponse;
- using google_apis::drive::UploadRangeCallback;
- namespace test_util = google_apis::test_util;
- namespace drive {
- namespace {
- const char kTestDummyMd5[] = "dummy_md5";
- const char kTestDocumentTitle[] = "Hello world";
- const char kTestInitiateUploadParentResourceId[] = "parent_resource_id";
- const char kTestInitiateUploadResourceId[] = "resource_id";
- const char kTestMimeType[] = "text/plain";
- const char kTestUploadNewFileURL[] = "http://test/upload_location/new_file";
- const char kTestUploadExistingFileURL[] =
- "http://test/upload_location/existing_file";
- const int64_t kUploadChunkSize = 1024 * 1024 * 1024;
- const char kTestETag[] = "test_etag";
- CancelCallbackOnce SendMultipartUploadResult(
- ApiErrorCode response_code,
- int64_t content_length,
- google_apis::FileResourceCallback callback,
- google_apis::ProgressCallback progress_callback) {
- // Callback progress
- if (!progress_callback.is_null()) {
- // For the testing purpose, it always notifies the progress at the end of
- // whole file uploading.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(progress_callback, content_length, content_length));
- }
- // MultipartUploadXXXFile is an asynchronous function, so don't callback
- // directly.
- auto entry = std::make_unique<FileResource>();
- entry->set_md5_checksum(kTestDummyMd5);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), response_code, std::move(entry)));
- return CancelCallbackOnce();
- }
- // Mock DriveService that verifies if the uploaded content matches the preset
- // expectation.
- class MockDriveServiceWithUploadExpectation : public DummyDriveService {
- public:
- // Sets up an expected upload content. InitiateUpload and ResumeUpload will
- // verify that the specified data is correctly uploaded.
- MockDriveServiceWithUploadExpectation(
- const base::FilePath& expected_upload_file,
- int64_t expected_content_length)
- : expected_upload_file_(expected_upload_file),
- expected_content_length_(expected_content_length),
- received_bytes_(0),
- resume_upload_call_count_(0),
- multipart_upload_call_count_(0) {}
- int64_t received_bytes() const { return received_bytes_; }
- void set_received_bytes(int64_t received_bytes) {
- received_bytes_ = received_bytes;
- }
- int64_t resume_upload_call_count() const { return resume_upload_call_count_; }
- int64_t multipart_upload_call_count() const {
- return multipart_upload_call_count_;
- }
- private:
- // DriveServiceInterface overrides.
- // Handles a request for obtaining an upload location URL.
- CancelCallbackOnce InitiateUploadNewFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& parent_resource_id,
- const std::string& title,
- const UploadNewFileOptions& options,
- InitiateUploadCallback callback) override {
- EXPECT_EQ(kTestDocumentTitle, title);
- EXPECT_EQ(kTestMimeType, content_type);
- EXPECT_EQ(expected_content_length_, content_length);
- EXPECT_EQ(kTestInitiateUploadParentResourceId, parent_resource_id);
- // Calls back the upload URL for subsequent ResumeUpload requests.
- // InitiateUpload is an asynchronous function, so don't callback directly.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
- GURL(kTestUploadNewFileURL)));
- return CancelCallbackOnce();
- }
- CancelCallbackOnce InitiateUploadExistingFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& resource_id,
- const UploadExistingFileOptions& options,
- InitiateUploadCallback callback) override {
- EXPECT_EQ(kTestMimeType, content_type);
- EXPECT_EQ(expected_content_length_, content_length);
- EXPECT_EQ(kTestInitiateUploadResourceId, resource_id);
- if (!options.etag.empty() && options.etag != kTestETag) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), HTTP_PRECONDITION, GURL()));
- return CancelCallbackOnce();
- }
- // Calls back the upload URL for subsequent ResumeUpload requests.
- // InitiateUpload is an asynchronous function, so don't callback directly.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
- GURL(kTestUploadExistingFileURL)));
- return CancelCallbackOnce();
- }
- // Handles a request for uploading a chunk of bytes.
- CancelCallbackOnce ResumeUpload(const GURL& upload_location,
- int64_t start_position,
- int64_t end_position,
- int64_t content_length,
- const std::string& content_type,
- const base::FilePath& local_file_path,
- UploadRangeCallback callback,
- ProgressCallback progress_callback) override {
- // The upload range should start from the current first unreceived byte.
- EXPECT_EQ(received_bytes_, start_position);
- EXPECT_EQ(expected_upload_file_, local_file_path);
- // The upload data must be split into 512KB chunks.
- const int64_t expected_chunk_end =
- std::min(received_bytes_ + kUploadChunkSize, expected_content_length_);
- EXPECT_EQ(expected_chunk_end, end_position);
- // The upload URL returned by InitiateUpload() must be used.
- EXPECT_TRUE(upload_location == kTestUploadNewFileURL ||
- upload_location == kTestUploadExistingFileURL);
- // Other parameters should be the exact values passed to DriveUploader.
- EXPECT_EQ(expected_content_length_, content_length);
- EXPECT_EQ(kTestMimeType, content_type);
- // Update the internal status of the current upload session.
- resume_upload_call_count_++;
- received_bytes_ = end_position;
- // Callback progress
- if (!progress_callback.is_null()) {
- // For the testing purpose, it always notifies the progress at the end of
- // each chunk uploading.
- int64_t chunk_size = end_position - start_position;
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(progress_callback, chunk_size, chunk_size));
- }
- SendUploadRangeResponse(upload_location, std::move(callback));
- return CancelCallbackOnce();
- }
- // Handles a request to fetch the current upload status.
- CancelCallbackOnce GetUploadStatus(const GURL& upload_location,
- int64_t content_length,
- UploadRangeCallback callback) override {
- EXPECT_EQ(expected_content_length_, content_length);
- // The upload URL returned by InitiateUpload() must be used.
- EXPECT_TRUE(upload_location == kTestUploadNewFileURL ||
- upload_location == kTestUploadExistingFileURL);
- SendUploadRangeResponse(upload_location, std::move(callback));
- return CancelCallbackOnce();
- }
- // Runs |callback| with the current upload status.
- void SendUploadRangeResponse(const GURL& upload_location,
- UploadRangeCallback callback) {
- // Callback with response.
- UploadRangeResponse response;
- std::unique_ptr<FileResource> entry;
- if (received_bytes_ == expected_content_length_) {
- ApiErrorCode response_code = upload_location == kTestUploadNewFileURL
- ? HTTP_CREATED
- : HTTP_SUCCESS;
- response = UploadRangeResponse(response_code, -1, -1);
- entry = std::make_unique<FileResource>();
- entry->set_md5_checksum(kTestDummyMd5);
- } else {
- response =
- UploadRangeResponse(HTTP_RESUME_INCOMPLETE, 0, received_bytes_);
- }
- // ResumeUpload is an asynchronous function, so don't callback directly.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), response, std::move(entry)));
- }
- CancelCallbackOnce MultipartUploadNewFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& parent_resource_id,
- const std::string& title,
- const base::FilePath& local_file_path,
- const UploadNewFileOptions& options,
- google_apis::FileResourceCallback callback,
- google_apis::ProgressCallback progress_callback) override {
- EXPECT_EQ(kTestMimeType, content_type);
- EXPECT_EQ(expected_content_length_, content_length);
- EXPECT_EQ(kTestInitiateUploadParentResourceId, parent_resource_id);
- EXPECT_EQ(kTestDocumentTitle, title);
- EXPECT_EQ(expected_upload_file_, local_file_path);
- received_bytes_ = content_length;
- multipart_upload_call_count_++;
- return SendMultipartUploadResult(HTTP_CREATED, content_length,
- std::move(callback), progress_callback);
- }
- CancelCallbackOnce MultipartUploadExistingFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& resource_id,
- const base::FilePath& local_file_path,
- const UploadExistingFileOptions& options,
- google_apis::FileResourceCallback callback,
- google_apis::ProgressCallback progress_callback) override {
- EXPECT_EQ(kTestMimeType, content_type);
- EXPECT_EQ(expected_content_length_, content_length);
- EXPECT_EQ(kTestInitiateUploadResourceId, resource_id);
- EXPECT_EQ(expected_upload_file_, local_file_path);
- if (!options.etag.empty() && options.etag != kTestETag) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), HTTP_PRECONDITION, nullptr));
- return CancelCallbackOnce();
- }
- received_bytes_ = content_length;
- multipart_upload_call_count_++;
- return SendMultipartUploadResult(HTTP_SUCCESS, content_length,
- std::move(callback), progress_callback);
- }
- const base::FilePath expected_upload_file_;
- const int64_t expected_content_length_;
- int64_t received_bytes_;
- int64_t resume_upload_call_count_;
- int64_t multipart_upload_call_count_;
- };
- // Mock DriveService that returns a failure at InitiateUpload().
- class MockDriveServiceNoConnectionAtInitiate : public DummyDriveService {
- // Returns error.
- CancelCallbackOnce InitiateUploadNewFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& parent_resource_id,
- const std::string& title,
- const UploadNewFileOptions& options,
- InitiateUploadCallback callback) override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION, GURL()));
- return CancelCallbackOnce();
- }
- CancelCallbackOnce InitiateUploadExistingFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& resource_id,
- const UploadExistingFileOptions& options,
- InitiateUploadCallback callback) override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION, GURL()));
- return CancelCallbackOnce();
- }
- // Should not be used.
- CancelCallbackOnce ResumeUpload(const GURL& upload_url,
- int64_t start_position,
- int64_t end_position,
- int64_t content_length,
- const std::string& content_type,
- const base::FilePath& local_file_path,
- UploadRangeCallback callback,
- ProgressCallback progress_callback) override {
- NOTREACHED();
- return CancelCallbackOnce();
- }
- CancelCallbackOnce MultipartUploadNewFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& parent_resource_id,
- const std::string& title,
- const base::FilePath& local_file_path,
- const UploadNewFileOptions& options,
- google_apis::FileResourceCallback callback,
- google_apis::ProgressCallback progress_callback) override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION, nullptr));
- return CancelCallbackOnce();
- }
- CancelCallbackOnce MultipartUploadExistingFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& resource_id,
- const base::FilePath& local_file_path,
- const UploadExistingFileOptions& options,
- google_apis::FileResourceCallback callback,
- google_apis::ProgressCallback progress_callback) override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), NO_CONNECTION, nullptr));
- return CancelCallbackOnce();
- }
- };
- // Mock DriveService that returns a failure at ResumeUpload().
- class MockDriveServiceNoConnectionAtResume : public DummyDriveService {
- // Succeeds and returns an upload location URL.
- CancelCallbackOnce InitiateUploadNewFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& parent_resource_id,
- const std::string& title,
- const UploadNewFileOptions& options,
- InitiateUploadCallback callback) override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
- GURL(kTestUploadNewFileURL)));
- return CancelCallbackOnce();
- }
- CancelCallbackOnce InitiateUploadExistingFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& resource_id,
- const UploadExistingFileOptions& options,
- InitiateUploadCallback callback) override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), HTTP_SUCCESS,
- GURL(kTestUploadExistingFileURL)));
- return CancelCallbackOnce();
- }
- // Returns error.
- CancelCallbackOnce ResumeUpload(const GURL& upload_url,
- int64_t start_position,
- int64_t end_position,
- int64_t content_length,
- const std::string& content_type,
- const base::FilePath& local_file_path,
- UploadRangeCallback callback,
- ProgressCallback progress_callback) override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback),
- UploadRangeResponse(NO_CONNECTION, -1, -1), nullptr));
- return CancelCallbackOnce();
- }
- };
- // Mock DriveService that returns a failure at GetUploadStatus().
- class MockDriveServiceNoConnectionAtGetUploadStatus : public DummyDriveService {
- // Returns error.
- CancelCallbackOnce GetUploadStatus(const GURL& upload_url,
- int64_t content_length,
- UploadRangeCallback callback) override {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback),
- UploadRangeResponse(NO_CONNECTION, -1, -1), nullptr));
- return CancelCallbackOnce();
- }
- };
- class DriveUploaderTest : public testing::Test {
- public:
- void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
- protected:
- base::test::SingleThreadTaskEnvironment task_environment_;
- base::ScopedTempDir temp_dir_;
- };
- } // namespace
- TEST_F(DriveUploaderTest, UploadExisting0KB) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(temp_dir_.GetPath(), 0,
- &local_path, &data));
- ApiErrorCode error = OTHER_ERROR;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- std::vector<test_util::ProgressInfo> upload_progress_values;
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId, local_path, kTestMimeType,
- UploadExistingFileOptions(),
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- base::BindRepeating(&test_util::AppendProgressCallbackResult,
- &upload_progress_values));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, mock_service.resume_upload_call_count());
- EXPECT_EQ(1, mock_service.multipart_upload_call_count());
- EXPECT_EQ(0, mock_service.received_bytes());
- EXPECT_EQ(HTTP_SUCCESS, error);
- EXPECT_TRUE(upload_location.is_empty());
- ASSERT_TRUE(entry);
- EXPECT_EQ(kTestDummyMd5, entry->md5_checksum());
- ASSERT_EQ(1U, upload_progress_values.size());
- EXPECT_EQ(test_util::ProgressInfo(0, 0), upload_progress_values[0]);
- }
- TEST_F(DriveUploaderTest, UploadExisting512KB) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 512 * 1024, &local_path, &data));
- ApiErrorCode error = OTHER_ERROR;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- std::vector<test_util::ProgressInfo> upload_progress_values;
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId, local_path, kTestMimeType,
- UploadExistingFileOptions(),
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- base::BindRepeating(&test_util::AppendProgressCallbackResult,
- &upload_progress_values));
- base::RunLoop().RunUntilIdle();
- // 512KB upload should be uploaded as multipart body.
- EXPECT_EQ(0, mock_service.resume_upload_call_count());
- EXPECT_EQ(1, mock_service.multipart_upload_call_count());
- EXPECT_EQ(512 * 1024, mock_service.received_bytes());
- EXPECT_EQ(HTTP_SUCCESS, error);
- EXPECT_TRUE(upload_location.is_empty());
- ASSERT_TRUE(entry);
- EXPECT_EQ(kTestDummyMd5, entry->md5_checksum());
- ASSERT_EQ(1U, upload_progress_values.size());
- EXPECT_EQ(test_util::ProgressInfo(512 * 1024, 512 * 1024),
- upload_progress_values[0]);
- }
- TEST_F(DriveUploaderTest, UploadExisting2MB) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 2 * 1024 * 1024, &local_path, &data));
- ApiErrorCode error = OTHER_ERROR;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- std::vector<test_util::ProgressInfo> upload_progress_values;
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId, local_path, kTestMimeType,
- UploadExistingFileOptions(),
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- base::BindRepeating(&test_util::AppendProgressCallbackResult,
- &upload_progress_values));
- base::RunLoop().RunUntilIdle();
- // 2MB upload should not be split into multiple chunks.
- EXPECT_EQ(1, mock_service.resume_upload_call_count());
- EXPECT_EQ(0, mock_service.multipart_upload_call_count());
- EXPECT_EQ(2 * 1024 * 1024, mock_service.received_bytes());
- EXPECT_EQ(HTTP_SUCCESS, error);
- EXPECT_TRUE(upload_location.is_empty());
- ASSERT_TRUE(entry);
- EXPECT_EQ(kTestDummyMd5, entry->md5_checksum());
- ASSERT_EQ(1U, upload_progress_values.size());
- EXPECT_EQ(test_util::ProgressInfo(2 * 1024 * 1024, 2 * 1024 * 1024),
- upload_progress_values[0]);
- }
- TEST_F(DriveUploaderTest, InitiateUploadFail) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 2 * 1024 * 1024, &local_path, &data));
- ApiErrorCode error = HTTP_SUCCESS;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceNoConnectionAtInitiate mock_service;
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId, local_path, kTestMimeType,
- UploadExistingFileOptions(),
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- google_apis::ProgressCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(NO_CONNECTION, error);
- EXPECT_TRUE(upload_location.is_empty());
- EXPECT_FALSE(entry);
- }
- TEST_F(DriveUploaderTest, MultipartUploadFail) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 512 * 1024, &local_path, &data));
- ApiErrorCode error = HTTP_SUCCESS;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceNoConnectionAtInitiate mock_service;
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId, local_path, kTestMimeType,
- UploadExistingFileOptions(),
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- google_apis::ProgressCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(NO_CONNECTION, error);
- EXPECT_TRUE(upload_location.is_empty());
- EXPECT_FALSE(entry);
- }
- TEST_F(DriveUploaderTest, InitiateUploadNoConflict) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 512 * 1024, &local_path, &data));
- ApiErrorCode error = OTHER_ERROR;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- UploadExistingFileOptions options;
- options.etag = kTestETag;
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId, local_path, kTestMimeType, options,
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- google_apis::ProgressCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(HTTP_SUCCESS, error);
- EXPECT_TRUE(upload_location.is_empty());
- }
- TEST_F(DriveUploaderTest, MultipartUploadConflict) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 512 * 1024, &local_path, &data));
- const std::string kDestinationETag("destination_etag");
- ApiErrorCode error = OTHER_ERROR;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- UploadExistingFileOptions options;
- options.etag = kDestinationETag;
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId, local_path, kTestMimeType, options,
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- google_apis::ProgressCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(HTTP_CONFLICT, error);
- EXPECT_TRUE(upload_location.is_empty());
- }
- TEST_F(DriveUploaderTest, InitiateUploadConflict) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 2 * 1024 * 1024, &local_path, &data));
- const std::string kDestinationETag("destination_etag");
- ApiErrorCode error = OTHER_ERROR;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- UploadExistingFileOptions options;
- options.etag = kDestinationETag;
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId, local_path, kTestMimeType, options,
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- google_apis::ProgressCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(HTTP_CONFLICT, error);
- EXPECT_TRUE(upload_location.is_empty());
- }
- TEST_F(DriveUploaderTest, ResumeUploadFail) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 2 * 1024 * 1024, &local_path, &data));
- ApiErrorCode error = HTTP_SUCCESS;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceNoConnectionAtResume mock_service;
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId, local_path, kTestMimeType,
- UploadExistingFileOptions(),
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- google_apis::ProgressCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(NO_CONNECTION, error);
- EXPECT_EQ(GURL(kTestUploadExistingFileURL), upload_location);
- }
- TEST_F(DriveUploaderTest, GetUploadStatusFail) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 2 * 1024 * 1024, &local_path, &data));
- ApiErrorCode error = HTTP_SUCCESS;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceNoConnectionAtGetUploadStatus mock_service;
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- uploader.ResumeUploadFile(
- GURL(kTestUploadExistingFileURL), local_path, kTestMimeType,
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- google_apis::ProgressCallback());
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(NO_CONNECTION, error);
- EXPECT_TRUE(upload_location.is_empty());
- }
- TEST_F(DriveUploaderTest, NonExistingSourceFile) {
- ApiErrorCode error = OTHER_ERROR;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- DriveUploader uploader(nullptr, // nullptr, the service won't be used.
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- uploader.UploadExistingFile(
- kTestInitiateUploadResourceId,
- temp_dir_.GetPath().AppendASCII("_this_path_should_not_exist_"),
- kTestMimeType, UploadExistingFileOptions(),
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- google_apis::ProgressCallback());
- base::RunLoop().RunUntilIdle();
- // Should return failure without doing any attempt to connect to the server.
- EXPECT_EQ(HTTP_NOT_FOUND, error);
- EXPECT_TRUE(upload_location.is_empty());
- }
- TEST_F(DriveUploaderTest, ResumeUpload) {
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), 1024 * 1024, &local_path, &data));
- ApiErrorCode error = OTHER_ERROR;
- GURL upload_location;
- std::unique_ptr<FileResource> entry;
- MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
- DriveUploader uploader(&mock_service,
- base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- // Emulate the situation that the only first part is successfully uploaded,
- // but not the latter half.
- mock_service.set_received_bytes(512 * 1024);
- std::vector<test_util::ProgressInfo> upload_progress_values;
- uploader.ResumeUploadFile(
- GURL(kTestUploadExistingFileURL), local_path, kTestMimeType,
- test_util::CreateCopyResultCallback(&error, &upload_location, &entry),
- base::BindRepeating(&test_util::AppendProgressCallbackResult,
- &upload_progress_values));
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, mock_service.resume_upload_call_count());
- EXPECT_EQ(1024 * 1024, mock_service.received_bytes());
- EXPECT_EQ(HTTP_SUCCESS, error);
- EXPECT_TRUE(upload_location.is_empty());
- ASSERT_TRUE(entry);
- EXPECT_EQ(kTestDummyMd5, entry->md5_checksum());
- ASSERT_EQ(1U, upload_progress_values.size());
- EXPECT_EQ(test_util::ProgressInfo(1024 * 1024, 1024 * 1024),
- upload_progress_values[0]);
- }
- class MockDriveServiceForBatchProcessing : public DummyDriveService {
- public:
- struct UploadFileInfo {
- enum { NEW_FILE, EXISTING_FILE } type;
- std::string content_type;
- uint64_t content_length;
- std::string parent_resource_id;
- std::string resource_id;
- std::string title;
- base::FilePath local_file_path;
- google_apis::FileResourceCallback callback;
- google_apis::ProgressCallback progress_callback;
- };
- class BatchRequestConfigurator : public BatchRequestConfiguratorInterface {
- public:
- explicit BatchRequestConfigurator(
- MockDriveServiceForBatchProcessing* service)
- : service(service) {}
- CancelCallbackOnce MultipartUploadNewFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& parent_resource_id,
- const std::string& title,
- const base::FilePath& local_file_path,
- const UploadNewFileOptions& options,
- google_apis::FileResourceCallback callback,
- google_apis::ProgressCallback progress_callback) override {
- UploadFileInfo info;
- info.type = UploadFileInfo::NEW_FILE;
- info.content_type = content_type;
- info.content_length = content_length;
- info.parent_resource_id = parent_resource_id;
- info.title = title;
- info.local_file_path = local_file_path;
- info.callback = std::move(callback);
- info.progress_callback = progress_callback;
- service->files.push_back(std::move(info));
- return CancelCallbackOnce();
- }
- CancelCallbackOnce MultipartUploadExistingFile(
- const std::string& content_type,
- int64_t content_length,
- const std::string& resource_id,
- const base::FilePath& local_file_path,
- const UploadExistingFileOptions& options,
- google_apis::FileResourceCallback callback,
- google_apis::ProgressCallback progress_callback) override {
- UploadFileInfo info;
- info.type = UploadFileInfo::EXISTING_FILE;
- info.content_type = content_type;
- info.content_length = content_length;
- info.resource_id = resource_id;
- info.local_file_path = local_file_path;
- info.callback = std::move(callback);
- info.progress_callback = progress_callback;
- service->files.push_back(std::move(info));
- return CancelCallbackOnce();
- }
- void Commit() override {
- ASSERT_FALSE(service->committed);
- service->committed = true;
- for (auto& file : service->files) {
- SendMultipartUploadResult(HTTP_SUCCESS, file.content_length,
- std::move(file.callback),
- file.progress_callback);
- }
- }
- private:
- raw_ptr<MockDriveServiceForBatchProcessing> service;
- };
- public:
- std::unique_ptr<BatchRequestConfiguratorInterface> StartBatchRequest()
- override {
- committed = false;
- return std::unique_ptr<BatchRequestConfiguratorInterface>(
- new BatchRequestConfigurator(this));
- }
- std::vector<UploadFileInfo> files;
- bool committed;
- };
- TEST_F(DriveUploaderTest, BatchProcessing) {
- // Preapre test file.
- const size_t kTestFileSize = 1024 * 512;
- base::FilePath local_path;
- std::string data;
- ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
- temp_dir_.GetPath(), kTestFileSize, &local_path, &data));
- // Prepare test target.
- MockDriveServiceForBatchProcessing service;
- DriveUploader uploader(&service, base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- struct {
- ApiErrorCode error;
- GURL resume_url;
- std::unique_ptr<FileResource> file;
- UploadCompletionCallback callback() {
- return test_util::CreateCopyResultCallback(&error, &resume_url, &file);
- }
- } results[2];
- uploader.StartBatchProcessing();
- uploader.UploadNewFile("parent_resource_id", local_path, "title",
- kTestMimeType, UploadNewFileOptions(),
- results[0].callback(),
- google_apis::ProgressCallback());
- uploader.UploadExistingFile(
- "resource_id", local_path, kTestMimeType, UploadExistingFileOptions(),
- results[1].callback(), google_apis::ProgressCallback());
- uploader.StopBatchProcessing();
- base::RunLoop().RunUntilIdle();
- ASSERT_EQ(2u, service.files.size());
- EXPECT_TRUE(service.committed);
- EXPECT_EQ(MockDriveServiceForBatchProcessing::UploadFileInfo::NEW_FILE,
- service.files[0].type);
- EXPECT_EQ(kTestMimeType, service.files[0].content_type);
- EXPECT_EQ(kTestFileSize, service.files[0].content_length);
- EXPECT_EQ("parent_resource_id", service.files[0].parent_resource_id);
- EXPECT_EQ("", service.files[0].resource_id);
- EXPECT_EQ("title", service.files[0].title);
- EXPECT_EQ(local_path.value(), service.files[0].local_file_path.value());
- EXPECT_EQ(MockDriveServiceForBatchProcessing::UploadFileInfo::EXISTING_FILE,
- service.files[1].type);
- EXPECT_EQ(kTestMimeType, service.files[1].content_type);
- EXPECT_EQ(kTestFileSize, service.files[1].content_length);
- EXPECT_EQ("", service.files[1].parent_resource_id);
- EXPECT_EQ("resource_id", service.files[1].resource_id);
- EXPECT_EQ("", service.files[1].title);
- EXPECT_EQ(local_path.value(), service.files[1].local_file_path.value());
- EXPECT_EQ(HTTP_SUCCESS, results[0].error);
- EXPECT_TRUE(results[0].resume_url.is_empty());
- EXPECT_TRUE(results[0].file);
- EXPECT_EQ(HTTP_SUCCESS, results[1].error);
- EXPECT_TRUE(results[1].resume_url.is_empty());
- EXPECT_TRUE(results[1].file);
- }
- TEST_F(DriveUploaderTest, BatchProcessingWithError) {
- // Prepare test target.
- MockDriveServiceForBatchProcessing service;
- DriveUploader uploader(&service, base::ThreadTaskRunnerHandle::Get().get(),
- mojo::NullRemote());
- struct {
- ApiErrorCode error;
- GURL resume_url;
- std::unique_ptr<FileResource> file;
- UploadCompletionCallback callback() {
- return test_util::CreateCopyResultCallback(&error, &resume_url, &file);
- }
- } results[2];
- uploader.StartBatchProcessing();
- uploader.UploadNewFile("parent_resource_id",
- base::FilePath(FILE_PATH_LITERAL("/path/non_exists")),
- "title", kTestMimeType, UploadNewFileOptions(),
- results[0].callback(),
- google_apis::ProgressCallback());
- uploader.UploadExistingFile(
- "resource_id", base::FilePath(FILE_PATH_LITERAL("/path/non_exists")),
- kTestMimeType, UploadExistingFileOptions(), results[1].callback(),
- google_apis::ProgressCallback());
- uploader.StopBatchProcessing();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0u, service.files.size());
- EXPECT_TRUE(service.committed);
- EXPECT_EQ(HTTP_NOT_FOUND, results[0].error);
- EXPECT_TRUE(results[0].resume_url.is_empty());
- EXPECT_FALSE(results[0].file);
- EXPECT_EQ(HTTP_NOT_FOUND, results[1].error);
- EXPECT_TRUE(results[1].resume_url.is_empty());
- EXPECT_FALSE(results[1].file);
- }
- } // namespace drive
|