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