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