local_to_remote_syncer_unittest.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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/local_to_remote_syncer.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/files/scoped_temp_dir.h"
10#include "base/logging.h"
11#include "base/run_loop.h"
12#include "base/thread_task_runner_handle.h"
13#include "chrome/browser/drive/drive_api_util.h"
14#include "chrome/browser/drive/drive_uploader.h"
15#include "chrome/browser/drive/fake_drive_service.h"
16#include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
17#include "chrome/browser/sync_file_system/drive_backend/drive_backend_test_util.h"
18#include "chrome/browser/sync_file_system/drive_backend/fake_drive_service_helper.h"
19#include "chrome/browser/sync_file_system/drive_backend/fake_drive_uploader.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/metadata_database.pb.h"
23#include "chrome/browser/sync_file_system/drive_backend/remote_to_local_syncer.h"
24#include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
25#include "chrome/browser/sync_file_system/drive_backend/sync_engine_initializer.h"
26#include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
27#include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
28#include "chrome/browser/sync_file_system/fake_remote_change_processor.h"
29#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
30#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
31#include "content/public/test/test_browser_thread_bundle.h"
32#include "google_apis/drive/drive_api_parser.h"
33#include "google_apis/drive/gdata_errorcode.h"
34#include "testing/gtest/include/gtest/gtest.h"
35#include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
36#include "third_party/leveldatabase/src/include/leveldb/env.h"
37
38namespace sync_file_system {
39namespace drive_backend {
40
41namespace {
42
43fileapi::FileSystemURL URL(const GURL& origin,
44                           const std::string& path) {
45  return CreateSyncableFileSystemURL(
46      origin, base::FilePath::FromUTF8Unsafe(path));
47}
48
49const int kRetryLimit = 100;
50
51}  // namespace
52
53class LocalToRemoteSyncerTest : public testing::Test {
54 public:
55  LocalToRemoteSyncerTest()
56      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
57  virtual ~LocalToRemoteSyncerTest() {}
58
59  virtual void SetUp() OVERRIDE {
60    ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
61    in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
62
63    scoped_ptr<FakeDriveServiceWrapper>
64        fake_drive_service(new FakeDriveServiceWrapper);
65    scoped_ptr<drive::DriveUploaderInterface>
66        drive_uploader(new FakeDriveUploader(fake_drive_service.get()));
67    fake_drive_helper_.reset(new FakeDriveServiceHelper(
68        fake_drive_service.get(),
69        drive_uploader.get(),
70        kSyncRootFolderTitle));
71    remote_change_processor_.reset(new FakeRemoteChangeProcessor);
72
73    context_.reset(new SyncEngineContext(
74        fake_drive_service.PassAs<drive::DriveServiceInterface>(),
75        drive_uploader.Pass(),
76        NULL,
77        base::ThreadTaskRunnerHandle::Get(),
78        base::ThreadTaskRunnerHandle::Get()));
79    context_->SetRemoteChangeProcessor(remote_change_processor_.get());
80
81    RegisterSyncableFileSystem();
82
83    sync_task_manager_.reset(new SyncTaskManager(
84        base::WeakPtr<SyncTaskManager::Client>(),
85        10 /* maximum_background_task */,
86        base::ThreadTaskRunnerHandle::Get()));
87    sync_task_manager_->Initialize(SYNC_STATUS_OK);
88  }
89
90  virtual void TearDown() OVERRIDE {
91    sync_task_manager_.reset();
92    RevokeSyncableFileSystem();
93    fake_drive_helper_.reset();
94    context_.reset();
95    base::RunLoop().RunUntilIdle();
96  }
97
98  void InitializeMetadataDatabase() {
99    SyncEngineInitializer* initializer =
100        new SyncEngineInitializer(context_.get(),
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->RunPreflight(SyncTaskToken::CreateForTesting(
178        CreateResultReceiver(&status)));
179    base::RunLoop().RunUntilIdle();
180    return status;
181  }
182
183  SyncStatusCode ListChanges() {
184    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
185    sync_task_manager_->ScheduleSyncTask(
186        FROM_HERE,
187        scoped_ptr<SyncTask>(new ListChangesTask(context_.get())),
188        SyncTaskManager::PRIORITY_MED,
189        CreateResultReceiver(&status));
190    base::RunLoop().RunUntilIdle();
191    return status;
192  }
193
194  SyncStatusCode RunRemoteToLocalSyncer() {
195    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
196    scoped_ptr<RemoteToLocalSyncer>
197        syncer(new RemoteToLocalSyncer(context_.get()));
198    syncer->RunPreflight(SyncTaskToken::CreateForTesting(
199        CreateResultReceiver(&status)));
200    base::RunLoop().RunUntilIdle();
201    return status;
202  }
203
204  SyncStatusCode RunRemoteToLocalSyncerUntilIdle() {
205    SyncStatusCode status;
206    int retry_count = 0;
207    do {
208      if (retry_count++ > kRetryLimit)
209        break;
210      status = RunRemoteToLocalSyncer();
211    } while (status == SYNC_STATUS_OK ||
212             status == SYNC_STATUS_RETRY ||
213             GetMetadataDatabase()->PromoteLowerPriorityTrackersToNormal());
214    EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC, status);
215    return status;
216  }
217
218  ScopedVector<google_apis::ResourceEntry>
219  GetResourceEntriesForParentAndTitle(const std::string& parent_folder_id,
220                                      const std::string& title) {
221    ScopedVector<google_apis::ResourceEntry> entries;
222    EXPECT_EQ(google_apis::HTTP_SUCCESS,
223              fake_drive_helper_->SearchByTitle(
224                  parent_folder_id, title, &entries));
225    return entries.Pass();
226  }
227
228  std::string GetFileIDForParentAndTitle(const std::string& parent_folder_id,
229                                         const std::string& title) {
230    ScopedVector<google_apis::ResourceEntry> entries =
231        GetResourceEntriesForParentAndTitle(parent_folder_id, title);
232    if (entries.size() != 1)
233      return std::string();
234    return entries[0]->resource_id();
235  }
236
237  void VerifyTitleUniqueness(
238      const std::string& parent_folder_id,
239      const std::string& title,
240      google_apis::ResourceEntry::ResourceEntryKind kind) {
241    ScopedVector<google_apis::ResourceEntry> entries;
242    EXPECT_EQ(google_apis::HTTP_SUCCESS,
243              fake_drive_helper_->SearchByTitle(
244                  parent_folder_id, title, &entries));
245    ASSERT_EQ(1u, entries.size());
246    EXPECT_EQ(kind, entries[0]->kind());
247  }
248
249  void VerifyFileDeletion(const std::string& parent_folder_id,
250                          const std::string& title) {
251    ScopedVector<google_apis::ResourceEntry> entries;
252    EXPECT_EQ(google_apis::HTTP_SUCCESS,
253              fake_drive_helper_->SearchByTitle(
254                  parent_folder_id, title, &entries));
255    EXPECT_TRUE(entries.empty());
256  }
257
258 private:
259  content::TestBrowserThreadBundle thread_bundle_;
260  base::ScopedTempDir database_dir_;
261  scoped_ptr<leveldb::Env> in_memory_env_;
262
263  scoped_ptr<SyncEngineContext> context_;
264  scoped_ptr<FakeDriveServiceHelper> fake_drive_helper_;
265  scoped_ptr<FakeRemoteChangeProcessor> remote_change_processor_;
266  scoped_ptr<SyncTaskManager> sync_task_manager_;
267
268  DISALLOW_COPY_AND_ASSIGN(LocalToRemoteSyncerTest);
269};
270
271TEST_F(LocalToRemoteSyncerTest, CreateFile) {
272  const GURL kOrigin("chrome-extension://example");
273  const std::string sync_root = CreateSyncRoot();
274  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
275  InitializeMetadataDatabase();
276  RegisterApp(kOrigin.host(), app_root);
277
278  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
279      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
280                 SYNC_FILE_TYPE_FILE),
281      URL(kOrigin, "file1")));
282  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
283      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
284                 SYNC_FILE_TYPE_DIRECTORY),
285      URL(kOrigin, "folder")));
286  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
287      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
288                 SYNC_FILE_TYPE_FILE),
289      URL(kOrigin, "folder/file2")));
290
291  std::string folder_id = GetFileIDForParentAndTitle(app_root, "folder");
292  ASSERT_FALSE(folder_id.empty());
293
294  VerifyTitleUniqueness(
295      app_root, "file1", google_apis::ResourceEntry::ENTRY_KIND_FILE);
296  VerifyTitleUniqueness(
297      app_root, "folder", google_apis::ResourceEntry::ENTRY_KIND_FOLDER);
298  VerifyTitleUniqueness(
299      folder_id, "file2", google_apis::ResourceEntry::ENTRY_KIND_FILE);
300}
301
302TEST_F(LocalToRemoteSyncerTest, CreateFileOnMissingPath) {
303  const GURL kOrigin("chrome-extension://example");
304  const std::string sync_root = CreateSyncRoot();
305  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
306  InitializeMetadataDatabase();
307  RegisterApp(kOrigin.host(), app_root);
308
309  // Run the syncer 3 times to create missing folder1 and folder2.
310  EXPECT_EQ(SYNC_STATUS_RETRY, RunLocalToRemoteSyncer(
311      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
312                 SYNC_FILE_TYPE_FILE),
313      URL(kOrigin, "folder1/folder2/file")));
314  EXPECT_EQ(SYNC_STATUS_RETRY, RunLocalToRemoteSyncer(
315      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
316                 SYNC_FILE_TYPE_FILE),
317      URL(kOrigin, "folder1/folder2/file")));
318  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
319      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
320                 SYNC_FILE_TYPE_FILE),
321      URL(kOrigin, "folder1/folder2/file")));
322
323  std::string folder_id1 = GetFileIDForParentAndTitle(app_root, "folder1");
324  ASSERT_FALSE(folder_id1.empty());
325  std::string folder_id2 = GetFileIDForParentAndTitle(folder_id1, "folder2");
326  ASSERT_FALSE(folder_id2.empty());
327
328  VerifyTitleUniqueness(
329      app_root, "folder1", google_apis::ResourceEntry::ENTRY_KIND_FOLDER);
330  VerifyTitleUniqueness(
331      folder_id1, "folder2", google_apis::ResourceEntry::ENTRY_KIND_FOLDER);
332  VerifyTitleUniqueness(
333      folder_id2, "file", google_apis::ResourceEntry::ENTRY_KIND_FILE);
334}
335
336TEST_F(LocalToRemoteSyncerTest, DeleteFile) {
337  const GURL kOrigin("chrome-extension://example");
338  const std::string sync_root = CreateSyncRoot();
339  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
340  InitializeMetadataDatabase();
341  RegisterApp(kOrigin.host(), app_root);
342
343  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
344      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
345                 SYNC_FILE_TYPE_FILE),
346      URL(kOrigin, "file")));
347  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
348      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
349                 SYNC_FILE_TYPE_DIRECTORY),
350      URL(kOrigin, "folder")));
351
352  VerifyTitleUniqueness(
353      app_root, "file", google_apis::ResourceEntry::ENTRY_KIND_FILE);
354  VerifyTitleUniqueness(
355      app_root, "folder", google_apis::ResourceEntry::ENTRY_KIND_FOLDER);
356
357  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
358      FileChange(FileChange::FILE_CHANGE_DELETE,
359                 SYNC_FILE_TYPE_FILE),
360      URL(kOrigin, "file")));
361  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
362      FileChange(FileChange::FILE_CHANGE_DELETE,
363                 SYNC_FILE_TYPE_DIRECTORY),
364      URL(kOrigin, "folder")));
365
366  VerifyFileDeletion(app_root, "file");
367  VerifyFileDeletion(app_root, "folder");
368}
369
370TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFolder) {
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  CreateRemoteFolder(app_root, "foo");
378  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
379  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
380      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
381                 SYNC_FILE_TYPE_FILE),
382      URL(kOrigin, "foo")));
383
384  // There should exist both file and folder on remote.
385  ScopedVector<google_apis::ResourceEntry> entries =
386      GetResourceEntriesForParentAndTitle(app_root, "foo");
387  ASSERT_EQ(2u, entries.size());
388  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FOLDER, entries[0]->kind());
389  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FILE, entries[1]->kind());
390}
391
392TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFolderOnFile) {
393  const GURL kOrigin("chrome-extension://example");
394  const std::string sync_root = CreateSyncRoot();
395  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
396  InitializeMetadataDatabase();
397  RegisterApp(kOrigin.host(), app_root);
398
399  CreateRemoteFile(app_root, "foo", "data");
400  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
401
402  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
403      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
404                 SYNC_FILE_TYPE_DIRECTORY),
405      URL(kOrigin, "foo")));
406
407  // There should exist both file and folder on remote.
408  ScopedVector<google_apis::ResourceEntry> entries =
409      GetResourceEntriesForParentAndTitle(app_root, "foo");
410  ASSERT_EQ(2u, entries.size());
411  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FILE, entries[0]->kind());
412  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FOLDER, entries[1]->kind());
413}
414
415TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFileOnFile) {
416  const GURL kOrigin("chrome-extension://example");
417  const std::string sync_root = CreateSyncRoot();
418  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
419  InitializeMetadataDatabase();
420  RegisterApp(kOrigin.host(), app_root);
421
422  CreateRemoteFile(app_root, "foo", "data");
423  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
424
425  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
426      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
427                 SYNC_FILE_TYPE_FILE),
428      URL(kOrigin, "foo")));
429
430  // There should exist both files on remote.
431  ScopedVector<google_apis::ResourceEntry> entries =
432      GetResourceEntriesForParentAndTitle(app_root, "foo");
433  ASSERT_EQ(2u, entries.size());
434  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FILE, entries[0]->kind());
435  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FILE, entries[1]->kind());
436}
437
438TEST_F(LocalToRemoteSyncerTest, Conflict_UpdateDeleteOnFile) {
439  const GURL kOrigin("chrome-extension://example");
440  const std::string sync_root = CreateSyncRoot();
441  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
442  InitializeMetadataDatabase();
443  RegisterApp(kOrigin.host(), app_root);
444
445  const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
446  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
447  EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC,
448            RunRemoteToLocalSyncerUntilIdle());
449
450  DeleteResource(file_id);
451
452  EXPECT_EQ(SYNC_STATUS_FILE_BUSY, RunLocalToRemoteSyncer(
453      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
454                 SYNC_FILE_TYPE_FILE),
455      URL(kOrigin, "foo")));
456  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
457      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
458                 SYNC_FILE_TYPE_FILE),
459      URL(kOrigin, "foo")));
460
461  ScopedVector<google_apis::ResourceEntry> entries =
462      GetResourceEntriesForParentAndTitle(app_root, "foo");
463  ASSERT_EQ(1u, entries.size());
464  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FILE, entries[0]->kind());
465  EXPECT_TRUE(!entries[0]->deleted());
466  EXPECT_NE(file_id, entries[0]->resource_id());
467}
468
469TEST_F(LocalToRemoteSyncerTest, Conflict_CreateDeleteOnFile) {
470  const GURL kOrigin("chrome-extension://example");
471  const std::string sync_root = CreateSyncRoot();
472  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
473  InitializeMetadataDatabase();
474  RegisterApp(kOrigin.host(), app_root);
475
476  const std::string file_id = CreateRemoteFile(app_root, "foo", "data");
477  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
478  EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC,
479            RunRemoteToLocalSyncerUntilIdle());
480
481  DeleteResource(file_id);
482
483  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
484
485  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
486      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
487                 SYNC_FILE_TYPE_FILE),
488      URL(kOrigin, "foo")));
489
490  ScopedVector<google_apis::ResourceEntry> entries =
491      GetResourceEntriesForParentAndTitle(app_root, "foo");
492  ASSERT_EQ(1u, entries.size());
493  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FILE, entries[0]->kind());
494  EXPECT_TRUE(!entries[0]->deleted());
495  EXPECT_NE(file_id, entries[0]->resource_id());
496}
497
498TEST_F(LocalToRemoteSyncerTest, Conflict_CreateFolderOnFolder) {
499  const GURL kOrigin("chrome-extension://example");
500  const std::string sync_root = CreateSyncRoot();
501  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
502  InitializeMetadataDatabase();
503  RegisterApp(kOrigin.host(), app_root);
504
505  const std::string folder_id = CreateRemoteFolder(app_root, "foo");
506
507  EXPECT_EQ(SYNC_STATUS_OK, RunLocalToRemoteSyncer(
508      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
509                 SYNC_FILE_TYPE_DIRECTORY),
510      URL(kOrigin, "foo")));
511
512  ScopedVector<google_apis::ResourceEntry> entries =
513      GetResourceEntriesForParentAndTitle(app_root, "foo");
514  ASSERT_EQ(2u, entries.size());
515  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FOLDER, entries[0]->kind());
516  EXPECT_EQ(google_apis::ResourceEntry::ENTRY_KIND_FOLDER, entries[1]->kind());
517  EXPECT_TRUE(!entries[0]->deleted());
518  EXPECT_TRUE(!entries[1]->deleted());
519  EXPECT_TRUE(folder_id == entries[0]->resource_id() ||
520              folder_id == entries[1]->resource_id());
521
522  TrackerIDSet trackers;
523  EXPECT_TRUE(GetMetadataDatabase()->FindTrackersByFileID(
524      folder_id, &trackers));
525  EXPECT_EQ(1u, trackers.size());
526  ASSERT_TRUE(trackers.has_active());
527}
528
529TEST_F(LocalToRemoteSyncerTest, AppRootDeletion) {
530  const GURL kOrigin("chrome-extension://example");
531  const std::string sync_root = CreateSyncRoot();
532  const std::string app_root = CreateRemoteFolder(sync_root, kOrigin.host());
533  InitializeMetadataDatabase();
534  RegisterApp(kOrigin.host(), app_root);
535
536  DeleteResource(app_root);
537  EXPECT_EQ(SYNC_STATUS_OK, ListChanges());
538  EXPECT_EQ(SYNC_STATUS_NO_CHANGE_TO_SYNC,
539            RunRemoteToLocalSyncerUntilIdle());
540
541  EXPECT_EQ(SYNC_STATUS_UNKNOWN_ORIGIN, RunLocalToRemoteSyncer(
542      FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
543                 SYNC_FILE_TYPE_DIRECTORY),
544      URL(kOrigin, "foo")));
545
546  // SyncEngine will re-register the app and resurrect the app root later.
547}
548
549}  // namespace drive_backend
550}  // namespace sync_file_system
551