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