This source file includes following definitions.
- AddObserver
- RemoveObserver
- UpdateObservers
- GetState
- SetState
- default_download_path
- set_default_download_path
- file_thread_
- SetUp
- TearDown
- CreateDownloadItem
- GetPathInDownloadsDirectory
- IsPathInUse
- CallGetReservedPath
- TestReservedPathCallback
- GetLongNamePathInDownloadsDirectory
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/observer_list.h"
#include "base/strings/stringprintf.h"
#include "base/test/test_file_util.h"
#include "chrome/browser/download/download_path_reservation_tracker.h"
#include "chrome/browser/download/download_target_determiner.h"
#include "content/public/test/mock_download_item.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::BrowserThread;
using content::DownloadItem;
using content::MockDownloadItem;
using testing::AnyNumber;
using testing::Return;
using testing::ReturnRef;
using testing::ReturnRefOfCopy;
namespace {
class FakeDownloadItem : public MockDownloadItem {
public:
explicit FakeDownloadItem()
: state_(IN_PROGRESS) {
}
virtual ~FakeDownloadItem() {
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this));
EXPECT_FALSE(observers_.might_have_observers());
}
virtual void AddObserver(Observer* observer) OVERRIDE {
observers_.AddObserver(observer);
}
virtual void RemoveObserver(Observer* observer) OVERRIDE {
observers_.RemoveObserver(observer);
}
virtual void UpdateObservers() OVERRIDE {
FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
}
virtual DownloadState GetState() const OVERRIDE {
return state_;
}
void SetState(DownloadState state) {
state_ = state;
UpdateObservers();
}
private:
DownloadState state_;
ObserverList<Observer> observers_;
};
class DownloadPathReservationTrackerTest : public testing::Test {
public:
DownloadPathReservationTrackerTest();
virtual void SetUp() OVERRIDE;
virtual void TearDown() OVERRIDE;
FakeDownloadItem* CreateDownloadItem(int32 id);
base::FilePath GetPathInDownloadsDirectory(
const base::FilePath::CharType* suffix);
bool IsPathInUse(const base::FilePath& path);
void CallGetReservedPath(
DownloadItem* download_item,
const base::FilePath& target_path,
bool create_directory,
DownloadPathReservationTracker::FilenameConflictAction conflict_action,
base::FilePath* return_path,
bool* return_verified);
const base::FilePath& default_download_path() const {
return default_download_path_;
}
void set_default_download_path(const base::FilePath& path) {
default_download_path_ = path;
}
base::FilePath GetLongNamePathInDownloadsDirectory(
size_t repeat, const base::FilePath::CharType* suffix);
protected:
base::ScopedTempDir test_download_dir_;
base::FilePath default_download_path_;
base::MessageLoopForUI message_loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread file_thread_;
private:
void TestReservedPathCallback(base::FilePath* return_path,
bool* return_verified, bool* did_run_callback,
const base::FilePath& path, bool verified);
};
DownloadPathReservationTrackerTest::DownloadPathReservationTrackerTest()
: ui_thread_(BrowserThread::UI, &message_loop_),
file_thread_(BrowserThread::FILE, &message_loop_) {
}
void DownloadPathReservationTrackerTest::SetUp() {
ASSERT_TRUE(test_download_dir_.CreateUniqueTempDir());
set_default_download_path(test_download_dir_.path());
}
void DownloadPathReservationTrackerTest::TearDown() {
message_loop_.RunUntilIdle();
}
FakeDownloadItem* DownloadPathReservationTrackerTest::CreateDownloadItem(
int32 id) {
FakeDownloadItem* item = new ::testing::StrictMock<FakeDownloadItem>;
EXPECT_CALL(*item, GetId())
.WillRepeatedly(Return(id));
EXPECT_CALL(*item, GetTargetFilePath())
.WillRepeatedly(ReturnRefOfCopy(base::FilePath()));
return item;
}
base::FilePath DownloadPathReservationTrackerTest::GetPathInDownloadsDirectory(
const base::FilePath::CharType* suffix) {
return default_download_path().Append(suffix).NormalizePathSeparators();
}
bool DownloadPathReservationTrackerTest::IsPathInUse(
const base::FilePath& path) {
return DownloadPathReservationTracker::IsPathInUseForTesting(path);
}
void DownloadPathReservationTrackerTest::CallGetReservedPath(
DownloadItem* download_item,
const base::FilePath& target_path,
bool create_directory,
DownloadPathReservationTracker::FilenameConflictAction conflict_action,
base::FilePath* return_path,
bool* return_verified) {
base::WeakPtrFactory<DownloadPathReservationTrackerTest> weak_ptr_factory(
this);
bool did_run_callback = false;
DownloadPathReservationTracker::GetReservedPath(
download_item,
target_path,
default_download_path(),
create_directory,
conflict_action,
base::Bind(&DownloadPathReservationTrackerTest::TestReservedPathCallback,
weak_ptr_factory.GetWeakPtr(), return_path, return_verified,
&did_run_callback));
message_loop_.RunUntilIdle();
EXPECT_TRUE(did_run_callback);
}
void DownloadPathReservationTrackerTest::TestReservedPathCallback(
base::FilePath* return_path, bool* return_verified, bool* did_run_callback,
const base::FilePath& path, bool verified) {
*did_run_callback = true;
*return_path = path;
*return_verified = verified;
}
base::FilePath
DownloadPathReservationTrackerTest::GetLongNamePathInDownloadsDirectory(
size_t repeat, const base::FilePath::CharType* suffix) {
return GetPathInDownloadsDirectory(
(base::FilePath::StringType(repeat, FILE_PATH_LITERAL('a'))
+ suffix).c_str());
}
}
TEST_F(DownloadPathReservationTrackerTest, BasicReservation) {
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
ASSERT_FALSE(IsPathInUse(path));
base::FilePath reserved_path;
bool verified = false;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::OVERWRITE;
bool create_directory = false;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_TRUE(IsPathInUse(path));
EXPECT_TRUE(verified);
EXPECT_EQ(path.value(), reserved_path.value());
item->SetState(DownloadItem::COMPLETE);
item.reset();
message_loop_.RunUntilIdle();
EXPECT_FALSE(IsPathInUse(path));
}
TEST_F(DownloadPathReservationTrackerTest, InterruptedDownload) {
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
ASSERT_FALSE(IsPathInUse(path));
base::FilePath reserved_path;
bool verified = false;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::OVERWRITE;
bool create_directory = false;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_TRUE(IsPathInUse(path));
EXPECT_TRUE(verified);
EXPECT_EQ(path.value(), reserved_path.value());
item->SetState(DownloadItem::INTERRUPTED);
message_loop_.RunUntilIdle();
EXPECT_FALSE(IsPathInUse(path));
}
TEST_F(DownloadPathReservationTrackerTest, CompleteDownload) {
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
ASSERT_FALSE(IsPathInUse(path));
base::FilePath reserved_path;
bool verified = false;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::OVERWRITE;
bool create_directory = false;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_TRUE(IsPathInUse(path));
EXPECT_TRUE(verified);
EXPECT_EQ(path.value(), reserved_path.value());
item->SetState(DownloadItem::COMPLETE);
message_loop_.RunUntilIdle();
EXPECT_FALSE(IsPathInUse(path));
}
TEST_F(DownloadPathReservationTrackerTest, ConflictingFiles) {
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
base::FilePath path1(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")));
ASSERT_EQ(0, base::WriteFile(path, "", 0));
ASSERT_EQ(0,
base::WriteFile(
DownloadTargetDeterminer::GetCrDownloadPath(path1), "", 0));
ASSERT_TRUE(IsPathInUse(path));
base::FilePath reserved_path;
bool verified = false;
bool create_directory = false;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::UNIQUIFY;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_TRUE(IsPathInUse(path));
EXPECT_TRUE(IsPathInUse(reserved_path));
EXPECT_TRUE(verified);
EXPECT_EQ(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")).value(),
reserved_path.value());
item->SetState(DownloadItem::COMPLETE);
item.reset();
message_loop_.RunUntilIdle();
EXPECT_TRUE(IsPathInUse(path));
EXPECT_FALSE(IsPathInUse(reserved_path));
}
TEST_F(DownloadPathReservationTrackerTest, ConflictingReservations) {
scoped_ptr<FakeDownloadItem> item1(CreateDownloadItem(1));
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
base::FilePath uniquified_path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")));
ASSERT_FALSE(IsPathInUse(path));
ASSERT_FALSE(IsPathInUse(uniquified_path));
base::FilePath reserved_path1;
bool verified = false;
bool create_directory = false;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::UNIQUIFY;
CallGetReservedPath(
item1.get(),
path,
create_directory,
conflict_action,
&reserved_path1,
&verified);
EXPECT_TRUE(IsPathInUse(path));
EXPECT_TRUE(verified);
{
scoped_ptr<FakeDownloadItem> item2(CreateDownloadItem(2));
base::FilePath reserved_path2;
CallGetReservedPath(
item2.get(),
path,
create_directory,
conflict_action,
&reserved_path2,
&verified);
EXPECT_TRUE(IsPathInUse(path));
EXPECT_TRUE(IsPathInUse(uniquified_path));
EXPECT_EQ(uniquified_path.value(), reserved_path2.value());
item2->SetState(DownloadItem::COMPLETE);
}
message_loop_.RunUntilIdle();
EXPECT_TRUE(IsPathInUse(path));
EXPECT_FALSE(IsPathInUse(uniquified_path));
{
scoped_ptr<FakeDownloadItem> item2(CreateDownloadItem(2));
base::FilePath reserved_path2;
CallGetReservedPath(
item2.get(),
path,
create_directory,
conflict_action,
&reserved_path2,
&verified);
EXPECT_TRUE(IsPathInUse(path));
EXPECT_TRUE(IsPathInUse(uniquified_path));
EXPECT_EQ(uniquified_path.value(), reserved_path2.value());
item2->SetState(DownloadItem::COMPLETE);
}
message_loop_.RunUntilIdle();
scoped_ptr<FakeDownloadItem> item3(CreateDownloadItem(2));
base::FilePath reserved_path3;
conflict_action = DownloadPathReservationTracker::OVERWRITE;
CallGetReservedPath(
item3.get(),
path,
create_directory,
conflict_action,
&reserved_path3,
&verified);
EXPECT_TRUE(IsPathInUse(path));
EXPECT_FALSE(IsPathInUse(uniquified_path));
EXPECT_EQ(path.value(), reserved_path1.value());
EXPECT_EQ(path.value(), reserved_path3.value());
item1->SetState(DownloadItem::COMPLETE);
item3->SetState(DownloadItem::COMPLETE);
}
TEST_F(DownloadPathReservationTrackerTest, UnresolvedConflicts) {
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
scoped_ptr<FakeDownloadItem> items[
DownloadPathReservationTracker::kMaxUniqueFiles + 1];
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::UNIQUIFY;
bool create_directory = false;
for (int i = 0; i <= DownloadPathReservationTracker::kMaxUniqueFiles; i++) {
base::FilePath reserved_path;
base::FilePath expected_path;
bool verified = false;
if (i > 0) {
expected_path =
path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", i));
} else {
expected_path = path;
}
items[i].reset(CreateDownloadItem(i));
EXPECT_FALSE(IsPathInUse(expected_path));
CallGetReservedPath(
items[i].get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_TRUE(IsPathInUse(expected_path));
EXPECT_EQ(expected_path.value(), reserved_path.value());
EXPECT_TRUE(verified);
}
scoped_ptr<FakeDownloadItem> item(
CreateDownloadItem(DownloadPathReservationTracker::kMaxUniqueFiles + 1));
base::FilePath reserved_path;
bool verified = true;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_FALSE(verified);
EXPECT_EQ(path.value(), reserved_path.value());
item->SetState(DownloadItem::COMPLETE);
for (int i = 0; i <= DownloadPathReservationTracker::kMaxUniqueFiles; i++) {
items[i]->SetState(DownloadItem::COMPLETE);
}
}
TEST_F(DownloadPathReservationTrackerTest, UnwriteableDirectory) {
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
base::FilePath dir(path.DirName());
ASSERT_FALSE(IsPathInUse(path));
{
file_util::PermissionRestorer restorer(dir);
EXPECT_TRUE(file_util::MakeFileUnwritable(dir));
base::FilePath reserved_path;
bool verified = true;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::OVERWRITE;
bool create_directory = false;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_FALSE(verified);
EXPECT_EQ(path.BaseName().value(), reserved_path.BaseName().value());
}
item->SetState(DownloadItem::COMPLETE);
}
TEST_F(DownloadPathReservationTrackerTest, CreateDefaultDownloadPath) {
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo/foo.txt")));
base::FilePath dir(path.DirName());
ASSERT_FALSE(base::DirectoryExists(dir));
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::OVERWRITE;
bool create_directory = false;
{
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath reserved_path;
bool verified = true;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_FALSE(verified);
item->SetState(DownloadItem::COMPLETE);
}
ASSERT_FALSE(IsPathInUse(path));
{
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath reserved_path;
bool verified = true;
set_default_download_path(dir);
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_TRUE(verified);
EXPECT_TRUE(base::DirectoryExists(dir));
item->SetState(DownloadItem::COMPLETE);
}
}
TEST_F(DownloadPathReservationTrackerTest, UpdatesToTargetPath) {
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
ASSERT_FALSE(IsPathInUse(path));
base::FilePath reserved_path;
bool verified = false;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::OVERWRITE;
bool create_directory = false;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_TRUE(IsPathInUse(path));
EXPECT_TRUE(verified);
EXPECT_EQ(path.value(), reserved_path.value());
ASSERT_EQ(base::FilePath::StringType(), item->GetTargetFilePath().value());
item->UpdateObservers();
message_loop_.RunUntilIdle();
EXPECT_TRUE(IsPathInUse(path));
base::FilePath new_target_path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("bar.txt")));
ASSERT_FALSE(IsPathInUse(new_target_path));
EXPECT_CALL(*item, GetTargetFilePath())
.WillRepeatedly(ReturnRef(new_target_path));
item->UpdateObservers();
message_loop_.RunUntilIdle();
EXPECT_FALSE(IsPathInUse(path));
EXPECT_TRUE(IsPathInUse(new_target_path));
item->SetState(DownloadItem::COMPLETE);
item.reset();
message_loop_.RunUntilIdle();
EXPECT_FALSE(IsPathInUse(new_target_path));
}
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
TEST_F(DownloadPathReservationTrackerTest, BasicTruncation) {
int real_max_length =
base::GetMaximumPathComponentLength(default_download_path());
ASSERT_NE(-1, real_max_length);
const size_t max_length = real_max_length - 11;
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath path(GetLongNamePathInDownloadsDirectory(
max_length, FILE_PATH_LITERAL(".txt")));
ASSERT_FALSE(IsPathInUse(path));
base::FilePath reserved_path;
bool verified = false;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::OVERWRITE;
bool create_directory = false;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_TRUE(IsPathInUse(reserved_path));
EXPECT_TRUE(verified);
EXPECT_EQ(max_length, reserved_path.BaseName().value().size());
EXPECT_EQ(path.Extension(), reserved_path.Extension());
item->SetState(DownloadItem::COMPLETE);
}
TEST_F(DownloadPathReservationTrackerTest, TruncationConflict) {
int real_max_length =
base::GetMaximumPathComponentLength(default_download_path());
ASSERT_NE(-1, real_max_length);
const size_t max_length = real_max_length - 11;
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath path(GetLongNamePathInDownloadsDirectory(
max_length, FILE_PATH_LITERAL(".txt")));
base::FilePath path0(GetLongNamePathInDownloadsDirectory(
max_length - 4, FILE_PATH_LITERAL(".txt")));
base::FilePath path1(GetLongNamePathInDownloadsDirectory(
max_length - 8, FILE_PATH_LITERAL(" (1).txt")));
base::FilePath path2(GetLongNamePathInDownloadsDirectory(
max_length - 8, FILE_PATH_LITERAL(" (2).txt")));
ASSERT_FALSE(IsPathInUse(path));
ASSERT_EQ(0, base::WriteFile(path0, "", 0));
ASSERT_EQ(0, base::WriteFile(path1, "", 0));
base::FilePath reserved_path;
bool verified = false;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::UNIQUIFY;
bool create_directory = false;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_TRUE(IsPathInUse(reserved_path));
EXPECT_TRUE(verified);
EXPECT_EQ(path2, reserved_path);
item->SetState(DownloadItem::COMPLETE);
}
TEST_F(DownloadPathReservationTrackerTest, TruncationFail) {
int real_max_length =
base::GetMaximumPathComponentLength(default_download_path());
ASSERT_NE(-1, real_max_length);
const size_t max_length = real_max_length - 11;
scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
base::FilePath path(GetPathInDownloadsDirectory(
(FILE_PATH_LITERAL("a.") +
base::FilePath::StringType(max_length, 'b')).c_str()));
ASSERT_FALSE(IsPathInUse(path));
base::FilePath reserved_path;
bool verified = false;
DownloadPathReservationTracker::FilenameConflictAction conflict_action =
DownloadPathReservationTracker::OVERWRITE;
bool create_directory = false;
CallGetReservedPath(
item.get(),
path,
create_directory,
conflict_action,
&reserved_path,
&verified);
EXPECT_FALSE(verified);
item->SetState(DownloadItem::COMPLETE);
}
#endif