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