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