blob: 813a6e07b4e23801911885f3949d527df2b2316d [file] [log] [blame]
// Copyright (c) 2013 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/chromeos/drive/download_handler.h"
#include <stdint.h>
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "chrome/browser/chromeos/drive/file_system_util.h"
#include "chrome/test/base/testing_profile.h"
#include "components/drive/chromeos/dummy_file_system.h"
#include "components/drive/file_system_core_util.h"
#include "content/public/test/mock_download_item.h"
#include "content/public/test/mock_download_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "google_apis/drive/test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace drive {
namespace {
// Test file system for verifying the behavior of DownloadHandler, by simulating
// various responses from FileSystem.
class DownloadHandlerTestFileSystem : public DummyFileSystem {
public:
DownloadHandlerTestFileSystem() : error_(FILE_ERROR_FAILED) {}
void set_error(FileError error) { error_ = error; }
// FileSystemInterface overrides.
void GetResourceEntry(const base::FilePath& file_path,
const GetResourceEntryCallback& callback) override {
callback.Run(error_, std::unique_ptr<ResourceEntry>(error_ == FILE_ERROR_OK
? new ResourceEntry
: NULL));
}
void CreateDirectory(const base::FilePath& directory_path,
bool is_exclusive,
bool is_recursive,
const FileOperationCallback& callback) override {
callback.Run(error_);
}
void FreeDiskSpaceIfNeededFor(
int64_t num_bytes,
const FreeDiskSpaceCallback& callback) override {
free_disk_space_if_needed_for_num_bytes_.push_back(num_bytes);
callback.Run(true);
}
std::vector<int64_t> free_disk_space_if_needed_for_num_bytes_;
private:
FileError error_;
};
class DownloadHandlerTestDownloadManager : public content::MockDownloadManager {
public:
void GetAllDownloads(
content::DownloadManager::DownloadVector* downloads) override {
for (auto* test_download : test_downloads_) {
downloads->push_back(test_download);
}
}
content::DownloadManager::DownloadVector test_downloads_;
};
class DownloadHandlerTestDownloadItem : public content::MockDownloadItem {
public:
bool IsDone() const override { return is_done_; }
int64_t GetTotalBytes() const override { return total_bytes_; }
int64_t GetReceivedBytes() const override { return received_bytes_; }
bool is_done_ = false;
int64_t total_bytes_ = 0;
int64_t received_bytes_ = 0;
};
} // namespace
class DownloadHandlerTest : public testing::Test {
public:
DownloadHandlerTest()
: download_manager_(new DownloadHandlerTestDownloadManager) {}
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
// Set expectations for download item.
EXPECT_CALL(download_item_, GetState())
.WillRepeatedly(testing::Return(content::DownloadItem::IN_PROGRESS));
download_handler_.reset(new DownloadHandler(&test_file_system_));
download_handler_->Initialize(download_manager_.get(), temp_dir_.GetPath());
download_handler_->SetFreeDiskSpaceDelayForTesting(
base::TimeDelta::FromMilliseconds(0));
}
protected:
base::ScopedTempDir temp_dir_;
content::TestBrowserThreadBundle thread_bundle_;
TestingProfile profile_;
std::unique_ptr<DownloadHandlerTestDownloadManager> download_manager_;
std::unique_ptr<DownloadHandlerTestDownloadManager>
incognito_download_manager_;
DownloadHandlerTestFileSystem test_file_system_;
std::unique_ptr<DownloadHandler> download_handler_;
content::MockDownloadItem download_item_;
};
TEST_F(DownloadHandlerTest, SubstituteDriveDownloadPathNonDrivePath) {
const base::FilePath non_drive_path(FILE_PATH_LITERAL("/foo/bar"));
ASSERT_FALSE(util::IsUnderDriveMountPoint(non_drive_path));
// Call SubstituteDriveDownloadPath()
base::FilePath substituted_path;
download_handler_->SubstituteDriveDownloadPath(
non_drive_path,
&download_item_,
google_apis::test_util::CreateCopyResultCallback(&substituted_path));
content::RunAllTasksUntilIdle();
// Check the result.
EXPECT_EQ(non_drive_path, substituted_path);
EXPECT_FALSE(download_handler_->IsDriveDownload(&download_item_));
}
TEST_F(DownloadHandlerTest, SubstituteDriveDownloadPath) {
const base::FilePath drive_path =
util::GetDriveMountPointPath(&profile_).AppendASCII("test.dat");
// Test the case that the download target directory already exists.
test_file_system_.set_error(FILE_ERROR_OK);
// Call SubstituteDriveDownloadPath()
base::FilePath substituted_path;
download_handler_->SubstituteDriveDownloadPath(
drive_path,
&download_item_,
google_apis::test_util::CreateCopyResultCallback(&substituted_path));
content::RunAllTasksUntilIdle();
// Check the result.
EXPECT_TRUE(temp_dir_.GetPath().IsParent(substituted_path));
ASSERT_TRUE(download_handler_->IsDriveDownload(&download_item_));
EXPECT_EQ(drive_path, download_handler_->GetTargetPath(&download_item_));
}
TEST_F(DownloadHandlerTest, SubstituteDriveDownloadPathGetEntryFailure) {
const base::FilePath drive_path =
util::GetDriveMountPointPath(&profile_).AppendASCII("test.dat");
// Test the case that access to the download target directory failed for some
// reason.
test_file_system_.set_error(FILE_ERROR_FAILED);
// Call SubstituteDriveDownloadPath()
base::FilePath substituted_path;
download_handler_->SubstituteDriveDownloadPath(
drive_path,
&download_item_,
google_apis::test_util::CreateCopyResultCallback(&substituted_path));
content::RunAllTasksUntilIdle();
// Check the result.
EXPECT_TRUE(substituted_path.empty());
}
// content::SavePackage calls SubstituteDriveDownloadPath before creating
// DownloadItem.
TEST_F(DownloadHandlerTest, SubstituteDriveDownloadPathForSavePackage) {
const base::FilePath drive_path =
util::GetDriveMountPointPath(&profile_).AppendASCII("test.dat");
test_file_system_.set_error(FILE_ERROR_OK);
// Call SubstituteDriveDownloadPath()
base::FilePath substituted_path;
download_handler_->SubstituteDriveDownloadPath(
drive_path,
NULL, // DownloadItem is not available at this moment.
google_apis::test_util::CreateCopyResultCallback(&substituted_path));
content::RunAllTasksUntilIdle();
// Check the result of SubstituteDriveDownloadPath().
EXPECT_TRUE(temp_dir_.GetPath().IsParent(substituted_path));
// |download_item_| is not a drive download yet.
EXPECT_FALSE(download_handler_->IsDriveDownload(&download_item_));
// Call SetDownloadParams().
download_handler_->SetDownloadParams(drive_path, &download_item_);
// |download_item_| is a drive download now.
ASSERT_TRUE(download_handler_->IsDriveDownload(&download_item_));
EXPECT_EQ(drive_path, download_handler_->GetTargetPath(&download_item_));
}
TEST_F(DownloadHandlerTest, CheckForFileExistence) {
const base::FilePath drive_path =
util::GetDriveMountPointPath(&profile_).AppendASCII("test.dat");
// Make |download_item_| a drive download.
download_handler_->SetDownloadParams(drive_path, &download_item_);
ASSERT_TRUE(download_handler_->IsDriveDownload(&download_item_));
EXPECT_EQ(drive_path, download_handler_->GetTargetPath(&download_item_));
// Test for the case when the path exists.
test_file_system_.set_error(FILE_ERROR_OK);
// Call CheckForFileExistence.
bool file_exists = false;
download_handler_->CheckForFileExistence(
&download_item_,
google_apis::test_util::CreateCopyResultCallback(&file_exists));
content::RunAllTasksUntilIdle();
// Check the result.
EXPECT_TRUE(file_exists);
// Test for the case when the path does not exist.
test_file_system_.set_error(FILE_ERROR_NOT_FOUND);
// Call CheckForFileExistence again.
download_handler_->CheckForFileExistence(
&download_item_,
google_apis::test_util::CreateCopyResultCallback(&file_exists));
content::RunAllTasksUntilIdle();
// Check the result.
EXPECT_FALSE(file_exists);
}
TEST_F(DownloadHandlerTest, FreeDiskSpace) {
// Add a download item to download manager.
DownloadHandlerTestDownloadItem download_item_a;
download_item_a.is_done_ = false;
download_item_a.total_bytes_ = 100;
download_item_a.received_bytes_ = 10;
download_manager_->test_downloads_.push_back(&download_item_a);
// Free disk space for download_item_a.
download_handler_->FreeDiskSpaceIfNeededImmediately();
ASSERT_EQ(1u,
test_file_system_.free_disk_space_if_needed_for_num_bytes_.size());
ASSERT_EQ(download_item_a.total_bytes_ - download_item_a.received_bytes_,
test_file_system_.free_disk_space_if_needed_for_num_bytes_[0]);
// Confirm that FreeDiskSpaceIfNeeded is rate limited by calling it twice.
download_handler_->FreeDiskSpaceIfNeeded();
download_handler_->FreeDiskSpaceIfNeeded();
ASSERT_EQ(1u,
test_file_system_.free_disk_space_if_needed_for_num_bytes_.size());
download_item_a.received_bytes_ = 20;
base::RunLoop().RunUntilIdle();
ASSERT_EQ(2u,
test_file_system_.free_disk_space_if_needed_for_num_bytes_.size());
ASSERT_EQ(download_item_a.total_bytes_ - download_item_a.received_bytes_,
test_file_system_.free_disk_space_if_needed_for_num_bytes_[1]);
// Observe incognito download manager and add another download item.
// FreeDiskSpace should be called with considering both download items.
incognito_download_manager_.reset(new DownloadHandlerTestDownloadManager);
download_handler_->ObserveIncognitoDownloadManager(
incognito_download_manager_.get());
DownloadHandlerTestDownloadItem download_item_b;
download_item_b.is_done_ = false;
download_item_b.total_bytes_ = 200;
download_item_b.received_bytes_ = 0;
incognito_download_manager_->test_downloads_.push_back(&download_item_b);
download_item_a.received_bytes_ = 30;
download_handler_->FreeDiskSpaceIfNeededImmediately();
ASSERT_EQ(3u,
test_file_system_.free_disk_space_if_needed_for_num_bytes_.size());
ASSERT_EQ(download_item_a.total_bytes_ - download_item_a.received_bytes_ +
download_item_b.total_bytes_ - download_item_b.received_bytes_,
test_file_system_.free_disk_space_if_needed_for_num_bytes_[2]);
// Free disk space after making both items completed. In this case
// FreeDiskSpace should be called with 0 byte to keep
// drive::internal::kMinFreeSpaceInBytes.
download_item_a.is_done_ = true;
download_item_b.is_done_ = true;
download_handler_->FreeDiskSpaceIfNeeded();
base::RunLoop().RunUntilIdle();
ASSERT_EQ(4u,
test_file_system_.free_disk_space_if_needed_for_num_bytes_.size());
ASSERT_EQ(0, test_file_system_.free_disk_space_if_needed_for_num_bytes_[3]);
}
TEST_F(DownloadHandlerTest, CalculateRequestSpace) {
DownloadHandlerTestDownloadItem download_item_a;
download_item_a.is_done_ = false;
download_item_a.total_bytes_ = 100;
download_item_a.received_bytes_ = 0;
DownloadHandlerTestDownloadItem download_item_b;
download_item_b.is_done_ = false;
download_item_b.total_bytes_ = 200;
download_item_b.received_bytes_ = 10;
content::DownloadManager::DownloadVector downloads;
downloads.push_back(&download_item_a);
downloads.push_back(&download_item_b);
ASSERT_EQ(download_item_a.total_bytes_ - download_item_a.received_bytes_ +
download_item_b.total_bytes_ - download_item_b.received_bytes_,
download_handler_->CalculateRequestSpace(downloads));
download_item_a.received_bytes_ = 10;
ASSERT_EQ(download_item_a.total_bytes_ - download_item_a.received_bytes_ +
download_item_b.total_bytes_ - download_item_b.received_bytes_,
download_handler_->CalculateRequestSpace(downloads));
download_item_b.is_done_ = true;
// Since download_item_b is completed, it shouldn't be counted.
ASSERT_EQ(download_item_a.total_bytes_ - download_item_a.received_bytes_,
download_handler_->CalculateRequestSpace(downloads));
// Add unknown size download item.
DownloadHandlerTestDownloadItem download_item_c;
download_item_c.is_done_ = false;
download_item_c.total_bytes_ = 0;
downloads.push_back(&download_item_c);
// Unknown size download should be counted as 0 byte.
ASSERT_EQ(download_item_a.total_bytes_ - download_item_a.received_bytes_,
download_handler_->CalculateRequestSpace(downloads));
// Add another unknown size download item.
DownloadHandlerTestDownloadItem download_item_d;
download_item_d.is_done_ = false;
download_item_d.total_bytes_ = 0;
downloads.push_back(&download_item_d);
// Unknown size downloads should be counted as 0 byte.
ASSERT_EQ(download_item_a.total_bytes_ - download_item_a.received_bytes_,
download_handler_->CalculateRequestSpace(downloads));
}
} // namespace drive