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/chromeos/drive/file_system/copy_operation.h"
6
7#include "base/files/file_util.h"
8#include "base/task_runner_util.h"
9#include "chrome/browser/chromeos/drive/file_cache.h"
10#include "chrome/browser/chromeos/drive/file_change.h"
11#include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
12#include "chrome/browser/chromeos/drive/file_system_util.h"
13#include "chrome/browser/chromeos/drive/resource_metadata.h"
14#include "chrome/browser/drive/drive_api_util.h"
15#include "chrome/browser/drive/fake_drive_service.h"
16#include "content/public/test/test_utils.h"
17#include "google_apis/drive/drive_api_parser.h"
18#include "google_apis/drive/test_util.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace drive {
22namespace file_system {
23
24namespace {
25
26// Used to handle WaitForSyncComplete() calls.
27bool CopyWaitForSyncCompleteArguments(std::string* out_local_id,
28                                      FileOperationCallback* out_callback,
29                                      const std::string& local_id,
30                                      const FileOperationCallback& callback) {
31  *out_local_id = local_id;
32  *out_callback = callback;
33  return true;
34}
35
36}  // namespace
37
38class CopyOperationTest : public OperationTestBase {
39 protected:
40  virtual void SetUp() OVERRIDE {
41   OperationTestBase::SetUp();
42   operation_.reset(new CopyOperation(
43       blocking_task_runner(), delegate(), scheduler(), metadata(), cache()));
44  }
45
46  scoped_ptr<CopyOperation> operation_;
47};
48
49TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_RegularFile) {
50  const base::FilePath local_src_path = temp_dir().AppendASCII("local.txt");
51  const base::FilePath remote_dest_path(
52      FILE_PATH_LITERAL("drive/root/remote.txt"));
53
54  // Prepare a local file.
55  ASSERT_TRUE(
56      google_apis::test_util::WriteStringToFile(local_src_path, "hello"));
57  // Confirm that the remote file does not exist.
58  ResourceEntry entry;
59  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
60            GetLocalResourceEntry(remote_dest_path, &entry));
61
62  // Transfer the local file to Drive.
63  FileError error = FILE_ERROR_FAILED;
64  operation_->TransferFileFromLocalToRemote(
65      local_src_path,
66      remote_dest_path,
67      google_apis::test_util::CreateCopyResultCallback(&error));
68  content::RunAllBlockingPoolTasksUntilIdle();
69  EXPECT_EQ(FILE_ERROR_OK, error);
70
71  // TransferFileFromLocalToRemote stores a copy of the local file in the cache,
72  // marks it dirty and requests the observer to upload the file.
73  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
74  EXPECT_EQ(1U, delegate()->updated_local_ids().count(entry.local_id()));
75  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
76  EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
77
78  EXPECT_EQ(1U, delegate()->get_changed_files().size());
79  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
80}
81
82TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_Overwrite) {
83  const base::FilePath local_src_path = temp_dir().AppendASCII("local.txt");
84  const base::FilePath remote_dest_path(
85      FILE_PATH_LITERAL("drive/root/File 1.txt"));
86
87  // Prepare a local file.
88  EXPECT_TRUE(
89      google_apis::test_util::WriteStringToFile(local_src_path, "hello"));
90  // Confirm that the remote file exists.
91  ResourceEntry entry;
92  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
93
94  // Transfer the local file to Drive.
95  FileError error = FILE_ERROR_FAILED;
96  operation_->TransferFileFromLocalToRemote(
97      local_src_path,
98      remote_dest_path,
99      google_apis::test_util::CreateCopyResultCallback(&error));
100  content::RunAllBlockingPoolTasksUntilIdle();
101  EXPECT_EQ(FILE_ERROR_OK, error);
102
103  // TransferFileFromLocalToRemote stores a copy of the local file in the cache,
104  // marks it dirty and requests the observer to upload the file.
105  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
106  EXPECT_EQ(1U, delegate()->updated_local_ids().count(entry.local_id()));
107  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
108  EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
109
110  EXPECT_EQ(1U, delegate()->get_changed_files().size());
111  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
112}
113
114TEST_F(CopyOperationTest,
115       TransferFileFromLocalToRemote_ExistingHostedDocument) {
116  const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc");
117  const base::FilePath remote_dest_path(FILE_PATH_LITERAL(
118      "drive/root/Directory 1/copied.gdoc"));
119
120  // Prepare a local file, which is a json file of a hosted document, which
121  // matches "drive/root/Document 1 excludeDir-test".
122  ASSERT_TRUE(util::CreateGDocFile(
123      local_src_path,
124      GURL("https://3_document_self_link/5_document_resource_id"),
125      "5_document_resource_id"));
126
127  ResourceEntry entry;
128  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
129            GetLocalResourceEntry(remote_dest_path, &entry));
130
131  // Transfer the local file to Drive.
132  FileError error = FILE_ERROR_FAILED;
133  operation_->TransferFileFromLocalToRemote(
134      local_src_path,
135      remote_dest_path,
136      google_apis::test_util::CreateCopyResultCallback(&error));
137  content::RunAllBlockingPoolTasksUntilIdle();
138  EXPECT_EQ(FILE_ERROR_OK, error);
139
140  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
141
142  EXPECT_EQ(1U, delegate()->get_changed_files().size());
143  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
144  // New copy is created.
145  EXPECT_NE("5_document_resource_id", entry.resource_id());
146}
147
148TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_OrphanHostedDocument) {
149  const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc");
150  const base::FilePath remote_dest_path(FILE_PATH_LITERAL(
151      "drive/root/Directory 1/moved.gdoc"));
152
153  // Prepare a local file, which is a json file of a hosted document, which
154  // matches "drive/other/Orphan Document".
155  ASSERT_TRUE(util::CreateGDocFile(
156      local_src_path,
157      GURL("https://3_document_self_link/orphan_doc_1"),
158      "orphan_doc_1"));
159
160  ResourceEntry entry;
161  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
162            GetLocalResourceEntry(remote_dest_path, &entry));
163
164  // Transfer the local file to Drive.
165  FileError error = FILE_ERROR_FAILED;
166  operation_->TransferFileFromLocalToRemote(
167      local_src_path,
168      remote_dest_path,
169      google_apis::test_util::CreateCopyResultCallback(&error));
170  content::RunAllBlockingPoolTasksUntilIdle();
171  EXPECT_EQ(FILE_ERROR_OK, error);
172
173  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
174  EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state());
175  EXPECT_TRUE(delegate()->updated_local_ids().count(entry.local_id()));
176
177  EXPECT_EQ(1U, delegate()->get_changed_files().size());
178  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
179  // The original document got new parent.
180  EXPECT_EQ("orphan_doc_1", entry.resource_id());
181}
182
183TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_NewHostedDocument) {
184  const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc");
185  const base::FilePath remote_dest_path(FILE_PATH_LITERAL(
186      "drive/root/Directory 1/moved.gdoc"));
187
188  // Create a hosted document on the server that is not synced to local yet.
189  google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
190  scoped_ptr<google_apis::FileResource> new_gdoc_entry;
191  fake_service()->AddNewFile(
192      "application/vnd.google-apps.document", "", "", "title", true,
193      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
194                                                       &new_gdoc_entry));
195  content::RunAllBlockingPoolTasksUntilIdle();
196  ASSERT_EQ(google_apis::HTTP_CREATED, gdata_error);
197
198  // Prepare a local file, which is a json file of the added hosted document.
199  ASSERT_TRUE(util::CreateGDocFile(
200      local_src_path,
201      GURL("https://3_document_self_link/" + new_gdoc_entry->file_id()),
202      new_gdoc_entry->file_id()));
203
204  ResourceEntry entry;
205  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
206            GetLocalResourceEntry(remote_dest_path, &entry));
207
208  // Transfer the local file to Drive.
209  FileError error = FILE_ERROR_FAILED;
210  operation_->TransferFileFromLocalToRemote(
211      local_src_path,
212      remote_dest_path,
213      google_apis::test_util::CreateCopyResultCallback(&error));
214  content::RunAllBlockingPoolTasksUntilIdle();
215  EXPECT_EQ(FILE_ERROR_OK, error);
216
217  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
218
219  EXPECT_EQ(1U, delegate()->get_changed_files().size());
220  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
221  // The original document got new parent.
222  EXPECT_EQ(new_gdoc_entry->file_id(), entry.resource_id());
223}
224
225TEST_F(CopyOperationTest, CopyNotExistingFile) {
226  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
227  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Test.log"));
228
229  ResourceEntry entry;
230  ASSERT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry));
231
232  FileError error = FILE_ERROR_OK;
233  operation_->Copy(src_path,
234                   dest_path,
235                   false,
236                   google_apis::test_util::CreateCopyResultCallback(&error));
237  content::RunAllBlockingPoolTasksUntilIdle();
238  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
239
240  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry));
241  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
242  EXPECT_TRUE(delegate()->get_changed_files().empty());
243}
244
245TEST_F(CopyOperationTest, CopyFileToNonExistingDirectory) {
246  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
247  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Dummy/Test.log"));
248
249  ResourceEntry entry;
250  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
251  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
252            GetLocalResourceEntry(dest_path.DirName(), &entry));
253
254  FileError error = FILE_ERROR_OK;
255  operation_->Copy(src_path,
256                   dest_path,
257                   false,
258                   google_apis::test_util::CreateCopyResultCallback(&error));
259  content::RunAllBlockingPoolTasksUntilIdle();
260  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
261
262  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
263  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
264  EXPECT_TRUE(delegate()->get_changed_files().empty());
265}
266
267// Test the case where the parent of the destination path is an existing file,
268// not a directory.
269TEST_F(CopyOperationTest, CopyFileToInvalidPath) {
270  base::FilePath src_path(FILE_PATH_LITERAL(
271      "drive/root/Document 1 excludeDir-test.gdoc"));
272  base::FilePath dest_path(FILE_PATH_LITERAL(
273      "drive/root/Duplicate Name.txt/Document 1 excludeDir-test.gdoc"));
274
275  ResourceEntry entry;
276  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
277  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path.DirName(), &entry));
278  ASSERT_FALSE(entry.file_info().is_directory());
279
280  FileError error = FILE_ERROR_OK;
281  operation_->Copy(src_path,
282                   dest_path,
283                   false,
284                   google_apis::test_util::CreateCopyResultCallback(&error));
285  content::RunAllBlockingPoolTasksUntilIdle();
286  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
287
288  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
289  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
290  EXPECT_TRUE(delegate()->get_changed_files().empty());
291}
292
293TEST_F(CopyOperationTest, CopyDirtyFile) {
294  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
295  base::FilePath dest_path(FILE_PATH_LITERAL(
296      "drive/root/Directory 1/New File.txt"));
297
298  ResourceEntry src_entry;
299  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
300
301  // Store a dirty cache file.
302  base::FilePath temp_file;
303  EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
304  std::string contents = "test content";
305  EXPECT_TRUE(google_apis::test_util::WriteStringToFile(temp_file, contents));
306  FileError error = FILE_ERROR_FAILED;
307  base::PostTaskAndReplyWithResult(
308      blocking_task_runner(),
309      FROM_HERE,
310      base::Bind(&internal::FileCache::Store,
311                 base::Unretained(cache()),
312                 src_entry.local_id(),
313                 std::string(),
314                 temp_file,
315                 internal::FileCache::FILE_OPERATION_MOVE),
316      google_apis::test_util::CreateCopyResultCallback(&error));
317  content::RunAllBlockingPoolTasksUntilIdle();
318  EXPECT_EQ(FILE_ERROR_OK, error);
319
320  // Copy.
321  operation_->Copy(src_path,
322                   dest_path,
323                   false,
324                   google_apis::test_util::CreateCopyResultCallback(&error));
325  content::RunAllBlockingPoolTasksUntilIdle();
326  EXPECT_EQ(FILE_ERROR_OK, error);
327
328  ResourceEntry dest_entry;
329  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry));
330  EXPECT_EQ(ResourceEntry::DIRTY, dest_entry.metadata_edit_state());
331
332  EXPECT_EQ(1u, delegate()->updated_local_ids().size());
333  EXPECT_TRUE(delegate()->updated_local_ids().count(dest_entry.local_id()));
334  EXPECT_EQ(1u, delegate()->get_changed_files().size());
335  EXPECT_TRUE(delegate()->get_changed_files().count(dest_path));
336
337  // Copied cache file should be dirty.
338  EXPECT_TRUE(dest_entry.file_specific_info().cache_state().is_dirty());
339
340  // File contents should match.
341  base::FilePath cache_file_path;
342  base::PostTaskAndReplyWithResult(
343      blocking_task_runner(),
344      FROM_HERE,
345      base::Bind(&internal::FileCache::GetFile,
346                 base::Unretained(cache()),
347                 dest_entry.local_id(),
348                 &cache_file_path),
349      google_apis::test_util::CreateCopyResultCallback(&error));
350  content::RunAllBlockingPoolTasksUntilIdle();
351  EXPECT_EQ(FILE_ERROR_OK, error);
352
353  std::string copied_contents;
354  EXPECT_TRUE(base::ReadFileToString(cache_file_path, &copied_contents));
355  EXPECT_EQ(contents, copied_contents);
356}
357
358TEST_F(CopyOperationTest, CopyFileOverwriteFile) {
359  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
360  base::FilePath dest_path(FILE_PATH_LITERAL(
361      "drive/root/Directory 1/SubDirectory File 1.txt"));
362
363  ResourceEntry old_dest_entry;
364  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &old_dest_entry));
365
366  FileError error = FILE_ERROR_OK;
367  operation_->Copy(src_path,
368                   dest_path,
369                   false,
370                   google_apis::test_util::CreateCopyResultCallback(&error));
371  content::RunAllBlockingPoolTasksUntilIdle();
372  EXPECT_EQ(FILE_ERROR_OK, error);
373
374  ResourceEntry new_dest_entry;
375  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &new_dest_entry));
376
377  EXPECT_EQ(1u, delegate()->updated_local_ids().size());
378  EXPECT_TRUE(delegate()->updated_local_ids().count(old_dest_entry.local_id()));
379  EXPECT_EQ(1u, delegate()->get_changed_files().size());
380  EXPECT_TRUE(delegate()->get_changed_files().count(dest_path));
381}
382
383TEST_F(CopyOperationTest, CopyFileOverwriteDirectory) {
384  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
385  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
386
387  FileError error = FILE_ERROR_OK;
388  operation_->Copy(src_path,
389                   dest_path,
390                   false,
391                   google_apis::test_util::CreateCopyResultCallback(&error));
392  content::RunAllBlockingPoolTasksUntilIdle();
393  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error);
394}
395
396TEST_F(CopyOperationTest, CopyDirectory) {
397  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
398  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/New Directory"));
399
400  ResourceEntry entry;
401  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
402  ASSERT_TRUE(entry.file_info().is_directory());
403  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path.DirName(), &entry));
404  ASSERT_TRUE(entry.file_info().is_directory());
405
406  FileError error = FILE_ERROR_OK;
407  operation_->Copy(src_path,
408                   dest_path,
409                   false,
410                   google_apis::test_util::CreateCopyResultCallback(&error));
411  content::RunAllBlockingPoolTasksUntilIdle();
412  EXPECT_EQ(FILE_ERROR_NOT_A_FILE, error);
413}
414
415TEST_F(CopyOperationTest, PreserveLastModified) {
416  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
417  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/File 2.txt"));
418
419  ResourceEntry entry;
420  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
421  ASSERT_EQ(FILE_ERROR_OK,
422            GetLocalResourceEntry(dest_path.DirName(), &entry));
423
424  FileError error = FILE_ERROR_OK;
425  operation_->Copy(src_path,
426                   dest_path,
427                   true,  // Preserve last modified.
428                   google_apis::test_util::CreateCopyResultCallback(&error));
429  content::RunAllBlockingPoolTasksUntilIdle();
430  EXPECT_EQ(FILE_ERROR_OK, error);
431
432  ResourceEntry entry2;
433  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
434  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &entry2));
435  EXPECT_EQ(entry.file_info().last_modified(),
436            entry2.file_info().last_modified());
437}
438
439TEST_F(CopyOperationTest, WaitForSyncComplete) {
440  // Create a directory locally.
441  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
442  base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory"));
443  base::FilePath dest_path = directory_path.AppendASCII("File 1.txt");
444
445  ResourceEntry directory_parent;
446  EXPECT_EQ(FILE_ERROR_OK,
447            GetLocalResourceEntry(directory_path.DirName(), &directory_parent));
448
449  ResourceEntry directory;
450  directory.set_parent_local_id(directory_parent.local_id());
451  directory.set_title(directory_path.BaseName().AsUTF8Unsafe());
452  directory.mutable_file_info()->set_is_directory(true);
453  directory.set_metadata_edit_state(ResourceEntry::DIRTY);
454
455  std::string directory_local_id;
456  FileError error = FILE_ERROR_FAILED;
457  base::PostTaskAndReplyWithResult(
458      blocking_task_runner(),
459      FROM_HERE,
460      base::Bind(&internal::ResourceMetadata::AddEntry,
461                 base::Unretained(metadata()), directory, &directory_local_id),
462      google_apis::test_util::CreateCopyResultCallback(&error));
463  content::RunAllBlockingPoolTasksUntilIdle();
464  EXPECT_EQ(FILE_ERROR_OK, error);
465
466  // Try to copy a file to the new directory which lacks resource ID.
467  // This should result in waiting for the directory to sync.
468  std::string waited_local_id;
469  FileOperationCallback pending_callback;
470  delegate()->set_wait_for_sync_complete_handler(
471      base::Bind(&CopyWaitForSyncCompleteArguments,
472                 &waited_local_id, &pending_callback));
473
474  FileError copy_error = FILE_ERROR_FAILED;
475  operation_->Copy(src_path,
476                   dest_path,
477                   true,  // Preserve last modified.
478                   google_apis::test_util::CreateCopyResultCallback(
479                       &copy_error));
480  content::RunAllBlockingPoolTasksUntilIdle();
481  EXPECT_EQ(directory_local_id, waited_local_id);
482  ASSERT_FALSE(pending_callback.is_null());
483
484  // Add a new directory to the server and store the resource ID locally.
485  google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
486  scoped_ptr<google_apis::FileResource> file_resource;
487  fake_service()->AddNewDirectory(
488      directory_parent.resource_id(),
489      directory.title(),
490      DriveServiceInterface::AddNewDirectoryOptions(),
491      google_apis::test_util::CreateCopyResultCallback(
492          &status, &file_resource));
493  content::RunAllBlockingPoolTasksUntilIdle();
494  EXPECT_EQ(google_apis::HTTP_CREATED, status);
495  ASSERT_TRUE(file_resource);
496
497  directory.set_local_id(directory_local_id);
498  directory.set_resource_id(file_resource->file_id());
499  base::PostTaskAndReplyWithResult(
500      blocking_task_runner(),
501      FROM_HERE,
502      base::Bind(&internal::ResourceMetadata::RefreshEntry,
503                 base::Unretained(metadata()), directory),
504      google_apis::test_util::CreateCopyResultCallback(&error));
505  content::RunAllBlockingPoolTasksUntilIdle();
506  EXPECT_EQ(FILE_ERROR_OK, error);
507
508  // Resume the copy operation.
509  pending_callback.Run(FILE_ERROR_OK);
510  content::RunAllBlockingPoolTasksUntilIdle();
511
512  EXPECT_EQ(FILE_ERROR_OK, copy_error);
513  ResourceEntry entry;
514  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &entry));
515}
516
517}  // namespace file_system
518}  // namespace drive
519