blob: cace34e52df40e03863d5eefb2637500ed7bda4f [file] [log] [blame]
// Copyright 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 <vector>
#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
#include "chrome/browser/media_galleries/fileapi/picasa_data_provider.h"
#include "chrome/common/media_galleries/picasa_test_util.h"
#include "chrome/common/media_galleries/picasa_types.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/test_browser_thread.h"
namespace picasa {
namespace {
void VerifyTestAlbumTable(PicasaDataProvider* data_provider,
base::FilePath test_folder_1_path,
base::FilePath test_folder_2_path) {
scoped_ptr<AlbumMap> folders = data_provider->GetFolders();
ASSERT_TRUE(folders.get());
EXPECT_EQ(2u, folders->size());
AlbumMap::const_iterator folder_1 = folders->find(
test_folder_1_path.BaseName().AsUTF8Unsafe() + " 1899-12-30");
EXPECT_NE(folders->end(), folder_1);
EXPECT_EQ(test_folder_1_path.BaseName().AsUTF8Unsafe(),
folder_1->second.name);
EXPECT_EQ(test_folder_1_path, folder_1->second.path);
EXPECT_EQ("uid1", folder_1->second.uid);
AlbumMap::const_iterator folder_2 = folders->find(
test_folder_2_path.BaseName().AsUTF8Unsafe() + " 1899-12-30");
EXPECT_NE(folders->end(), folder_2);
EXPECT_EQ(test_folder_2_path.BaseName().AsUTF8Unsafe(),
folder_2->second.name);
EXPECT_EQ(test_folder_2_path, folder_2->second.path);
EXPECT_EQ("uid4", folder_2->second.uid);
scoped_ptr<AlbumMap> albums = data_provider->GetAlbums();
ASSERT_TRUE(albums.get());
EXPECT_EQ(2u, albums->size());
AlbumMap::const_iterator album_1 = albums->find("Album 1 Name 1899-12-30");
EXPECT_NE(albums->end(), album_1);
EXPECT_EQ("Album 1 Name", album_1->second.name);
EXPECT_EQ(base::FilePath(), album_1->second.path);
EXPECT_EQ("uid3", album_1->second.uid);
AlbumMap::const_iterator album_2 = albums->find("Album 2 Name 1899-12-30");
EXPECT_NE(albums->end(), album_2);
EXPECT_EQ("Album 2 Name", album_2->second.name);
EXPECT_EQ(base::FilePath(), album_2->second.path);
EXPECT_EQ("uid5", album_2->second.uid);
}
void VerifyTestAlbumsImagesIndex(PicasaDataProvider* data_provider,
base::FilePath test_folder_1_path,
base::FilePath test_folder_2_path) {
base::File::Error error;
scoped_ptr<AlbumImages> album_1_images =
data_provider->FindAlbumImages("uid3", &error);
ASSERT_TRUE(album_1_images);
EXPECT_EQ(base::File::FILE_OK, error);
EXPECT_EQ(2u, album_1_images->size());
EXPECT_NE(album_1_images->end(), album_1_images->find("InBoth.jpg"));
EXPECT_EQ(test_folder_1_path.AppendASCII("InBoth.jpg"),
(*album_1_images)["InBoth.jpg"]);
EXPECT_NE(album_1_images->end(),
album_1_images->find("InFirstAlbumOnly.jpg"));
EXPECT_EQ(test_folder_2_path.AppendASCII("InFirstAlbumOnly.jpg"),
(*album_1_images)["InFirstAlbumOnly.jpg"]);
scoped_ptr<AlbumImages> album_2_images =
data_provider->FindAlbumImages("uid5", &error);
ASSERT_TRUE(album_2_images);
EXPECT_EQ(base::File::FILE_OK, error);
EXPECT_EQ(2u, album_2_images->size());
EXPECT_NE(album_2_images->end(), album_2_images->find("InBoth.jpg"));
EXPECT_EQ(test_folder_1_path.AppendASCII("InBoth.jpg"),
(*album_2_images)["InBoth.jpg"]);
EXPECT_NE(album_2_images->end(),
album_2_images->find("InSecondAlbumOnly.jpg"));
EXPECT_EQ(test_folder_1_path.AppendASCII("InSecondAlbumOnly.jpg"),
(*album_2_images)["InSecondAlbumOnly.jpg"]);
}
} // namespace
class TestPicasaDataProvider : public PicasaDataProvider {
public:
explicit TestPicasaDataProvider(const base::FilePath& database_path)
: PicasaDataProvider(database_path),
file_watch_request_returned_(false) {
}
virtual ~TestPicasaDataProvider() {}
// |ready_callback| called with true if and when the file watch is started
// successfully. If the file watch fails, it's called with false.
void EnsureFileWatchStartedForTesting(const ReadyCallback& ready_callback) {
if (!file_watch_request_returned_) {
file_watch_started_callbacks_.push_back(ready_callback);
return;
}
ready_callback.Run(temp_dir_watcher_.get() != NULL);
}
// Simulates the actual writing process of moving all the database files
// from the temporary directory to the database directory in a loop.
void MoveTempFilesToDatabase() {
DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
base::FileEnumerator file_enumerator(
database_path_.DirName().AppendASCII(kPicasaTempDirName),
false /* recursive */,
base::FileEnumerator::FILES);
for (base::FilePath src_path = file_enumerator.Next(); !src_path.empty();
src_path = file_enumerator.Next()) {
ASSERT_TRUE(
base::Move(src_path, database_path_.Append(src_path.BaseName())));
}
}
void SetInvalidateCallback(const base::Closure& callback) {
DCHECK(invalidate_callback_.is_null());
invalidate_callback_ = callback;
}
virtual void InvalidateData() OVERRIDE {
PicasaDataProvider::InvalidateData();
if (!invalidate_callback_.is_null()) {
invalidate_callback_.Run();
invalidate_callback_.Reset();
}
}
void SetAlbumMapsForTesting(const AlbumMap& album_map,
const AlbumMap& folder_map) {
album_map_ = album_map;
folder_map_ = folder_map;
}
private:
virtual void OnTempDirWatchStarted(
scoped_ptr<base::FilePathWatcher> temp_dir_watcher) OVERRIDE {
PicasaDataProvider::OnTempDirWatchStarted(temp_dir_watcher.Pass());
file_watch_request_returned_ = true;
for (std::vector<ReadyCallback>::const_iterator it =
file_watch_started_callbacks_.begin();
it != file_watch_started_callbacks_.end();
++it) {
it->Run(temp_dir_watcher_.get() != NULL);
}
file_watch_started_callbacks_.clear();
}
// Used for test that utilizes file watch
bool file_watch_request_returned_;
std::vector<ReadyCallback> file_watch_started_callbacks_;
base::Closure invalidate_callback_;
};
class PicasaDataProviderTest : public InProcessBrowserTest {
public:
PicasaDataProviderTest() {}
virtual ~PicasaDataProviderTest() {}
protected:
// Runs on the MediaTaskRunner and designed to be overridden by subclasses.
virtual void InitializeTestData() {}
void RunTest() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::RunLoop loop;
quit_closure_ = loop.QuitClosure();
MediaFileSystemBackend::MediaTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&PicasaDataProviderTest::SetupFoldersAndDataProvider,
base::Unretained(this)));
MediaFileSystemBackend::MediaTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&PicasaDataProviderTest::InitializeTestData,
base::Unretained(this)));
MediaFileSystemBackend::MediaTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&PicasaDataProviderTest::StartTestOnMediaTaskRunner,
base::Unretained(this)));
loop.Run();
}
virtual PicasaDataProvider::DataType RequestedDataType() const = 0;
// Start the test. The data provider is refreshed before calling StartTest
// and the result of the refresh is passed in.
virtual void VerifyRefreshResults(bool parse_success) {};
void TestDone() {
DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
// The data provider must be destructed on the MediaTaskRunner. This is done
// in a posted task rather than directly because TestDone is called by
// PicasaDataProvider. The callee should not destroy the caller.
MediaFileSystemBackend::MediaTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&PicasaDataProviderTest::DestructDataProviderThenQuit,
base::Unretained(this)));
}
const base::FilePath& test_folder_1_path() { return test_folder_1_.path(); }
const base::FilePath& test_folder_2_path() { return test_folder_2_.path(); }
TestPicasaDataProvider* data_provider() const {
return picasa_data_provider_.get();
}
const base::FilePath GetTempDirPath() const {
return picasa_root_dir_.path().AppendASCII(kPicasaTempDirName);
}
virtual base::FilePath GetColumnFileDestination() const {
return picasa_root_dir_.path().AppendASCII(kPicasaDatabaseDirName);
}
private:
void SetupFoldersAndDataProvider() {
DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
ASSERT_TRUE(test_folder_1_.CreateUniqueTempDir());
ASSERT_TRUE(test_folder_2_.CreateUniqueTempDir());
ASSERT_TRUE(picasa_root_dir_.CreateUniqueTempDir());
ASSERT_TRUE(base::CreateDirectory(
picasa_root_dir_.path().AppendASCII(kPicasaDatabaseDirName)));
ASSERT_TRUE(base::CreateDirectory(
picasa_root_dir_.path().AppendASCII(kPicasaTempDirName)));
picasa_data_provider_.reset(new TestPicasaDataProvider(
picasa_root_dir_.path().AppendASCII(kPicasaDatabaseDirName)));
}
virtual void StartTestOnMediaTaskRunner() {
DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
data_provider()->RefreshData(
RequestedDataType(),
base::Bind(&PicasaDataProviderTest::VerifyRefreshResults,
base::Unretained(this)));
}
void DestructDataProviderThenQuit() {
DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
picasa_data_provider_.reset();
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, quit_closure_);
}
base::ScopedTempDir test_folder_1_;
base::ScopedTempDir test_folder_2_;
base::ScopedTempDir picasa_root_dir_;
scoped_ptr<TestPicasaDataProvider> picasa_data_provider_;
base::Closure quit_closure_;
DISALLOW_COPY_AND_ASSIGN(PicasaDataProviderTest);
};
class PicasaDataProviderNoDatabaseGetListTest : public PicasaDataProviderTest {
protected:
virtual PicasaDataProvider::DataType RequestedDataType() const OVERRIDE {
return PicasaDataProvider::LIST_OF_ALBUMS_AND_FOLDERS_DATA;
}
virtual void VerifyRefreshResults(bool parse_success) OVERRIDE {
EXPECT_FALSE(parse_success);
TestDone();
}
};
IN_PROC_BROWSER_TEST_F(PicasaDataProviderNoDatabaseGetListTest,
NoDatabaseGetList) {
RunTest();
}
class PicasaDataProviderNoDatabaseGetAlbumsImagesTest
: public PicasaDataProviderTest {
protected:
virtual PicasaDataProvider::DataType RequestedDataType() const OVERRIDE {
return PicasaDataProvider::ALBUMS_IMAGES_DATA;
}
virtual void VerifyRefreshResults(bool parse_success) OVERRIDE {
EXPECT_FALSE(parse_success);
TestDone();
}
};
IN_PROC_BROWSER_TEST_F(PicasaDataProviderNoDatabaseGetAlbumsImagesTest,
NoDatabaseGetAlbumsImages) {
RunTest();
}
class PicasaDataProviderGetListTest : public PicasaDataProviderTest {
protected:
virtual void InitializeTestData() OVERRIDE {
WriteTestAlbumTable(GetColumnFileDestination(), test_folder_1_path(),
test_folder_2_path());
}
virtual PicasaDataProvider::DataType RequestedDataType() const OVERRIDE {
return PicasaDataProvider::LIST_OF_ALBUMS_AND_FOLDERS_DATA;
}
virtual void VerifyRefreshResults(bool parse_success) OVERRIDE {
ASSERT_TRUE(parse_success);
VerifyTestAlbumTable(
data_provider(), test_folder_1_path(), test_folder_2_path());
TestDone();
}
};
IN_PROC_BROWSER_TEST_F(PicasaDataProviderGetListTest, GetListTest) {
RunTest();
}
class PicasaDataProviderGetAlbumsImagesTest : public PicasaDataProviderTest {
protected:
virtual void InitializeTestData() OVERRIDE {
WriteTestAlbumTable(GetColumnFileDestination(), test_folder_1_path(),
test_folder_2_path());
WriteTestAlbumsImagesIndex(test_folder_1_path(), test_folder_2_path());
}
virtual PicasaDataProvider::DataType RequestedDataType() const OVERRIDE {
return PicasaDataProvider::ALBUMS_IMAGES_DATA;
}
virtual void VerifyRefreshResults(bool parse_success) OVERRIDE {
ASSERT_TRUE(parse_success);
VerifyTestAlbumTable(
data_provider(), test_folder_1_path(), test_folder_2_path());
VerifyTestAlbumsImagesIndex(
data_provider(), test_folder_1_path(), test_folder_2_path());
TestDone();
}
};
IN_PROC_BROWSER_TEST_F(PicasaDataProviderGetAlbumsImagesTest,
GetAlbumsImagesTest) {
RunTest();
}
class PicasaDataProviderMultipleMixedCallbacksTest
: public PicasaDataProviderTest {
public:
PicasaDataProviderMultipleMixedCallbacksTest()
: list_callbacks_called_(0), albums_images_callbacks_called_(0) {}
virtual void InitializeTestData() OVERRIDE {
WriteTestAlbumTable(GetColumnFileDestination(), test_folder_1_path(),
test_folder_2_path());
WriteTestAlbumsImagesIndex(test_folder_1_path(), test_folder_2_path());
}
virtual PicasaDataProvider::DataType RequestedDataType() const OVERRIDE {
return PicasaDataProvider::ALBUMS_IMAGES_DATA;
}
protected:
virtual void ListCallback(int expected_list_callbacks_called,
bool parse_success) {
ASSERT_TRUE(parse_success);
ASSERT_EQ(expected_list_callbacks_called, ++list_callbacks_called_);
VerifyTestAlbumTable(
data_provider(), test_folder_1_path(), test_folder_2_path());
CheckTestDone();
}
virtual void AlbumsImagesCallback(int expected_albums_images_callbacks_called,
bool parse_success) {
ASSERT_TRUE(parse_success);
ASSERT_EQ(expected_albums_images_callbacks_called,
++albums_images_callbacks_called_);
VerifyTestAlbumsImagesIndex(
data_provider(), test_folder_1_path(), test_folder_2_path());
CheckTestDone();
}
private:
void CheckTestDone() {
ASSERT_LE(list_callbacks_called_, 2);
ASSERT_LE(albums_images_callbacks_called_, 2);
if (list_callbacks_called_ == 2 && albums_images_callbacks_called_ == 2)
TestDone();
}
virtual void StartTestOnMediaTaskRunner() OVERRIDE {
DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
data_provider()->RefreshData(
PicasaDataProvider::LIST_OF_ALBUMS_AND_FOLDERS_DATA,
base::Bind(&PicasaDataProviderMultipleMixedCallbacksTest::ListCallback,
base::Unretained(this),
1));
data_provider()->RefreshData(
PicasaDataProvider::ALBUMS_IMAGES_DATA,
base::Bind(
&PicasaDataProviderMultipleMixedCallbacksTest::AlbumsImagesCallback,
base::Unretained(this),
1));
data_provider()->RefreshData(
PicasaDataProvider::LIST_OF_ALBUMS_AND_FOLDERS_DATA,
base::Bind(&PicasaDataProviderMultipleMixedCallbacksTest::ListCallback,
base::Unretained(this),
2));
data_provider()->RefreshData(
PicasaDataProvider::ALBUMS_IMAGES_DATA,
base::Bind(
&PicasaDataProviderMultipleMixedCallbacksTest::AlbumsImagesCallback,
base::Unretained(this),
2));
}
int list_callbacks_called_;
int albums_images_callbacks_called_;
};
IN_PROC_BROWSER_TEST_F(PicasaDataProviderMultipleMixedCallbacksTest,
MultipleMixedCallbacks) {
RunTest();
}
class PicasaDataProviderFileWatcherInvalidateTest
: public PicasaDataProviderGetListTest {
protected:
virtual void ListCallback(bool parse_success) {
ASSERT_FALSE(parse_success);
data_provider()->EnsureFileWatchStartedForTesting(
base::Bind(&PicasaDataProviderFileWatcherInvalidateTest::
OnPicasaTempDirWatchStarted,
base::Unretained(this)));
}
void OnPicasaTempDirWatchStarted(bool file_watch_successful) {
ASSERT_TRUE(file_watch_successful);
// Validate the list after the file move triggers an invalidate.
data_provider()->SetInvalidateCallback(base::Bind(
&PicasaDataProvider::RefreshData,
base::Unretained(data_provider()),
RequestedDataType(),
base::Bind(
&PicasaDataProviderFileWatcherInvalidateTest::VerifyRefreshResults,
base::Unretained(this))));
data_provider()->MoveTempFilesToDatabase();
}
virtual base::FilePath GetColumnFileDestination() const OVERRIDE {
return GetTempDirPath();
}
private:
virtual void StartTestOnMediaTaskRunner() OVERRIDE {
DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
// Refresh before moving album table to database dir, guaranteeing failure.
data_provider()->RefreshData(
RequestedDataType(),
base::Bind(
&PicasaDataProviderFileWatcherInvalidateTest::ListCallback,
base::Unretained(this)));
}
};
IN_PROC_BROWSER_TEST_F(PicasaDataProviderFileWatcherInvalidateTest,
FileWatcherInvalidateTest) {
RunTest();
}
class PicasaDataProviderInvalidateInflightTableReaderTest
: public PicasaDataProviderGetListTest {
protected:
// Don't write the database files until later.
virtual void InitializeTestData() OVERRIDE {}
private:
virtual void StartTestOnMediaTaskRunner() OVERRIDE {
DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
// Refresh before the database files have been written.
// This is guaranteed to fail to read the album table.
data_provider()->RefreshData(
RequestedDataType(),
base::Bind(&PicasaDataProviderInvalidateInflightTableReaderTest::
VerifyRefreshResults,
base::Unretained(this)));
// Now write the album table and invalidate the inflight table reader.
PicasaDataProviderGetListTest::InitializeTestData();
data_provider()->InvalidateData();
// VerifyRefreshResults callback should receive correct results now.
}
};
IN_PROC_BROWSER_TEST_F(PicasaDataProviderInvalidateInflightTableReaderTest,
InvalidateInflightTableReaderTest) {
RunTest();
}
class PicasaDataProviderInvalidateInflightAlbumsIndexerTest
: public PicasaDataProviderGetAlbumsImagesTest {
protected:
virtual void ListCallback(bool parse_success) {
ASSERT_TRUE(parse_success);
// Empty the album maps to guarantee that the first utility process will
// fail to get the correct albums-images index.
data_provider()->SetAlbumMapsForTesting(AlbumMap(), AlbumMap());
data_provider()->RefreshData(
PicasaDataProvider::ALBUMS_IMAGES_DATA,
base::Bind(&PicasaDataProviderInvalidateInflightAlbumsIndexerTest::
VerifyRefreshResults,
base::Unretained(this)));
// Now invalidate all the data. The album maps will be re-read.
data_provider()->InvalidateData();
// VerifyRefreshResults callback should receive correct results now.
}
private:
virtual void StartTestOnMediaTaskRunner() OVERRIDE {
DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
data_provider()->RefreshData(
PicasaDataProvider::LIST_OF_ALBUMS_AND_FOLDERS_DATA,
base::Bind(&PicasaDataProviderInvalidateInflightAlbumsIndexerTest::
ListCallback,
base::Unretained(this)));
}
};
IN_PROC_BROWSER_TEST_F(PicasaDataProviderInvalidateInflightAlbumsIndexerTest,
InvalidateInflightAlbumsIndexerTest) {
RunTest();
}
} // namespace picasa