Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / sync_client_unittest.cc
index c5a5019..b0f516e 100644 (file)
@@ -4,26 +4,31 @@
 
 #include "chrome/browser/chromeos/drive/sync_client.h"
 
-#include "base/file_util.h"
 #include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
 #include "base/test/test_timeouts.h"
 #include "chrome/browser/chromeos/drive/change_list_loader.h"
-#include "chrome/browser/chromeos/drive/change_list_processor.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
-#include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
+#include "chrome/browser/chromeos/drive/file_change.h"
+#include "chrome/browser/chromeos/drive/file_system/move_operation.h"
+#include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
+#include "chrome/browser/chromeos/drive/file_system/remove_operation.h"
+#include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/chromeos/drive/test_util.h"
+#include "chrome/browser/drive/event_logger.h"
 #include "chrome/browser/drive/fake_drive_service.h"
-#include "chrome/browser/google_apis/test_util.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "google_apis/drive/drive_api_parser.h"
+#include "google_apis/drive/test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace drive {
@@ -41,6 +46,8 @@ const char kRemoteContent[] = "World!";
 // made with the specified resource ID.
 class SyncClientTestDriveService : public ::drive::FakeDriveService {
  public:
+  SyncClientTestDriveService() : download_file_count_(0) {}
+
   // FakeDriveService override:
   virtual google_apis::CancelCallback DownloadFile(
       const base::FilePath& local_cache_path,
@@ -48,6 +55,7 @@ class SyncClientTestDriveService : public ::drive::FakeDriveService {
       const google_apis::DownloadActionCallback& download_action_callback,
       const google_apis::GetContentCallback& get_content_callback,
       const google_apis::ProgressCallback& progress_callback) OVERRIDE {
+    ++download_file_count_;
     if (resource_id == resource_id_to_be_cancelled_) {
       base::MessageLoopProxy::current()->PostTask(
           FROM_HERE,
@@ -56,6 +64,12 @@ class SyncClientTestDriveService : public ::drive::FakeDriveService {
                      base::FilePath()));
       return google_apis::CancelCallback();
     }
+    if (resource_id == resource_id_to_be_paused_) {
+      paused_action_ = base::Bind(download_action_callback,
+                                  google_apis::GDATA_OTHER_ERROR,
+                                  base::FilePath());
+      return google_apis::CancelCallback();
+    }
     return FakeDriveService::DownloadFile(local_cache_path,
                                           resource_id,
                                           download_action_callback,
@@ -63,20 +77,23 @@ class SyncClientTestDriveService : public ::drive::FakeDriveService {
                                           progress_callback);
   }
 
+  int download_file_count() const { return download_file_count_; }
+
   void set_resource_id_to_be_cancelled(const std::string& resource_id) {
     resource_id_to_be_cancelled_ = resource_id;
   }
 
+  void set_resource_id_to_be_paused(const std::string& resource_id) {
+    resource_id_to_be_paused_ = resource_id;
+  }
+
+  const base::Closure& paused_action() const { return paused_action_; }
+
  private:
+  int download_file_count_;
   std::string resource_id_to_be_cancelled_;
-};
-
-class DummyOperationObserver : public file_system::OperationObserver {
-  // OperationObserver override:
-  virtual void OnDirectoryChangedByOperation(
-      const base::FilePath& path) OVERRIDE {}
-  virtual void OnCacheFileUploadNeededByOperation(
-      const std::string& local_id) OVERRIDE {}
+  std::string resource_id_to_be_paused_;
+  base::Closure paused_action_;
 };
 
 }  // namespace
@@ -92,12 +109,12 @@ class SyncClientTest : public testing::Test {
     fake_network_change_notifier_.reset(
         new test_util::FakeNetworkChangeNotifier);
 
+    logger_.reset(new EventLogger);
+
     drive_service_.reset(new SyncClientTestDriveService);
-    drive_service_->LoadResourceListForWapi("gdata/empty_feed.json");
-    drive_service_->LoadAccountMetadataForWapi(
-        "gdata/account_metadata.json");
 
     scheduler_.reset(new JobScheduler(pref_service_.get(),
+                                      logger_.get(),
                                       drive_service_.get(),
                                       base::MessageLoopProxy::current().get()));
 
@@ -105,23 +122,34 @@ class SyncClientTest : public testing::Test {
         temp_dir_.path(), base::MessageLoopProxy::current().get()));
     ASSERT_TRUE(metadata_storage_->Initialize());
 
-    metadata_.reset(new internal::ResourceMetadata(
-        metadata_storage_.get(), base::MessageLoopProxy::current()));
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
-
     cache_.reset(new FileCache(metadata_storage_.get(),
                                temp_dir_.path(),
                                base::MessageLoopProxy::current().get(),
                                NULL /* free_disk_space_getter */));
     ASSERT_TRUE(cache_->Initialize());
 
+    metadata_.reset(new internal::ResourceMetadata(
+        metadata_storage_.get(), cache_.get(),
+        base::MessageLoopProxy::current()));
+    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
+
+    about_resource_loader_.reset(new AboutResourceLoader(scheduler_.get()));
+    loader_controller_.reset(new LoaderController);
+    change_list_loader_.reset(new ChangeListLoader(
+        logger_.get(),
+        base::MessageLoopProxy::current().get(),
+        metadata_.get(),
+        scheduler_.get(),
+        about_resource_loader_.get(),
+        loader_controller_.get()));
     ASSERT_NO_FATAL_FAILURE(SetUpTestData());
 
     sync_client_.reset(new SyncClient(base::MessageLoopProxy::current().get(),
-                                      &observer_,
+                                      &delegate_,
                                       scheduler_.get(),
                                       metadata_.get(),
                                       cache_.get(),
+                                      loader_controller_.get(),
                                       temp_dir_.path()));
 
     // Disable delaying so that DoSyncLoop() starts immediately.
@@ -131,7 +159,7 @@ class SyncClientTest : public testing::Test {
   // Adds a file to the service root and |resource_ids_|.
   void AddFileEntry(const std::string& title) {
     google_apis::GDataErrorCode error = google_apis::GDATA_FILE_ERROR;
-    scoped_ptr<google_apis::ResourceEntry> entry;
+    scoped_ptr<google_apis::FileResource> entry;
     drive_service_->AddNewFile(
         "text/plain",
         kRemoteContent,
@@ -142,15 +170,14 @@ class SyncClientTest : public testing::Test {
     base::RunLoop().RunUntilIdle();
     ASSERT_EQ(google_apis::HTTP_CREATED, error);
     ASSERT_TRUE(entry);
-    resource_ids_[title] = entry->resource_id();
+    resource_ids_[title] = entry->file_id();
   }
 
   // Sets up data for tests.
   void SetUpTestData() {
     // Prepare a temp file.
     base::FilePath temp_file;
-    EXPECT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir_.path(),
-                                                    &temp_file));
+    EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &temp_file));
     ASSERT_TRUE(google_apis::test_util::WriteStringToFile(temp_file,
                                                           kLocalContent));
 
@@ -160,16 +187,12 @@ class SyncClientTest : public testing::Test {
     ASSERT_NO_FATAL_FAILURE(AddFileEntry("baz"));
     ASSERT_NO_FATAL_FAILURE(AddFileEntry("fetched"));
     ASSERT_NO_FATAL_FAILURE(AddFileEntry("dirty"));
+    ASSERT_NO_FATAL_FAILURE(AddFileEntry("removed"));
+    ASSERT_NO_FATAL_FAILURE(AddFileEntry("moved"));
 
     // Load data from the service to the metadata.
     FileError error = FILE_ERROR_FAILED;
-    internal::ChangeListLoader change_list_loader(
-        base::MessageLoopProxy::current().get(),
-        metadata_.get(),
-        scheduler_.get(),
-        drive_service_.get());
-    change_list_loader.LoadIfNeeded(
-        DirectoryFetchInfo(),
+    change_list_loader_->LoadIfNeeded(
         google_apis::test_util::CreateCopyResultCallback(&error));
     base::RunLoop().RunUntilIdle();
     EXPECT_EQ(FILE_ERROR_OK, error);
@@ -187,13 +210,31 @@ class SyncClientTest : public testing::Test {
     EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("fetched")));
 
     // Prepare a pinned-and-fetched-and-dirty file.
-    const std::string md5_dirty = "";  // Don't care.
     EXPECT_EQ(FILE_ERROR_OK,
-              cache_->Store(GetLocalId("dirty"), md5_dirty,
+              cache_->Store(GetLocalId("dirty"), std::string(),
                             temp_file, FileCache::FILE_OPERATION_COPY));
     EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("dirty")));
-    EXPECT_EQ(FILE_ERROR_OK, cache_->MarkDirty(GetLocalId("dirty")));
 
+    // Prepare a removed file.
+    file_system::RemoveOperation remove_operation(
+        base::MessageLoopProxy::current().get(), &delegate_, metadata_.get(),
+        cache_.get());
+    remove_operation.Remove(
+        util::GetDriveMyDriveRootPath().AppendASCII("removed"),
+        false,  // is_recursive
+        google_apis::test_util::CreateCopyResultCallback(&error));
+    base::RunLoop().RunUntilIdle();
+    EXPECT_EQ(FILE_ERROR_OK, error);
+
+    // Prepare a moved file.
+    file_system::MoveOperation move_operation(
+        base::MessageLoopProxy::current().get(), &delegate_, metadata_.get());
+    move_operation.Move(
+        util::GetDriveMyDriveRootPath().AppendASCII("moved"),
+        util::GetDriveMyDriveRootPath().AppendASCII("moved_new_title"),
+        google_apis::test_util::CreateCopyResultCallback(&error));
+    base::RunLoop().RunUntilIdle();
+    EXPECT_EQ(FILE_ERROR_OK, error);
   }
 
  protected:
