Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / drive_backend / metadata_database_unittest.cc
blob107f93fe92331f27526d2e101358aa267f5c849a
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
7 #include "base/bind.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
13 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_test_util.h"
14 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
15 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
16 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
17 #include "google_apis/drive/drive_api_parser.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/leveldatabase/src/include/leveldb/db.h"
20 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
22 #define FPL(a) FILE_PATH_LITERAL(a)
24 namespace sync_file_system {
25 namespace drive_backend {
27 namespace {
29 typedef MetadataDatabase::FileIDList FileIDList;
31 const int64 kInitialChangeID = 1234;
32 const int64 kSyncRootTrackerID = 100;
33 const char kSyncRootFolderID[] = "sync_root_folder_id";
35 // This struct is used to setup initial state of the database in the test and
36 // also used to match to the modified content of the database as the
37 // expectation.
38 struct TrackedFile {
39 // Holds the latest remote metadata which may be not-yet-synced to |tracker|.
40 FileMetadata metadata;
41 FileTracker tracker;
43 // Implies the file should not in the database.
44 bool should_be_absent;
46 // Implies the file should have a tracker in the database but should have no
47 // metadata.
48 bool tracker_only;
50 TrackedFile() : should_be_absent(false), tracker_only(false) {}
53 void ExpectEquivalent(const ServiceMetadata* left,
54 const ServiceMetadata* right) {
55 test_util::ExpectEquivalentServiceMetadata(*left, *right);
58 void ExpectEquivalent(const FileMetadata* left, const FileMetadata* right) {
59 if (!left) {
60 ASSERT_FALSE(right);
61 return;
63 ASSERT_TRUE(right);
64 test_util::ExpectEquivalentMetadata(*left, *right);
67 void ExpectEquivalent(const FileTracker* left, const FileTracker* right) {
68 if (!left) {
69 ASSERT_FALSE(right);
70 return;
72 ASSERT_TRUE(right);
73 test_util::ExpectEquivalentTrackers(*left, *right);
76 template <typename Container>
77 void ExpectEquivalentMaps(const Container& left, const Container& right);
78 template <typename Key, typename Value, typename Compare>
79 void ExpectEquivalent(const std::map<Key, Value, Compare>& left,
80 const std::map<Key, Value, Compare>& right) {
81 ExpectEquivalentMaps(left, right);
84 template <typename Container>
85 void ExpectEquivalentSets(const Container& left, const Container& right);
86 template <typename Value, typename Compare>
87 void ExpectEquivalent(const std::set<Value, Compare>& left,
88 const std::set<Value, Compare>& right) {
89 return ExpectEquivalentSets(left, right);
92 void ExpectEquivalent(const TrackerSet& left,
93 const TrackerSet& right) {
95 SCOPED_TRACE("Expect equivalent active_tracker");
96 ExpectEquivalent(left.active_tracker(), right.active_tracker());
98 ExpectEquivalent(left.tracker_set(), right.tracker_set());
101 template <typename Container>
102 void ExpectEquivalentMaps(const Container& left, const Container& right) {
103 ASSERT_EQ(left.size(), right.size());
105 typedef typename Container::const_iterator const_iterator;
106 const_iterator left_itr = left.begin();
107 const_iterator right_itr = right.begin();
108 while (left_itr != left.end()) {
109 EXPECT_EQ(left_itr->first, right_itr->first);
110 ExpectEquivalent(left_itr->second, right_itr->second);
111 ++left_itr;
112 ++right_itr;
116 template <typename Container>
117 void ExpectEquivalentSets(const Container& left, const Container& right) {
118 ASSERT_EQ(left.size(), right.size());
120 typedef typename Container::const_iterator const_iterator;
121 const_iterator left_itr = left.begin();
122 const_iterator right_itr = right.begin();
123 while (left_itr != left.end()) {
124 ExpectEquivalent(*left_itr, *right_itr);
125 ++left_itr;
126 ++right_itr;
130 base::FilePath CreateNormalizedPath(const base::FilePath::StringType& path) {
131 return base::FilePath(path).NormalizePathSeparators();
134 } // namespace
136 class MetadataDatabaseTest : public testing::Test {
137 public:
138 MetadataDatabaseTest()
139 : current_change_id_(kInitialChangeID),
140 next_tracker_id_(kSyncRootTrackerID + 1),
141 next_file_id_number_(1),
142 next_md5_sequence_number_(1) {}
144 virtual ~MetadataDatabaseTest() {}
146 virtual void SetUp() OVERRIDE {
147 ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
150 virtual void TearDown() OVERRIDE { DropDatabase(); }
152 protected:
153 std::string GenerateFileID() {
154 return "file_id_" + base::Int64ToString(next_file_id_number_++);
157 int64 GetTrackerIDByFileID(const std::string& file_id) {
158 TrackerSet trackers;
159 if (metadata_database_->FindTrackersByFileID(file_id, &trackers)) {
160 EXPECT_FALSE(trackers.empty());
161 return (*trackers.begin())->tracker_id();
163 return 0;
166 SyncStatusCode InitializeMetadataDatabase() {
167 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
168 MetadataDatabase::Create(base::MessageLoopProxy::current(),
169 database_dir_.path(),
170 CreateResultReceiver(&status,
171 &metadata_database_));
172 message_loop_.RunUntilIdle();
173 return status;
176 void DropDatabase() {
177 metadata_database_.reset();
178 message_loop_.RunUntilIdle();
181 void SetUpDatabaseByTrackedFiles(const TrackedFile** tracked_files,
182 int size) {
183 scoped_ptr<leveldb::DB> db = InitializeLevelDB();
184 ASSERT_TRUE(db);
186 for (int i = 0; i < size; ++i) {
187 const TrackedFile* file = tracked_files[i];
188 if (file->should_be_absent)
189 continue;
190 if (!file->tracker_only)
191 EXPECT_TRUE(PutFileToDB(db.get(), file->metadata).ok());
192 EXPECT_TRUE(PutTrackerToDB(db.get(), file->tracker).ok());
196 void VerifyTrackedFile(const TrackedFile& file) {
197 if (!file.should_be_absent) {
198 if (file.tracker_only) {
199 EXPECT_FALSE(metadata_database()->FindFileByFileID(
200 file.metadata.file_id(), NULL));
201 } else {
202 VerifyFile(file.metadata);
204 VerifyTracker(file.tracker);
205 return;
208 EXPECT_FALSE(metadata_database()->FindFileByFileID(
209 file.metadata.file_id(), NULL));
210 EXPECT_FALSE(metadata_database()->FindTrackerByTrackerID(
211 file.tracker.tracker_id(), NULL));
214 void VerifyTrackedFiles(const TrackedFile** tracked_files, int size) {
215 for (int i = 0; i < size; ++i)
216 VerifyTrackedFile(*tracked_files[i]);
219 MetadataDatabase* metadata_database() { return metadata_database_.get(); }
221 scoped_ptr<leveldb::DB> InitializeLevelDB() {
222 leveldb::DB* db = NULL;
223 leveldb::Options options;
224 options.create_if_missing = true;
225 options.max_open_files = 0; // Use minimum.
226 leveldb::Status status =
227 leveldb::DB::Open(options, database_dir_.path().AsUTF8Unsafe(), &db);
228 EXPECT_TRUE(status.ok());
230 db->Put(leveldb::WriteOptions(),
231 kDatabaseVersionKey,
232 base::Int64ToString(3));
233 SetUpServiceMetadata(db);
235 return make_scoped_ptr(db);
238 void SetUpServiceMetadata(leveldb::DB* db) {
239 ServiceMetadata service_metadata;
240 service_metadata.set_largest_change_id(kInitialChangeID);
241 service_metadata.set_sync_root_tracker_id(kSyncRootTrackerID);
242 service_metadata.set_next_tracker_id(next_tracker_id_);
243 leveldb::WriteBatch batch;
244 PutServiceMetadataToBatch(service_metadata, &batch);
245 EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
248 FileMetadata CreateSyncRootMetadata() {
249 FileMetadata sync_root;
250 sync_root.set_file_id(kSyncRootFolderID);
251 FileDetails* details = sync_root.mutable_details();
252 details->set_title(kSyncRootFolderTitle);
253 details->set_file_kind(FILE_KIND_FOLDER);
254 return sync_root;
257 FileMetadata CreateFileMetadata(const FileMetadata& parent,
258 const std::string& title) {
259 FileMetadata file;
260 file.set_file_id(GenerateFileID());
261 FileDetails* details = file.mutable_details();
262 details->add_parent_folder_ids(parent.file_id());
263 details->set_title(title);
264 details->set_file_kind(FILE_KIND_FILE);
265 details->set_md5(
266 "md5_value_" + base::Int64ToString(next_md5_sequence_number_++));
267 return file;
270 FileMetadata CreateFolderMetadata(const FileMetadata& parent,
271 const std::string& title) {
272 FileMetadata folder;
273 folder.set_file_id(GenerateFileID());
274 FileDetails* details = folder.mutable_details();
275 details->add_parent_folder_ids(parent.file_id());
276 details->set_title(title);
277 details->set_file_kind(FILE_KIND_FOLDER);
278 return folder;
281 FileTracker CreateSyncRootTracker(const FileMetadata& sync_root) {
282 FileTracker sync_root_tracker;
283 sync_root_tracker.set_tracker_id(kSyncRootTrackerID);
284 sync_root_tracker.set_parent_tracker_id(0);
285 sync_root_tracker.set_file_id(sync_root.file_id());
286 sync_root_tracker.set_dirty(false);
287 sync_root_tracker.set_active(true);
288 sync_root_tracker.set_needs_folder_listing(false);
289 *sync_root_tracker.mutable_synced_details() = sync_root.details();
290 return sync_root_tracker;
293 FileTracker CreateTracker(const FileTracker& parent_tracker,
294 const FileMetadata& file) {
295 FileTracker tracker;
296 tracker.set_tracker_id(next_tracker_id_++);
297 tracker.set_parent_tracker_id(parent_tracker.tracker_id());
298 tracker.set_file_id(file.file_id());
299 tracker.set_app_id(parent_tracker.app_id());
300 tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
301 tracker.set_dirty(false);
302 tracker.set_active(true);
303 tracker.set_needs_folder_listing(false);
304 *tracker.mutable_synced_details() = file.details();
305 return tracker;
308 TrackedFile CreateTrackedSyncRoot() {
309 TrackedFile sync_root;
310 sync_root.metadata = CreateSyncRootMetadata();
311 sync_root.tracker = CreateSyncRootTracker(sync_root.metadata);
312 return sync_root;
315 TrackedFile CreateTrackedAppRoot(const TrackedFile& sync_root,
316 const std::string& app_id) {
317 TrackedFile app_root(CreateTrackedFolder(sync_root, app_id));
318 app_root.tracker.set_app_id(app_id);
319 app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
320 return app_root;
323 TrackedFile CreateTrackedFile(const TrackedFile& parent,
324 const std::string& title) {
325 TrackedFile file;
326 file.metadata = CreateFileMetadata(parent.metadata, title);
327 file.tracker = CreateTracker(parent.tracker, file.metadata);
328 return file;
331 TrackedFile CreateTrackedFolder(const TrackedFile& parent,
332 const std::string& title) {
333 TrackedFile folder;
334 folder.metadata = CreateFolderMetadata(parent.metadata, title);
335 folder.tracker = CreateTracker(parent.tracker, folder.metadata);
336 return folder;
339 scoped_ptr<google_apis::FileResource> CreateFileResourceFromMetadata(
340 const FileMetadata& file) {
341 scoped_ptr<google_apis::FileResource> file_resource(
342 new google_apis::FileResource);
343 ScopedVector<google_apis::ParentReference> parents;
344 for (int i = 0; i < file.details().parent_folder_ids_size(); ++i) {
345 scoped_ptr<google_apis::ParentReference> parent(
346 new google_apis::ParentReference);
347 parent->set_file_id(file.details().parent_folder_ids(i));
348 parents.push_back(parent.release());
351 file_resource->set_file_id(file.file_id());
352 file_resource->set_parents(parents.Pass());
353 file_resource->set_title(file.details().title());
354 if (file.details().file_kind() == FILE_KIND_FOLDER)
355 file_resource->set_mime_type("application/vnd.google-apps.folder");
356 else if (file.details().file_kind() == FILE_KIND_FILE)
357 file_resource->set_mime_type("text/plain");
358 else
359 file_resource->set_mime_type("application/vnd.google-apps.document");
360 file_resource->set_md5_checksum(file.details().md5());
361 file_resource->set_etag(file.details().etag());
362 file_resource->set_created_date(base::Time::FromInternalValue(
363 file.details().creation_time()));
364 file_resource->set_modified_date(base::Time::FromInternalValue(
365 file.details().modification_time()));
367 return file_resource.Pass();
370 scoped_ptr<google_apis::ChangeResource> CreateChangeResourceFromMetadata(
371 const FileMetadata& file) {
372 scoped_ptr<google_apis::ChangeResource> change(
373 new google_apis::ChangeResource);
374 change->set_change_id(file.details().change_id());
375 change->set_file_id(file.file_id());
376 change->set_deleted(file.details().missing());
377 if (change->is_deleted())
378 return change.Pass();
380 change->set_file(CreateFileResourceFromMetadata(file));
381 return change.Pass();
384 void ApplyRenameChangeToMetadata(const std::string& new_title,
385 FileMetadata* file) {
386 FileDetails* details = file->mutable_details();
387 details->set_title(new_title);
388 details->set_change_id(++current_change_id_);
391 void ApplyReorganizeChangeToMetadata(const std::string& new_parent,
392 FileMetadata* file) {
393 FileDetails* details = file->mutable_details();
394 details->clear_parent_folder_ids();
395 details->add_parent_folder_ids(new_parent);
396 details->set_change_id(++current_change_id_);
399 void ApplyContentChangeToMetadata(FileMetadata* file) {
400 FileDetails* details = file->mutable_details();
401 details->set_md5(
402 "md5_value_" + base::Int64ToString(next_md5_sequence_number_++));
403 details->set_change_id(++current_change_id_);
406 void ApplyNoopChangeToMetadata(FileMetadata* file) {
407 file->mutable_details()->set_change_id(++current_change_id_);
410 void PushToChangeList(scoped_ptr<google_apis::ChangeResource> change,
411 ScopedVector<google_apis::ChangeResource>* changes) {
412 changes->push_back(change.release());
415 leveldb::Status PutFileToDB(leveldb::DB* db, const FileMetadata& file) {
416 leveldb::WriteBatch batch;
417 PutFileToBatch(file, &batch);
418 return db->Write(leveldb::WriteOptions(), &batch);
421 leveldb::Status PutTrackerToDB(leveldb::DB* db,
422 const FileTracker& tracker) {
423 leveldb::WriteBatch batch;
424 PutTrackerToBatch(tracker, &batch);
425 return db->Write(leveldb::WriteOptions(), &batch);
428 void VerifyReloadConsistency() {
429 scoped_ptr<MetadataDatabase> metadata_database_2;
430 ASSERT_EQ(SYNC_STATUS_OK,
431 MetadataDatabase::CreateForTesting(
432 metadata_database_->db_.Pass(),
433 &metadata_database_2));
434 metadata_database_->db_ = metadata_database_2->db_.Pass();
437 SCOPED_TRACE("Expect equivalent service_metadata");
438 ExpectEquivalent(metadata_database_->service_metadata_.get(),
439 metadata_database_2->service_metadata_.get());
443 SCOPED_TRACE("Expect equivalent file_by_id_ contents.");
444 ExpectEquivalent(metadata_database_->file_by_id_,
445 metadata_database_2->file_by_id_);
449 SCOPED_TRACE("Expect equivalent tracker_by_id_ contents.");
450 ExpectEquivalent(metadata_database_->tracker_by_id_,
451 metadata_database_2->tracker_by_id_);
455 SCOPED_TRACE("Expect equivalent trackers_by_file_id_ contents.");
456 ExpectEquivalent(metadata_database_->trackers_by_file_id_,
457 metadata_database_2->trackers_by_file_id_);
461 SCOPED_TRACE("Expect equivalent app_root_by_app_id_ contents.");
462 ExpectEquivalent(metadata_database_->app_root_by_app_id_,
463 metadata_database_2->app_root_by_app_id_);
467 SCOPED_TRACE("Expect equivalent trackers_by_parent_and_title_ contents.");
468 ExpectEquivalent(metadata_database_->trackers_by_parent_and_title_,
469 metadata_database_2->trackers_by_parent_and_title_);
473 SCOPED_TRACE("Expect equivalent dirty_trackers_ contents.");
474 ExpectEquivalent(metadata_database_->dirty_trackers_,
475 metadata_database_2->dirty_trackers_);
479 void VerifyFile(const FileMetadata& file) {
480 FileMetadata file_in_metadata_database;
481 ASSERT_TRUE(metadata_database()->FindFileByFileID(
482 file.file_id(), &file_in_metadata_database));
484 SCOPED_TRACE("Expect equivalent " + file.file_id());
485 ExpectEquivalent(&file, &file_in_metadata_database);
488 void VerifyTracker(const FileTracker& tracker) {
489 FileTracker tracker_in_metadata_database;
490 ASSERT_TRUE(metadata_database()->FindTrackerByTrackerID(
491 tracker.tracker_id(), &tracker_in_metadata_database));
493 SCOPED_TRACE("Expect equivalent tracker[" +
494 base::Int64ToString(tracker.tracker_id()) + "]");
495 ExpectEquivalent(&tracker, &tracker_in_metadata_database);
498 SyncStatusCode RegisterApp(const std::string& app_id,
499 const std::string& folder_id) {
500 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
501 metadata_database_->RegisterApp(
502 app_id, folder_id,
503 CreateResultReceiver(&status));
504 message_loop_.RunUntilIdle();
505 return status;
508 SyncStatusCode DisableApp(const std::string& app_id) {
509 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
510 metadata_database_->DisableApp(
511 app_id, CreateResultReceiver(&status));
512 message_loop_.RunUntilIdle();
513 return status;
516 SyncStatusCode EnableApp(const std::string& app_id) {
517 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
518 metadata_database_->EnableApp(
519 app_id, CreateResultReceiver(&status));
520 message_loop_.RunUntilIdle();
521 return status;
524 SyncStatusCode UnregisterApp(const std::string& app_id) {
525 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
526 metadata_database_->UnregisterApp(
527 app_id, CreateResultReceiver(&status));
528 message_loop_.RunUntilIdle();
529 return status;
532 SyncStatusCode UpdateByChangeList(
533 ScopedVector<google_apis::ChangeResource> changes) {
534 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
535 metadata_database_->UpdateByChangeList(
536 current_change_id_,
537 changes.Pass(), CreateResultReceiver(&status));
538 message_loop_.RunUntilIdle();
539 return status;
542 SyncStatusCode PopulateFolder(const std::string& folder_id,
543 const FileIDList& listed_children) {
544 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
545 metadata_database_->PopulateFolderByChildList(
546 folder_id, listed_children,
547 CreateResultReceiver(&status));
548 message_loop_.RunUntilIdle();
549 return status;
552 SyncStatusCode UpdateTracker(const FileTracker& tracker) {
553 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
554 metadata_database_->UpdateTracker(
555 tracker.tracker_id(), tracker.synced_details(),
556 CreateResultReceiver(&status));
557 message_loop_.RunUntilIdle();
558 return status;
561 SyncStatusCode PopulateInitialData(
562 int64 largest_change_id,
563 const google_apis::FileResource& sync_root_folder,
564 const ScopedVector<google_apis::FileResource>& app_root_folders) {
565 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
566 metadata_database_->PopulateInitialData(
567 largest_change_id,
568 sync_root_folder,
569 app_root_folders,
570 CreateResultReceiver(&status));
571 message_loop_.RunUntilIdle();
572 return status;
575 void ResetTrackerID(FileTracker* tracker) {
576 tracker->set_tracker_id(GetTrackerIDByFileID(tracker->file_id()));
579 private:
580 base::ScopedTempDir database_dir_;
581 base::MessageLoop message_loop_;
583 scoped_ptr<MetadataDatabase> metadata_database_;
585 int64 current_change_id_;
586 int64 next_tracker_id_;
587 int64 next_file_id_number_;
588 int64 next_md5_sequence_number_;
590 DISALLOW_COPY_AND_ASSIGN(MetadataDatabaseTest);
593 TEST_F(MetadataDatabaseTest, InitializationTest_Empty) {
594 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
595 DropDatabase();
596 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
599 TEST_F(MetadataDatabaseTest, InitializationTest_SimpleTree) {
600 TrackedFile sync_root(CreateTrackedSyncRoot());
601 TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id"));
602 app_root.tracker.set_app_id(app_root.metadata.details().title());
603 app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
605 TrackedFile file(CreateTrackedFile(app_root, "file"));
606 TrackedFile folder(CreateTrackedFolder(app_root, "folder"));
607 TrackedFile file_in_folder(CreateTrackedFile(folder, "file_in_folder"));
608 TrackedFile orphaned_file(CreateTrackedFile(sync_root, "orphaned_file"));
609 orphaned_file.metadata.mutable_details()->clear_parent_folder_ids();
610 orphaned_file.tracker.set_parent_tracker_id(0);
612 const TrackedFile* tracked_files[] = {
613 &sync_root, &app_root, &file, &folder, &file_in_folder, &orphaned_file
616 SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
617 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
619 orphaned_file.should_be_absent = true;
620 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
623 TEST_F(MetadataDatabaseTest, AppManagementTest) {
624 TrackedFile sync_root(CreateTrackedSyncRoot());
625 TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id"));
626 app_root.tracker.set_app_id(app_root.metadata.details().title());
627 app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
629 TrackedFile file(CreateTrackedFile(app_root, "file"));
630 TrackedFile folder(CreateTrackedFolder(sync_root, "folder"));
631 folder.tracker.set_active(false);
633 const TrackedFile* tracked_files[] = {
634 &sync_root, &app_root, &file, &folder,
636 SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
637 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
638 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
640 folder.tracker.set_app_id("foo");
641 EXPECT_EQ(SYNC_STATUS_OK, RegisterApp(
642 folder.tracker.app_id(), folder.metadata.file_id()));
643 folder.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
644 folder.tracker.set_active(true);
645 folder.tracker.set_dirty(true);
646 folder.tracker.set_needs_folder_listing(true);
647 VerifyTrackedFile(folder);
648 VerifyReloadConsistency();
650 EXPECT_EQ(SYNC_STATUS_OK, DisableApp(folder.tracker.app_id()));
651 folder.tracker.set_tracker_kind(TRACKER_KIND_DISABLED_APP_ROOT);
652 VerifyTrackedFile(folder);
653 VerifyReloadConsistency();
655 EXPECT_EQ(SYNC_STATUS_OK, EnableApp(folder.tracker.app_id()));
656 folder.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
657 VerifyTrackedFile(folder);
658 VerifyReloadConsistency();
660 EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(folder.tracker.app_id()));
661 folder.tracker.set_app_id(std::string());
662 folder.tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
663 folder.tracker.set_active(false);
664 VerifyTrackedFile(folder);
665 VerifyReloadConsistency();
667 EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(app_root.tracker.app_id()));
668 app_root.tracker.set_app_id(std::string());
669 app_root.tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
670 app_root.tracker.set_active(false);
671 app_root.tracker.set_dirty(true);
672 file.should_be_absent = true;
673 VerifyTrackedFile(app_root);
674 VerifyTrackedFile(file);
675 VerifyReloadConsistency();
678 TEST_F(MetadataDatabaseTest, BuildPathTest) {
679 FileMetadata sync_root(CreateSyncRootMetadata());
680 FileTracker sync_root_tracker(CreateSyncRootTracker(sync_root));
682 FileMetadata app_root(CreateFolderMetadata(sync_root, "app_id"));
683 FileTracker app_root_tracker(
684 CreateTracker(sync_root_tracker, app_root));
685 app_root_tracker.set_app_id(app_root.details().title());
686 app_root_tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
688 FileMetadata folder(CreateFolderMetadata(app_root, "folder"));
689 FileTracker folder_tracker(CreateTracker(app_root_tracker, folder));
691 FileMetadata file(CreateFileMetadata(folder, "file"));
692 FileTracker file_tracker(CreateTracker(folder_tracker, file));
694 FileMetadata inactive_folder(CreateFolderMetadata(app_root, "folder"));
695 FileTracker inactive_folder_tracker(CreateTracker(app_root_tracker,
696 inactive_folder));
697 inactive_folder_tracker.set_active(false);
700 scoped_ptr<leveldb::DB> db = InitializeLevelDB();
701 ASSERT_TRUE(db);
703 EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
704 EXPECT_TRUE(PutTrackerToDB(db.get(), sync_root_tracker).ok());
705 EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
706 EXPECT_TRUE(PutTrackerToDB(db.get(), app_root_tracker).ok());
707 EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
708 EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker).ok());
709 EXPECT_TRUE(PutFileToDB(db.get(), file).ok());
710 EXPECT_TRUE(PutTrackerToDB(db.get(), file_tracker).ok());
713 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
715 base::FilePath path;
716 EXPECT_FALSE(metadata_database()->BuildPathForTracker(
717 sync_root_tracker.tracker_id(), &path));
718 EXPECT_TRUE(metadata_database()->BuildPathForTracker(
719 app_root_tracker.tracker_id(), &path));
720 EXPECT_EQ(base::FilePath(FPL("/")).NormalizePathSeparators(), path);
721 EXPECT_TRUE(metadata_database()->BuildPathForTracker(
722 file_tracker.tracker_id(), &path));
723 EXPECT_EQ(base::FilePath(FPL("/folder/file")).NormalizePathSeparators(),
724 path);
727 TEST_F(MetadataDatabaseTest, FindNearestActiveAncestorTest) {
728 const std::string kAppID = "app_id";
730 FileMetadata sync_root(CreateSyncRootMetadata());
731 FileTracker sync_root_tracker(CreateSyncRootTracker(sync_root));
733 FileMetadata app_root(CreateFolderMetadata(sync_root, kAppID));
734 FileTracker app_root_tracker(
735 CreateTracker(sync_root_tracker, app_root));
736 app_root_tracker.set_app_id(app_root.details().title());
737 app_root_tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
739 // Create directory structure like this: "/folder1/folder2/file"
740 FileMetadata folder1(CreateFolderMetadata(app_root, "folder1"));
741 FileTracker folder_tracker1(CreateTracker(app_root_tracker, folder1));
742 FileMetadata folder2(CreateFolderMetadata(folder1, "folder2"));
743 FileTracker folder_tracker2(CreateTracker(folder_tracker1, folder2));
744 FileMetadata file(CreateFileMetadata(folder2, "file"));
745 FileTracker file_tracker(CreateTracker(folder_tracker2, file));
747 FileMetadata inactive_folder(CreateFolderMetadata(app_root, "folder1"));
748 FileTracker inactive_folder_tracker(CreateTracker(app_root_tracker,
749 inactive_folder));
750 inactive_folder_tracker.set_active(false);
753 scoped_ptr<leveldb::DB> db = InitializeLevelDB();
754 ASSERT_TRUE(db);
756 EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
757 EXPECT_TRUE(PutTrackerToDB(db.get(), sync_root_tracker).ok());
758 EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
759 EXPECT_TRUE(PutTrackerToDB(db.get(), app_root_tracker).ok());
760 EXPECT_TRUE(PutFileToDB(db.get(), folder1).ok());
761 EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker1).ok());
762 EXPECT_TRUE(PutFileToDB(db.get(), folder2).ok());
763 EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker2).ok());
764 EXPECT_TRUE(PutFileToDB(db.get(), file).ok());
765 EXPECT_TRUE(PutTrackerToDB(db.get(), file_tracker).ok());
766 EXPECT_TRUE(PutFileToDB(db.get(), inactive_folder).ok());
767 EXPECT_TRUE(PutTrackerToDB(db.get(), inactive_folder_tracker).ok());
770 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
773 base::FilePath path;
774 FileTracker tracker;
775 EXPECT_FALSE(metadata_database()->FindNearestActiveAncestor(
776 "non_registered_app_id",
777 CreateNormalizedPath(FPL("folder1/folder2/file")),
778 &tracker, &path));
782 base::FilePath path;
783 FileTracker tracker;
784 EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor(
785 kAppID, CreateNormalizedPath(FPL("")), &tracker, &path));
786 EXPECT_EQ(app_root_tracker.tracker_id(), tracker.tracker_id());
787 EXPECT_EQ(CreateNormalizedPath(FPL("")), path);
791 base::FilePath path;
792 FileTracker tracker;
793 EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor(
794 kAppID, CreateNormalizedPath(FPL("folder1/folder2")),
795 &tracker, &path));
796 EXPECT_EQ(folder_tracker2.tracker_id(), tracker.tracker_id());
797 EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2")), path);
801 base::FilePath path;
802 FileTracker tracker;
803 EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor(
804 kAppID, CreateNormalizedPath(FPL("folder1/folder2/file")),
805 &tracker, &path));
806 EXPECT_EQ(file_tracker.tracker_id(), tracker.tracker_id());
807 EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2/file")), path);
811 base::FilePath path;
812 FileTracker tracker;
813 EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor(
814 kAppID,
815 CreateNormalizedPath(FPL("folder1/folder2/folder3/folder4/file")),
816 &tracker, &path));
817 EXPECT_EQ(folder_tracker2.tracker_id(), tracker.tracker_id());
818 EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2")), path);
822 base::FilePath path;
823 FileTracker tracker;
824 EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor(
825 kAppID, CreateNormalizedPath(FPL("folder1/folder2/file/folder4/file")),
826 &tracker, &path));
827 EXPECT_EQ(folder_tracker2.tracker_id(), tracker.tracker_id());
828 EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2")), path);
832 TEST_F(MetadataDatabaseTest, UpdateByChangeListTest) {
833 TrackedFile sync_root(CreateTrackedSyncRoot());
834 TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id"));
835 TrackedFile disabled_app_root(CreateTrackedFolder(sync_root, "disabled_app"));
836 TrackedFile file(CreateTrackedFile(app_root, "file"));
837 TrackedFile renamed_file(CreateTrackedFile(app_root, "to be renamed"));
838 TrackedFile folder(CreateTrackedFolder(app_root, "folder"));
839 TrackedFile reorganized_file(
840 CreateTrackedFile(app_root, "to be reorganized"));
841 TrackedFile updated_file(
842 CreateTrackedFile(app_root, "to be updated"));
843 TrackedFile noop_file(CreateTrackedFile(app_root, "has noop change"));
844 TrackedFile new_file(CreateTrackedFile(app_root, "to be added later"));
845 new_file.should_be_absent = true;
847 const TrackedFile* tracked_files[] = {
848 &sync_root, &app_root, &disabled_app_root,
849 &file, &renamed_file, &folder, &reorganized_file, &updated_file, &noop_file,
850 &new_file,
853 SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
854 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
856 ApplyRenameChangeToMetadata("renamed", &renamed_file.metadata);
857 ApplyReorganizeChangeToMetadata(folder.metadata.file_id(),
858 &reorganized_file.metadata);
859 ApplyContentChangeToMetadata(&updated_file.metadata);
861 // Update change ID.
862 ApplyNoopChangeToMetadata(&noop_file.metadata);
864 ScopedVector<google_apis::ChangeResource> changes;
865 PushToChangeList(
866 CreateChangeResourceFromMetadata(renamed_file.metadata), &changes);
867 PushToChangeList(
868 CreateChangeResourceFromMetadata(reorganized_file.metadata), &changes);
869 PushToChangeList(
870 CreateChangeResourceFromMetadata(updated_file.metadata), &changes);
871 PushToChangeList(
872 CreateChangeResourceFromMetadata(noop_file.metadata), &changes);
873 PushToChangeList(
874 CreateChangeResourceFromMetadata(new_file.metadata), &changes);
875 EXPECT_EQ(SYNC_STATUS_OK, UpdateByChangeList(changes.Pass()));
877 renamed_file.tracker.set_dirty(true);
878 reorganized_file.tracker.set_dirty(true);
879 updated_file.tracker.set_dirty(true);
880 noop_file.tracker.set_dirty(true);
881 new_file.tracker.mutable_synced_details()->set_missing(true);
882 new_file.tracker.mutable_synced_details()->clear_md5();
883 new_file.tracker.set_active(false);
884 new_file.tracker.set_dirty(true);
885 ResetTrackerID(&new_file.tracker);
886 EXPECT_NE(0, new_file.tracker.tracker_id());
888 new_file.should_be_absent = false;
890 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
891 VerifyReloadConsistency();
894 TEST_F(MetadataDatabaseTest, PopulateFolderTest_RegularFolder) {
895 TrackedFile sync_root(CreateTrackedSyncRoot());
896 TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id"));
897 app_root.tracker.set_app_id(app_root.metadata.details().title());
899 TrackedFile folder_to_populate(
900 CreateTrackedFolder(app_root, "folder_to_populate"));
901 folder_to_populate.tracker.set_needs_folder_listing(true);
902 folder_to_populate.tracker.set_dirty(true);
904 TrackedFile known_file(CreateTrackedFile(folder_to_populate, "known_file"));
905 TrackedFile new_file(CreateTrackedFile(folder_to_populate, "new_file"));
906 new_file.should_be_absent = true;
908 const TrackedFile* tracked_files[] = {
909 &sync_root, &app_root, &folder_to_populate, &known_file, &new_file
912 SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
913 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
914 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
916 FileIDList listed_children;
917 listed_children.push_back(known_file.metadata.file_id());
918 listed_children.push_back(new_file.metadata.file_id());
920 EXPECT_EQ(SYNC_STATUS_OK,
921 PopulateFolder(folder_to_populate.metadata.file_id(),
922 listed_children));
924 folder_to_populate.tracker.set_dirty(false);
925 folder_to_populate.tracker.set_needs_folder_listing(false);
926 ResetTrackerID(&new_file.tracker);
927 new_file.tracker.set_dirty(true);
928 new_file.tracker.set_active(false);
929 new_file.tracker.clear_synced_details();
930 new_file.should_be_absent = false;
931 new_file.tracker_only = true;
932 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
933 VerifyReloadConsistency();
936 TEST_F(MetadataDatabaseTest, PopulateFolderTest_InactiveFolder) {
937 TrackedFile sync_root(CreateTrackedSyncRoot());
938 TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id"));
940 TrackedFile inactive_folder(CreateTrackedFolder(app_root, "inactive_folder"));
941 inactive_folder.tracker.set_active(false);
942 inactive_folder.tracker.set_dirty(true);
944 TrackedFile new_file(
945 CreateTrackedFile(inactive_folder, "file_in_inactive_folder"));
946 new_file.should_be_absent = true;
948 const TrackedFile* tracked_files[] = {
949 &sync_root, &app_root, &inactive_folder, &new_file,
952 SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
953 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
954 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
956 FileIDList listed_children;
957 listed_children.push_back(new_file.metadata.file_id());
959 EXPECT_EQ(SYNC_STATUS_OK,
960 PopulateFolder(inactive_folder.metadata.file_id(),
961 listed_children));
962 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
963 VerifyReloadConsistency();
966 TEST_F(MetadataDatabaseTest, PopulateFolderTest_DisabledAppRoot) {
967 TrackedFile sync_root(CreateTrackedSyncRoot());
968 TrackedFile disabled_app_root(
969 CreateTrackedAppRoot(sync_root, "disabled_app"));
970 disabled_app_root.tracker.set_dirty(true);
971 disabled_app_root.tracker.set_needs_folder_listing(true);
973 TrackedFile known_file(CreateTrackedFile(disabled_app_root, "known_file"));
974 TrackedFile file(CreateTrackedFile(disabled_app_root, "file"));
975 file.should_be_absent = true;
977 const TrackedFile* tracked_files[] = {
978 &sync_root, &disabled_app_root, &disabled_app_root, &known_file, &file,
981 SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
982 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
983 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
985 FileIDList disabled_app_children;
986 disabled_app_children.push_back(file.metadata.file_id());
987 EXPECT_EQ(SYNC_STATUS_OK, PopulateFolder(
988 disabled_app_root.metadata.file_id(), disabled_app_children));
989 ResetTrackerID(&file.tracker);
990 file.tracker.clear_synced_details();
991 file.tracker.set_dirty(true);
992 file.tracker.set_active(false);
993 file.should_be_absent = false;
994 file.tracker_only = true;
996 disabled_app_root.tracker.set_dirty(false);
997 disabled_app_root.tracker.set_needs_folder_listing(false);
998 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
999 VerifyReloadConsistency();
1002 // TODO(tzik): Fix expectation and re-enable this test.
1003 TEST_F(MetadataDatabaseTest, DISABLED_UpdateTrackerTest) {
1004 TrackedFile sync_root(CreateTrackedSyncRoot());
1005 TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_root"));
1006 TrackedFile file(CreateTrackedFile(app_root, "file"));
1007 file.tracker.set_dirty(true);
1008 file.metadata.mutable_details()->set_title("renamed file");
1010 TrackedFile inactive_file(CreateTrackedFile(app_root, "inactive_file"));
1011 inactive_file.tracker.set_active(false);
1012 inactive_file.tracker.set_dirty(true);
1013 inactive_file.metadata.mutable_details()->set_title("renamed inactive file");
1014 inactive_file.metadata.mutable_details()->set_md5("modified_md5");
1016 TrackedFile new_conflict(CreateTrackedFile(app_root, "new conflict file"));
1017 new_conflict.tracker.set_dirty(true);
1018 new_conflict.metadata.mutable_details()->set_title("renamed file");
1020 const TrackedFile* tracked_files[] = {
1021 &sync_root, &app_root, &file, &inactive_file, &new_conflict
1024 SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
1025 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
1026 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
1027 VerifyReloadConsistency();
1029 *file.tracker.mutable_synced_details() = file.metadata.details();
1030 file.tracker.set_dirty(false);
1031 EXPECT_EQ(SYNC_STATUS_OK, UpdateTracker(file.tracker));
1032 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
1033 VerifyReloadConsistency();
1035 *inactive_file.tracker.mutable_synced_details() =
1036 inactive_file.metadata.details();
1037 inactive_file.tracker.set_dirty(false);
1038 inactive_file.tracker.set_active(true);
1039 EXPECT_EQ(SYNC_STATUS_OK, UpdateTracker(inactive_file.tracker));
1040 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
1041 VerifyReloadConsistency();
1043 *new_conflict.tracker.mutable_synced_details() =
1044 new_conflict.metadata.details();
1045 new_conflict.tracker.set_dirty(false);
1046 new_conflict.tracker.set_active(true);
1047 file.tracker.set_dirty(true);
1048 file.tracker.set_active(false);
1049 EXPECT_EQ(SYNC_STATUS_OK, UpdateTracker(new_conflict.tracker));
1050 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
1051 VerifyReloadConsistency();
1054 TEST_F(MetadataDatabaseTest, PopulateInitialDataTest) {
1055 TrackedFile sync_root(CreateTrackedSyncRoot());
1056 TrackedFile app_root(CreateTrackedFolder(sync_root, "app_root"));
1057 app_root.tracker.set_active(false);
1059 const TrackedFile* tracked_files[] = {
1060 &sync_root, &app_root
1063 int64 largest_change_id = 42;
1064 scoped_ptr<google_apis::FileResource> sync_root_folder(
1065 CreateFileResourceFromMetadata(sync_root.metadata));
1066 scoped_ptr<google_apis::FileResource> app_root_folder(
1067 CreateFileResourceFromMetadata(app_root.metadata));
1069 ScopedVector<google_apis::FileResource> app_root_folders;
1070 app_root_folders.push_back(app_root_folder.release());
1072 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
1073 EXPECT_EQ(SYNC_STATUS_OK, PopulateInitialData(
1074 largest_change_id,
1075 *sync_root_folder,
1076 app_root_folders));
1078 ResetTrackerID(&sync_root.tracker);
1079 ResetTrackerID(&app_root.tracker);
1080 app_root.tracker.set_parent_tracker_id(sync_root.tracker.tracker_id());
1082 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
1083 VerifyReloadConsistency();
1086 TEST_F(MetadataDatabaseTest, DumpFiles) {
1087 TrackedFile sync_root(CreateTrackedSyncRoot());
1088 TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id"));
1089 app_root.tracker.set_app_id(app_root.metadata.details().title());
1091 TrackedFile folder_0(CreateTrackedFolder(app_root, "folder_0"));
1092 TrackedFile file_0(CreateTrackedFile(folder_0, "file_0"));
1094 const TrackedFile* tracked_files[] = {
1095 &sync_root, &app_root, &folder_0, &file_0
1098 SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
1099 EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
1100 VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
1102 scoped_ptr<base::ListValue> files =
1103 metadata_database()->DumpFiles(app_root.tracker.app_id());
1104 ASSERT_EQ(2u, files->GetSize());
1106 base::DictionaryValue* file = NULL;
1107 std::string str;
1109 ASSERT_TRUE(files->GetDictionary(0, &file));
1110 EXPECT_TRUE(file->GetString("title", &str) && str == "folder_0");
1111 EXPECT_TRUE(file->GetString("type", &str) && str == "folder");
1112 EXPECT_TRUE(file->HasKey("details"));
1114 ASSERT_TRUE(files->GetDictionary(1, &file));
1115 EXPECT_TRUE(file->GetString("title", &str) && str == "file_0");
1116 EXPECT_TRUE(file->GetString("type", &str) && str == "file");
1117 EXPECT_TRUE(file->HasKey("details"));
1120 } // namespace drive_backend
1121 } // namespace sync_file_system