sync_engine_initializer_unittest.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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/sync_engine_initializer.h"
6
7#include "base/bind.h"
8#include "base/files/scoped_temp_dir.h"
9#include "base/run_loop.h"
10#include "base/thread_task_runner_handle.h"
11#include "chrome/browser/drive/drive_api_util.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_test_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/sync_task_manager.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/drive_api_parser.h"
23#include "google_apis/drive/gdata_wapi_parser.h"
24#include "testing/gtest/include/gtest/gtest.h"
25#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
26#include "third_party/leveldatabase/src/include/leveldb/env.h"
27
28namespace sync_file_system {
29namespace drive_backend {
30
31namespace {
32
33const int64 kInitialLargestChangeID = 1234;
34
35}  // namespace
36
37class SyncEngineInitializerTest : public testing::Test {
38 public:
39  struct TrackedFile {
40    scoped_ptr<google_apis::FileResource> resource;
41    FileMetadata metadata;
42    FileTracker tracker;
43  };
44
45  SyncEngineInitializerTest() {}
46  virtual ~SyncEngineInitializerTest() {}
47
48  virtual void SetUp() OVERRIDE {
49    ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
50    in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
51
52    scoped_ptr<drive::DriveServiceInterface>
53        fake_drive_service(new drive::FakeDriveService);
54
55    sync_context_.reset(new SyncEngineContext(
56        fake_drive_service.Pass(),
57        scoped_ptr<drive::DriveUploaderInterface>(),
58        NULL,
59        base::ThreadTaskRunnerHandle::Get(),
60        base::ThreadTaskRunnerHandle::Get()));
61
62    sync_task_manager_.reset(new SyncTaskManager(
63        base::WeakPtr<SyncTaskManager::Client>(),
64        1 /* maximum_parallel_task */,
65        base::ThreadTaskRunnerHandle::Get()));
66    sync_task_manager_->Initialize(SYNC_STATUS_OK);
67  }
68
69  virtual void TearDown() OVERRIDE {
70    sync_task_manager_.reset();
71    metadata_database_.reset();
72    sync_context_.reset();
73    base::RunLoop().RunUntilIdle();
74  }
75
76  base::FilePath database_path() {
77    return database_dir_.path();
78  }
79
80  SyncStatusCode RunInitializer() {
81    SyncEngineInitializer* initializer =
82        new SyncEngineInitializer(sync_context_.get(),
83                                  database_path(),
84                                  in_memory_env_.get());
85    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
86
87    sync_task_manager_->ScheduleSyncTask(
88        FROM_HERE,
89        scoped_ptr<SyncTask>(initializer),
90        SyncTaskManager::PRIORITY_MED,
91        base::Bind(&SyncEngineInitializerTest::DidRunInitializer,
92                   base::Unretained(this), initializer, &status));
93
94    base::RunLoop().RunUntilIdle();
95    return status;
96  }
97
98  void DidRunInitializer(SyncEngineInitializer* initializer,
99                         SyncStatusCode* status_out,
100                         SyncStatusCode status) {
101    *status_out = status;
102    metadata_database_ = initializer->PassMetadataDatabase();
103  }
104
105  SyncStatusCode PopulateDatabase(
106      const google_apis::FileResource& sync_root,
107      const google_apis::FileResource** app_roots,
108      size_t app_roots_count) {
109    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
110    scoped_ptr<MetadataDatabase> database = MetadataDatabase::Create(
111        database_path(), in_memory_env_.get(), &status);
112    if (status != SYNC_STATUS_OK)
113      return status;
114
115    // |app_root_list| must not own the resources here. Be sure to call
116    // weak_clear later.
117    ScopedVector<google_apis::FileResource> app_root_list;
118    for (size_t i = 0; i < app_roots_count; ++i) {
119      app_root_list.push_back(
120          const_cast<google_apis::FileResource*>(app_roots[i]));
121    }
122
123    status = database->PopulateInitialData(
124        kInitialLargestChangeID, sync_root, app_root_list);
125
126    app_root_list.weak_clear();
127    return status;
128  }
129
130  scoped_ptr<google_apis::FileResource> CreateRemoteFolder(
131      const std::string& parent_folder_id,
132      const std::string& title) {
133    google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
134    scoped_ptr<google_apis::FileResource> entry;
135    sync_context_->GetDriveService()->AddNewDirectory(
136        parent_folder_id, title,
137        drive::DriveServiceInterface::AddNewDirectoryOptions(),
138        CreateResultReceiver(&error, &entry));
139    base::RunLoop().RunUntilIdle();
140
141    EXPECT_EQ(google_apis::HTTP_CREATED, error);
142    return entry.Pass();
143  }
144
145  scoped_ptr<google_apis::FileResource> CreateRemoteSyncRoot() {
146    scoped_ptr<google_apis::FileResource> sync_root(
147        CreateRemoteFolder(std::string(), kSyncRootFolderTitle));
148
149    for (size_t i = 0; i < sync_root->parents().size(); ++i) {
150      google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
151      sync_context_->GetDriveService()->RemoveResourceFromDirectory(
152          sync_root->parents()[i].file_id(),
153          sync_root->file_id(),
154          CreateResultReceiver(&error));
155      base::RunLoop().RunUntilIdle();
156      EXPECT_EQ(google_apis::HTTP_NO_CONTENT, error);
157    }
158
159    return sync_root.Pass();
160  }
161
162  std::string GetSyncRootFolderID() {
163    int64 sync_root_tracker_id = metadata_database_->GetSyncRootTrackerID();
164    FileTracker sync_root_tracker;
165    EXPECT_TRUE(metadata_database_->FindTrackerByTrackerID(
166        sync_root_tracker_id, &sync_root_tracker));
167    return sync_root_tracker.file_id();
168  }
169
170  size_t CountTrackersForFile(const std::string& file_id) {
171    TrackerIDSet trackers;
172    metadata_database_->FindTrackersByFileID(file_id, &trackers);
173    return trackers.size();
174  }
175
176  bool HasActiveTracker(const std::string& file_id) {
177    TrackerIDSet trackers;
178    return metadata_database_->FindTrackersByFileID(file_id, &trackers) &&
179        trackers.has_active();
180  }
181
182  bool HasNoParent(const std::string& file_id) {
183    google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
184    scoped_ptr<google_apis::FileResource> entry;
185    sync_context_->GetDriveService()->GetFileResource(
186        file_id,
187        CreateResultReceiver(&error, &entry));
188    base::RunLoop().RunUntilIdle();
189    EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
190    return entry->parents().empty();
191  }
192
193  size_t CountFileMetadata() {
194    return metadata_database_->CountFileMetadata();
195  }
196
197  size_t CountFileTracker() {
198    return metadata_database_->CountFileTracker();
199  }
200
201  google_apis::GDataErrorCode AddParentFolder(
202      const std::string& new_parent_folder_id,
203      const std::string& file_id) {
204    google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
205    sync_context_->GetDriveService()->AddResourceToDirectory(
206        new_parent_folder_id, file_id,
207        CreateResultReceiver(&error));
208    base::RunLoop().RunUntilIdle();
209    return error;
210  }
211
212 private:
213  content::TestBrowserThreadBundle browser_threads_;
214  base::ScopedTempDir database_dir_;
215  scoped_ptr<leveldb::Env> in_memory_env_;
216
217  scoped_ptr<MetadataDatabase> metadata_database_;
218  scoped_ptr<SyncTaskManager> sync_task_manager_;
219  scoped_ptr<SyncEngineContext> sync_context_;
220
221  DISALLOW_COPY_AND_ASSIGN(SyncEngineInitializerTest);
222};
223
224TEST_F(SyncEngineInitializerTest, EmptyDatabase_NoRemoteSyncRoot) {
225  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
226
227  std::string sync_root_folder_id = GetSyncRootFolderID();
228  EXPECT_EQ(1u, CountTrackersForFile(sync_root_folder_id));
229
230  EXPECT_TRUE(HasActiveTracker(sync_root_folder_id));
231
232  EXPECT_EQ(1u, CountFileMetadata());
233  EXPECT_EQ(1u, CountFileTracker());
234}
235
236TEST_F(SyncEngineInitializerTest, EmptyDatabase_RemoteSyncRootExists) {
237  scoped_ptr<google_apis::FileResource> sync_root(
238      CreateRemoteSyncRoot());
239  scoped_ptr<google_apis::FileResource> app_root_1(
240      CreateRemoteFolder(sync_root->file_id(), "app-root 1"));
241  scoped_ptr<google_apis::FileResource> app_root_2(
242      CreateRemoteFolder(sync_root->file_id(), "app-root 2"));
243
244  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
245
246  EXPECT_EQ(1u, CountTrackersForFile(sync_root->file_id()));
247  EXPECT_EQ(1u, CountTrackersForFile(app_root_1->file_id()));
248  EXPECT_EQ(1u, CountTrackersForFile(app_root_2->file_id()));
249
250  EXPECT_TRUE(HasActiveTracker(sync_root->file_id()));
251  EXPECT_FALSE(HasActiveTracker(app_root_1->file_id()));
252  EXPECT_FALSE(HasActiveTracker(app_root_2->file_id()));
253
254  EXPECT_EQ(3u, CountFileMetadata());
255  EXPECT_EQ(3u, CountFileTracker());
256}
257
258TEST_F(SyncEngineInitializerTest, DatabaseAlreadyInitialized) {
259  scoped_ptr<google_apis::FileResource> sync_root(CreateRemoteSyncRoot());
260  scoped_ptr<google_apis::FileResource> app_root_1(
261      CreateRemoteFolder(sync_root->file_id(), "app-root 1"));
262  scoped_ptr<google_apis::FileResource> app_root_2(
263      CreateRemoteFolder(sync_root->file_id(), "app-root 2"));
264
265  const google_apis::FileResource* app_roots[] = {
266    app_root_1.get(), app_root_2.get()
267  };
268  EXPECT_EQ(SYNC_STATUS_OK,
269            PopulateDatabase(*sync_root, app_roots, arraysize(app_roots)));
270
271  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
272
273  EXPECT_EQ(1u, CountTrackersForFile(sync_root->file_id()));
274  EXPECT_EQ(1u, CountTrackersForFile(app_root_1->file_id()));
275  EXPECT_EQ(1u, CountTrackersForFile(app_root_2->file_id()));
276
277  EXPECT_TRUE(HasActiveTracker(sync_root->file_id()));
278  EXPECT_FALSE(HasActiveTracker(app_root_1->file_id()));
279  EXPECT_FALSE(HasActiveTracker(app_root_2->file_id()));
280
281  EXPECT_EQ(3u, CountFileMetadata());
282  EXPECT_EQ(3u, CountFileTracker());
283}
284
285TEST_F(SyncEngineInitializerTest, EmptyDatabase_MultiCandidate) {
286  scoped_ptr<google_apis::FileResource> sync_root_1(CreateRemoteSyncRoot());
287  scoped_ptr<google_apis::FileResource> sync_root_2(CreateRemoteSyncRoot());
288
289  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
290
291  EXPECT_EQ(1u, CountTrackersForFile(sync_root_1->file_id()));
292  EXPECT_EQ(0u, CountTrackersForFile(sync_root_2->file_id()));
293
294  EXPECT_TRUE(HasActiveTracker(sync_root_1->file_id()));
295  EXPECT_FALSE(HasActiveTracker(sync_root_2->file_id()));
296
297  EXPECT_EQ(1u, CountFileMetadata());
298  EXPECT_EQ(1u, CountFileTracker());
299}
300
301TEST_F(SyncEngineInitializerTest, EmptyDatabase_UndetachedRemoteSyncRoot) {
302  scoped_ptr<google_apis::FileResource> sync_root(CreateRemoteFolder(
303      std::string(), kSyncRootFolderTitle));
304  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
305
306  EXPECT_EQ(1u, CountTrackersForFile(sync_root->file_id()));
307  EXPECT_TRUE(HasActiveTracker(sync_root->file_id()));
308
309  EXPECT_TRUE(HasNoParent(sync_root->file_id()));
310
311  EXPECT_EQ(1u, CountFileMetadata());
312  EXPECT_EQ(1u, CountFileTracker());
313}
314
315TEST_F(SyncEngineInitializerTest, EmptyDatabase_MultiparentSyncRoot) {
316  scoped_ptr<google_apis::FileResource> folder(CreateRemoteFolder(
317      std::string(), "folder"));
318  scoped_ptr<google_apis::FileResource> sync_root(CreateRemoteFolder(
319      std::string(), kSyncRootFolderTitle));
320  AddParentFolder(sync_root->file_id(), folder->file_id());
321
322  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
323
324  EXPECT_EQ(1u, CountTrackersForFile(sync_root->file_id()));
325  EXPECT_TRUE(HasActiveTracker(sync_root->file_id()));
326
327  EXPECT_TRUE(HasNoParent(sync_root->file_id()));
328
329  EXPECT_EQ(1u, CountFileMetadata());
330  EXPECT_EQ(1u, CountFileTracker());
331}
332
333TEST_F(SyncEngineInitializerTest, EmptyDatabase_FakeRemoteSyncRoot) {
334  scoped_ptr<google_apis::FileResource> folder(CreateRemoteFolder(
335      std::string(), "folder"));
336  scoped_ptr<google_apis::FileResource> sync_root(CreateRemoteFolder(
337      folder->file_id(), kSyncRootFolderTitle));
338
339  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
340
341  EXPECT_EQ(0u, CountTrackersForFile(sync_root->file_id()));
342  EXPECT_FALSE(HasNoParent(sync_root->file_id()));
343
344  EXPECT_EQ(1u, CountFileMetadata());
345  EXPECT_EQ(1u, CountFileTracker());
346}
347
348}  // namespace drive_backend
349}  // namespace sync_file_system
350