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