local_to_remote_syncer_unittest.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Copyright 2013 The Chromium Authors. All rights reserved.
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Use of this source code is governed by a BSD-style license that can be
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// found in the LICENSE file.
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/local_to_remote_syncer.h"
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "base/bind.h"
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "base/callback.h"
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "base/files/scoped_temp_dir.h"
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "base/logging.h"
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "base/run_loop.h"
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/drive/drive_api_util.h"
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/drive/drive_uploader.h"
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/drive/fake_drive_service.h"
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/drive_backend_test_util.h"
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/fake_drive_uploader.h"
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/list_changes_task.h"
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h"
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/fake_remote_change_processor.h"
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "content/public/test/test_browser_thread_bundle.h"
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "google_apis/drive/drive_api_parser.h"
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "google_apis/drive/gdata_errorcode.h"
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "testing/gtest/include/gtest/gtest.h"
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "third_party/leveldatabase/src/include/leveldb/env.h"
35
36namespace sync_file_system {
37namespace drive_backend {
38
39namespace {
40
41fileapi::FileSystemURL URL(const GURL& origin,
42                           const std::string& path) {
43  return CreateSyncableFileSystemURL(
44      origin, base::FilePath::FromUTF8Unsafe(path));
45}
46
47}  // namespace
48
49class LocalToRemoteSyncerTest : public testing::Test {
50 public:
51  LocalToRemoteSyncerTest()
52      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
53  virtual ~LocalToRemoteSyncerTest() {}
54
55  virtual void SetUp() OVERRIDE {
56    ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
57    in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
58
59    fake_drive_service_.reset(new FakeDriveServiceWrapper);
60
61    drive_uploader_.reset(new FakeDriveUploader(fake_drive_service_.get()));
62    fake_drive_helper_.reset(new FakeDriveServiceHelper(
63        fake_drive_service_.get(),
64        drive_uploader_.get(),
65        kSyncRootFolderTitle));
66    fake_remote_change_processor_.reset(new FakeRemoteChangeProcessor);
67
68    context_.reset(new SyncEngineContext(
69        fake_drive_service_.get(),
70        drive_uploader_.get(),
71        base::MessageLoopProxy::current(),
72        base::MessageLoopProxy::current(),
73        base::MessageLoopProxy::current()));
74    context_->SetRemoteChangeProcessor(fake_remote_change_processor_.get());
75
76    RegisterSyncableFileSystem();
77
78    sync_task_manager_.reset(new SyncTaskManager(
79        base::WeakPtr<SyncTaskManager::Client>(),
80        10 /* maximum_background_task */));
81    sync_task_manager_->Initialize(SYNC_STATUS_OK);
82  }
83
84  virtual void TearDown() OVERRIDE {
85    sync_task_manager_.reset();
86    fake_drive_service_.reset();
87    drive_uploader_.reset();
88
89    RevokeSyncableFileSystem();
90
91    fake_remote_change_processor_.reset();
92    fake_drive_helper_.reset();
93    context_.reset();
94    base::RunLoop().RunUntilIdle();
95  }
96
97  void InitializeMetadataDatabase() {
98    SyncEngineInitializer* initializer =
99        new SyncEngineInitializer(context_.get(),
100                                  base::MessageLoopProxy::current(),
101                                  database_dir_.path(),
102                                  in_memory_env_.get());
103    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
104
105    sync_task_manager_->ScheduleSyncTask(
106        FROM_HERE,
107        scoped_ptr<SyncTask>(initializer),
108        SyncTaskManager::PRIORITY_MED,
109        base::Bind(&LocalToRemoteSyncerTest::DidInitializeMetadataDatabase,
110                   base::Unretained(this), initializer, &status));
111
112    base::RunLoop().RunUntilIdle();
113    EXPECT_EQ(SYNC_STATUS_OK, status);
114  }
115
116  void DidInitializeMetadataDatabase(SyncEngineInitializer* initializer,
117                                     SyncStatusCode* status_out,
118                                     SyncStatusCode status) {
119    *status_out = status;
120    context_->SetMetadataDatabase(initializer->PassMetadataDatabase());
121  }
122
123  void RegisterApp(const std::string& app_id,
124                   const std::string& app_root_folder_id) {
125    SyncStatusCode status = SYNC_STATUS_FAILED;
126    context_->GetMetadataDatabase()->RegisterApp(
127        app_id, app_root_folder_id, CreateResultReceiver(&status));
128    base::RunLoop().RunUntilIdle();
129    EXPECT_EQ(SYNC_STATUS_OK, status);
130  }
131
132  MetadataDatabase* GetMetadataDatabase() {
133    return context_->GetMetadataDatabase();
134  }
135
136 protected:
137  std::string CreateSyncRoot() {
138    std::string sync_root_folder_id;
139    EXPECT_EQ(google_apis::HTTP_CREATED,
140              fake_drive_helper_->AddOrphanedFolder(
141                  kSyncRootFolderTitle, &sync_root_folder_id));
142    return sync_root_folder_id;
143  }
144
145  std::string CreateRemoteFolder(const std::string& parent_folder_id,
146                                 const std::string& title) {
147    std::string folder_id;
148    EXPECT_EQ(google_apis::HTTP_CREATED,
149              fake_drive_helper_->AddFolder(
150                  parent_folder_id, title, &folder_id));
151    return folder_id;
152  }
153
154  std::string CreateRemoteFile(const std::string& parent_folder_id,
155                               const std::string& title,
156                               const std::string& content) {
157    std::string file_id;
158    EXPECT_EQ(google_apis::HTTP_SUCCESS,
159              fake_drive_helper_->AddFile(
160                  parent_folder_id, title, content, &file_id));
161    return file_id;
162  }
163
164  void DeleteResource(const std::string& file_id) {
165    EXPECT_EQ(google_apis::HTTP_NO_CONTENT,
166              fake_drive_helper_->DeleteResource(file_id));
167  }
168
169  SyncStatusCode RunLocalToRemoteSyncer(FileChange file_change,
170                           const fileapi::FileSystemURL& url) {
171    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
172    base::FilePath local_path = base::FilePath::FromUTF8Unsafe("dummy");
173    scoped_ptr<LocalToRemoteSyncer> syncer(new LocalToRemoteSyncer(
174        context_.get(),
175        SyncFileMetadata(file_change.file_type(), 0, base::Time()),
176        file_change, local_path, url));
177    syncer->RunExclusive(CreateResultReceiver(&status));
178    base::RunLoop().RunUntilIdle();
179    return status;
180  }
181
182  SyncStatusCode ListChanges() {
183    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
184    sync_task_manager_->ScheduleSyncTask(
185        FROM_HERE,
186        scoped_ptr<SyncTask>(new ListChangesTask(context_.get())),
187        SyncTaskManager::PRIORITY_MED,
188        CreateResultReceiver(&status));
189    base::RunLoop().RunUntilIdle();
190    return status;
191  }
192
193  SyncStatusCode RunRemoteToLocalSyncer() {
194    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
195    scoped_ptr<RemoteToLocalSyncer>
196        syncer(new RemoteToLocalSyncer(context_.get()));
197    syncer->RunExclusive(CreateResultReceiver(&status));
198    base::RunLoop().RunUntilIdle();
199    return status;
200  }
201
202  ScopedVector<google_apis::ResourceEntry>
203  GetResourceEntriesForParentAndTitle(const std::string& parent_folder_id,
204                                      const std::string& title) {
205    ScopedVector<google_apis::ResourceEntry> entries;
206    EXPECT_EQ(google_apis::HTTP_SUCCESS,
207              fake_drive_helper_->SearchByTitle(
208                  parent_folder_id, title, &entries));
209    return entries.Pass();
210  }
211
212  std::string GetFileIDForParentAndTitle(const std::string& parent_folder_id,
213                                         const std::string& title) {
214    ScopedVector<google_apis::ResourceEntry> entries =
215        GetResourceEntriesForParentAndTitle(parent_folder_id, title);
216    if (entries.size() != 1)
217      return std::string();
218    return entries[0]->resource_id();
219  }
220
221  void VerifyTitleUniqueness(const std::string& parent_folder_id,
222                             const std::string& title,
223                             google_apis::DriveEntryKind kind) {
224    ScopedVector<google_apis::ResourceEntry> entries;
225    EXPECT_EQ(google_apis::HTTP_SUCCESS,
226              fake_drive_helper_->SearchByTitle(
227                  parent_folder_id, title, &entries));
228    ASSERT_EQ(1u, entries.size());
229    EXPECT_EQ(kind, entries[0]->kind());
230  }
231
232  void VerifyFileDeletion(const std::string& parent_folder_id,
233                          const std::string& title) {
234    ScopedVector<google_apis::ResourceEntry> entries;
235    EXPECT_EQ(google_apis::HTTP_SUCCESS,
236              fake_drive_helper_->SearchByTitle(
237                  parent_folder_id, title, &entries));
238    EXPECT_TRUE(entries.empty());
239  }
240
241 private:
242  content::TestBrowserThreadBundle thread_bundle_;
243  base::ScopedTempDir database_dir_;
244  scoped_ptr<leveldb::Env> in_memory_env_;
245
246  scoped_ptr<FakeDriveServiceWrapper> fake_drive_service_;
247  scoped_ptr<drive::DriveUploaderInterface> drive_uploader_;
248  scoped_ptr<SyncEngineContext> context_;
249  scoped_ptr<FakeDriveServiceHelper> fake_drive_helper_;
250  scoped_ptr<MetadataDatabase> metadata_database_;
251  scoped_ptr<FakeRemoteChangeProcessor> fake_remote_change_processor_;
252  scoped_ptr<SyncTaskManager> sync_task_manager_;
253
254  DISALLOW_COPY_AND_ASSIGN(LocalToRemoteSyncerTest);
255};
256
257TEST_F(LocalToRemoteSyncerTest, CreateFile) {
258  const GURL kOrigin("chrome-extension://example");
259  const std::string sync_root = CreateSyncRoot();
260  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
261  InitializeMetadataDatabase();
262  RegisterApp(kOrigin.host(), app_root);
263
264  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
265      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
266                 SYNC_FILE_TYPE_FILE),
267      URL(kOrigin, "file1")));
268  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
269      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
270                 SYNC_FILE_TYPE_DIRECTORY),
271      URL(kOrigin, "folder")));
272  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
273      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
274                 SYNC_FILE_TYPE_FILE),
275      URL(kOrigin, "folder/file2")));
276
277  std::string folder_id = GetFileIDForParentAndTitle(app_root, "folder");
278  ASSERT_FALSE(folder_id.empty());
279
280  VerifyTitleUniqueness(app_root, "file1", google_apis::ENTRY_KIND_FILE);
281  VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER);
282  VerifyTitleUniqueness(folder_id, "file2", google_apis::ENTRY_KIND_FILE);
283}
284
285TEST_F(LocalToRemoteSyncerTest, CreateFileOnMissingPath) {
286  const GURL kOrigin("chrome-extension://example");
287  const std::string sync_root = CreateSyncRoot();
288  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
289  InitializeMetadataDatabase();
290  RegisterApp(kOrigin.host(), app_root);
291
292  // Run the syncer 3 times to create missing folder1 and folder2.
293  EXPECT_EQ(SYNC_STATUS_RETRY, RunLocalToRemoteSyncer(
294      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
295                 SYNC_FILE_TYPE_FILE),
296      URL(kOrigin, "folder1/folder2/file")));
297  EXPECT_EQ(SYNC_STATUS_RETRY, RunLocalToRemoteSyncer(
298      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
299                 SYNC_FILE_TYPE_FILE),
300      URL(kOrigin, "folder1/folder2/file")));
301  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
302      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
303                 SYNC_FILE_TYPE_FILE),
304      URL(kOrigin, "folder1/folder2/file")));
305
306  std::string folder_id1 = GetFileIDForParentAndTitle(app_root, "folder1");
307  ASSERT_FALSE(folder_id1.empty());
308  std::string folder_id2 = GetFileIDForParentAndTitle(folder_id1, "folder2");
309  ASSERT_FALSE(folder_id2.empty());
310
311  VerifyTitleUniqueness(app_root, "folder1", google_apis::ENTRY_KIND_FOLDER);
312  VerifyTitleUniqueness(folder_id1, "folder2", google_apis::ENTRY_KIND_FOLDER);
313  VerifyTitleUniqueness(folder_id2, "file", google_apis::ENTRY_KIND_FILE);
314}
315
316TEST_F(LocalToRemoteSyncerTest, DeleteFile) {
317  const GURL kOrigin("chrome-extension://example");
318  const std::string sync_root = CreateSyncRoot();
319  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
320  InitializeMetadataDatabase();
321  RegisterApp(kOrigin.host(), app_root);
322
323  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
324      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
325                 SYNC_FILE_TYPE_FILE),
326      URL(kOrigin, "file")));
327  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
328      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
329                 SYNC_FILE_TYPE_DIRECTORY),
330      URL(kOrigin, "folder")));
331
332  VerifyTitleUniqueness(app_root, "file", google_apis::ENTRY_KIND_FILE);
333  VerifyTitleUniqueness(app_root, "folder", google_apis::ENTRY_KIND_FOLDER);
334
335  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
336      FileChange(FileChange::FILE_CHANGE_DELETE,
337                 SYNC_FILE_TYPE_FILE),
338      URL(kOrigin, "file")));
339  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
340      FileChange(FileChange::FILE_CHANGE_DELETE,
341                 SYNC_FILE_TYPE_DIRECTORY),
342      URL(kOrigin, "folder")));
343
344  VerifyFileDeletion(app_root, "file");
345  VerifyFileDeletion(app_root, "folder");
346}
347
348TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFolder) {
349  const GURL kOrigin("chrome-extension://example");
350  const std::string sync_root = CreateSyncRoot();
351  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
352  InitializeMetadataDatabase();
353  RegisterApp(kOrigin.host(), app_root);
354
355  CreateRemoteFolder(app_root, "foo");
356  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
357  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
358      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
359                 SYNC_FILE_TYPE_FILE),
360      URL(kOrigin, "foo")));
361
362  // There should exist both file and folder on remote.
363  ScopedVector<google_apis::ResourceEntry> entries =
364      GetResourceEntriesForParentAndTitle(app_root, "foo");
365  ASSERT_EQ(2u, entries.size());
366  EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[0]->kind());
367  EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[1]->kind());
368}
369
370TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFolderOnFile) {
371  const GURL kOrigin("chrome-extension://example");
372  const std::string sync_root = CreateSyncRoot();
373  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
374  InitializeMetadataDatabase();
375  RegisterApp(kOrigin.host(), app_root);
376
377  CreateRemoteFile(app_root, "foo", "data");
378  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
379
380  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
381      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
382                 SYNC_FILE_TYPE_DIRECTORY),
383      URL(kOrigin, "foo")));
384
385  // There should exist both file and folder on remote.
386  ScopedVector<google_apis::ResourceEntry> entries =
387      GetResourceEntriesForParentAndTitle(app_root, "foo");
388  ASSERT_EQ(2u, entries.size());
389  EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
390  EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[1]->kind());
391}
392
393TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFile) {
394  const GURL kOrigin("chrome-extension://example");
395  const std::string sync_root = CreateSyncRoot();
396  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
397  InitializeMetadataDatabase();
398  RegisterApp(kOrigin.host(), app_root);
399
400  CreateRemoteFile(app_root, "foo", "data");
401  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
402
403  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
404      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
405                 SYNC_FILE_TYPE_FILE),
406      URL(kOrigin, "foo")));
407
408  // There should exist both files on remote.
409  ScopedVector<google_apis::ResourceEntry> entries =
410      GetResourceEntriesForParentAndTitle(app_root, "foo");
411  ASSERT_EQ(2u, entries.size());
412  EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
413  EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[1]->kind());
414}
415
416TEST_F(LocalToRemoteSyncerTest, Conflict_UpdateDeleteOnFile) {
417  const GURL kOrigin("chrome-extension://example");
418  const std::string sync_root = CreateSyncRoot();
419  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
420  InitializeMetadataDatabase();
421  RegisterApp(kOrigin.host(), app_root);
422
423  const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
424  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
425
426  SyncStatusCode status;
427  do {
428    status = RunRemoteToLocalSyncer();
429    EXPECT_TRUE(status == SYNC_STATUS_OK ||
430                status == SYNC_STATUS_RETRY ||
431                status == SYNC_STATUS_NO_CHANGE_TO_SYNC);
432  } while (status != SYNC_STATUS_NO_CHANGE_TO_SYNC);
433
434  DeleteResource(file_id);
435
436  EXPECT_EQ(SYNC_STATUS_FILE_BUSY, RunLocalToRemoteSyncer(
437      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
438                 SYNC_FILE_TYPE_FILE),
439      URL(kOrigin, "foo")));
440  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
441      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
442                 SYNC_FILE_TYPE_FILE),
443      URL(kOrigin, "foo")));
444
445  ScopedVector<google_apis::ResourceEntry> entries =
446      GetResourceEntriesForParentAndTitle(app_root, "foo");
447  ASSERT_EQ(1u, entries.size());
448  EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
449  EXPECT_TRUE(!entries[0]->deleted());
450  EXPECT_NE(file_id, entries[0]->resource_id());
451}
452
453TEST_F(LocalToRemoteSyncerTest, Conflict_CreateDeleteOnFile) {
454  const GURL kOrigin("chrome-extension://example");
455  const std::string sync_root = CreateSyncRoot();
456  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
457  InitializeMetadataDatabase();
458  RegisterApp(kOrigin.host(), app_root);
459
460  const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
461  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
462  SyncStatusCode status;
463  do {
464    status = RunRemoteToLocalSyncer();
465    EXPECT_TRUE(status == SYNC_STATUS_OK ||
466                status == SYNC_STATUS_RETRY ||
467                status == SYNC_STATUS_NO_CHANGE_TO_SYNC);
468  } while (status != SYNC_STATUS_NO_CHANGE_TO_SYNC);
469
470  DeleteResource(file_id);
471
472  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
473
474  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
475      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
476                 SYNC_FILE_TYPE_FILE),
477      URL(kOrigin, "foo")));
478
479  ScopedVector<google_apis::ResourceEntry> entries =
480      GetResourceEntriesForParentAndTitle(app_root, "foo");
481  ASSERT_EQ(1u, entries.size());
482  EXPECT_EQ(google_apis::ENTRY_KIND_FILE, entries[0]->kind());
483  EXPECT_TRUE(!entries[0]->deleted());
484  EXPECT_NE(file_id, entries[0]->resource_id());
485}
486
487TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFolderOnFolder) {
488  const GURL kOrigin("chrome-extension://example");
489  const std::string sync_root = CreateSyncRoot();
490  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
491  InitializeMetadataDatabase();
492  RegisterApp(kOrigin.host(), app_root);
493
494  const std::string folder_id = CreateRemoteFolder(app_root, "foo");
495
496  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
497      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
498                 SYNC_FILE_TYPE_DIRECTORY),
499      URL(kOrigin, "foo")));
500
501  ScopedVector<google_apis::ResourceEntry> entries =
502      GetResourceEntriesForParentAndTitle(app_root, "foo");
503  ASSERT_EQ(2u, entries.size());
504  EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[0]->kind());
505  EXPECT_EQ(google_apis::ENTRY_KIND_FOLDER, entries[1]->kind());
506  EXPECT_TRUE(!entries[0]->deleted());
507  EXPECT_TRUE(!entries[1]->deleted());
508  EXPECT_TRUE(folder_id == entries[0]->resource_id() ||
509              folder_id == entries[1]->resource_id());
510
511  TrackerIDSet trackers;
512  EXPECT_TRUE(GetMetadataDatabase()->FindTrackersByFileID(
513      folder_id, &trackers));
514  EXPECT_EQ(1u, trackers.size());
515  ASSERT_TRUE(trackers.has_active());
516}
517
518TEST_F(LocalToRemoteSyncerTest, AppRootDeletion) {
519  const GURL kOrigin("chrome-extension://example");
520  const std::string sync_root = CreateSyncRoot();
521  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
522  InitializeMetadataDatabase();
523  RegisterApp(kOrigin.host(), app_root);
524
525  DeleteResource(app_root);
526  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
527  SyncStatusCode status;
528  do {
529    status = RunRemoteToLocalSyncer();
530    EXPECT_TRUE(status == SYNC_STATUS_OK ||
531                status == SYNC_STATUS_RETRY ||
532                status == SYNC_STATUS_NO_CHANGE_TO_SYNC);
533  } while (status != SYNC_STATUS_NO_CHANGE_TO_SYNC);
534
535  EXPECT_EQ(SYNC_STATUS_UNKNOWN_ORIGIN, RunLocalToRemoteSyncer(
536      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
537                 SYNC_FILE_TYPE_DIRECTORY),
538      URL(kOrigin, "foo")));
539
540  // SyncEngine will re-register the app and resurrect the app root later.
541}
542
543}  // namespace drive_backend
544}  // namespace sync_file_system
545