sync_engine_initializer_unittest.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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    sync_task_manager_->Initialize(SYNC_STATUS_OK);
66  }
67
68  virtual void TearDown() OVERRIDE {
69    sync_task_manager_.reset();
70    metadata_database_.reset();
71    sync_context_.reset();
72    base::RunLoop().RunUntilIdle();
73  }
74
75  base::FilePath database_path() {
76    return database_dir_.path();
77  }
78
79  SyncStatusCode RunInitializer() {
80    SyncEngineInitializer* initializer =
81        new SyncEngineInitializer(sync_context_.get(),
82                                  database_path(),
83                                  in_memory_env_.get());
84    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
85
86    sync_task_manager_->ScheduleSyncTask(
87        FROM_HERE,
88        scoped_ptr<SyncTask>(initializer),
89        SyncTaskManager::PRIORITY_MED,
90        base::Bind(&SyncEngineInitializerTest::DidRunInitializer,
91                   base::Unretained(this), initializer, &status));
92
93    base::RunLoop().RunUntilIdle();
94    return status;
95  }
96
97  void DidRunInitializer(SyncEngineInitializer* initializer,
98                         SyncStatusCode* status_out,
99                         SyncStatusCode status) {
100    *status_out = status;
101    metadata_database_ = initializer->PassMetadataDatabase();
102  }
103
104  SyncStatusCode PopulateDatabase(
105      const google_apis::FileResource& sync_root,
106      const google_apis::FileResource** app_roots,
107      size_t app_roots_count) {
108    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
109    scoped_ptr<MetadataDatabase> database;
110    MetadataDatabase::Create(
111        base::MessageLoopProxy::current(),
112        base::MessageLoopProxy::current(),
113        database_path(),
114        in_memory_env_.get(),
115        CreateResultReceiver(&status, &database));
116    base::RunLoop().RunUntilIdle();
117    if (status != SYNC_STATUS_OK)
118      return status;
119
120    // |app_root_list| must not own the resources here. Be sure to call
121    // weak_clear later.
122    ScopedVector<google_apis::FileResource> app_root_list;
123    for (size_t i = 0; i < app_roots_count; ++i) {
124      app_root_list.push_back(
125          const_cast<google_apis::FileResource*>(app_roots[i]));
126    }
127
128    status = SYNC_STATUS_UNKNOWN;
129    database->PopulateInitialData(kInitialLargestChangeID,
130                                  sync_root,
131                                  app_root_list,
132                                  CreateResultReceiver(&status));
133    base::RunLoop().RunUntilIdle();
134
135    app_root_list.weak_clear();
136
137    return SYNC_STATUS_OK;
138  }
139
140  scoped_ptr<google_apis::FileResource> CreateRemoteFolder(
141      const std::string& parent_folder_id,
142      const std::string& title) {
143    google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
144    scoped_ptr<google_apis::FileResource> entry;
145    sync_context_->GetDriveService()->AddNewDirectory(
146        parent_folder_id, title,
147        drive::DriveServiceInterface::AddNewDirectoryOptions(),
148        CreateResultReceiver(&error, &entry));
149    base::RunLoop().RunUntilIdle();
150
151    EXPECT_EQ(google_apis::HTTP_CREATED, error);
152    return entry.Pass();
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::FileResource> entry;
195    sync_context_->GetDriveService()->GetFileResource(
196        file_id,
197        CreateResultReceiver(&error, &entry));
198    base::RunLoop().RunUntilIdle();
199    EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
200    return entry->parents().empty();
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
231  DISALLOW_COPY_AND_ASSIGN(SyncEngineInitializerTest);
232};
233
234TEST_F(SyncEngineInitializerTest, EmptyDatabase_NoRemoteSyncRoot) {
235  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
236
237  std::string sync_root_folder_id = GetSyncRootFolderID();
238  EXPECT_EQ(1u, CountTrackersForFile(sync_root_folder_id));
239
240  EXPECT_TRUE(HasActiveTracker(sync_root_folder_id));
241
242  EXPECT_EQ(1u, CountFileMetadata());
243  EXPECT_EQ(1u, CountFileTracker());
244}
245
246TEST_F(SyncEngineInitializerTest, EmptyDatabase_RemoteSyncRootExists) {
247  scoped_ptr<google_apis::FileResource> sync_root(
248      CreateRemoteSyncRoot());
249  scoped_ptr<google_apis::FileResource> app_root_1(
250      CreateRemoteFolder(sync_root->file_id(), "app-root 1"));
251  scoped_ptr<google_apis::FileResource> app_root_2(
252      CreateRemoteFolder(sync_root->file_id(), "app-root 2"));
253
254  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
255
256  EXPECT_EQ(1u, CountTrackersForFile(sync_root->file_id()));
257  EXPECT_EQ(1u, CountTrackersForFile(app_root_1->file_id()));
258  EXPECT_EQ(1u, CountTrackersForFile(app_root_2->file_id()));
259
260  EXPECT_TRUE(HasActiveTracker(sync_root->file_id()));
261  EXPECT_FALSE(HasActiveTracker(app_root_1->file_id()));
262  EXPECT_FALSE(HasActiveTracker(app_root_2->file_id()));
263
264  EXPECT_EQ(3u, CountFileMetadata());
265  EXPECT_EQ(3u, CountFileTracker());
266}
267
268TEST_F(SyncEngineInitializerTest, DatabaseAlreadyInitialized) {
269  scoped_ptr<google_apis::FileResource> sync_root(CreateRemoteSyncRoot());
270  scoped_ptr<google_apis::FileResource> app_root_1(
271      CreateRemoteFolder(sync_root->file_id(), "app-root 1"));
272  scoped_ptr<google_apis::FileResource> app_root_2(
273      CreateRemoteFolder(sync_root->file_id(), "app-root 2"));
274
275  const google_apis::FileResource* app_roots[] = {
276    app_root_1.get(), app_root_2.get()
277  };
278  EXPECT_EQ(SYNC_STATUS_OK,
279            PopulateDatabase(*sync_root, app_roots, arraysize(app_roots)));
280
281  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
282
283  EXPECT_EQ(1u, CountTrackersForFile(sync_root->file_id()));
284  EXPECT_EQ(1u, CountTrackersForFile(app_root_1->file_id()));
285  EXPECT_EQ(1u, CountTrackersForFile(app_root_2->file_id()));
286
287  EXPECT_TRUE(HasActiveTracker(sync_root->file_id()));
288  EXPECT_FALSE(HasActiveTracker(app_root_1->file_id()));
289  EXPECT_FALSE(HasActiveTracker(app_root_2->file_id()));
290
291  EXPECT_EQ(3u, CountFileMetadata());
292  EXPECT_EQ(3u, CountFileTracker());
293}
294
295TEST_F(SyncEngineInitializerTest, EmptyDatabase_MultiCandidate) {
296  scoped_ptr<google_apis::FileResource> sync_root_1(CreateRemoteSyncRoot());
297  scoped_ptr<google_apis::FileResource> sync_root_2(CreateRemoteSyncRoot());
298
299  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
300
301  EXPECT_EQ(1u, CountTrackersForFile(sync_root_1->file_id()));
302  EXPECT_EQ(0u, CountTrackersForFile(sync_root_2->file_id()));
303
304  EXPECT_TRUE(HasActiveTracker(sync_root_1->file_id()));
305  EXPECT_FALSE(HasActiveTracker(sync_root_2->file_id()));
306
307  EXPECT_EQ(1u, CountFileMetadata());
308  EXPECT_EQ(1u, CountFileTracker());
309}
310
311TEST_F(SyncEngineInitializerTest, EmptyDatabase_UndetachedRemoteSyncRoot) {
312  scoped_ptr<google_apis::FileResource> sync_root(CreateRemoteFolder(
313      std::string(), kSyncRootFolderTitle));
314  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
315
316  EXPECT_EQ(1u, CountTrackersForFile(sync_root->file_id()));
317  EXPECT_TRUE(HasActiveTracker(sync_root->file_id()));
318
319  EXPECT_TRUE(HasNoParent(sync_root->file_id()));
320
321  EXPECT_EQ(1u, CountFileMetadata());
322  EXPECT_EQ(1u, CountFileTracker());
323}
324
325TEST_F(SyncEngineInitializerTest, EmptyDatabase_MultiparentSyncRoot) {
326  scoped_ptr<google_apis::FileResource> folder(CreateRemoteFolder(
327      std::string(), "folder"));
328  scoped_ptr<google_apis::FileResource> sync_root(CreateRemoteFolder(
329      std::string(), kSyncRootFolderTitle));
330  AddParentFolder(sync_root->file_id(), folder->file_id());
331
332  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
333
334  EXPECT_EQ(1u, CountTrackersForFile(sync_root->file_id()));
335  EXPECT_TRUE(HasActiveTracker(sync_root->file_id()));
336
337  EXPECT_TRUE(HasNoParent(sync_root->file_id()));
338
339  EXPECT_EQ(1u, CountFileMetadata());
340  EXPECT_EQ(1u, CountFileTracker());
341}
342
343TEST_F(SyncEngineInitializerTest, EmptyDatabase_FakeRemoteSyncRoot) {
344  scoped_ptr<google_apis::FileResource> folder(CreateRemoteFolder(
345      std::string(), "folder"));
346  scoped_ptr<google_apis::FileResource> sync_root(CreateRemoteFolder(
347      folder->file_id(), kSyncRootFolderTitle));
348
349  EXPECT_EQ(SYNC_STATUS_OK, RunInitializer());
350
351  EXPECT_EQ(0u, CountTrackersForFile(sync_root->file_id()));
352  EXPECT_FALSE(HasNoParent(sync_root->file_id()));
353
354  EXPECT_EQ(1u, CountFileMetadata());
355  EXPECT_EQ(1u, CountFileTracker());
356}
357
358}  // namespace drive_backend
359}  // namespace sync_file_system
360