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