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