| // 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 "chrome/browser/sync_file_system/drive_backend/metadata_database.h" |
| |
| #include <stdint.h> |
| |
| #include <unordered_map> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| |
| #include "base/run_loop.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/test/task_environment.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h" |
| #include "chrome/browser/sync_file_system/drive_backend/drive_backend_test_util.h" |
| #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h" |
| #include "chrome/browser/sync_file_system/drive_backend/leveldb_wrapper.h" |
| #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h" |
| #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index.h" |
| #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index_interface.h" |
| #include "chrome/browser/sync_file_system/drive_backend/metadata_database_index_on_disk.h" |
| #include "chrome/browser/sync_file_system/sync_file_system_test_util.h" |
| #include "google_apis/drive/drive_api_parser.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/leveldatabase/env_chromium.h" |
| #include "third_party/leveldatabase/leveldb_chrome.h" |
| #include "third_party/leveldatabase/src/include/leveldb/db.h" |
| #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" |
| |
| #define FPL(a) FILE_PATH_LITERAL(a) |
| |
| namespace sync_file_system { |
| namespace drive_backend { |
| |
| namespace { |
| |
| typedef MetadataDatabase::FileIDList FileIDList; |
| |
| const int64_t kInitialChangeID = 1234; |
| const int64_t kSyncRootTrackerID = 100; |
| const char kSyncRootFolderID[] = "sync_root_folder_id"; |
| |
| // This struct is used to setup initial state of the database in the test and |
| // also used to match to the modified content of the database as the |
| // expectation. |
| struct TrackedFile { |
| // Holds the latest remote metadata which may be not-yet-synced to |tracker|. |
| FileMetadata metadata; |
| FileTracker tracker; |
| |
| // Implies the file should not in the database. |
| bool should_be_absent; |
| |
| // Implies the file should have a tracker in the database but should have no |
| // metadata. |
| bool tracker_only; |
| |
| TrackedFile() : should_be_absent(false), tracker_only(false) {} |
| }; |
| |
| void ExpectEquivalentServiceMetadata( |
| const MetadataDatabaseIndexInterface* left, |
| const MetadataDatabaseIndexInterface* right) { |
| EXPECT_EQ(left->GetLargestChangeID(), right->GetLargestChangeID()); |
| EXPECT_EQ(left->GetSyncRootTrackerID(), right->GetSyncRootTrackerID()); |
| EXPECT_EQ(left->GetNextTrackerID(), right->GetNextTrackerID()); |
| } |
| |
| void ExpectEquivalent(const FileMetadata* left, const FileMetadata* right) { |
| if (!left) { |
| ASSERT_FALSE(right); |
| return; |
| } |
| ASSERT_TRUE(right); |
| test_util::ExpectEquivalentMetadata(*left, *right); |
| } |
| |
| void ExpectEquivalent(const FileTracker* left, const FileTracker* right) { |
| if (!left) { |
| ASSERT_FALSE(right); |
| return; |
| } |
| ASSERT_TRUE(right); |
| test_util::ExpectEquivalentTrackers(*left, *right); |
| } |
| |
| void ExpectEquivalent(int64_t left, int64_t right) { |
| EXPECT_EQ(left, right); |
| } |
| |
| template <typename Container> |
| void ExpectEquivalentMaps(const Container& left, const Container& right); |
| |
| template <typename Key, typename Value> |
| void ExpectEquivalent(const std::map<Key, Value>& left, |
| const std::map<Key, Value>& right) { |
| ExpectEquivalentMaps(left, right); |
| } |
| |
| template <typename Key, typename Value> |
| void ExpectEquivalent(const std::unordered_map<Key, Value>& left, |
| const std::unordered_map<Key, Value>& right) { |
| // Convert from a hash container to an ordered container for comparison. |
| ExpectEquivalentMaps(std::map<Key, Value>(left.begin(), left.end()), |
| std::map<Key, Value>(right.begin(), right.end())); |
| } |
| |
| template <typename Key, typename Value> |
| void ExpectEquivalent( |
| const std::unordered_map<Key, std::unique_ptr<Value>>& left, |
| const std::unordered_map<Key, std::unique_ptr<Value>>& right) { |
| // Convert from a hash container to an ordered container for comparison. |
| std::map<Key, Value*> left_ordered; |
| std::map<Key, Value*> right_ordered; |
| for (const auto& item : left) |
| left_ordered[item.first] = item.second.get(); |
| for (const auto& item : right) |
| right_ordered[item.first] = item.second.get(); |
| |
| ExpectEquivalentMaps(left_ordered, right_ordered); |
| } |
| |
| template <typename Container> |
| void ExpectEquivalentSets(const Container& left, const Container& right); |
| |
| template <typename Value, typename Comparator> |
| void ExpectEquivalent(const std::set<Value, Comparator>& left, |
| const std::set<Value, Comparator>& right) { |
| return ExpectEquivalentSets(left, right); |
| } |
| |
| template <typename Value> |
| void ExpectEquivalent(const std::unordered_set<Value>& left, |
| const std::unordered_set<Value>& right) { |
| // Convert from a hash container to an ordered container for comparison. |
| return ExpectEquivalentSets(std::set<Value>(left.begin(), left.end()), |
| std::set<Value>(right.begin(), right.end())); |
| } |
| |
| void ExpectEquivalent(const TrackerIDSet& left, |
| const TrackerIDSet& right) { |
| { |
| SCOPED_TRACE("Expect equivalent active_tracker"); |
| EXPECT_EQ(left.active_tracker(), right.active_tracker()); |
| } |
| ExpectEquivalent(left.tracker_set(), right.tracker_set()); |
| } |
| |
| template <typename Container> |
| void ExpectEquivalentMaps(const Container& left, const Container& right) { |
| ASSERT_EQ(left.size(), right.size()); |
| |
| auto left_itr = left.begin(); |
| auto right_itr = right.begin(); |
| while (left_itr != left.end()) { |
| EXPECT_EQ(left_itr->first, right_itr->first); |
| ExpectEquivalent(left_itr->second, right_itr->second); |
| ++left_itr; |
| ++right_itr; |
| } |
| } |
| |
| template <typename Container> |
| void ExpectEquivalentSets(const Container& left, const Container& right) { |
| ASSERT_EQ(left.size(), right.size()); |
| |
| auto left_itr = left.begin(); |
| auto right_itr = right.begin(); |
| while (left_itr != left.end()) { |
| ExpectEquivalent(*left_itr, *right_itr); |
| ++left_itr; |
| ++right_itr; |
| } |
| } |
| |
| base::FilePath CreateNormalizedPath(const base::FilePath::StringType& path) { |
| return base::FilePath(path).NormalizePathSeparators(); |
| } |
| |
| } // namespace |
| |
| class MetadataDatabaseTest : public testing::TestWithParam<bool> { |
| public: |
| MetadataDatabaseTest() |
| : current_change_id_(kInitialChangeID), |
| next_tracker_id_(kSyncRootTrackerID + 1), |
| next_file_id_number_(1), |
| next_md5_sequence_number_(1) {} |
| |
| virtual ~MetadataDatabaseTest() {} |
| |
| void SetUp() override { |
| ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); |
| in_memory_env_ = leveldb_chrome::NewMemEnv("MetadataDatabaseTest"); |
| } |
| |
| void TearDown() override { DropDatabase(); } |
| |
| protected: |
| std::string GenerateFileID() { |
| return "file_id_" + base::NumberToString(next_file_id_number_++); |
| } |
| |
| int64_t GetTrackerIDByFileID(const std::string& file_id) { |
| TrackerIDSet trackers; |
| if (metadata_database_->FindTrackersByFileID(file_id, &trackers)) { |
| EXPECT_FALSE(trackers.empty()); |
| return *trackers.begin(); |
| } |
| return 0; |
| } |
| |
| bool enable_on_disk_index() const { return GetParam(); } |
| |
| leveldb::Env* in_memory_env() const { return in_memory_env_.get(); } |
| |
| const base::FilePath& DatabasePath() const { return database_dir_.GetPath(); } |
| |
| SyncStatusCode InitializeMetadataDatabase() { |
| SyncStatusCode status = SYNC_STATUS_UNKNOWN; |
| metadata_database_ = MetadataDatabase::CreateInternal( |
| DatabasePath(), in_memory_env_.get(), enable_on_disk_index(), &status); |
| return status; |
| } |
| |
| void DropDatabase() { |
| metadata_database_.reset(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void SetUpDatabaseByTrackedFiles(const TrackedFile** tracked_files, |
| int size) { |
| std::unique_ptr<LevelDBWrapper> db = InitializeLevelDB(); |
| ASSERT_TRUE(db); |
| |
| for (int i = 0; i < size; ++i) { |
| const TrackedFile* file = tracked_files[i]; |
| if (file->should_be_absent) |
| continue; |
| if (!file->tracker_only) |
| EXPECT_TRUE(PutFileToDB(db.get(), file->metadata).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), file->tracker).ok()); |
| } |
| } |
| |
| void VerifyTrackedFile(const TrackedFile& file) { |
| if (!file.should_be_absent) { |
| if (file.tracker_only) { |
| EXPECT_FALSE(metadata_database()->FindFileByFileID( |
| file.metadata.file_id(), nullptr)); |
| } else { |
| VerifyFile(file.metadata); |
| } |
| VerifyTracker(file.tracker); |
| return; |
| } |
| |
| EXPECT_FALSE(metadata_database()->FindFileByFileID( |
| file.metadata.file_id(), nullptr)); |
| EXPECT_FALSE(metadata_database()->FindTrackerByTrackerID( |
| file.tracker.tracker_id(), nullptr)); |
| } |
| |
| void VerifyTrackedFiles(const TrackedFile** tracked_files, int size) { |
| for (int i = 0; i < size; ++i) |
| VerifyTrackedFile(*tracked_files[i]); |
| } |
| |
| MetadataDatabase* metadata_database() { return metadata_database_.get(); } |
| |
| std::unique_ptr<LevelDBWrapper> InitializeLevelDB() { |
| std::unique_ptr<leveldb::DB> db; |
| leveldb_env::Options options; |
| options.create_if_missing = true; |
| options.max_open_files = 0; // Use minimum. |
| options.env = in_memory_env_.get(); |
| leveldb::Status status = |
| leveldb_env::OpenDB(options, DatabasePath().AsUTF8Unsafe(), &db); |
| EXPECT_TRUE(status.ok()); |
| |
| std::unique_ptr<LevelDBWrapper> wrapper(new LevelDBWrapper(std::move(db))); |
| |
| wrapper->Put(kDatabaseVersionKey, base::NumberToString(3)); |
| SetUpServiceMetadata(wrapper.get()); |
| |
| return wrapper; |
| } |
| |
| void SetUpServiceMetadata(LevelDBWrapper* db) { |
| ServiceMetadata service_metadata; |
| service_metadata.set_largest_change_id(kInitialChangeID); |
| service_metadata.set_sync_root_tracker_id(kSyncRootTrackerID); |
| service_metadata.set_next_tracker_id(next_tracker_id_); |
| PutServiceMetadataToDB(service_metadata, db); |
| EXPECT_TRUE(db->Commit().ok()); |
| } |
| |
| FileMetadata CreateSyncRootMetadata() { |
| FileMetadata sync_root; |
| sync_root.set_file_id(kSyncRootFolderID); |
| FileDetails* details = sync_root.mutable_details(); |
| details->set_title(kSyncRootFolderTitle); |
| details->set_file_kind(FILE_KIND_FOLDER); |
| details->set_change_id(current_change_id_); |
| return sync_root; |
| } |
| |
| FileMetadata CreateFileMetadata(const FileMetadata& parent, |
| const std::string& title) { |
| FileMetadata file; |
| file.set_file_id(GenerateFileID()); |
| FileDetails* details = file.mutable_details(); |
| details->add_parent_folder_ids(parent.file_id()); |
| details->set_title(title); |
| details->set_file_kind(FILE_KIND_FILE); |
| details->set_md5("md5_value_" + |
| base::NumberToString(next_md5_sequence_number_++)); |
| details->set_change_id(current_change_id_); |
| return file; |
| } |
| |
| FileMetadata CreateFolderMetadata(const FileMetadata& parent, |
| const std::string& title) { |
| FileMetadata folder; |
| folder.set_file_id(GenerateFileID()); |
| FileDetails* details = folder.mutable_details(); |
| details->add_parent_folder_ids(parent.file_id()); |
| details->set_title(title); |
| details->set_file_kind(FILE_KIND_FOLDER); |
| details->set_change_id(current_change_id_); |
| return folder; |
| } |
| |
| FileTracker CreateSyncRootTracker(const FileMetadata& sync_root) { |
| FileTracker sync_root_tracker; |
| sync_root_tracker.set_tracker_id(kSyncRootTrackerID); |
| sync_root_tracker.set_parent_tracker_id(0); |
| sync_root_tracker.set_file_id(sync_root.file_id()); |
| sync_root_tracker.set_dirty(false); |
| sync_root_tracker.set_active(true); |
| sync_root_tracker.set_needs_folder_listing(false); |
| *sync_root_tracker.mutable_synced_details() = sync_root.details(); |
| return sync_root_tracker; |
| } |
| |
| FileTracker CreateTracker(const FileTracker& parent_tracker, |
| const FileMetadata& file) { |
| FileTracker tracker; |
| tracker.set_tracker_id(next_tracker_id_++); |
| tracker.set_parent_tracker_id(parent_tracker.tracker_id()); |
| tracker.set_file_id(file.file_id()); |
| tracker.set_app_id(parent_tracker.app_id()); |
| tracker.set_tracker_kind(TRACKER_KIND_REGULAR); |
| tracker.set_dirty(false); |
| tracker.set_active(true); |
| tracker.set_needs_folder_listing(false); |
| *tracker.mutable_synced_details() = file.details(); |
| return tracker; |
| } |
| |
| TrackedFile CreateTrackedSyncRoot() { |
| TrackedFile sync_root; |
| sync_root.metadata = CreateSyncRootMetadata(); |
| sync_root.tracker = CreateSyncRootTracker(sync_root.metadata); |
| return sync_root; |
| } |
| |
| TrackedFile CreateTrackedAppRoot(const TrackedFile& sync_root, |
| const std::string& app_id) { |
| TrackedFile app_root(CreateTrackedFolder(sync_root, app_id)); |
| app_root.tracker.set_app_id(app_id); |
| app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT); |
| return app_root; |
| } |
| |
| TrackedFile CreateTrackedFile(const TrackedFile& parent, |
| const std::string& title) { |
| TrackedFile file; |
| file.metadata = CreateFileMetadata(parent.metadata, title); |
| file.tracker = CreateTracker(parent.tracker, file.metadata); |
| return file; |
| } |
| |
| TrackedFile CreateTrackedFolder(const TrackedFile& parent, |
| const std::string& title) { |
| TrackedFile folder; |
| folder.metadata = CreateFolderMetadata(parent.metadata, title); |
| folder.tracker = CreateTracker(parent.tracker, folder.metadata); |
| return folder; |
| } |
| |
| std::unique_ptr<google_apis::FileResource> CreateFileResourceFromMetadata( |
| const FileMetadata& file) { |
| std::unique_ptr<google_apis::FileResource> file_resource( |
| new google_apis::FileResource); |
| for (int i = 0; i < file.details().parent_folder_ids_size(); ++i) { |
| google_apis::ParentReference parent; |
| parent.set_file_id(file.details().parent_folder_ids(i)); |
| file_resource->mutable_parents()->push_back(parent); |
| } |
| |
| file_resource->set_file_id(file.file_id()); |
| file_resource->set_title(file.details().title()); |
| if (file.details().file_kind() == FILE_KIND_FOLDER) { |
| file_resource->set_mime_type("application/vnd.google-apps.folder"); |
| } else if (file.details().file_kind() == FILE_KIND_FILE) { |
| file_resource->set_mime_type("text/plain"); |
| file_resource->set_file_size(0); |
| } else { |
| file_resource->set_mime_type("application/vnd.google-apps.document"); |
| } |
| file_resource->set_md5_checksum(file.details().md5()); |
| file_resource->set_etag(file.details().etag()); |
| file_resource->set_created_date(base::Time::FromInternalValue( |
| file.details().creation_time())); |
| file_resource->set_modified_date(base::Time::FromInternalValue( |
| file.details().modification_time())); |
| |
| return file_resource; |
| } |
| |
| std::unique_ptr<google_apis::ChangeResource> CreateChangeResourceFromMetadata( |
| const FileMetadata& file) { |
| std::unique_ptr<google_apis::ChangeResource> change( |
| new google_apis::ChangeResource); |
| change->set_change_id(file.details().change_id()); |
| change->set_type(google_apis::ChangeResource::FILE); |
| change->set_file_id(file.file_id()); |
| change->set_deleted(file.details().missing()); |
| if (change->is_deleted()) |
| return change; |
| |
| change->set_file(CreateFileResourceFromMetadata(file)); |
| return change; |
| } |
| |
| void ApplyRenameChangeToMetadata(const std::string& new_title, |
| FileMetadata* file) { |
| FileDetails* details = file->mutable_details(); |
| details->set_title(new_title); |
| details->set_change_id(++current_change_id_); |
| } |
| |
| void ApplyReorganizeChangeToMetadata(const std::string& new_parent, |
| FileMetadata* file) { |
| FileDetails* details = file->mutable_details(); |
| details->clear_parent_folder_ids(); |
| details->add_parent_folder_ids(new_parent); |
| details->set_change_id(++current_change_id_); |
| } |
| |
| void ApplyContentChangeToMetadata(FileMetadata* file) { |
| FileDetails* details = file->mutable_details(); |
| details->set_md5("md5_value_" + |
| base::NumberToString(next_md5_sequence_number_++)); |
| details->set_change_id(++current_change_id_); |
| } |
| |
| void ApplyNoopChangeToMetadata(FileMetadata* file) { |
| file->mutable_details()->set_change_id(++current_change_id_); |
| } |
| |
| void PushToChangeList( |
| std::unique_ptr<google_apis::ChangeResource> change, |
| std::vector<std::unique_ptr<google_apis::ChangeResource>>* changes) { |
| changes->push_back(std::move(change)); |
| } |
| |
| leveldb::Status PutFileToDB(LevelDBWrapper* db, const FileMetadata& file) { |
| PutFileMetadataToDB(file, db); |
| return db->Commit(); |
| } |
| |
| leveldb::Status PutTrackerToDB(LevelDBWrapper* db, |
| const FileTracker& tracker) { |
| PutFileTrackerToDB(tracker, db); |
| return db->Commit(); |
| } |
| |
| void VerifyReloadConsistencyForOnMemory(MetadataDatabaseIndex* index1, |
| MetadataDatabaseIndex* index2) { |
| ExpectEquivalentServiceMetadata(index1, index2); |
| { |
| SCOPED_TRACE("Expect equivalent metadata_by_id_ contents."); |
| ExpectEquivalent(index1->metadata_by_id_, index2->metadata_by_id_); |
| } |
| { |
| SCOPED_TRACE("Expect equivalent tracker_by_id_ contents."); |
| ExpectEquivalent(index1->tracker_by_id_, index2->tracker_by_id_); |
| } |
| { |
| SCOPED_TRACE("Expect equivalent trackers_by_file_id_ contents."); |
| ExpectEquivalent(index1->trackers_by_file_id_, |
| index2->trackers_by_file_id_); |
| } |
| { |
| SCOPED_TRACE("Expect equivalent app_root_by_app_id_ contents."); |
| ExpectEquivalent(index1->app_root_by_app_id_, |
| index2->app_root_by_app_id_); |
| } |
| { |
| SCOPED_TRACE("Expect equivalent trackers_by_parent_and_title_ contents."); |
| ExpectEquivalent(index1->trackers_by_parent_and_title_, |
| index2->trackers_by_parent_and_title_); |
| } |
| { |
| SCOPED_TRACE("Expect equivalent dirty_trackers_ contents."); |
| ExpectEquivalent(index1->dirty_trackers_, index2->dirty_trackers_); |
| } |
| } |
| |
| void VerifyReloadConsistencyForOnDisk( |
| MetadataDatabaseIndexOnDisk* index1, |
| MetadataDatabaseIndexOnDisk* index2) { |
| ExpectEquivalentServiceMetadata(index1, index2); |
| std::unique_ptr<LevelDBWrapper::Iterator> itr1 = |
| index1->GetDBForTesting()->NewIterator(); |
| std::unique_ptr<LevelDBWrapper::Iterator> itr2 = |
| index2->GetDBForTesting()->NewIterator(); |
| for (itr1->SeekToFirst(), itr2->SeekToFirst(); |
| itr1->Valid() && itr2->Valid(); |
| itr1->Next(), itr2->Next()) { |
| EXPECT_EQ(itr1->key().ToString(), itr2->key().ToString()); |
| EXPECT_EQ(itr1->value().ToString(), itr2->value().ToString()); |
| } |
| EXPECT_TRUE(!itr1->Valid()); |
| EXPECT_TRUE(!itr2->Valid()); |
| } |
| |
| void VerifyReloadConsistency() { |
| std::unique_ptr<MetadataDatabase> metadata_database_2; |
| ASSERT_EQ(SYNC_STATUS_OK, MetadataDatabase::CreateForTesting( |
| std::move(metadata_database_->db_), |
| metadata_database_->enable_on_disk_index_, |
| &metadata_database_2)); |
| metadata_database_->db_ = std::move(metadata_database_2->db_); |
| |
| MetadataDatabaseIndexInterface* index1 = metadata_database_->index_.get(); |
| MetadataDatabaseIndexInterface* index2 = metadata_database_2->index_.get(); |
| if (enable_on_disk_index()) { |
| VerifyReloadConsistencyForOnDisk( |
| static_cast<MetadataDatabaseIndexOnDisk*>(index1), |
| static_cast<MetadataDatabaseIndexOnDisk*>(index2)); |
| } else { |
| VerifyReloadConsistencyForOnMemory( |
| static_cast<MetadataDatabaseIndex*>(index1), |
| static_cast<MetadataDatabaseIndex*>(index2)); |
| } |
| } |
| |
| void VerifyFile(const FileMetadata& file) { |
| FileMetadata file_in_metadata_database; |
| ASSERT_TRUE(metadata_database()->FindFileByFileID( |
| file.file_id(), &file_in_metadata_database)); |
| |
| SCOPED_TRACE("Expect equivalent " + file.file_id()); |
| ExpectEquivalent(&file, &file_in_metadata_database); |
| } |
| |
| void VerifyTracker(const FileTracker& tracker) { |
| FileTracker tracker_in_metadata_database; |
| ASSERT_TRUE(metadata_database()->FindTrackerByTrackerID( |
| tracker.tracker_id(), &tracker_in_metadata_database)); |
| |
| SCOPED_TRACE("Expect equivalent tracker[" + |
| base::NumberToString(tracker.tracker_id()) + "]"); |
| ExpectEquivalent(&tracker, &tracker_in_metadata_database); |
| } |
| |
| SyncStatusCode RegisterApp(const std::string& app_id, |
| const std::string& folder_id) { |
| return metadata_database_->RegisterApp(app_id, folder_id); |
| } |
| |
| SyncStatusCode DisableApp(const std::string& app_id) { |
| return metadata_database_->DisableApp(app_id); |
| } |
| |
| SyncStatusCode EnableApp(const std::string& app_id) { |
| return metadata_database_->EnableApp(app_id); |
| } |
| |
| SyncStatusCode UnregisterApp(const std::string& app_id) { |
| return metadata_database_->UnregisterApp(app_id); |
| } |
| |
| SyncStatusCode UpdateByChangeList( |
| std::vector<std::unique_ptr<google_apis::ChangeResource>> changes) { |
| return metadata_database_->UpdateByChangeList(current_change_id_, |
| std::move(changes)); |
| } |
| |
| SyncStatusCode PopulateFolder(const std::string& folder_id, |
| const FileIDList& listed_children) { |
| return metadata_database_->PopulateFolderByChildList( |
| folder_id, listed_children); |
| } |
| |
| SyncStatusCode UpdateTracker(const FileTracker& tracker) { |
| return metadata_database_->UpdateTracker( |
| tracker.tracker_id(), tracker.synced_details()); |
| } |
| |
| SyncStatusCode PopulateInitialData( |
| int64_t largest_change_id, |
| const google_apis::FileResource& sync_root_folder, |
| const std::vector<std::unique_ptr<google_apis::FileResource>>& |
| app_root_folders) { |
| return metadata_database_->PopulateInitialData( |
| largest_change_id, sync_root_folder, app_root_folders); |
| } |
| |
| void ResetTrackerID(FileTracker* tracker) { |
| tracker->set_tracker_id(GetTrackerIDByFileID(tracker->file_id())); |
| } |
| |
| int64_t current_change_id() const { return current_change_id_; } |
| |
| private: |
| base::ScopedTempDir database_dir_; |
| base::test::SingleThreadTaskEnvironment task_environment_; |
| |
| std::unique_ptr<leveldb::Env> in_memory_env_; |
| std::unique_ptr<MetadataDatabase> metadata_database_; |
| |
| int64_t current_change_id_; |
| int64_t next_tracker_id_; |
| int64_t next_file_id_number_; |
| int64_t next_md5_sequence_number_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MetadataDatabaseTest); |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(MetadataDatabaseTestWithIndexesOnDisk, |
| MetadataDatabaseTest, |
| ::testing::Values(true, false)); |
| |
| TEST_P(MetadataDatabaseTest, InitializationTest_Empty) { |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| DropDatabase(); |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| |
| DropDatabase(); |
| |
| std::unique_ptr<LevelDBWrapper> db = InitializeLevelDB(); |
| db->Put(kServiceMetadataKey, "Unparsable string"); |
| EXPECT_TRUE(db->Commit().ok()); |
| db.reset(); |
| |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| } |
| |
| TEST_P(MetadataDatabaseTest, InitializationTest_SimpleTree) { |
| TrackedFile sync_root(CreateTrackedSyncRoot()); |
| TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id")); |
| app_root.tracker.set_app_id(app_root.metadata.details().title()); |
| app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT); |
| |
| TrackedFile file(CreateTrackedFile(app_root, "file")); |
| TrackedFile folder(CreateTrackedFolder(app_root, "folder")); |
| TrackedFile file_in_folder(CreateTrackedFile(folder, "file_in_folder")); |
| TrackedFile orphaned_file(CreateTrackedFile(sync_root, "orphaned_file")); |
| orphaned_file.metadata.mutable_details()->clear_parent_folder_ids(); |
| orphaned_file.tracker.set_parent_tracker_id(0); |
| |
| const TrackedFile* tracked_files[] = { |
| &sync_root, &app_root, &file, &folder, &file_in_folder, &orphaned_file |
| }; |
| |
| SetUpDatabaseByTrackedFiles(tracked_files, base::size(tracked_files)); |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| |
| orphaned_file.should_be_absent = true; |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| } |
| |
| TEST_P(MetadataDatabaseTest, AppManagementTest) { |
| TrackedFile sync_root(CreateTrackedSyncRoot()); |
| TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id")); |
| app_root.tracker.set_app_id(app_root.metadata.details().title()); |
| app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT); |
| |
| TrackedFile file(CreateTrackedFile(app_root, "file")); |
| TrackedFile folder(CreateTrackedFolder(sync_root, "folder")); |
| folder.tracker.set_active(false); |
| |
| const TrackedFile* tracked_files[] = { |
| &sync_root, &app_root, &file, &folder, |
| }; |
| SetUpDatabaseByTrackedFiles(tracked_files, base::size(tracked_files)); |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| |
| folder.tracker.set_app_id("foo"); |
| EXPECT_EQ(SYNC_STATUS_OK, RegisterApp( |
| folder.tracker.app_id(), folder.metadata.file_id())); |
| folder.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT); |
| folder.tracker.set_active(true); |
| folder.tracker.set_dirty(true); |
| folder.tracker.set_needs_folder_listing(true); |
| VerifyTrackedFile(folder); |
| VerifyReloadConsistency(); |
| |
| EXPECT_EQ(SYNC_STATUS_OK, DisableApp(folder.tracker.app_id())); |
| folder.tracker.set_tracker_kind(TRACKER_KIND_DISABLED_APP_ROOT); |
| VerifyTrackedFile(folder); |
| VerifyReloadConsistency(); |
| |
| EXPECT_EQ(SYNC_STATUS_OK, EnableApp(folder.tracker.app_id())); |
| folder.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT); |
| VerifyTrackedFile(folder); |
| VerifyReloadConsistency(); |
| |
| EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(folder.tracker.app_id())); |
| folder.tracker.set_app_id(std::string()); |
| folder.tracker.set_tracker_kind(TRACKER_KIND_REGULAR); |
| folder.tracker.set_active(false); |
| VerifyTrackedFile(folder); |
| VerifyReloadConsistency(); |
| |
| EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(app_root.tracker.app_id())); |
| app_root.tracker.set_app_id(std::string()); |
| app_root.tracker.set_tracker_kind(TRACKER_KIND_REGULAR); |
| app_root.tracker.set_active(false); |
| app_root.tracker.set_dirty(true); |
| file.should_be_absent = true; |
| VerifyTrackedFile(app_root); |
| VerifyTrackedFile(file); |
| VerifyReloadConsistency(); |
| } |
| |
| TEST_P(MetadataDatabaseTest, BuildPathTest) { |
| FileMetadata sync_root(CreateSyncRootMetadata()); |
| FileTracker sync_root_tracker(CreateSyncRootTracker(sync_root)); |
| |
| FileMetadata app_root(CreateFolderMetadata(sync_root, "app_id")); |
| FileTracker app_root_tracker( |
| CreateTracker(sync_root_tracker, app_root)); |
| app_root_tracker.set_app_id(app_root.details().title()); |
| app_root_tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT); |
| |
| FileMetadata folder(CreateFolderMetadata(app_root, "folder")); |
| FileTracker folder_tracker(CreateTracker(app_root_tracker, folder)); |
| |
| FileMetadata file(CreateFileMetadata(folder, "file")); |
| FileTracker file_tracker(CreateTracker(folder_tracker, file)); |
| |
| FileMetadata inactive_folder(CreateFolderMetadata(app_root, "folder")); |
| FileTracker inactive_folder_tracker(CreateTracker(app_root_tracker, |
| inactive_folder)); |
| inactive_folder_tracker.set_active(false); |
| |
| { |
| std::unique_ptr<LevelDBWrapper> db = InitializeLevelDB(); |
| ASSERT_TRUE(db); |
| |
| EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), sync_root_tracker).ok()); |
| EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), app_root_tracker).ok()); |
| EXPECT_TRUE(PutFileToDB(db.get(), folder).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker).ok()); |
| EXPECT_TRUE(PutFileToDB(db.get(), file).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), file_tracker).ok()); |
| } |
| |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| |
| base::FilePath path; |
| EXPECT_FALSE(metadata_database()->BuildPathForTracker( |
| sync_root_tracker.tracker_id(), &path)); |
| EXPECT_TRUE(metadata_database()->BuildPathForTracker( |
| app_root_tracker.tracker_id(), &path)); |
| EXPECT_EQ(base::FilePath(FPL("/")).NormalizePathSeparators(), path); |
| EXPECT_TRUE(metadata_database()->BuildPathForTracker( |
| file_tracker.tracker_id(), &path)); |
| EXPECT_EQ(base::FilePath(FPL("/folder/file")).NormalizePathSeparators(), |
| path); |
| } |
| |
| TEST_P(MetadataDatabaseTest, FindNearestActiveAncestorTest) { |
| const std::string kAppID = "app_id"; |
| |
| FileMetadata sync_root(CreateSyncRootMetadata()); |
| FileTracker sync_root_tracker(CreateSyncRootTracker(sync_root)); |
| |
| FileMetadata app_root(CreateFolderMetadata(sync_root, kAppID)); |
| FileTracker app_root_tracker( |
| CreateTracker(sync_root_tracker, app_root)); |
| app_root_tracker.set_app_id(app_root.details().title()); |
| app_root_tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT); |
| |
| // Create directory structure like this: "/folder1/folder2/file" |
| FileMetadata folder1(CreateFolderMetadata(app_root, "folder1")); |
| FileTracker folder_tracker1(CreateTracker(app_root_tracker, folder1)); |
| FileMetadata folder2(CreateFolderMetadata(folder1, "folder2")); |
| FileTracker folder_tracker2(CreateTracker(folder_tracker1, folder2)); |
| FileMetadata file(CreateFileMetadata(folder2, "file")); |
| FileTracker file_tracker(CreateTracker(folder_tracker2, file)); |
| |
| FileMetadata inactive_folder(CreateFolderMetadata(app_root, "folder1")); |
| FileTracker inactive_folder_tracker(CreateTracker(app_root_tracker, |
| inactive_folder)); |
| inactive_folder_tracker.set_active(false); |
| |
| { |
| std::unique_ptr<LevelDBWrapper> db = InitializeLevelDB(); |
| ASSERT_TRUE(db); |
| |
| EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), sync_root_tracker).ok()); |
| EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), app_root_tracker).ok()); |
| EXPECT_TRUE(PutFileToDB(db.get(), folder1).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker1).ok()); |
| EXPECT_TRUE(PutFileToDB(db.get(), folder2).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker2).ok()); |
| EXPECT_TRUE(PutFileToDB(db.get(), file).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), file_tracker).ok()); |
| EXPECT_TRUE(PutFileToDB(db.get(), inactive_folder).ok()); |
| EXPECT_TRUE(PutTrackerToDB(db.get(), inactive_folder_tracker).ok()); |
| } |
| |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| |
| { |
| base::FilePath path; |
| FileTracker tracker; |
| EXPECT_FALSE(metadata_database()->FindNearestActiveAncestor( |
| "non_registered_app_id", |
| CreateNormalizedPath(FPL("folder1/folder2/file")), |
| &tracker, &path)); |
| } |
| |
| { |
| base::FilePath path; |
| FileTracker tracker; |
| EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor( |
| kAppID, CreateNormalizedPath(FPL("")), &tracker, &path)); |
| EXPECT_EQ(app_root_tracker.tracker_id(), tracker.tracker_id()); |
| EXPECT_EQ(CreateNormalizedPath(FPL("")), path); |
| } |
| |
| { |
| base::FilePath path; |
| FileTracker tracker; |
| EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor( |
| kAppID, CreateNormalizedPath(FPL("folder1/folder2")), |
| &tracker, &path)); |
| EXPECT_EQ(folder_tracker2.tracker_id(), tracker.tracker_id()); |
| EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2")), path); |
| } |
| |
| { |
| base::FilePath path; |
| FileTracker tracker; |
| EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor( |
| kAppID, CreateNormalizedPath(FPL("folder1/folder2/file")), |
| &tracker, &path)); |
| EXPECT_EQ(file_tracker.tracker_id(), tracker.tracker_id()); |
| EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2/file")), path); |
| } |
| |
| { |
| base::FilePath path; |
| FileTracker tracker; |
| EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor( |
| kAppID, |
| CreateNormalizedPath(FPL("folder1/folder2/folder3/folder4/file")), |
| &tracker, &path)); |
| EXPECT_EQ(folder_tracker2.tracker_id(), tracker.tracker_id()); |
| EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2")), path); |
| } |
| |
| { |
| base::FilePath path; |
| FileTracker tracker; |
| EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor( |
| kAppID, CreateNormalizedPath(FPL("folder1/folder2/file/folder4/file")), |
| &tracker, &path)); |
| EXPECT_EQ(folder_tracker2.tracker_id(), tracker.tracker_id()); |
| EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2")), path); |
| } |
| } |
| |
| TEST_P(MetadataDatabaseTest, UpdateByChangeListTest) { |
| TrackedFile sync_root(CreateTrackedSyncRoot()); |
| TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id")); |
| TrackedFile disabled_app_root(CreateTrackedFolder(sync_root, "disabled_app")); |
| TrackedFile file(CreateTrackedFile(app_root, "file")); |
| TrackedFile renamed_file(CreateTrackedFile(app_root, "to be renamed")); |
| TrackedFile folder(CreateTrackedFolder(app_root, "folder")); |
| TrackedFile reorganized_file( |
| CreateTrackedFile(app_root, "to be reorganized")); |
| TrackedFile updated_file( |
| CreateTrackedFile(app_root, "to be updated")); |
| TrackedFile noop_file(CreateTrackedFile(app_root, "has noop change")); |
| TrackedFile new_file(CreateTrackedFile(app_root, "to be added later")); |
| new_file.should_be_absent = true; |
| |
| const TrackedFile* tracked_files[] = { |
| &sync_root, &app_root, &disabled_app_root, |
| &file, &renamed_file, &folder, &reorganized_file, &updated_file, &noop_file, |
| &new_file, |
| }; |
| |
| SetUpDatabaseByTrackedFiles(tracked_files, base::size(tracked_files)); |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| |
| ApplyRenameChangeToMetadata("renamed", &renamed_file.metadata); |
| ApplyReorganizeChangeToMetadata(folder.metadata.file_id(), |
| &reorganized_file.metadata); |
| ApplyContentChangeToMetadata(&updated_file.metadata); |
| |
| // Update change ID. |
| ApplyNoopChangeToMetadata(&noop_file.metadata); |
| |
| std::vector<std::unique_ptr<google_apis::ChangeResource>> changes; |
| PushToChangeList( |
| CreateChangeResourceFromMetadata(renamed_file.metadata), &changes); |
| PushToChangeList( |
| CreateChangeResourceFromMetadata(reorganized_file.metadata), &changes); |
| PushToChangeList( |
| CreateChangeResourceFromMetadata(updated_file.metadata), &changes); |
| PushToChangeList( |
| CreateChangeResourceFromMetadata(noop_file.metadata), &changes); |
| PushToChangeList( |
| CreateChangeResourceFromMetadata(new_file.metadata), &changes); |
| EXPECT_EQ(SYNC_STATUS_OK, UpdateByChangeList(std::move(changes))); |
| |
| renamed_file.tracker.set_dirty(true); |
| reorganized_file.tracker.set_dirty(true); |
| updated_file.tracker.set_dirty(true); |
| noop_file.tracker.set_dirty(true); |
| new_file.tracker.mutable_synced_details()->set_missing(true); |
| new_file.tracker.mutable_synced_details()->clear_md5(); |
| new_file.tracker.set_active(false); |
| new_file.tracker.set_dirty(true); |
| ResetTrackerID(&new_file.tracker); |
| EXPECT_NE(0, new_file.tracker.tracker_id()); |
| |
| new_file.should_be_absent = false; |
| |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| VerifyReloadConsistency(); |
| } |
| |
| TEST_P(MetadataDatabaseTest, PopulateFolderTest_RegularFolder) { |
| TrackedFile sync_root(CreateTrackedSyncRoot()); |
| TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id")); |
| app_root.tracker.set_app_id(app_root.metadata.details().title()); |
| |
| TrackedFile folder_to_populate( |
| CreateTrackedFolder(app_root, "folder_to_populate")); |
| folder_to_populate.tracker.set_needs_folder_listing(true); |
| folder_to_populate.tracker.set_dirty(true); |
| |
| TrackedFile known_file(CreateTrackedFile(folder_to_populate, "known_file")); |
| TrackedFile new_file(CreateTrackedFile(folder_to_populate, "new_file")); |
| new_file.should_be_absent = true; |
| |
| const TrackedFile* tracked_files[] = { |
| &sync_root, &app_root, &folder_to_populate, &known_file, &new_file |
| }; |
| |
| SetUpDatabaseByTrackedFiles(tracked_files, base::size(tracked_files)); |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| |
| FileIDList listed_children; |
| listed_children.push_back(known_file.metadata.file_id()); |
| listed_children.push_back(new_file.metadata.file_id()); |
| |
| EXPECT_EQ(SYNC_STATUS_OK, |
| PopulateFolder(folder_to_populate.metadata.file_id(), |
| listed_children)); |
| |
| folder_to_populate.tracker.set_dirty(false); |
| folder_to_populate.tracker.set_needs_folder_listing(false); |
| ResetTrackerID(&new_file.tracker); |
| new_file.tracker.set_dirty(true); |
| new_file.tracker.set_active(false); |
| new_file.tracker.clear_synced_details(); |
| new_file.should_be_absent = false; |
| new_file.tracker_only = true; |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| VerifyReloadConsistency(); |
| } |
| |
| TEST_P(MetadataDatabaseTest, PopulateFolderTest_InactiveFolder) { |
| TrackedFile sync_root(CreateTrackedSyncRoot()); |
| TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id")); |
| |
| TrackedFile inactive_folder(CreateTrackedFolder(app_root, "inactive_folder")); |
| inactive_folder.tracker.set_active(false); |
| inactive_folder.tracker.set_dirty(true); |
| |
| TrackedFile new_file( |
| CreateTrackedFile(inactive_folder, "file_in_inactive_folder")); |
| new_file.should_be_absent = true; |
| |
| const TrackedFile* tracked_files[] = { |
| &sync_root, &app_root, &inactive_folder, &new_file, |
| }; |
| |
| SetUpDatabaseByTrackedFiles(tracked_files, base::size(tracked_files)); |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| |
| FileIDList listed_children; |
| listed_children.push_back(new_file.metadata.file_id()); |
| |
| EXPECT_EQ(SYNC_STATUS_OK, |
| PopulateFolder(inactive_folder.metadata.file_id(), |
| listed_children)); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| VerifyReloadConsistency(); |
| } |
| |
| TEST_P(MetadataDatabaseTest, PopulateFolderTest_DisabledAppRoot) { |
| TrackedFile sync_root(CreateTrackedSyncRoot()); |
| TrackedFile disabled_app_root( |
| CreateTrackedAppRoot(sync_root, "disabled_app")); |
| disabled_app_root.tracker.set_dirty(true); |
| disabled_app_root.tracker.set_needs_folder_listing(true); |
| |
| TrackedFile known_file(CreateTrackedFile(disabled_app_root, "known_file")); |
| TrackedFile file(CreateTrackedFile(disabled_app_root, "file")); |
| file.should_be_absent = true; |
| |
| const TrackedFile* tracked_files[] = { |
| &sync_root, &disabled_app_root, &disabled_app_root, &known_file, &file, |
| }; |
| |
| SetUpDatabaseByTrackedFiles(tracked_files, base::size(tracked_files)); |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| |
| FileIDList disabled_app_children; |
| disabled_app_children.push_back(file.metadata.file_id()); |
| EXPECT_EQ(SYNC_STATUS_OK, PopulateFolder( |
| disabled_app_root.metadata.file_id(), disabled_app_children)); |
| ResetTrackerID(&file.tracker); |
| file.tracker.clear_synced_details(); |
| file.tracker.set_dirty(true); |
| file.tracker.set_active(false); |
| file.should_be_absent = false; |
| file.tracker_only = true; |
| |
| disabled_app_root.tracker.set_dirty(false); |
| disabled_app_root.tracker.set_needs_folder_listing(false); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| VerifyReloadConsistency(); |
| } |
| |
| // TODO(tzik): Fix expectation and re-enable this test. |
| TEST_P(MetadataDatabaseTest, DISABLED_UpdateTrackerTest) { |
| TrackedFile sync_root(CreateTrackedSyncRoot()); |
| TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_root")); |
| TrackedFile file(CreateTrackedFile(app_root, "file")); |
| file.tracker.set_dirty(true); |
| file.metadata.mutable_details()->set_title("renamed file"); |
| |
| TrackedFile inactive_file(CreateTrackedFile(app_root, "inactive_file")); |
| inactive_file.tracker.set_active(false); |
| inactive_file.tracker.set_dirty(true); |
| inactive_file.metadata.mutable_details()->set_title("renamed inactive file"); |
| inactive_file.metadata.mutable_details()->set_md5("modified_md5"); |
| |
| TrackedFile new_conflict(CreateTrackedFile(app_root, "new conflict file")); |
| new_conflict.tracker.set_dirty(true); |
| new_conflict.metadata.mutable_details()->set_title("renamed file"); |
| |
| const TrackedFile* tracked_files[] = { |
| &sync_root, &app_root, &file, &inactive_file, &new_conflict |
| }; |
| |
| SetUpDatabaseByTrackedFiles(tracked_files, base::size(tracked_files)); |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| VerifyReloadConsistency(); |
| |
| *file.tracker.mutable_synced_details() = file.metadata.details(); |
| file.tracker.set_dirty(false); |
| EXPECT_EQ(SYNC_STATUS_OK, UpdateTracker(file.tracker)); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| VerifyReloadConsistency(); |
| |
| *inactive_file.tracker.mutable_synced_details() = |
| inactive_file.metadata.details(); |
| inactive_file.tracker.set_dirty(false); |
| inactive_file.tracker.set_active(true); |
| EXPECT_EQ(SYNC_STATUS_OK, UpdateTracker(inactive_file.tracker)); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| VerifyReloadConsistency(); |
| |
| *new_conflict.tracker.mutable_synced_details() = |
| new_conflict.metadata.details(); |
| new_conflict.tracker.set_dirty(false); |
| new_conflict.tracker.set_active(true); |
| file.tracker.set_dirty(true); |
| file.tracker.set_active(false); |
| EXPECT_EQ(SYNC_STATUS_OK, UpdateTracker(new_conflict.tracker)); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| VerifyReloadConsistency(); |
| } |
| |
| TEST_P(MetadataDatabaseTest, PopulateInitialDataTest) { |
| TrackedFile sync_root(CreateTrackedSyncRoot()); |
| TrackedFile app_root(CreateTrackedFolder(sync_root, "app_root")); |
| app_root.tracker.set_active(false); |
| |
| const TrackedFile* tracked_files[] = { |
| &sync_root, &app_root |
| }; |
| |
| std::unique_ptr<google_apis::FileResource> sync_root_folder( |
| CreateFileResourceFromMetadata(sync_root.metadata)); |
| std::unique_ptr<google_apis::FileResource> app_root_folder( |
| CreateFileResourceFromMetadata(app_root.metadata)); |
| |
| std::vector<std::unique_ptr<google_apis::FileResource>> app_root_folders; |
| app_root_folders.push_back(std::move(app_root_folder)); |
| |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| EXPECT_EQ(SYNC_STATUS_OK, PopulateInitialData( |
| current_change_id(), |
| *sync_root_folder, |
| app_root_folders)); |
| |
| ResetTrackerID(&sync_root.tracker); |
| ResetTrackerID(&app_root.tracker); |
| app_root.tracker.set_parent_tracker_id(sync_root.tracker.tracker_id()); |
| |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| VerifyReloadConsistency(); |
| } |
| |
| TEST_P(MetadataDatabaseTest, DumpFiles) { |
| TrackedFile sync_root(CreateTrackedSyncRoot()); |
| TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id")); |
| app_root.tracker.set_app_id(app_root.metadata.details().title()); |
| |
| TrackedFile folder_0(CreateTrackedFolder(app_root, "folder_0")); |
| TrackedFile file_0(CreateTrackedFile(folder_0, "file_0")); |
| |
| const TrackedFile* tracked_files[] = { |
| &sync_root, &app_root, &folder_0, &file_0 |
| }; |
| |
| SetUpDatabaseByTrackedFiles(tracked_files, base::size(tracked_files)); |
| EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase()); |
| VerifyTrackedFiles(tracked_files, base::size(tracked_files)); |
| |
| std::unique_ptr<base::ListValue> files = |
| metadata_database()->DumpFiles(app_root.tracker.app_id()); |
| ASSERT_EQ(2u, files->GetSize()); |
| |
| base::DictionaryValue* file = nullptr; |
| std::string str; |
| |
| ASSERT_TRUE(files->GetDictionary(0, &file)); |
| EXPECT_TRUE(file->GetString("title", &str) && str == "folder_0"); |
| EXPECT_TRUE(file->GetString("type", &str) && str == "folder"); |
| EXPECT_TRUE(file->HasKey("details")); |
| |
| ASSERT_TRUE(files->GetDictionary(1, &file)); |
| EXPECT_TRUE(file->GetString("title", &str) && str == "file_0"); |
| EXPECT_TRUE(file->GetString("type", &str) && str == "file"); |
| EXPECT_TRUE(file->HasKey("details")); |
| } |
| |
| TEST_P(MetadataDatabaseTest, ClearDatabase) { |
| const bool db_on_disk = enable_on_disk_index(); |
| leveldb::Env* env = db_on_disk ? leveldb::Env::Default() : in_memory_env(); |
| std::vector<std::string> children; |
| EXPECT_TRUE(env->GetChildren(DatabasePath().AsUTF8Unsafe(), &children).ok()); |
| EXPECT_EQ(children.size(), 0ul); |
| |
| SyncStatusCode status = SYNC_STATUS_UNKNOWN; |
| std::unique_ptr<MetadataDatabase> metadata_database = |
| MetadataDatabase::CreateInternal(DatabasePath(), env, |
| enable_on_disk_index(), &status); |
| ASSERT_EQ(SYNC_STATUS_OK, status); |
| EXPECT_TRUE(env->GetChildren(DatabasePath().AsUTF8Unsafe(), &children).ok()); |
| EXPECT_GT(children.size(), 0ul); |
| |
| MetadataDatabase::ClearDatabase(std::move(metadata_database)); |
| |
| if (db_on_disk) { |
| EXPECT_FALSE(base::PathExists(DatabasePath())); |
| } else { |
| EXPECT_TRUE(base::PathExists(DatabasePath())); |
| } |
| } |
| |
| } // namespace drive_backend |
| } // namespace sync_file_system |