metadata_database_unittest.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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.
4
5#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
6
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/google_apis/drive_api_parser.h"
13#include "chrome/browser/sync_file_system/drive_backend/drive_backend_test_util.h"
14#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
15#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
16#include "testing/gtest/include/gtest/gtest.h"
17#include "third_party/leveldatabase/src/include/leveldb/db.h"
18#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
19
20#define FPL(a) FILE_PATH_LITERAL(a)
21
22namespace sync_file_system {
23namespace drive_backend {
24
25namespace {
26
27typedef MetadataDatabase::FileIDList FileIDList;
28
29const int64 kInitialChangeID = 1234;
30const int64 kSyncRootTrackerID = 100;
31const char kSyncRootFolderID[] = "sync_root_folder_id";
32
33// This struct is used to setup initial state of the database in the test and
34// also used to match to the modified content of the database as the
35// expectation.
36struct TrackedFile {
37  // Holds the latest remote metadata which may be not-yet-synced to |tracker|.
38  FileMetadata metadata;
39  FileTracker tracker;
40
41  // Implies the file should not in the database.
42  bool should_be_absent;
43
44  // Implies the file should have a tracker in the database but should have no
45  // metadata.
46  bool tracker_only;
47
48  TrackedFile() : should_be_absent(false), tracker_only(false) {}
49};
50
51void ExpectEquivalent(const ServiceMetadata* left,
52                      const ServiceMetadata* right) {
53  test_util::ExpectEquivalentServiceMetadata(*left, *right);
54}
55
56void ExpectEquivalent(const FileDetails* left, const FileDetails* right) {
57  if (!left) {
58    ASSERT_FALSE(right);
59    return;
60  }
61  ASSERT_TRUE(right);
62  test_util::ExpectEquivalentDetails(*left, *right);
63}
64
65void ExpectEquivalent(const FileMetadata* left, const FileMetadata* right) {
66  if (!left) {
67    ASSERT_FALSE(right);
68    return;
69  }
70  ASSERT_TRUE(right);
71  test_util::ExpectEquivalentMetadata(*left, *right);
72}
73
74void ExpectEquivalent(const FileTracker* left, const FileTracker* right) {
75  if (!left) {
76    ASSERT_FALSE(right);
77    return;
78  }
79  ASSERT_TRUE(right);
80  test_util::ExpectEquivalentTrackers(*left, *right);
81}
82
83template <typename Container>
84void ExpectEquivalentMaps(const Container& left, const Container& right);
85template <typename Key, typename Value, typename Compare>
86void ExpectEquivalent(const std::map<Key, Value, Compare>& left,
87                      const std::map<Key, Value, Compare>& right) {
88  ExpectEquivalentMaps(left, right);
89}
90
91template <typename Container>
92void ExpectEquivalentSets(const Container& left, const Container& right);
93template <typename Value, typename Compare>
94void ExpectEquivalent(const std::set<Value, Compare>& left,
95                      const std::set<Value, Compare>& right) {
96  return ExpectEquivalentSets(left, right);
97}
98
99void ExpectEquivalent(const TrackerSet& left,
100                      const TrackerSet& right) {
101  {
102    SCOPED_TRACE("Expect equivalent active_tracker");
103    ExpectEquivalent(left.active_tracker(), right.active_tracker());
104  }
105  ExpectEquivalent(left.tracker_set(), right.tracker_set());
106}
107
108template <typename Container>
109void ExpectEquivalentMaps(const Container& left, const Container& right) {
110  ASSERT_EQ(left.size(), right.size());
111
112  typedef typename Container::const_iterator const_iterator;
113  const_iterator left_itr = left.begin();
114  const_iterator right_itr = right.begin();
115  while (left_itr != left.end()) {
116    EXPECT_EQ(left_itr->first, right_itr->first);
117    ExpectEquivalent(left_itr->second, right_itr->second);
118    ++left_itr;
119    ++right_itr;
120  }
121}
122
123template <typename Container>
124void ExpectEquivalentSets(const Container& left, const Container& right) {
125  ASSERT_EQ(left.size(), right.size());
126
127  typedef typename Container::const_iterator const_iterator;
128  const_iterator left_itr = left.begin();
129  const_iterator right_itr = right.begin();
130  while (left_itr != left.end()) {
131    ExpectEquivalent(*left_itr, *right_itr);
132    ++left_itr;
133    ++right_itr;
134  }
135}
136
137}  // namespace
138
139class MetadataDatabaseTest : public testing::Test {
140 public:
141  MetadataDatabaseTest()
142      : current_change_id_(kInitialChangeID),
143        next_tracker_id_(kSyncRootTrackerID + 1),
144        next_file_id_number_(1),
145        next_md5_sequence_number_(1) {}
146
147  virtual ~MetadataDatabaseTest() {}
148
149  virtual void SetUp() OVERRIDE {
150    ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
151  }
152
153  virtual void TearDown() OVERRIDE { DropDatabase(); }
154
155 protected:
156  std::string GenerateFileID() {
157    return "file_id_" + base::Int64ToString(next_file_id_number_++);
158  }
159
160  int64 GetTrackerIDByFileID(const std::string& file_id) {
161    TrackerSet trackers;
162    if (metadata_database_->FindTrackersByFileID(file_id, &trackers)) {
163      EXPECT_FALSE(trackers.empty());
164      return (*trackers.begin())->tracker_id();
165    }
166    return 0;
167  }
168
169  SyncStatusCode InitializeMetadataDatabase() {
170    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
171    MetadataDatabase::Create(base::MessageLoopProxy::current(),
172                             database_dir_.path(),
173                             CreateResultReceiver(&status,
174                                                  &metadata_database_));
175    message_loop_.RunUntilIdle();
176    return status;
177  }
178
179  void DropDatabase() {
180    metadata_database_.reset();
181    message_loop_.RunUntilIdle();
182  }
183
184  void SetUpDatabaseByTrackedFiles(const TrackedFile** tracked_files,
185                                   int size) {
186    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
187    ASSERT_TRUE(db);
188
189    for (int i = 0; i < size; ++i) {
190      const TrackedFile* file = tracked_files[i];
191      if (file->should_be_absent)
192        continue;
193      if (!file->tracker_only)
194        EXPECT_TRUE(PutFileToDB(db.get(), file->metadata).ok());
195      EXPECT_TRUE(PutTrackerToDB(db.get(), file->tracker).ok());
196    }
197  }
198
199  void VerifyTrackedFile(const TrackedFile& file) {
200    if (!file.should_be_absent) {
201      if (file.tracker_only) {
202        EXPECT_FALSE(metadata_database()->FindFileByFileID(
203            file.metadata.file_id(), NULL));
204      } else {
205        VerifyFile(file.metadata);
206      }
207      VerifyTracker(file.tracker);
208      return;
209    }
210
211    EXPECT_FALSE(metadata_database()->FindFileByFileID(
212        file.metadata.file_id(), NULL));
213    EXPECT_FALSE(metadata_database()->FindTrackerByTrackerID(
214        file.tracker.tracker_id(), NULL));
215  }
216
217  void VerifyTrackedFiles(const TrackedFile** tracked_files, int size) {
218    for (int i = 0; i < size; ++i)
219      VerifyTrackedFile(*tracked_files[i]);
220  }
221
222  MetadataDatabase* metadata_database() { return metadata_database_.get(); }
223
224  leveldb::DB* db() {
225    if (!metadata_database_)
226      return NULL;
227    return metadata_database_->db_.get();
228  }
229
230  scoped_ptr<leveldb::DB> InitializeLevelDB() {
231    leveldb::DB* db = NULL;
232    leveldb::Options options;
233    options.create_if_missing = true;
234    options.max_open_files = 0;  // Use minimum.
235    leveldb::Status status =
236        leveldb::DB::Open(options, database_dir_.path().AsUTF8Unsafe(), &db);
237    EXPECT_TRUE(status.ok());
238
239    db->Put(leveldb::WriteOptions(), "VERSION", base::Int64ToString(3));
240    SetUpServiceMetadata(db);
241
242    return make_scoped_ptr(db);
243  }
244
245  void SetUpServiceMetadata(leveldb::DB* db) {
246    ServiceMetadata service_metadata;
247    service_metadata.set_largest_change_id(kInitialChangeID);
248    service_metadata.set_sync_root_tracker_id(kSyncRootTrackerID);
249    service_metadata.set_next_tracker_id(next_tracker_id_);
250    std::string value;
251    ASSERT_TRUE(service_metadata.SerializeToString(&value));
252    db->Put(leveldb::WriteOptions(), "SERVICE", value);
253  }
254
255  FileMetadata CreateSyncRootMetadata() {
256    FileMetadata sync_root;
257    sync_root.set_file_id(kSyncRootFolderID);
258    FileDetails* details = sync_root.mutable_details();
259    details->set_title("Chrome Syncable FileSystem");
260    details->set_file_kind(FILE_KIND_FOLDER);
261    return sync_root;
262  }
263
264  FileMetadata CreateFileMetadata(const FileMetadata& parent,
265                                  const std::string& title) {
266    FileMetadata file;
267    file.set_file_id(GenerateFileID());
268    FileDetails* details = file.mutable_details();
269    details->add_parent_folder_ids(parent.file_id());
270    details->set_title(title);
271    details->set_file_kind(FILE_KIND_FILE);
272    details->set_md5(
273        "md5_value_" + base::Int64ToString(next_md5_sequence_number_++));
274    return file;
275  }
276
277  FileMetadata CreateFolderMetadata(const FileMetadata& parent,
278                                    const std::string& title) {
279    FileMetadata folder;
280    folder.set_file_id(GenerateFileID());
281    FileDetails* details = folder.mutable_details();
282    details->add_parent_folder_ids(parent.file_id());
283    details->set_title(title);
284    details->set_file_kind(FILE_KIND_FOLDER);
285    return folder;
286  }
287
288  FileTracker CreateSyncRootTracker(const FileMetadata& sync_root) {
289    FileTracker sync_root_tracker;
290    sync_root_tracker.set_tracker_id(kSyncRootTrackerID);
291    sync_root_tracker.set_parent_tracker_id(0);
292    sync_root_tracker.set_file_id(sync_root.file_id());
293    sync_root_tracker.set_dirty(false);
294    sync_root_tracker.set_active(true);
295    sync_root_tracker.set_needs_folder_listing(false);
296    *sync_root_tracker.mutable_synced_details() = sync_root.details();
297    return sync_root_tracker;
298  }
299
300  FileTracker CreateTracker(const FileTracker& parent_tracker,
301                            const FileMetadata& file) {
302    FileTracker tracker;
303    tracker.set_tracker_id(next_tracker_id_++);
304    tracker.set_parent_tracker_id(parent_tracker.tracker_id());
305    tracker.set_file_id(file.file_id());
306    tracker.set_app_id(parent_tracker.app_id());
307    tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
308    tracker.set_dirty(false);
309    tracker.set_active(true);
310    tracker.set_needs_folder_listing(false);
311    *tracker.mutable_synced_details() = file.details();
312    return tracker;
313  }
314
315  TrackedFile CreateTrackedSyncRoot() {
316    TrackedFile sync_root;
317    sync_root.metadata = CreateSyncRootMetadata();
318    sync_root.tracker = CreateSyncRootTracker(sync_root.metadata);
319    return sync_root;
320  }
321
322  TrackedFile CreateTrackedAppRoot(const TrackedFile& sync_root,
323                                   const std::string& app_id) {
324    TrackedFile app_root(CreateTrackedFolder(sync_root, app_id));
325    app_root.tracker.set_app_id(app_id);
326    app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
327    return app_root;
328  }
329
330  TrackedFile CreateTrackedFile(const TrackedFile& parent,
331                                const std::string& title) {
332    TrackedFile file;
333    file.metadata = CreateFileMetadata(parent.metadata, title);
334    file.tracker = CreateTracker(parent.tracker, file.metadata);
335    return file;
336  }
337
338  TrackedFile CreateTrackedFolder(const TrackedFile& parent,
339                                  const std::string& title) {
340    TrackedFile folder;
341    folder.metadata = CreateFolderMetadata(parent.metadata, title);
342    folder.tracker = CreateTracker(parent.tracker, folder.metadata);
343    return folder;
344  }
345
346  scoped_ptr<google_apis::FileResource> CreateFileResourceFromMetadata(
347      const FileMetadata& file) {
348    scoped_ptr<google_apis::FileResource> file_resource(
349        new google_apis::FileResource);
350    ScopedVector<google_apis::ParentReference> parents;
351    for (int i = 0; i < file.details().parent_folder_ids_size(); ++i) {
352      scoped_ptr<google_apis::ParentReference> parent(
353          new google_apis::ParentReference);
354      parent->set_file_id(file.details().parent_folder_ids(i));
355      parents.push_back(parent.release());
356    }
357
358    file_resource->set_file_id(file.file_id());
359    file_resource->set_parents(parents.Pass());
360    file_resource->set_title(file.details().title());
361    if (file.details().file_kind() == FILE_KIND_FOLDER)
362      file_resource->set_mime_type("application/vnd.google-apps.folder");
363    else if (file.details().file_kind() == FILE_KIND_FILE)
364      file_resource->set_mime_type("text/plain");
365    else
366      file_resource->set_mime_type("application/vnd.google-apps.document");
367    file_resource->set_md5_checksum(file.details().md5());
368    file_resource->set_etag(file.details().etag());
369    file_resource->set_created_date(base::Time::FromInternalValue(
370        file.details().creation_time()));
371    file_resource->set_modified_date(base::Time::FromInternalValue(
372        file.details().modification_time()));
373
374    return file_resource.Pass();
375  }
376
377  scoped_ptr<google_apis::ChangeResource> CreateChangeResourceFromMetadata(
378      const FileMetadata& file) {
379    scoped_ptr<google_apis::ChangeResource> change(
380        new google_apis::ChangeResource);
381    change->set_change_id(file.details().change_id());
382    change->set_file_id(file.file_id());
383    change->set_deleted(file.details().deleted());
384    if (change->is_deleted())
385      return change.Pass();
386
387    change->set_file(CreateFileResourceFromMetadata(file));
388    return change.Pass();
389  }
390
391  void ApplyRenameChangeToMetadata(const std::string& new_title,
392                                   FileMetadata* file) {
393    FileDetails* details = file->mutable_details();
394    details->set_title(new_title);
395    details->set_change_id(++current_change_id_);
396  }
397
398  void ApplyReorganizeChangeToMetadata(const std::string& new_parent,
399                                       FileMetadata* file) {
400    FileDetails* details = file->mutable_details();
401    details->clear_parent_folder_ids();
402    details->add_parent_folder_ids(new_parent);
403    details->set_change_id(++current_change_id_);
404  }
405
406  void ApplyContentChangeToMetadata(FileMetadata* file) {
407    FileDetails* details = file->mutable_details();
408    details->set_md5(
409        "md5_value_" + base::Int64ToString(next_md5_sequence_number_++));
410    details->set_change_id(++current_change_id_);
411  }
412
413  void PushToChangeList(scoped_ptr<google_apis::ChangeResource> change,
414                        ScopedVector<google_apis::ChangeResource>* changes) {
415    changes->push_back(change.release());
416  }
417
418  leveldb::Status PutFileToDB(leveldb::DB* db, const FileMetadata& file) {
419    std::string key = "FILE: " + file.file_id();
420    std::string value;
421    file.SerializeToString(&value);
422    return db->Put(leveldb::WriteOptions(), key, value);
423  }
424
425  leveldb::Status PutTrackerToDB(leveldb::DB* db,
426                                 const FileTracker& tracker) {
427    std::string key = "TRACKER: " + base::Int64ToString(tracker.tracker_id());
428    std::string value;
429    tracker.SerializeToString(&value);
430    return db->Put(leveldb::WriteOptions(), key, value);
431  }
432
433  void VerifyReloadConsistency() {
434    scoped_ptr<MetadataDatabase> metadata_database_2;
435    ASSERT_EQ(SYNC_STATUS_OK,
436              MetadataDatabase::CreateForTesting(
437                  metadata_database_->db_.Pass(),
438                  &metadata_database_2));
439    metadata_database_->db_ = metadata_database_2->db_.Pass();
440
441    {
442      SCOPED_TRACE("Expect equivalent service_metadata");
443      ExpectEquivalent(metadata_database_->service_metadata_.get(),
444                       metadata_database_2->service_metadata_.get());
445    }
446
447    {
448      SCOPED_TRACE("Expect equivalent file_by_id_ contents.");
449      ExpectEquivalent(metadata_database_->file_by_id_,
450                       metadata_database_2->file_by_id_);
451    }
452
453    {
454      SCOPED_TRACE("Expect equivalent tracker_by_id_ contents.");
455      ExpectEquivalent(metadata_database_->tracker_by_id_,
456                       metadata_database_2->tracker_by_id_);
457    }
458
459    {
460      SCOPED_TRACE("Expect equivalent trackers_by_file_id_ contents.");
461      ExpectEquivalent(metadata_database_->trackers_by_file_id_,
462                       metadata_database_2->trackers_by_file_id_);
463    }
464
465    {
466      SCOPED_TRACE("Expect equivalent app_root_by_app_id_ contents.");
467      ExpectEquivalent(metadata_database_->app_root_by_app_id_,
468                       metadata_database_2->app_root_by_app_id_);
469    }
470
471    {
472      SCOPED_TRACE("Expect equivalent trackers_by_parent_and_title_ contents.");
473      ExpectEquivalent(metadata_database_->trackers_by_parent_and_title_,
474                       metadata_database_2->trackers_by_parent_and_title_);
475    }
476
477    {
478      SCOPED_TRACE("Expect equivalent dirty_trackers_ contents.");
479      ExpectEquivalent(metadata_database_->dirty_trackers_,
480                       metadata_database_2->dirty_trackers_);
481    }
482  }
483
484  void VerifyFile(const FileMetadata& file) {
485    FileMetadata file_in_metadata_database;
486    ASSERT_TRUE(metadata_database()->FindFileByFileID(
487        file.file_id(), &file_in_metadata_database));
488
489    SCOPED_TRACE("Expect equivalent " + file.file_id());
490    ExpectEquivalent(&file, &file_in_metadata_database);
491  }
492
493  void VerifyTracker(const FileTracker& tracker) {
494    FileTracker tracker_in_metadata_database;
495    ASSERT_TRUE(metadata_database()->FindTrackerByTrackerID(
496        tracker.tracker_id(), &tracker_in_metadata_database));
497
498    SCOPED_TRACE("Expect equivalent tracker[" +
499                 base::Int64ToString(tracker.tracker_id()) + "]");
500    ExpectEquivalent(&tracker, &tracker_in_metadata_database);
501  }
502
503  SyncStatusCode RegisterApp(const std::string& app_id,
504                             const std::string& folder_id) {
505    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
506    metadata_database_->RegisterApp(
507        app_id, folder_id,
508        CreateResultReceiver(&status));
509    message_loop_.RunUntilIdle();
510    return status;
511  }
512
513  SyncStatusCode DisableApp(const std::string& app_id) {
514    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
515    metadata_database_->DisableApp(
516        app_id, CreateResultReceiver(&status));
517    message_loop_.RunUntilIdle();
518    return status;
519  }
520
521  SyncStatusCode EnableApp(const std::string& app_id) {
522    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
523    metadata_database_->EnableApp(
524        app_id, CreateResultReceiver(&status));
525    message_loop_.RunUntilIdle();
526    return status;
527  }
528
529  SyncStatusCode UnregisterApp(const std::string& app_id) {
530    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
531    metadata_database_->UnregisterApp(
532        app_id, CreateResultReceiver(&status));
533    message_loop_.RunUntilIdle();
534    return status;
535  }
536
537  SyncStatusCode UpdateByChangeList(
538      ScopedVector<google_apis::ChangeResource> changes) {
539    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
540    metadata_database_->UpdateByChangeList(
541        current_change_id_,
542        changes.Pass(), CreateResultReceiver(&status));
543    message_loop_.RunUntilIdle();
544    return status;
545  }
546
547  SyncStatusCode PopulateFolder(const std::string& folder_id,
548                                const FileIDList& listed_children) {
549    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
550    metadata_database_->PopulateFolderByChildList(
551        folder_id, listed_children,
552        CreateResultReceiver(&status));
553    message_loop_.RunUntilIdle();
554    return status;
555  }
556
557  SyncStatusCode UpdateTracker(const FileTracker& tracker) {
558    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
559    metadata_database_->UpdateTracker(
560        tracker.tracker_id(), tracker.synced_details(),
561        CreateResultReceiver(&status));
562    message_loop_.RunUntilIdle();
563    return status;
564  }
565
566  SyncStatusCode PopulateInitialData(
567      int64 largest_change_id,
568      const google_apis::FileResource& sync_root_folder,
569      const ScopedVector<google_apis::FileResource>& app_root_folders) {
570    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
571    metadata_database_->PopulateInitialData(
572        largest_change_id,
573        sync_root_folder,
574        app_root_folders,
575        CreateResultReceiver(&status));
576    message_loop_.RunUntilIdle();
577    return status;
578  }
579
580  void ResetTrackerID(FileTracker* tracker) {
581    tracker->set_tracker_id(GetTrackerIDByFileID(tracker->file_id()));
582  }
583
584 private:
585  base::ScopedTempDir database_dir_;
586  base::MessageLoop message_loop_;
587
588  scoped_ptr<MetadataDatabase> metadata_database_;
589
590  int64 current_change_id_;
591  int64 next_tracker_id_;
592  int64 next_file_id_number_;
593  int64 next_md5_sequence_number_;
594
595  DISALLOW_COPY_AND_ASSIGN(MetadataDatabaseTest);
596};
597
598TEST_F(MetadataDatabaseTest, InitializationTest_Empty) {
599  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
600  DropDatabase();
601  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
602}
603
604TEST_F(MetadataDatabaseTest, InitializationTest_SimpleTree) {
605  TrackedFile sync_root(CreateTrackedSyncRoot());
606  TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id"));
607  app_root.tracker.set_app_id(app_root.metadata.details().title());
608  app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
609
610  TrackedFile file(CreateTrackedFile(app_root, "file"));
611  TrackedFile folder(CreateTrackedFolder(app_root, "folder"));
612  TrackedFile file_in_folder(CreateTrackedFile(folder, "file_in_folder"));
613  TrackedFile orphaned_file(CreateTrackedFile(sync_root, "orphaned_file"));
614  orphaned_file.metadata.mutable_details()->clear_parent_folder_ids();
615  orphaned_file.tracker.set_parent_tracker_id(0);
616
617  const TrackedFile* tracked_files[] = {
618    &sync_root, &app_root, &file, &folder, &file_in_folder, &orphaned_file
619  };
620
621  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
622  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
623
624  orphaned_file.should_be_absent = true;
625  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
626}
627
628TEST_F(MetadataDatabaseTest, AppManagementTest) {
629  TrackedFile sync_root(CreateTrackedSyncRoot());
630  TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id"));
631  app_root.tracker.set_app_id(app_root.metadata.details().title());
632  app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
633
634  TrackedFile file(CreateTrackedFile(app_root, "file"));
635  TrackedFile folder(CreateTrackedFolder(sync_root, "folder"));
636  folder.tracker.set_active(false);
637
638  const TrackedFile* tracked_files[] = {
639    &sync_root, &app_root, &file, &folder,
640  };
641  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
642  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
643  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
644
645  folder.tracker.set_app_id("foo");
646  EXPECT_EQ(SYNC_STATUS_OK, RegisterApp(
647      folder.tracker.app_id(), folder.metadata.file_id()));
648  folder.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
649  folder.tracker.set_active(true);
650  folder.tracker.set_dirty(true);
651  folder.tracker.set_needs_folder_listing(true);
652  VerifyTrackedFile(folder);
653  VerifyReloadConsistency();
654
655  EXPECT_EQ(SYNC_STATUS_OK, DisableApp(folder.tracker.app_id()));
656  folder.tracker.set_tracker_kind(TRACKER_KIND_DISABLED_APP_ROOT);
657  VerifyTrackedFile(folder);
658  VerifyReloadConsistency();
659
660  EXPECT_EQ(SYNC_STATUS_OK, EnableApp(folder.tracker.app_id()));
661  folder.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
662  VerifyTrackedFile(folder);
663  VerifyReloadConsistency();
664
665  EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(folder.tracker.app_id()));
666  folder.tracker.set_app_id(std::string());
667  folder.tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
668  folder.tracker.set_active(false);
669  VerifyTrackedFile(folder);
670  VerifyReloadConsistency();
671
672  EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(app_root.tracker.app_id()));
673  app_root.tracker.set_app_id(std::string());
674  app_root.tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
675  app_root.tracker.set_active(false);
676  app_root.tracker.set_dirty(true);
677  file.should_be_absent = true;
678  VerifyTrackedFile(app_root);
679  VerifyTrackedFile(file);
680  VerifyReloadConsistency();
681}
682
683TEST_F(MetadataDatabaseTest, BuildPathTest) {
684  FileMetadata sync_root(CreateSyncRootMetadata());
685  FileTracker sync_root_tracker(CreateSyncRootTracker(sync_root));
686
687  FileMetadata app_root(CreateFolderMetadata(sync_root, "app_id"));
688  FileTracker app_root_tracker(
689      CreateTracker(sync_root_tracker, app_root));
690  app_root_tracker.set_app_id(app_root.details().title());
691  app_root_tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
692
693  FileMetadata folder(CreateFolderMetadata(app_root, "folder"));
694  FileTracker folder_tracker(CreateTracker(app_root_tracker, folder));
695
696  FileMetadata file(CreateFolderMetadata(folder, "file"));
697  FileTracker file_tracker(CreateTracker(folder_tracker, file));
698
699  FileMetadata inactive_folder(CreateFolderMetadata(app_root, "folder"));
700  FileTracker inactive_folder_tracker(CreateTracker(app_root_tracker,
701                                                          inactive_folder));
702  inactive_folder_tracker.set_active(false);
703
704  {
705    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
706    ASSERT_TRUE(db);
707
708    EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
709    EXPECT_TRUE(PutTrackerToDB(db.get(), sync_root_tracker).ok());
710    EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
711    EXPECT_TRUE(PutTrackerToDB(db.get(), app_root_tracker).ok());
712    EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
713    EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker).ok());
714    EXPECT_TRUE(PutFileToDB(db.get(), file).ok());
715    EXPECT_TRUE(PutTrackerToDB(db.get(), file_tracker).ok());
716  }
717
718  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
719
720  base::FilePath path;
721  EXPECT_FALSE(metadata_database()->BuildPathForTracker(
722      sync_root_tracker.tracker_id(), &path));
723  EXPECT_TRUE(metadata_database()->BuildPathForTracker(
724      app_root_tracker.tracker_id(), &path));
725  EXPECT_EQ(base::FilePath(FPL("/")).NormalizePathSeparators(), path);
726  EXPECT_TRUE(metadata_database()->BuildPathForTracker(
727      file_tracker.tracker_id(), &path));
728  EXPECT_EQ(base::FilePath(FPL("/folder/file")).NormalizePathSeparators(),
729            path);
730}
731
732TEST_F(MetadataDatabaseTest, UpdateByChangeListTest) {
733  TrackedFile sync_root(CreateTrackedSyncRoot());
734  TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id"));
735  TrackedFile disabled_app_root(CreateTrackedFolder(sync_root, "disabled_app"));
736  TrackedFile file(CreateTrackedFile(app_root, "file"));
737  TrackedFile renamed_file(CreateTrackedFile(app_root, "to be renamed"));
738  TrackedFile folder(CreateTrackedFolder(app_root, "folder"));
739  TrackedFile reorganized_file(
740      CreateTrackedFile(app_root, "to be reorganized"));
741  TrackedFile updated_file(
742      CreateTrackedFile(app_root, "to be updated"));
743  TrackedFile noop_file(CreateTrackedFile(app_root, "has noop change"));
744  TrackedFile new_file(CreateTrackedFile(app_root, "to be added later"));
745  new_file.should_be_absent = true;
746
747  const TrackedFile* tracked_files[] = {
748    &sync_root, &app_root, &disabled_app_root,
749    &file, &renamed_file, &folder, &reorganized_file, &updated_file, &noop_file,
750    &new_file,
751  };
752
753  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
754  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
755
756  ApplyRenameChangeToMetadata("renamed", &renamed_file.metadata);
757  ApplyReorganizeChangeToMetadata(folder.metadata.file_id(),
758                                  &reorganized_file.metadata);
759  ApplyContentChangeToMetadata(&updated_file.metadata);
760
761  ScopedVector<google_apis::ChangeResource> changes;
762  PushToChangeList(
763      CreateChangeResourceFromMetadata(renamed_file.metadata), &changes);
764  PushToChangeList(
765      CreateChangeResourceFromMetadata(reorganized_file.metadata), &changes);
766  PushToChangeList(
767      CreateChangeResourceFromMetadata(updated_file.metadata), &changes);
768  PushToChangeList(
769      CreateChangeResourceFromMetadata(noop_file.metadata), &changes);
770  PushToChangeList(
771      CreateChangeResourceFromMetadata(new_file.metadata), &changes);
772  EXPECT_EQ(SYNC_STATUS_OK, UpdateByChangeList(changes.Pass()));
773
774  renamed_file.tracker.set_dirty(true);
775  reorganized_file.tracker.set_dirty(true);
776  updated_file.tracker.set_dirty(true);
777  noop_file.tracker.set_dirty(true);
778  new_file.tracker.clear_synced_details();
779  new_file.tracker.set_active(false);
780  new_file.tracker.set_dirty(true);
781  ResetTrackerID(&new_file.tracker);
782  EXPECT_NE(0, new_file.tracker.tracker_id());
783
784  new_file.should_be_absent = false;
785
786  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
787  VerifyReloadConsistency();
788}
789
790TEST_F(MetadataDatabaseTest, PopulateFolderTest_RegularFolder) {
791  TrackedFile sync_root(CreateTrackedSyncRoot());
792  TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id"));
793  app_root.tracker.set_app_id(app_root.metadata.details().title());
794
795  TrackedFile folder_to_populate(
796      CreateTrackedFolder(app_root, "folder_to_populate"));
797  folder_to_populate.tracker.set_needs_folder_listing(true);
798  folder_to_populate.tracker.set_dirty(true);
799
800  TrackedFile known_file(CreateTrackedFile(folder_to_populate, "known_file"));
801  TrackedFile new_file(CreateTrackedFile(folder_to_populate, "new_file"));
802  new_file.should_be_absent = true;
803
804  const TrackedFile* tracked_files[] = {
805    &sync_root, &app_root, &folder_to_populate, &known_file, &new_file
806  };
807
808  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
809  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
810  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
811
812  FileIDList listed_children;
813  listed_children.push_back(known_file.metadata.file_id());
814  listed_children.push_back(new_file.metadata.file_id());
815
816  EXPECT_EQ(SYNC_STATUS_OK,
817            PopulateFolder(folder_to_populate.metadata.file_id(),
818                           listed_children));
819
820  folder_to_populate.tracker.set_dirty(false);
821  folder_to_populate.tracker.set_needs_folder_listing(false);
822  ResetTrackerID(&new_file.tracker);
823  new_file.tracker.set_dirty(true);
824  new_file.tracker.set_active(false);
825  new_file.tracker.clear_synced_details();
826  new_file.should_be_absent = false;
827  new_file.tracker_only = true;
828  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
829  VerifyReloadConsistency();
830}
831
832TEST_F(MetadataDatabaseTest, PopulateFolderTest_InactiveFolder) {
833  TrackedFile sync_root(CreateTrackedSyncRoot());
834  TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id"));
835
836  TrackedFile inactive_folder(CreateTrackedFolder(app_root, "inactive_folder"));
837  inactive_folder.tracker.set_active(false);
838  inactive_folder.tracker.set_dirty(true);
839
840  TrackedFile new_file(
841      CreateTrackedFile(inactive_folder, "file_in_inactive_folder"));
842  new_file.should_be_absent = true;
843
844  const TrackedFile* tracked_files[] = {
845    &sync_root, &app_root, &inactive_folder, &new_file,
846  };
847
848  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
849  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
850  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
851
852  FileIDList listed_children;
853  listed_children.push_back(new_file.metadata.file_id());
854
855  EXPECT_EQ(SYNC_STATUS_OK,
856            PopulateFolder(inactive_folder.metadata.file_id(),
857                           listed_children));
858  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
859  VerifyReloadConsistency();
860}
861
862TEST_F(MetadataDatabaseTest, PopulateFolderTest_DisabledAppRoot) {
863  TrackedFile sync_root(CreateTrackedSyncRoot());
864  TrackedFile disabled_app_root(
865      CreateTrackedAppRoot(sync_root, "disabled_app"));
866  disabled_app_root.tracker.set_dirty(true);
867  disabled_app_root.tracker.set_needs_folder_listing(true);
868
869  TrackedFile known_file(CreateTrackedFile(disabled_app_root, "known_file"));
870  TrackedFile file(CreateTrackedFile(disabled_app_root, "file"));
871  file.should_be_absent = true;
872
873  const TrackedFile* tracked_files[] = {
874    &sync_root, &disabled_app_root, &disabled_app_root, &known_file, &file,
875  };
876
877  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
878  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
879  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
880
881  FileIDList disabled_app_children;
882  disabled_app_children.push_back(file.metadata.file_id());
883  EXPECT_EQ(SYNC_STATUS_OK, PopulateFolder(
884      disabled_app_root.metadata.file_id(), disabled_app_children));
885  ResetTrackerID(&file.tracker);
886  file.tracker.clear_synced_details();
887  file.tracker.set_dirty(true);
888  file.tracker.set_active(false);
889  file.should_be_absent = false;
890  file.tracker_only = true;
891
892  disabled_app_root.tracker.set_dirty(false);
893  disabled_app_root.tracker.set_needs_folder_listing(false);
894  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
895  VerifyReloadConsistency();
896}
897
898TEST_F(MetadataDatabaseTest, UpdateTrackerTest) {
899  TrackedFile sync_root(CreateTrackedSyncRoot());
900  TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_root"));
901  TrackedFile file(CreateTrackedFile(app_root, "file"));
902  file.tracker.set_dirty(true);
903  file.metadata.mutable_details()->set_title("renamed file");;
904
905  TrackedFile inactive_file(CreateTrackedFile(app_root, "inactive_file"));
906  inactive_file.tracker.set_active(false);
907  inactive_file.tracker.set_dirty(true);
908  inactive_file.metadata.mutable_details()->set_title("renamed inactive file");
909  inactive_file.metadata.mutable_details()->set_md5("modified_md5");
910
911  TrackedFile new_conflict(CreateTrackedFile(app_root, "new conflict file"));
912  new_conflict.tracker.set_dirty(true);
913  new_conflict.metadata.mutable_details()->set_title("renamed file");
914
915  const TrackedFile* tracked_files[] = {
916    &sync_root, &app_root, &file, &inactive_file, &new_conflict
917  };
918
919  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
920  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
921  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
922  VerifyReloadConsistency();
923
924  *file.tracker.mutable_synced_details() = file.metadata.details();
925  file.tracker.set_dirty(false);
926  EXPECT_EQ(SYNC_STATUS_OK, UpdateTracker(file.tracker));
927  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
928  VerifyReloadConsistency();
929
930  *inactive_file.tracker.mutable_synced_details() =
931       inactive_file.metadata.details();
932  inactive_file.tracker.set_dirty(false);
933  inactive_file.tracker.set_active(true);
934  EXPECT_EQ(SYNC_STATUS_OK, UpdateTracker(inactive_file.tracker));
935  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
936  VerifyReloadConsistency();
937
938  *new_conflict.tracker.mutable_synced_details() =
939       new_conflict.metadata.details();
940  new_conflict.tracker.set_dirty(false);
941  new_conflict.tracker.set_active(true);
942  file.tracker.set_dirty(true);
943  file.tracker.set_active(false);
944  EXPECT_EQ(SYNC_STATUS_OK, UpdateTracker(new_conflict.tracker));
945  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
946  VerifyReloadConsistency();
947}
948
949TEST_F(MetadataDatabaseTest, PopulateInitialDataTest) {
950  TrackedFile sync_root(CreateTrackedSyncRoot());
951  TrackedFile app_root(CreateTrackedFolder(sync_root, "app_root"));
952  app_root.tracker.set_active(false);
953
954  const TrackedFile* tracked_files[] = {
955    &sync_root, &app_root
956  };
957
958  int64 largest_change_id = 42;
959  scoped_ptr<google_apis::FileResource> sync_root_folder(
960      CreateFileResourceFromMetadata(sync_root.metadata));
961  scoped_ptr<google_apis::FileResource> app_root_folder(
962      CreateFileResourceFromMetadata(app_root.metadata));
963
964  ScopedVector<google_apis::FileResource> app_root_folders;
965  app_root_folders.push_back(app_root_folder.release());
966
967  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
968  EXPECT_EQ(SYNC_STATUS_OK, PopulateInitialData(
969      largest_change_id,
970      *sync_root_folder,
971      app_root_folders));
972
973  ResetTrackerID(&sync_root.tracker);
974  ResetTrackerID(&app_root.tracker);
975  app_root.tracker.set_parent_tracker_id(sync_root.tracker.tracker_id());
976
977  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
978  VerifyReloadConsistency();
979}
980
981}  // namespace drive_backend
982}  // namespace sync_file_system
983