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