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