diff options
author | satorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-19 05:06:00 +0000 |
---|---|---|
committer | satorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-19 05:06:00 +0000 |
commit | cd8b0793d16921957a01c64000d314bdef082c84 (patch) | |
tree | a80dde37e23d6179ded5e87ef1ac5848a08a69a1 /chrome/browser/drive/drive_uploader_unittest.cc | |
parent | ec8e8b03f347e11bc22282300dcd12914dc913bc (diff) | |
download | chromium_src-cd8b0793d16921957a01c64000d314bdef082c84.zip chromium_src-cd8b0793d16921957a01c64000d314bdef082c84.tar.gz chromium_src-cd8b0793d16921957a01c64000d314bdef082c84.tar.bz2 |
drive: Move DriveUploader to c/b/drive
This shouldn't be in 'google_apis' where only low level
network code should be placed.
BUG=244325
TEST=none
R=kinaba@chromium.org, kinuko@chromium.org
Review URL: https://codereview.chromium.org/17395008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207182 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/drive/drive_uploader_unittest.cc')
-rw-r--r-- | chrome/browser/drive/drive_uploader_unittest.cc | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/chrome/browser/drive/drive_uploader_unittest.cc b/chrome/browser/drive/drive_uploader_unittest.cc new file mode 100644 index 0000000..363e5af --- /dev/null +++ b/chrome/browser/drive/drive_uploader_unittest.cc @@ -0,0 +1,545 @@ +// 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 "chrome/browser/drive/drive_uploader.h" + +#include <algorithm> +#include <cstdlib> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/files/scoped_temp_dir.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/values.h" +#include "chrome/browser/drive/dummy_drive_service.h" +#include "chrome/browser/google_apis/test_util.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace google_apis { + +namespace { + +const char kTestDummyId[] = "file:dummy_id"; +const char kTestDocumentTitle[] = "Hello world"; +const char kTestDrivePath[] = "drive/dummy.txt"; +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 kUploadChunkSize = 512 * 1024; +const char kTestETag[] = "test_etag"; + +// 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 expected_content_length) + : expected_upload_file_(expected_upload_file), + expected_content_length_(expected_content_length), + received_bytes_(0), + resume_upload_call_count_(0) {} + + int64 received_bytes() const { return received_bytes_; } + void set_received_bytes(int64 received_bytes) { + received_bytes_ = received_bytes; + } + + int64 resume_upload_call_count() const { return resume_upload_call_count_; } + + private: + // DriveServiceInterface overrides. + // Handles a request for obtaining an upload location URL. + virtual CancelCallback InitiateUploadNewFile( + const base::FilePath& drive_file_path, + const std::string& content_type, + int64 content_length, + const std::string& parent_resource_id, + const std::string& title, + const 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::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadNewFileURL))); + return CancelCallback(); + } + + virtual CancelCallback InitiateUploadExistingFile( + const base::FilePath& drive_file_path, + const std::string& content_type, + int64 content_length, + const std::string& resource_id, + const std::string& etag, + const InitiateUploadCallback& callback) OVERRIDE { + EXPECT_EQ(kTestMimeType, content_type); + EXPECT_EQ(expected_content_length_, content_length); + EXPECT_EQ(kTestInitiateUploadResourceId, resource_id); + + if (!etag.empty() && etag != kTestETag) { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, HTTP_PRECONDITION, GURL())); + return CancelCallback(); + } + + // Calls back the upload URL for subsequent ResumeUpload requests. + // InitiateUpload is an asynchronous function, so don't callback directly. + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadExistingFileURL))); + return CancelCallback(); + } + + // Handles a request for uploading a chunk of bytes. + virtual CancelCallback ResumeUpload( + const base::FilePath& drive_file_path, + 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) 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 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(GURL(kTestUploadNewFileURL) == upload_location || + GURL(kTestUploadExistingFileURL) == upload_location); + + // 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 chunk_size = end_position - start_position; + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(progress_callback, chunk_size, chunk_size)); + } + + SendUploadRangeResponse(upload_location, callback); + return CancelCallback(); + } + + // Handles a request to fetch the current upload status. + virtual CancelCallback GetUploadStatus( + const base::FilePath& drive_file_path, + const GURL& upload_location, + int64 content_length, + const UploadRangeCallback& callback) OVERRIDE { + EXPECT_EQ(expected_content_length_, content_length); + // The upload URL returned by InitiateUpload() must be used. + EXPECT_TRUE(GURL(kTestUploadNewFileURL) == upload_location || + GURL(kTestUploadExistingFileURL) == upload_location); + + SendUploadRangeResponse(upload_location, callback); + return CancelCallback(); + } + + // Runs |callback| with the current upload status. + void SendUploadRangeResponse(const GURL& upload_location, + const UploadRangeCallback& callback) { + // Callback with response. + UploadRangeResponse response; + scoped_ptr<ResourceEntry> entry; + if (received_bytes_ == expected_content_length_) { + GDataErrorCode response_code = + upload_location == GURL(kTestUploadNewFileURL) ? + HTTP_CREATED : HTTP_SUCCESS; + response = UploadRangeResponse(response_code, -1, -1); + + base::DictionaryValue dict; + dict.Set("id.$t", new base::StringValue(kTestDummyId)); + entry = ResourceEntry::CreateFrom(dict); + } else { + response = UploadRangeResponse( + HTTP_RESUME_INCOMPLETE, 0, received_bytes_); + } + // ResumeUpload is an asynchronous function, so don't callback directly. + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, response, base::Passed(&entry))); + } + + const base::FilePath expected_upload_file_; + const int64 expected_content_length_; + int64 received_bytes_; + int64 resume_upload_call_count_; +}; + +// Mock DriveService that returns a failure at InitiateUpload(). +class MockDriveServiceNoConnectionAtInitiate : public DummyDriveService { + // Returns error. + virtual CancelCallback InitiateUploadNewFile( + const base::FilePath& drive_file_path, + const std::string& content_type, + int64 content_length, + const std::string& parent_resource_id, + const std::string& title, + const InitiateUploadCallback& callback) OVERRIDE { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, GDATA_NO_CONNECTION, GURL())); + return CancelCallback(); + } + + virtual CancelCallback InitiateUploadExistingFile( + const base::FilePath& drive_file_path, + const std::string& content_type, + int64 content_length, + const std::string& resource_id, + const std::string& etag, + const InitiateUploadCallback& callback) OVERRIDE { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, GDATA_NO_CONNECTION, GURL())); + return CancelCallback(); + } + + // Should not be used. + virtual CancelCallback ResumeUpload( + const base::FilePath& drive_file_path, + 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) OVERRIDE { + NOTREACHED(); + return CancelCallback(); + } +}; + +// Mock DriveService that returns a failure at ResumeUpload(). +class MockDriveServiceNoConnectionAtResume : public DummyDriveService { + // Succeeds and returns an upload location URL. + virtual CancelCallback InitiateUploadNewFile( + const base::FilePath& drive_file_path, + const std::string& content_type, + int64 content_length, + const std::string& parent_resource_id, + const std::string& title, + const InitiateUploadCallback& callback) OVERRIDE { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadNewFileURL))); + return CancelCallback(); + } + + virtual CancelCallback InitiateUploadExistingFile( + const base::FilePath& drive_file_path, + const std::string& content_type, + int64 content_length, + const std::string& resource_id, + const std::string& etag, + const InitiateUploadCallback& callback) OVERRIDE { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadExistingFileURL))); + return CancelCallback(); + } + + // Returns error. + virtual CancelCallback ResumeUpload( + const base::FilePath& drive_file_path, + 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) OVERRIDE { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback, + UploadRangeResponse(GDATA_NO_CONNECTION, -1, -1), + base::Passed(scoped_ptr<ResourceEntry>()))); + return CancelCallback(); + } +}; + +class DriveUploaderTest : public testing::Test { + public: + virtual void SetUp() OVERRIDE { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + } + + virtual void TearDown() OVERRIDE { + ASSERT_TRUE(temp_dir_.Delete()); + } + + protected: + content::TestBrowserThreadBundle thread_bundle_; + base::ScopedTempDir temp_dir_; +}; + +} // namespace + +TEST_F(DriveUploaderTest, UploadExisting0KB) { + base::FilePath local_path; + std::string data; + ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize( + temp_dir_.path(), 0, &local_path, &data)); + + GDataErrorCode error = GDATA_OTHER_ERROR; + GURL upload_location; + scoped_ptr<ResourceEntry> resource_entry; + + MockDriveServiceWithUploadExpectation mock_service(local_path, data.size()); + DriveUploader uploader(&mock_service); + std::vector<test_util::ProgressInfo> upload_progress_values; + uploader.UploadExistingFile( + kTestInitiateUploadResourceId, + base::FilePath::FromUTF8Unsafe(kTestDrivePath), + local_path, + kTestMimeType, + std::string(), // etag + test_util::CreateCopyResultCallback( + &error, &upload_location, &resource_entry), + base::Bind(&test_util::AppendProgressCallbackResult, + &upload_progress_values)); + test_util::RunBlockingPoolTask(); + + EXPECT_EQ(1, mock_service.resume_upload_call_count()); + EXPECT_EQ(0, mock_service.received_bytes()); + EXPECT_EQ(HTTP_SUCCESS, error); + EXPECT_TRUE(upload_location.is_empty()); + ASSERT_TRUE(resource_entry); + EXPECT_EQ(kTestDummyId, resource_entry->id()); + 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_.path(), 512 * 1024, &local_path, &data)); + + GDataErrorCode error = GDATA_OTHER_ERROR; + GURL upload_location; + scoped_ptr<ResourceEntry> resource_entry; + + MockDriveServiceWithUploadExpectation mock_service(local_path, data.size()); + DriveUploader uploader(&mock_service); + std::vector<test_util::ProgressInfo> upload_progress_values; + uploader.UploadExistingFile( + kTestInitiateUploadResourceId, + base::FilePath::FromUTF8Unsafe(kTestDrivePath), + local_path, + kTestMimeType, + std::string(), // etag + test_util::CreateCopyResultCallback( + &error, &upload_location, &resource_entry), + base::Bind(&test_util::AppendProgressCallbackResult, + &upload_progress_values)); + test_util::RunBlockingPoolTask(); + + // 512KB upload should not be split into multiple chunks. + EXPECT_EQ(1, mock_service.resume_upload_call_count()); + EXPECT_EQ(512 * 1024, mock_service.received_bytes()); + EXPECT_EQ(HTTP_SUCCESS, error); + EXPECT_TRUE(upload_location.is_empty()); + ASSERT_TRUE(resource_entry); + EXPECT_EQ(kTestDummyId, resource_entry->id()); + ASSERT_EQ(1U, upload_progress_values.size()); + EXPECT_EQ(test_util::ProgressInfo(512 * 1024, 512 * 1024), + upload_progress_values[0]); +} + +TEST_F(DriveUploaderTest, InitiateUploadFail) { + base::FilePath local_path; + std::string data; + ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize( + temp_dir_.path(), 512 * 1024, &local_path, &data)); + + GDataErrorCode error = HTTP_SUCCESS; + GURL upload_location; + scoped_ptr<ResourceEntry> resource_entry; + + MockDriveServiceNoConnectionAtInitiate mock_service; + DriveUploader uploader(&mock_service); + uploader.UploadExistingFile( + kTestInitiateUploadResourceId, + base::FilePath::FromUTF8Unsafe(kTestDrivePath), + local_path, + kTestMimeType, + std::string(), // etag + test_util::CreateCopyResultCallback( + &error, &upload_location, &resource_entry), + google_apis::ProgressCallback()); + test_util::RunBlockingPoolTask(); + + EXPECT_EQ(GDATA_NO_CONNECTION, error); + EXPECT_TRUE(upload_location.is_empty()); + EXPECT_FALSE(resource_entry); +} + +TEST_F(DriveUploaderTest, InitiateUploadNoConflict) { + base::FilePath local_path; + std::string data; + ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize( + temp_dir_.path(), 512 * 1024, &local_path, &data)); + + GDataErrorCode error = GDATA_OTHER_ERROR; + GURL upload_location; + scoped_ptr<ResourceEntry> resource_entry; + + MockDriveServiceWithUploadExpectation mock_service(local_path, data.size()); + DriveUploader uploader(&mock_service); + uploader.UploadExistingFile( + kTestInitiateUploadResourceId, + base::FilePath::FromUTF8Unsafe(kTestDrivePath), + local_path, + kTestMimeType, + kTestETag, + test_util::CreateCopyResultCallback( + &error, &upload_location, &resource_entry), + google_apis::ProgressCallback()); + test_util::RunBlockingPoolTask(); + + EXPECT_EQ(HTTP_SUCCESS, 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_.path(), 512 * 1024, &local_path, &data)); + const std::string kDestinationETag("destination_etag"); + + GDataErrorCode error = GDATA_OTHER_ERROR; + GURL upload_location; + scoped_ptr<ResourceEntry> resource_entry; + + MockDriveServiceWithUploadExpectation mock_service(local_path, data.size()); + DriveUploader uploader(&mock_service); + uploader.UploadExistingFile( + kTestInitiateUploadResourceId, + base::FilePath::FromUTF8Unsafe(kTestDrivePath), + local_path, + kTestMimeType, + kDestinationETag, + test_util::CreateCopyResultCallback( + &error, &upload_location, &resource_entry), + google_apis::ProgressCallback()); + test_util::RunBlockingPoolTask(); + + 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_.path(), 512 * 1024, &local_path, &data)); + + GDataErrorCode error = HTTP_SUCCESS; + GURL upload_location; + scoped_ptr<ResourceEntry> resource_entry; + + MockDriveServiceNoConnectionAtResume mock_service; + DriveUploader uploader(&mock_service); + uploader.UploadExistingFile( + kTestInitiateUploadResourceId, + base::FilePath::FromUTF8Unsafe(kTestDrivePath), + local_path, + kTestMimeType, + std::string(), // etag + test_util::CreateCopyResultCallback( + &error, &upload_location, &resource_entry), + google_apis::ProgressCallback()); + test_util::RunBlockingPoolTask(); + + EXPECT_EQ(GDATA_NO_CONNECTION, error); + EXPECT_EQ(GURL(kTestUploadExistingFileURL), upload_location); +} + +TEST_F(DriveUploaderTest, NonExistingSourceFile) { + GDataErrorCode error = GDATA_OTHER_ERROR; + GURL upload_location; + scoped_ptr<ResourceEntry> resource_entry; + + DriveUploader uploader(NULL); // NULL, the service won't be used. + uploader.UploadExistingFile( + kTestInitiateUploadResourceId, + base::FilePath::FromUTF8Unsafe(kTestDrivePath), + temp_dir_.path().AppendASCII("_this_path_should_not_exist_"), + kTestMimeType, + std::string(), // etag + test_util::CreateCopyResultCallback( + &error, &upload_location, &resource_entry), + google_apis::ProgressCallback()); + test_util::RunBlockingPoolTask(); + + // 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_.path(), 1024 * 1024, &local_path, &data)); + + GDataErrorCode error = GDATA_OTHER_ERROR; + GURL upload_location; + scoped_ptr<ResourceEntry> resource_entry; + + MockDriveServiceWithUploadExpectation mock_service(local_path, data.size()); + DriveUploader uploader(&mock_service); + // 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), + base::FilePath::FromUTF8Unsafe(kTestDrivePath), + local_path, + kTestMimeType, + test_util::CreateCopyResultCallback( + &error, &upload_location, &resource_entry), + base::Bind(&test_util::AppendProgressCallbackResult, + &upload_progress_values)); + test_util::RunBlockingPoolTask(); + + 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(resource_entry); + EXPECT_EQ(kTestDummyId, resource_entry->id()); + ASSERT_EQ(1U, upload_progress_values.size()); + EXPECT_EQ(test_util::ProgressInfo(1024 * 1024, 1024 * 1024), + upload_progress_values[0]); +} + +} // namespace google_apis |