sync_engine_initializer_unittest.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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    fake_drive_service_.reset(new drive::FakeDriveService());
52
53    sync_context_.reset(new SyncEngineContext(
54        fake_drive_service_.get(),
55        NULL /* drive_uploader */,
56        base::MessageLoopProxy::current()));
57
58    sync_task_manager_.reset(new SyncTaskManager(
59        base::WeakPtr<SyncTaskManager::Client>(),
60        1 /* maximum_parallel_task */));
61    sync_task_manager_->Initialize(SYNC_STATUS_OK);
62  }
63
64  virtual void TearDown() OVERRIDE {
65    sync_task_manager_.reset();
66    metadata_database_.reset();
67    sync_context_.reset();
68    fake_drive_service_.reset();
69    base::RunLoop().RunUntilIdle();
70  }
71
72  base::FilePath database_path() {
73    return database_dir_.path();
74  }
75
76  SyncStatusCode RunInitializer() {
77    SyncEngineInitializer* initializer =
78        new SyncEngineInitializer(
79            sync_context_.get(),
80            base::MessageLoopProxy::current(),
81            database_path(),
82            in_memory_env_.get());
83    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
84
85    sync_task_manager_->ScheduleSyncTask(
86        FROM_HERE,
87        scoped_ptr<SyncTask>(initializer),
88        SyncTaskManager::PRIORITY_MED,
89        base::Bind(&SyncEngineInitializerTest::DidRunInitializer,
90                   base::Unretained(this), initializer, &status));
91
92    base::RunLoop().RunUntilIdle();
93    return status;
94  }
95
96  void DidRunInitializer(SyncEngineInitializer* initializer,
97                         SyncStatusCode* status_out,
98                         SyncStatusCode status) {
99    *status_out = status;
100    metadata_database_ = initializer->PassMetadataDatabase();
101  }
102
103  SyncStatusCode PopulateDatabase(
104      const google_apis::FileResource& sync_root,
105      const google_apis::FileResource** app_roots,
106      size_t app_roots_count) {
107    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
108    scoped_ptr<MetadataDatabase> database;
109    MetadataDatabase::Create(
110        base::MessageLoopProxy::current(),
111        database_path(),
112        in_memory_env_.get(),
113        CreateResultReceiver(&status, &database));
114    base::RunLoop().RunUntilIdle();
115    if (status != SYNC_STATUS_OK)
116      return status;
117
118    // |app_root_list| must not own the resources here. Be sure to call
119    // weak_clear later.
120    ScopedVector<google_apis::FileResource> app_root_list;
121    for (size_t i = 0; i < app_roots_count; ++i) {
122      app_root_list.push_back(
123          const_cast<google_apis::FileResource*>(app_roots[i]));
124    }
125
126    status = SYNC_STATUS_UNKNOWN;
127    database->PopulateInitialData(kInitialLargestChangeID,
128                                  sync_root,
129                                  app_root_list,
130                                  CreateResultReceiver(&status));
131    base::RunLoop().RunUntilIdle();
132
133    app_root_list.weak_clear();
134
135    return SYNC_STATUS_OK;
136  }
137
138  scoped_ptr<google_apis::FileResource> CreateRemoteFolder(
139      const std::string& parent_folder_id,
140      const std::string& title) {
141    google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
142    scoped_ptr<google_apis::ResourceEntry> entry;
143    sync_context_->GetDriveService()->AddNewDirectory(
144        parent_folder_id, title,
145        drive::DriveServiceInterface::AddNewDirectoryOptions(),
146        CreateResultReceiver(&error, &entry));
147    base::RunLoop().RunUntilIdle();
148
149    EXPECT_EQ(google_apis::HTTP_CREATED, error);
150    if (!entry)
151      scoped_ptr<google_apis::FileResource>();
152    return drive::util::ConvertResourceEntryToFileResource(*entry);
153  }
154
155  scoped_ptr<google_apis::FileResource> CreateRemoteSyncRoot() {
156    scoped_ptr<google_apis::FileResource> sync_root(
157        CreateRemoteFolder(std::string(), kSyncRootFolderTitle));
158
159    for (size_t i = 0; i < sync_root->parents().size(); ++i) {
160      google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
161      sync_context_->GetDriveService()->RemoveResourceFromDirectory(
162          sync_root->parents()[i].file_id(),
163          sync_root->file_id(),
164          CreateResultReceiver(&error));
165      base::RunLoop().RunUntilIdle();
166      EXPECT_EQ(google_apis::HTTP_NO_CONTENT, error);
167    }
168
169    return sync_root.Pass();
170  }
171
172  std::string GetSyncRootFolderID() {
173    int64 sync_root_tracker_id = metadata_database_->GetSyncRootTrackerID();
174    FileTracker sync_root_tracker;
175    EXPECT_TRUE(metadata_database_->FindTrackerByTrackerID(
176        sync_root_tracker_id, &sync_root_tracker));
177    return sync_root_tracker.file_id();
178  }
179
180  size_t CountTrackersForFile(const std::string& file_id) {
181    TrackerIDSet trackers;
182    metadata_database_->FindTrackersByFileID(file_id, &trackers);
183    return trackers.size();
184  }
185
186  bool HasActiveTracker(const std::string& file_id) {
187    TrackerIDSet trackers;
188    return metadata_database_->FindTrackersByFileID(file_id, &trackers) &&
189        trackers.has_active();
190  }
191
192  bool HasNoParent(const std::string& file_id) {
193    google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
194    scoped_ptr<google_apis::ResourceEntry> entry;
195    sync_context_->GetDriveService()->GetResourceEntry(
196        file_id,
197        CreateResultReceiver(&error, &entry));
198    base::RunLoop().RunUntilIdle();
199    EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
200    return !entry->GetLinkByType(google_apis::Link::LINK_PARENT);
201  }
202
203  size_t CountFileMetadata() {
204    return metadata_database_->CountFileMetadata();
205  }
206
207  size_t CountFileTracker() {
208    return metadata_database_->CountFileTracker();
209  }
210
211  google_apis::GDataErrorCode AddParentFolder(
212      const std::string& new_parent_folder_id,
213      const std::string& file_id) {
214    google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
215    sync_context_->GetDriveService()->AddResourceToDirectory(
216        new_parent_folder_id, file_id,
217        CreateResultReceiver(&error));
218    base::RunLoop().RunUntilIdle();
219    return error;
220  }
221
222 private:
223  content::TestBrowserThreadBundle browser_threads_;
224  base::ScopedTempDir database_dir_;
225  scoped_ptr<leveldb::Env> in_memory_env_;
226
227  scoped_ptr<MetadataDatabase> metadata_database_;
228  scoped_ptr<SyncTaskManager> sync_task_manager_;
229  scoped_ptr<SyncEngineContext> sync_context_;
230  scoped_ptr<drive::FakeDriveService> fake_drive_service_;
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