@@ -210,13 +251,17 @@ class SyncClientTest : public testing::Test {
   scoped_ptr<TestingPrefServiceSimple> pref_service_;
   scoped_ptr<test_util::FakeNetworkChangeNotifier>
       fake_network_change_notifier_;
+  scoped_ptr<EventLogger> logger_;
   scoped_ptr<SyncClientTestDriveService> drive_service_;
-  DummyOperationObserver observer_;
+  file_system::OperationDelegate delegate_;
   scoped_ptr<JobScheduler> scheduler_;
   scoped_ptr<ResourceMetadataStorage,
              test_util::DestroyHelperForTests> metadata_storage_;
-  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
   scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
+  scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
+  scoped_ptr<AboutResourceLoader> about_resource_loader_;
+  scoped_ptr<LoaderController> loader_controller_;
+  scoped_ptr<ChangeListLoader> change_list_loader_;
   scoped_ptr<SyncClient> sync_client_;
 
   std::map<std::string, std::string> resource_ids_;  // Name-to-id map.
@@ -226,29 +271,55 @@ TEST_F(SyncClientTest, StartProcessingBacklog) {
   sync_client_->StartProcessingBacklog();
   base::RunLoop().RunUntilIdle();
 
-  FileCacheEntry cache_entry;
+  ResourceEntry entry;
   // Pinned files get downloaded.
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("foo"), &cache_entry));
-  EXPECT_TRUE(cache_entry.is_present());
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
+  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
 
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("bar"), &cache_entry));
-  EXPECT_TRUE(cache_entry.is_present());
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("bar"), &entry));
+  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
 
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("baz"), &cache_entry));
-  EXPECT_TRUE(cache_entry.is_present());
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("baz"), &entry));
+  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
 
   // Dirty file gets uploaded.
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("dirty"), &cache_entry));
-  EXPECT_FALSE(cache_entry.is_dirty());
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry));
+  EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
+
+  // Removed entry is not found.
+  google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<google_apis::FileResource> server_entry;
+  drive_service_->GetFileResource(
+      resource_ids_["removed"],
+      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
+  ASSERT_TRUE(server_entry);
+  EXPECT_TRUE(server_entry->labels().is_trashed());
+
+  // Moved entry was moved.
+  status = google_apis::GDATA_OTHER_ERROR;
+  drive_service_->GetFileResource(
+      resource_ids_["moved"],
+      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
+  ASSERT_TRUE(server_entry);
+  EXPECT_EQ("moved_new_title", server_entry->title());
 }
 
 TEST_F(SyncClientTest, AddFetchTask) {
   sync_client_->AddFetchTask(GetLocalId("foo"));
   base::RunLoop().RunUntilIdle();
 
-  FileCacheEntry cache_entry;
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("foo"), &cache_entry));
-  EXPECT_TRUE(cache_entry.is_present());
+  ResourceEntry entry;
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
+  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
 }
 
 TEST_F(SyncClientTest, AddFetchTaskAndCancelled) {
@@ -258,8 +329,10 @@ TEST_F(SyncClientTest, AddFetchTaskAndCancelled) {
   base::RunLoop().RunUntilIdle();
 
   // The file should be unpinned if the user wants the download to be cancelled.
-  FileCacheEntry cache_entry;
-  EXPECT_FALSE(cache_->GetCacheEntry(GetLocalId("foo"), &cache_entry));
+  ResourceEntry entry;
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
+  EXPECT_FALSE(entry.file_specific_info().cache_state().is_pinned());
 }
 
 TEST_F(SyncClientTest, RemoveFetchTask) {
@@ -272,15 +345,18 @@ TEST_F(SyncClientTest, RemoveFetchTask) {
   base::RunLoop().RunUntilIdle();
 
   // Only "bar" should be fetched.
-  FileCacheEntry cache_entry;
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("foo"), &cache_entry));
-  EXPECT_FALSE(cache_entry.is_present());
+  ResourceEntry entry;
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
+  EXPECT_FALSE(entry.file_specific_info().cache_state().is_present());
 
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("bar"), &cache_entry));
-  EXPECT_TRUE(cache_entry.is_present());
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("bar"), &entry));
+  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
 
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("baz"), &cache_entry));
-  EXPECT_FALSE(cache_entry.is_present());
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("baz"), &entry));
+  EXPECT_FALSE(entry.file_specific_info().cache_state().is_present());
 
 }
 
