register_app_task_unittest.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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/register_app_task.h"
6
7#include "base/files/scoped_temp_dir.h"
8#include "base/format_macros.h"
9#include "base/run_loop.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/strings/stringprintf.h"
12#include "chrome/browser/drive/fake_drive_service.h"
13#include "chrome/browser/google_apis/gdata_wapi_parser.h"
14#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
15#include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
16#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
17#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
18#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
19#include "chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h"
20#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
21#include "content/public/test/test_browser_thread_bundle.h"
22#include "testing/gtest/include/gtest/gtest.h"
23#include "third_party/leveldatabase/src/include/leveldb/db.h"
24#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
25
26namespace sync_file_system {
27namespace drive_backend {
28
29namespace {
30const int64 kSyncRootTrackerID = 100;
31}  // namespace
32
33class RegisterAppTaskTest : public testing::Test,
34                            public SyncEngineContext {
35 public:
36  RegisterAppTaskTest()
37      : next_file_id_(1000),
38        next_tracker_id_(10000) {}
39  virtual ~RegisterAppTaskTest() {}
40
41  virtual void SetUp() OVERRIDE {
42    ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
43
44    fake_drive_service_.reset(new drive::FakeDriveService);
45    ASSERT_TRUE(fake_drive_service_->LoadAccountMetadataForWapi(
46        "sync_file_system/account_metadata.json"));
47    ASSERT_TRUE(fake_drive_service_->LoadResourceListForWapi(
48        "gdata/empty_feed.json"));
49
50    drive_uploader_.reset(new drive::DriveUploader(
51        fake_drive_service_.get(), base::MessageLoopProxy::current()));
52
53    fake_drive_service_helper_.reset(new FakeDriveServiceHelper(
54        fake_drive_service_.get(), drive_uploader_.get()));
55
56    ASSERT_EQ(google_apis::HTTP_CREATED,
57              fake_drive_service_helper_->AddOrphanedFolder(
58                  kSyncRootFolderTitle, &sync_root_folder_id_));
59  }
60
61  virtual void TearDown() OVERRIDE {
62    metadata_database_.reset();
63    base::RunLoop().RunUntilIdle();
64  }
65
66  virtual drive::DriveServiceInterface* GetDriveService() OVERRIDE {
67    return fake_drive_service_.get();
68  }
69
70  virtual MetadataDatabase* GetMetadataDatabase() OVERRIDE {
71    return metadata_database_.get();
72  }
73
74 protected:
75  scoped_ptr<leveldb::DB> OpenLevelDB() {
76    leveldb::DB* db = NULL;
77    leveldb::Options options;
78    options.create_if_missing = true;
79    leveldb::Status status =
80        leveldb::DB::Open(options, database_dir_.path().AsUTF8Unsafe(), &db);
81    EXPECT_TRUE(status.ok());
82    return make_scoped_ptr<leveldb::DB>(db);
83  }
84
85  void SetUpInitialData(leveldb::DB* db) {
86    ServiceMetadata service_metadata;
87    service_metadata.set_largest_change_id(100);
88    service_metadata.set_sync_root_tracker_id(kSyncRootTrackerID);
89    service_metadata.set_next_tracker_id(next_tracker_id_);
90
91    FileDetails sync_root_details;
92    sync_root_details.set_title(kSyncRootFolderTitle);
93    sync_root_details.set_file_kind(FILE_KIND_FOLDER);
94    sync_root_details.set_change_id(1);
95
96    FileMetadata sync_root_metadata;
97    sync_root_metadata.set_file_id(sync_root_folder_id_);
98    *sync_root_metadata.mutable_details() = sync_root_details;
99
100    FileTracker sync_root_tracker;
101    sync_root_tracker.set_tracker_id(service_metadata.sync_root_tracker_id());
102    sync_root_tracker.set_parent_tracker_id(0);
103    sync_root_tracker.set_file_id(sync_root_metadata.file_id());
104    sync_root_tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
105    *sync_root_tracker.mutable_synced_details() = sync_root_details;
106    sync_root_tracker.set_active(true);
107
108    leveldb::WriteBatch batch;
109    batch.Put(kDatabaseVersionKey,
110              base::Int64ToString(kCurrentDatabaseVersion));
111    PutServiceMetadataToBatch(service_metadata, &batch);
112    PutFileToBatch(sync_root_metadata, &batch);
113    PutTrackerToBatch(sync_root_tracker, &batch);
114    EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
115  }
116
117  void CreateMetadataDatabase(scoped_ptr<leveldb::DB> db) {
118    ASSERT_TRUE(db);
119    ASSERT_FALSE(metadata_database_);
120    ASSERT_EQ(SYNC_STATUS_OK,
121              MetadataDatabase::CreateForTesting(
122                  db.Pass(), &metadata_database_));
123  }
124
125  SyncStatusCode RunRegisterAppTask(const std::string& app_id) {
126    RegisterAppTask task(this, app_id);
127    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
128    task.Run(CreateResultReceiver(&status));
129    base::RunLoop().RunUntilIdle();
130    return status;
131  }
132
133  void SetUpRegisteredAppRoot(
134      const std::string& app_id,
135      leveldb::DB* db) {
136    FileDetails details;
137    details.set_title(app_id);
138    details.set_file_kind(FILE_KIND_FOLDER);
139    details.add_parent_folder_ids(sync_root_folder_id_);
140
141    FileMetadata metadata;
142    metadata.set_file_id(GenerateFileID());
143    *metadata.mutable_details() = details;
144
145    FileTracker tracker;
146    tracker.set_parent_tracker_id(kSyncRootTrackerID);
147    tracker.set_tracker_id(next_tracker_id_++);
148    tracker.set_file_id(metadata.file_id());
149    tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
150    tracker.set_app_id(app_id);
151    *tracker.mutable_synced_details() = details;
152    tracker.set_active(true);
153
154    leveldb::WriteBatch batch;
155    PutFileToBatch(metadata, &batch);
156    PutTrackerToBatch(tracker, &batch);
157    EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
158  }
159
160  void SetUpUnregisteredAppRoot(const std::string& app_id,
161                                leveldb::DB* db) {
162    FileDetails details;
163    details.set_title(app_id);
164    details.set_file_kind(FILE_KIND_FOLDER);
165    details.add_parent_folder_ids(sync_root_folder_id_);
166
167    FileMetadata metadata;
168    metadata.set_file_id(GenerateFileID());
169    *metadata.mutable_details() = details;
170
171    FileTracker tracker;
172    tracker.set_parent_tracker_id(kSyncRootTrackerID);
173    tracker.set_tracker_id(next_tracker_id_++);
174    tracker.set_file_id(metadata.file_id());
175    tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
176    *tracker.mutable_synced_details() = details;
177    tracker.set_active(false);
178
179    leveldb::WriteBatch batch;
180    PutFileToBatch(metadata, &batch);
181    PutTrackerToBatch(tracker, &batch);
182    EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
183  }
184
185  size_t CountRegisteredAppRoot() {
186    // TODO(tzik): Add function to MetadataDatabase to list trackers by parent.
187    typedef MetadataDatabase::TrackersByTitle TrackersByTitle;
188    const TrackersByTitle& trackers_by_title =
189        metadata_database_->trackers_by_parent_and_title_[kSyncRootTrackerID];
190
191    size_t count = 0;
192    for (TrackersByTitle::const_iterator itr = trackers_by_title.begin();
193         itr != trackers_by_title.end(); ++itr) {
194      if (itr->second.has_active())
195        ++count;
196    }
197
198    return count;
199  }
200
201  bool IsAppRegistered(const std::string& app_id) {
202    TrackerSet trackers;
203    if (!metadata_database_->FindTrackersByParentAndTitle(
204            kSyncRootTrackerID, app_id, &trackers))
205      return false;
206    return trackers.has_active();
207  }
208
209  size_t CountRemoteFileInSyncRoot() {
210    ScopedVector<google_apis::ResourceEntry> files;
211    EXPECT_EQ(google_apis::HTTP_SUCCESS,
212              fake_drive_service_helper_->ListFilesInFolder(
213                  sync_root_folder_id_, &files));
214    return files.size();
215  }
216
217  bool HasRemoteAppRoot(const std::string& app_id) {
218    TrackerSet files;
219    if (!metadata_database_->FindTrackersByParentAndTitle(
220            kSyncRootTrackerID, app_id, &files) ||
221        !files.has_active())
222      return false;
223
224    std::string app_root_folder_id = files.active_tracker()->file_id();
225    scoped_ptr<google_apis::ResourceEntry> entry;
226    if (google_apis::HTTP_SUCCESS !=
227        fake_drive_service_helper_->GetResourceEntry(
228            app_root_folder_id, &entry))
229      return false;
230
231    return !entry->deleted();
232  }
233
234 private:
235  std::string GenerateFileID() {
236    return base::StringPrintf("file_id_%" PRId64, next_file_id_++);
237  }
238
239  std::string sync_root_folder_id_;
240
241  int64 next_file_id_;
242  int64 next_tracker_id_;
243
244  content::TestBrowserThreadBundle browser_threads_;
245  base::ScopedTempDir database_dir_;
246
247  scoped_ptr<drive::FakeDriveService> fake_drive_service_;
248  scoped_ptr<drive::DriveUploader> drive_uploader_;
249  scoped_ptr<FakeDriveServiceHelper> fake_drive_service_helper_;
250
251  scoped_ptr<MetadataDatabase> metadata_database_;
252
253  DISALLOW_COPY_AND_ASSIGN(RegisterAppTaskTest);
254};
255
256TEST_F(RegisterAppTaskTest, AlreadyRegistered) {
257  scoped_ptr<leveldb::DB> db(OpenLevelDB());
258  ASSERT_TRUE(db);
259  SetUpInitialData(db.get());
260
261  const std::string kAppID = "app_id";
262  SetUpRegisteredAppRoot(kAppID, db.get());
263
264  CreateMetadataDatabase(db.Pass());
265  EXPECT_EQ(SYNC_STATUS_OK, RunRegisterAppTask(kAppID));
266
267  EXPECT_EQ(1u, CountRegisteredAppRoot());
268  EXPECT_TRUE(IsAppRegistered(kAppID));
269}
270
271TEST_F(RegisterAppTaskTest, CreateAppFolder) {
272  scoped_ptr<leveldb::DB> db(OpenLevelDB());
273  ASSERT_TRUE(db);
274  SetUpInitialData(db.get());
275
276  const std::string kAppID = "app_id";
277  CreateMetadataDatabase(db.Pass());
278  RunRegisterAppTask(kAppID);
279
280  EXPECT_EQ(1u, CountRegisteredAppRoot());
281  EXPECT_TRUE(IsAppRegistered(kAppID));
282
283  EXPECT_EQ(1u, CountRemoteFileInSyncRoot());
284  EXPECT_TRUE(HasRemoteAppRoot(kAppID));
285}
286
287TEST_F(RegisterAppTaskTest, RegisterExistingFolder) {
288  scoped_ptr<leveldb::DB> db(OpenLevelDB());
289  ASSERT_TRUE(db);
290  SetUpInitialData(db.get());
291
292  const std::string kAppID = "app_id";
293  SetUpUnregisteredAppRoot(kAppID, db.get());
294
295  CreateMetadataDatabase(db.Pass());
296  RunRegisterAppTask(kAppID);
297
298  EXPECT_EQ(1u, CountRegisteredAppRoot());
299  EXPECT_TRUE(IsAppRegistered(kAppID));
300}
301
302TEST_F(RegisterAppTaskTest, RegisterExistingFolder_MultipleCandidate) {
303  scoped_ptr<leveldb::DB> db(OpenLevelDB());
304  ASSERT_TRUE(db);
305  SetUpInitialData(db.get());
306
307  const std::string kAppID = "app_id";
308  SetUpUnregisteredAppRoot(kAppID, db.get());
309  SetUpUnregisteredAppRoot(kAppID, db.get());
310
311  CreateMetadataDatabase(db.Pass());
312  RunRegisterAppTask(kAppID);
313
314  EXPECT_EQ(1u, CountRegisteredAppRoot());
315  EXPECT_TRUE(IsAppRegistered(kAppID));
316}
317
318}  // namespace drive_backend
319}  // namespace sync_file_system
320