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"
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
{
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
39 // Holds the latest remote metadata which may be not-yet-synced to |tracker|.
40 FileMetadata metadata
;
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
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
) {
64 test_util::ExpectEquivalentMetadata(*left
, *right
);
67 void ExpectEquivalent(const FileTracker
* left
, const FileTracker
* 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
);
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
);
130 base::FilePath
CreateNormalizedPath(const base::FilePath::StringType
& path
) {
131 return base::FilePath(path
).NormalizePathSeparators();
136 class MetadataDatabaseTest
: public testing::Test
{
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(); }
153 std::string
GenerateFileID() {
154 return "file_id_" + base::Int64ToString(next_file_id_number_
++);
157 int64
GetTrackerIDByFileID(const std::string
& file_id
) {
159 if (metadata_database_
->FindTrackersByFileID(file_id
, &trackers
)) {
160 EXPECT_FALSE(trackers
.empty());
161 return (*trackers
.begin())->tracker_id();
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();
176 void DropDatabase() {
177 metadata_database_
.reset();
178 message_loop_
.RunUntilIdle();
181 void SetUpDatabaseByTrackedFiles(const TrackedFile
** tracked_files
,
183 scoped_ptr
<leveldb::DB
> db
= InitializeLevelDB();
186 for (int i
= 0; i
< size
; ++i
) {
187 const TrackedFile
* file
= tracked_files
[i
];
188 if (file
->should_be_absent
)
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
));
202 VerifyFile(file
.metadata
);
204 VerifyTracker(file
.tracker
);
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(),
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
);
257 FileMetadata
CreateFileMetadata(const FileMetadata
& parent
,
258 const std::string
& title
) {
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
);
266 "md5_value_" + base::Int64ToString(next_md5_sequence_number_
++));
270 FileMetadata
CreateFolderMetadata(const FileMetadata
& parent
,
271 const std::string
& title
) {
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
);
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
) {
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();
308 TrackedFile
CreateTrackedSyncRoot() {
309 TrackedFile sync_root
;
310 sync_root
.metadata
= CreateSyncRootMetadata();
311 sync_root
.tracker
= CreateSyncRootTracker(sync_root
.metadata
);
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
);
323 TrackedFile
CreateTrackedFile(const TrackedFile
& parent
,
324 const std::string
& title
) {
326 file
.metadata
= CreateFileMetadata(parent
.metadata
, title
);
327 file
.tracker
= CreateTracker(parent
.tracker
, file
.metadata
);
331 TrackedFile
CreateTrackedFolder(const TrackedFile
& parent
,
332 const std::string
& title
) {
334 folder
.metadata
= CreateFolderMetadata(parent
.metadata
, title
);
335 folder
.tracker
= CreateTracker(parent
.tracker
, folder
.metadata
);
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");
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();
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(
503 CreateResultReceiver(&status
));
504 message_loop_
.RunUntilIdle();
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();
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();
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();
532 SyncStatusCode
UpdateByChangeList(
533 ScopedVector
<google_apis::ChangeResource
> changes
) {
534 SyncStatusCode status
= SYNC_STATUS_UNKNOWN
;
535 metadata_database_
->UpdateByChangeList(
537 changes
.Pass(), CreateResultReceiver(&status
));
538 message_loop_
.RunUntilIdle();
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();
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();
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(
570 CreateResultReceiver(&status
));
571 message_loop_
.RunUntilIdle();
575 void ResetTrackerID(FileTracker
* tracker
) {
576 tracker
->set_tracker_id(GetTrackerIDByFileID(tracker
->file_id()));
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());
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
,
697 inactive_folder_tracker
.set_active(false);
700 scoped_ptr
<leveldb::DB
> db
= InitializeLevelDB();
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());
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(),
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
,
750 inactive_folder_tracker
.set_active(false);
753 scoped_ptr
<leveldb::DB
> db
= InitializeLevelDB();
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());
775 EXPECT_FALSE(metadata_database()->FindNearestActiveAncestor(
776 "non_registered_app_id",
777 CreateNormalizedPath(FPL("folder1/folder2/file")),
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
);
793 EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor(
794 kAppID
, CreateNormalizedPath(FPL("folder1/folder2")),
796 EXPECT_EQ(folder_tracker2
.tracker_id(), tracker
.tracker_id());
797 EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2")), path
);
803 EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor(
804 kAppID
, CreateNormalizedPath(FPL("folder1/folder2/file")),
806 EXPECT_EQ(file_tracker
.tracker_id(), tracker
.tracker_id());
807 EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2/file")), path
);
813 EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor(
815 CreateNormalizedPath(FPL("folder1/folder2/folder3/folder4/file")),
817 EXPECT_EQ(folder_tracker2
.tracker_id(), tracker
.tracker_id());
818 EXPECT_EQ(CreateNormalizedPath(FPL("folder1/folder2")), path
);
824 EXPECT_TRUE(metadata_database()->FindNearestActiveAncestor(
825 kAppID
, CreateNormalizedPath(FPL("folder1/folder2/file/folder4/file")),
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
,
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
);
862 ApplyNoopChangeToMetadata(&noop_file
.metadata
);
864 ScopedVector
<google_apis::ChangeResource
> changes
;
866 CreateChangeResourceFromMetadata(renamed_file
.metadata
), &changes
);
868 CreateChangeResourceFromMetadata(reorganized_file
.metadata
), &changes
);
870 CreateChangeResourceFromMetadata(updated_file
.metadata
), &changes
);
872 CreateChangeResourceFromMetadata(noop_file
.metadata
), &changes
);
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(),
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(),
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(
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
;
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