@@ -320,15 +396,18 @@ TEST_F(SyncClientTest, RetryOnDisconnection) {
 
   // Try fetch and upload.
   sync_client_->AddFetchTask(GetLocalId("foo"));
-  sync_client_->AddUploadTask(GetLocalId("dirty"));
+  sync_client_->AddUpdateTask(ClientContext(USER_INITIATED),
+                              GetLocalId("dirty"));
   base::RunLoop().RunUntilIdle();
 
   // Not yet fetched nor uploaded.
-  FileCacheEntry cache_entry;
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("foo"), &cache_entry));
-  EXPECT_FALSE(cache_entry.is_present());
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("dirty"), &cache_entry));
-  EXPECT_TRUE(cache_entry.is_dirty());
+  ResourceEntry entry;
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
+  EXPECT_FALSE(entry.file_specific_info().cache_state().is_present());
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry));
+  EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
 
   // Switch to online.
   fake_network_change_notifier_->SetConnectionType(
@@ -337,10 +416,104 @@ TEST_F(SyncClientTest, RetryOnDisconnection) {
   base::RunLoop().RunUntilIdle();
 
   // Fetched and uploaded.
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("foo"), &cache_entry));
-  EXPECT_TRUE(cache_entry.is_present());
-  EXPECT_TRUE(cache_->GetCacheEntry(GetLocalId("dirty"), &cache_entry));
-  EXPECT_FALSE(cache_entry.is_dirty());
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
+  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry));
+  EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
+}
+
+TEST_F(SyncClientTest, ScheduleRerun) {
+  // Add a fetch task for "foo", this should result in being paused.
+  drive_service_->set_resource_id_to_be_paused(resource_ids_["foo"]);
+  sync_client_->AddFetchTask(GetLocalId("foo"));
+  base::RunLoop().RunUntilIdle();
+
+  // While the first task is paused, add a task again.
+  // This results in scheduling rerun of the task.
+  sync_client_->AddFetchTask(GetLocalId("foo"));
+  base::RunLoop().RunUntilIdle();
+
+  // Resume the paused task.
+  drive_service_->set_resource_id_to_be_paused(std::string());
+  ASSERT_FALSE(drive_service_->paused_action().is_null());
+  drive_service_->paused_action().Run();
+  base::RunLoop().RunUntilIdle();
+
+  // Task should be run twice.
+  EXPECT_EQ(2, drive_service_->download_file_count());
+}
+
+TEST_F(SyncClientTest, Dependencies) {
+  // Create directories locally.
+  const base::FilePath kPath1(FILE_PATH_LITERAL("drive/root/dir1"));
+  const base::FilePath kPath2 = kPath1.AppendASCII("dir2");
+
+  ResourceEntry parent;
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryByPath(kPath1.DirName(), &parent));
+
+  ResourceEntry entry1;
+  entry1.set_parent_local_id(parent.local_id());
+  entry1.set_title(kPath1.BaseName().AsUTF8Unsafe());
+  entry1.mutable_file_info()->set_is_directory(true);
+  entry1.set_metadata_edit_state(ResourceEntry::DIRTY);
+  std::string local_id1;
+  EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry1, &local_id1));
+
+  ResourceEntry entry2;
+  entry2.set_parent_local_id(local_id1);
+  entry2.set_title(kPath2.BaseName().AsUTF8Unsafe());
+  entry2.mutable_file_info()->set_is_directory(true);
+  entry2.set_metadata_edit_state(ResourceEntry::DIRTY);
+  std::string local_id2;
+  EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry2, &local_id2));
+
+  // Start syncing the child first.
+  sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id2);
+  // Start syncing the parent later.
+  sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id1);
+  base::RunLoop().RunUntilIdle();
+
+  // Both entries are synced.
+  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id1, &entry1));
+  EXPECT_EQ(ResourceEntry::CLEAN, entry1.metadata_edit_state());
+  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id2, &entry2));
+  EXPECT_EQ(ResourceEntry::CLEAN, entry2.metadata_edit_state());
+}
+
+TEST_F(SyncClientTest, WaitForUpdateTaskToComplete) {
+  // Create a directory locally.
+  const base::FilePath kPath(FILE_PATH_LITERAL("drive/root/dir1"));
+
+  ResourceEntry parent;
+  EXPECT_EQ(FILE_ERROR_OK,
+            metadata_->GetResourceEntryByPath(kPath.DirName(), &parent));
+
+  ResourceEntry entry;
+  entry.set_parent_local_id(parent.local_id());
+  entry.set_title(kPath.BaseName().AsUTF8Unsafe());
+  entry.mutable_file_info()->set_is_directory(true);
+  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
+  std::string local_id;
+  EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry, &local_id));
+
+  // Sync task is not yet avialable.
+  FileError error = FILE_ERROR_FAILED;
+  EXPECT_FALSE(sync_client_->WaitForUpdateTaskToComplete(
+      local_id, google_apis::test_util::CreateCopyResultCallback(&error)));
+
+  // Start syncing the directory and wait for it to complete.
+  sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id);
+
+  EXPECT_TRUE(sync_client_->WaitForUpdateTaskToComplete(
+      local_id, google_apis::test_util::CreateCopyResultCallback(&error)));
+
+  base::RunLoop().RunUntilIdle();
+
+  // The callback is called.
+  EXPECT_EQ(FILE_ERROR_OK, error);
 }
 
 }  // namespace internal