Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / drive_backend / remote_to_local_syncer_unittest.cc
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/remote_to_local_syncer.h"
6
7 #include <map>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/logging.h"
13 #include "base/run_loop.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "chrome/browser/drive/drive_uploader.h"
16 #include "chrome/browser/drive/fake_drive_service.h"
17 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
18 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_test_util.h"
19 #include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
20 #include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h"
21 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
22 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
23 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
24 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
25 #include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
26 #include "chrome/browser/sync_file_system/fake_remote_change_processor.h"
27 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
28 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
29 #include "content/public/test/test_browser_thread_bundle.h"
30 #include "google_apis/drive/gdata_errorcode.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
33 #include "third_party/leveldatabase/src/include/leveldb/env.h"
34
35 namespace sync_file_system {
36 namespace drive_backend {
37
38 namespace {
39
40 storage::FileSystemURL URL(const GURL& origin, const std::string& path) {
41   return CreateSyncableFileSystemURL(
42       origin, base::FilePath::FromUTF8Unsafe(path));
43 }
44
45 }  // namespace
46
47 class RemoteToLocalSyncerTest : public testing::Test {
48  public:
49   typedef FakeRemoteChangeProcessor::URLToFileChangesMap URLToFileChangesMap;
50
51   RemoteToLocalSyncerTest()
52       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
53   ~RemoteToLocalSyncerTest() override {}
54
55   void SetUp() override {
56     ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
57     in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
58
59     scoped_ptr<drive::FakeDriveService>
60         fake_drive_service(new drive::FakeDriveService);
61
62     scoped_ptr<drive::DriveUploaderInterface>
63         drive_uploader(new drive::DriveUploader(
64             fake_drive_service.get(),
65             base::ThreadTaskRunnerHandle::Get().get()));
66     fake_drive_helper_.reset(
67         new FakeDriveServiceHelper(fake_drive_service.get(),
68                                    drive_uploader.get(),
69                                    kSyncRootFolderTitle));
70     remote_change_processor_.reset(new FakeRemoteChangeProcessor);
71
72     context_.reset(new SyncEngineContext(fake_drive_service.Pass(),
73                                          drive_uploader.Pass(),
74                                          nullptr,
75                                          base::ThreadTaskRunnerHandle::Get(),
76                                          base::ThreadTaskRunnerHandle::Get()));
77     context_->SetRemoteChangeProcessor(remote_change_processor_.get());
78
79     RegisterSyncableFileSystem();
80
81     sync_task_manager_.reset(new SyncTaskManager(
82         base::WeakPtr<SyncTaskManager::Client>(),
83         10 /* max_parallel_task */,
84         base::ThreadTaskRunnerHandle::Get()));
85     sync_task_manager_->Initialize(SYNC_STATUS_OK);
86   }
87
88   void TearDown() override {
89     sync_task_manager_.reset();
90     RevokeSyncableFileSystem();
91     fake_drive_helper_.reset();
92     context_.reset();
93     base::RunLoop().RunUntilIdle();
94   }
95
96   void InitializeMetadataDatabase() {
97     SyncEngineInitializer* initializer =
98         new SyncEngineInitializer(context_.get(),
99                                   database_dir_.path(),
100                                   in_memory_env_.get());
101     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
102     sync_task_manager_->ScheduleSyncTask(
103         FROM_HERE,
104         scoped_ptr<SyncTask>(initializer),
105         SyncTaskManager::PRIORITY_MED,
106         base::Bind(&RemoteToLocalSyncerTest::DidInitializeMetadataDatabase,
107                    base::Unretained(this),
108                    initializer, &status));
109
110     base::RunLoop().RunUntilIdle();
111     EXPECT_EQ(SYNC_STATUS_OK, status);
112   }
113
114   void DidInitializeMetadataDatabase(SyncEngineInitializer* initializer,
115                                      SyncStatusCode* status_out,
116                                      SyncStatusCode status) {
117     *status_out = status;
118     context_->SetMetadataDatabase(initializer->PassMetadataDatabase());
119   }
120
121
122   void RegisterApp(const std::string& app_id,
123                    const std::string& app_root_folder_id) {
124     SyncStatusCode status = context_->GetMetadataDatabase()->RegisterApp(
125         app_id, app_root_folder_id);
126     EXPECT_EQ(SYNC_STATUS_OK, status);
127   }
128
129   MetadataDatabase* GetMetadataDatabase() {
130     return context_->GetMetadataDatabase();
131   }
132
133  protected:
134   std::string CreateSyncRoot() {
135     std::string sync_root_folder_id;
136     EXPECT_EQ(google_apis::HTTP_CREATED,
137               fake_drive_helper_->AddOrphanedFolder(
138                   kSyncRootFolderTitle, &sync_root_folder_id));
139     return sync_root_folder_id;
140   }
141
142   std::string CreateRemoteFolder(const std::string& parent_folder_id,
143                                  const std::string& title) {
144     std::string folder_id;
145     EXPECT_EQ(google_apis::HTTP_CREATED,
146               fake_drive_helper_->AddFolder(
147                   parent_folder_id, title, &folder_id));
148     return folder_id;
149   }
150
151   std::string CreateRemoteFile(const std::string& parent_folder_id,
152                                const std::string& title,
153                                const std::string& content) {
154     std::string file_id;
155     EXPECT_EQ(google_apis::HTTP_SUCCESS,
156               fake_drive_helper_->AddFile(
157                   parent_folder_id, title, content, &file_id));
158     return file_id;
159   }
160
161   void DeleteRemoteFile(const std::string& file_id) {
162     EXPECT_EQ(google_apis::HTTP_NO_CONTENT,
163               fake_drive_helper_->DeleteResource(file_id));
164   }
165
166   void CreateLocalFolder(const storage::FileSystemURL& url) {
167     remote_change_processor_->UpdateLocalFileMetadata(
168         url, FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
169                         SYNC_FILE_TYPE_DIRECTORY));
170   }
171
172   void CreateLocalFile(const storage::FileSystemURL& url) {
173     remote_change_processor_->UpdateLocalFileMetadata(
174         url, FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
175                         SYNC_FILE_TYPE_FILE));
176   }
177
178   SyncStatusCode RunSyncer() {
179     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
180     scoped_ptr<RemoteToLocalSyncer>
181         syncer(new RemoteToLocalSyncer(context_.get()));
182     syncer->RunPreflight(SyncTaskToken::CreateForTesting(
183         CreateResultReceiver(&status)));
184     base::RunLoop().RunUntilIdle();
185     return status;
186   }
187
188   SyncStatusCode RunSyncerUntilIdle() {
189     const int kRetryLimit = 100;
190     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
191     int count = 0;
192     do {
193       if (count++ > kRetryLimit)
194         return status;
195       status = RunSyncer();
196     } while (status == SYNC_STATUS_OK ||
197              status == SYNC_STATUS_RETRY);
198     return status;
199   }
200
201   SyncStatusCode RunSyncerAndPromoteUntilIdle() {
202     const int kRetryLimit = 100;
203     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
204     MetadataDatabase* metadata_database = context_->GetMetadataDatabase();
205     int count = 0;
206     do {
207       if (count++ > kRetryLimit)
208         return status;
209       status = RunSyncer();
210     } while (status == SYNC_STATUS_OK ||
211              status == SYNC_STATUS_RETRY ||
212              metadata_database->PromoteDemotedTrackers());
213     return status;
214   }
215
216   SyncStatusCode ListChanges() {
217     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
218     sync_task_manager_->ScheduleSyncTask(
219         FROM_HERE,
220         scoped_ptr<SyncTask>(new ListChangesTask(context_.get())),
221         SyncTaskManager::PRIORITY_MED,
222         CreateResultReceiver(&status));
223     base::RunLoop().RunUntilIdle();
224     return status;
225   }
226
227   void AppendExpectedChange(const storage::FileSystemURL& url,
228                             FileChange::ChangeType change_type,
229                             SyncFileType file_type) {
230     expected_changes_[url].push_back(FileChange(change_type, file_type));
231   }
232
233   void VerifyConsistency() {
234     remote_change_processor_->VerifyConsistency(expected_changes_);
235   }
236
237  private:
238   content::TestBrowserThreadBundle thread_bundle_;
239   base::ScopedTempDir database_dir_;
240   scoped_ptr<leveldb::Env> in_memory_env_;
241
242   scoped_ptr<SyncEngineContext> context_;
243   scoped_ptr<FakeDriveServiceHelper> fake_drive_helper_;
244   scoped_ptr<FakeRemoteChangeProcessor> remote_change_processor_;
245
246   scoped_ptr<SyncTaskManager> sync_task_manager_;
247
248   URLToFileChangesMap expected_changes_;
249
250   DISALLOW_COPY_AND_ASSIGN(RemoteToLocalSyncerTest);
251 };
252
253 TEST_F(RemoteToLocalSyncerTest, AddNewFile) {
254   const GURL kOrigin("chrome-extension://example");
255   const std::string sync_root = CreateSyncRoot();
256   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
257   InitializeMetadataDatabase();
258   RegisterApp(kOrigin.host(), app_root);
259
260   const std::string folder1 = CreateRemoteFolder(app_root, "folder1");
261   const std::string file1 = CreateRemoteFile(app_root, "file1", "data1");
262   const std::string folder2 = CreateRemoteFolder(folder1, "folder2");
263   const std::string file2 = CreateRemoteFile(folder1, "file2", "data2");
264
265   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerAndPromoteUntilIdle());
266
267   // Create expected changes.
268   // TODO(nhiroki): Clean up creating URL part.
269   AppendExpectedChange(URL(kOrigin, "folder1"),
270                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
271                        SYNC_FILE_TYPE_DIRECTORY);
272   AppendExpectedChange(URL(kOrigin, "file1"),
273                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
274                        SYNC_FILE_TYPE_FILE);
275   AppendExpectedChange(URL(kOrigin, "folder1/folder2"),
276                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
277                        SYNC_FILE_TYPE_DIRECTORY);
278   AppendExpectedChange(URL(kOrigin, "folder1/file2"),
279                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
280                        SYNC_FILE_TYPE_FILE);
281
282   VerifyConsistency();
283
284   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
285 }
286
287 TEST_F(RemoteToLocalSyncerTest, DeleteFile) {
288   const GURL kOrigin("chrome-extension://example");
289   const std::string sync_root = CreateSyncRoot();
290   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
291   InitializeMetadataDatabase();
292   RegisterApp(kOrigin.host(), app_root);
293
294   const std::string folder = CreateRemoteFolder(app_root, "folder");
295   const std::string file = CreateRemoteFile(app_root, "file", "data");
296
297   AppendExpectedChange(URL(kOrigin, "folder"),
298                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
299                        SYNC_FILE_TYPE_DIRECTORY);
300   AppendExpectedChange(URL(kOrigin, "file"),
301                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
302                        SYNC_FILE_TYPE_FILE);
303
304   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerAndPromoteUntilIdle());
305   VerifyConsistency();
306
307   DeleteRemoteFile(folder);
308   DeleteRemoteFile(file);
309
310   AppendExpectedChange(URL(kOrigin, "folder"),
311                        FileChange::FILE_CHANGE_DELETE,
312                        SYNC_FILE_TYPE_UNKNOWN);
313   AppendExpectedChange(URL(kOrigin, "file"),
314                        FileChange::FILE_CHANGE_DELETE,
315                        SYNC_FILE_TYPE_UNKNOWN);
316
317   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
318   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
319   VerifyConsistency();
320
321   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
322 }
323
324 TEST_F(RemoteToLocalSyncerTest, DeleteNestedFiles) {
325   const GURL kOrigin("chrome-extension://example");
326   const std::string sync_root = CreateSyncRoot();
327   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
328   InitializeMetadataDatabase();
329   RegisterApp(kOrigin.host(), app_root);
330
331   const std::string folder1 = CreateRemoteFolder(app_root, "folder1");
332   const std::string file1 = CreateRemoteFile(app_root, "file1", "data1");
333   const std::string folder2 = CreateRemoteFolder(folder1, "folder2");
334   const std::string file2 = CreateRemoteFile(folder1, "file2", "data2");
335
336   AppendExpectedChange(URL(kOrigin, "folder1"),
337                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
338                        SYNC_FILE_TYPE_DIRECTORY);
339   AppendExpectedChange(URL(kOrigin, "file1"),
340                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
341                        SYNC_FILE_TYPE_FILE);
342   AppendExpectedChange(URL(kOrigin, "folder1/folder2"),
343                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
344                        SYNC_FILE_TYPE_DIRECTORY);
345   AppendExpectedChange(URL(kOrigin, "folder1/file2"),
346                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
347                        SYNC_FILE_TYPE_FILE);
348
349   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerAndPromoteUntilIdle());
350   VerifyConsistency();
351
352   DeleteRemoteFile(folder1);
353
354   AppendExpectedChange(URL(kOrigin, "folder1"),
355                        FileChange::FILE_CHANGE_DELETE,
356                        SYNC_FILE_TYPE_UNKNOWN);
357   // Changes for descendant files ("folder2" and "file2") should be ignored.
358
359   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
360   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
361   VerifyConsistency();
362
363   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
364 }
365
366 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateFileOnFolder) {
367   const GURL kOrigin("chrome-extension://example");
368   const std::string sync_root = CreateSyncRoot();
369   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
370   InitializeMetadataDatabase();
371   RegisterApp(kOrigin.host(), app_root);
372
373   CreateLocalFolder(URL(kOrigin, "folder"));
374   CreateRemoteFile(app_root, "folder", "data");
375
376   // Folder-File conflict happens. File creation should be ignored.
377
378   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
379   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
380   VerifyConsistency();
381
382   // Tracker for the remote file should has low priority.
383   EXPECT_FALSE(GetMetadataDatabase()->GetDirtyTracker(nullptr));
384   EXPECT_TRUE(GetMetadataDatabase()->HasDemotedDirtyTracker());
385 }
386
387 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateFolderOnFile) {
388   const GURL kOrigin("chrome-extension://example");
389   const std::string sync_root = CreateSyncRoot();
390   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
391   InitializeMetadataDatabase();
392   RegisterApp(kOrigin.host(), app_root);
393
394   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
395   VerifyConsistency();
396
397   CreateLocalFile(URL(kOrigin, "file"));
398   CreateRemoteFolder(app_root, "file");
399
400   // File-Folder conflict happens. Folder should override the existing file.
401   AppendExpectedChange(URL(kOrigin, "file"),
402                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
403                        SYNC_FILE_TYPE_DIRECTORY);
404
405   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
406   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
407   VerifyConsistency();
408
409   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
410 }
411
412 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateFolderOnFolder) {
413   const GURL kOrigin("chrome-extension://example");
414   const std::string sync_root = CreateSyncRoot();
415   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
416   InitializeMetadataDatabase();
417   RegisterApp(kOrigin.host(), app_root);
418
419   CreateLocalFolder(URL(kOrigin, "folder"));
420   CreateRemoteFolder(app_root, "folder");
421
422   // Folder-Folder conflict happens. Folder creation should be ignored.
423
424   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
425   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
426   VerifyConsistency();
427
428   EXPECT_FALSE(GetMetadataDatabase()->HasDirtyTracker());
429 }
430
431 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateFileOnFile) {
432   const GURL kOrigin("chrome-extension://example");
433   const std::string sync_root = CreateSyncRoot();
434   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
435   InitializeMetadataDatabase();
436   RegisterApp(kOrigin.host(), app_root);
437
438   CreateLocalFile(URL(kOrigin, "file"));
439   CreateRemoteFile(app_root, "file", "data");
440
441   // File-File conflict happens. File creation should be ignored.
442
443   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
444   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
445   VerifyConsistency();
446
447   // Tracker for the remote file should be lowered.
448   EXPECT_FALSE(GetMetadataDatabase()->GetDirtyTracker(nullptr));
449   EXPECT_TRUE(GetMetadataDatabase()->HasDemotedDirtyTracker());
450 }
451
452 TEST_F(RemoteToLocalSyncerTest, Conflict_CreateNestedFolderOnFile) {
453   const GURL kOrigin("chrome-extension://example");
454   const std::string sync_root = CreateSyncRoot();
455   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
456   InitializeMetadataDatabase();
457   RegisterApp(kOrigin.host(), app_root);
458
459   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
460   VerifyConsistency();
461
462   const std::string folder = CreateRemoteFolder(app_root, "folder");
463   CreateLocalFile(URL(kOrigin, "/folder"));
464   CreateRemoteFile(folder, "file", "data");
465
466   // File-Folder conflict happens. Folder should override the existing file.
467   AppendExpectedChange(URL(kOrigin, "/folder"),
468                        FileChange::FILE_CHANGE_ADD_OR_UPDATE,
469                        SYNC_FILE_TYPE_DIRECTORY);
470
471   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
472   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
473   VerifyConsistency();
474 }
475
476 TEST_F(RemoteToLocalSyncerTest, AppRootDeletion) {
477   const GURL kOrigin("chrome-extension://example");
478   const std::string sync_root = CreateSyncRoot();
479   const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
480   InitializeMetadataDatabase();
481   RegisterApp(kOrigin.host(), app_root);
482
483   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
484   VerifyConsistency();
485
486   DeleteRemoteFile(app_root);
487
488   AppendExpectedChange(URL(kOrigin, "/"),
489                        FileChange::FILE_CHANGE_DELETE,
490                        SYNC_FILE_TYPE_UNKNOWN);
491
492   EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
493   EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, RunSyncerUntilIdle());
494   VerifyConsistency();
495
496   // SyncEngine will re-register the app and resurrect the app root later.
497 }
498
499 }  // namespace drive_backend
500 }  // namespace sync_file_system