Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / sync / entry_update_performer_unittest.cc
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/sync/entry_update_performer.h"
6
7 #include "base/callback_helpers.h"
8 #include "base/file_util.h"
9 #include "base/md5.h"
10 #include "base/task_runner_util.h"
11 #include "chrome/browser/chromeos/drive/file_cache.h"
12 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
13 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
14 #include "chrome/browser/chromeos/drive/job_scheduler.h"
15 #include "chrome/browser/chromeos/drive/resource_metadata.h"
16 #include "chrome/browser/drive/drive_api_util.h"
17 #include "chrome/browser/drive/fake_drive_service.h"
18 #include "google_apis/drive/drive_api_parser.h"
19 #include "google_apis/drive/gdata_wapi_parser.h"
20 #include "google_apis/drive/test_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace drive {
24 namespace internal {
25
26 class EntryUpdatePerformerTest : public file_system::OperationTestBase {
27  protected:
28   virtual void SetUp() OVERRIDE {
29     OperationTestBase::SetUp();
30     performer_.reset(new EntryUpdatePerformer(blocking_task_runner(),
31                                               observer(),
32                                               scheduler(),
33                                               metadata(),
34                                               cache(),
35                                               loader_controller()));
36   }
37
38   // Stores |content| to the cache and mark it as dirty.
39   FileError StoreAndMarkDirty(const std::string& local_id,
40                               const std::string& content) {
41     base::FilePath path;
42     if (!base::CreateTemporaryFileInDir(temp_dir(), &path) ||
43         !google_apis::test_util::WriteStringToFile(path, content))
44       return FILE_ERROR_FAILED;
45
46     // Store the file to cache.
47     FileError error = FILE_ERROR_FAILED;
48     base::PostTaskAndReplyWithResult(
49         blocking_task_runner(),
50         FROM_HERE,
51         base::Bind(&FileCache::Store,
52                    base::Unretained(cache()),
53                    local_id, std::string(), path,
54                    FileCache::FILE_OPERATION_COPY),
55         google_apis::test_util::CreateCopyResultCallback(&error));
56     test_util::RunBlockingPoolTask();
57     return error;
58   }
59
60   scoped_ptr<EntryUpdatePerformer> performer_;
61 };
62
63 TEST_F(EntryUpdatePerformerTest, UpdateEntry) {
64   base::FilePath src_path(
65       FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
66   base::FilePath dest_path(
67       FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder"));
68
69   ResourceEntry src_entry, dest_entry;
70   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
71   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry));
72
73   // Update local entry.
74   base::Time new_last_modified = base::Time::FromInternalValue(
75       src_entry.file_info().last_modified()) + base::TimeDelta::FromSeconds(1);
76   base::Time new_last_accessed = base::Time::FromInternalValue(
77       src_entry.file_info().last_accessed()) + base::TimeDelta::FromSeconds(2);
78
79   src_entry.set_parent_local_id(dest_entry.local_id());
80   src_entry.set_title("Moved" + src_entry.title());
81   src_entry.mutable_file_info()->set_last_modified(
82       new_last_modified.ToInternalValue());
83   src_entry.mutable_file_info()->set_last_accessed(
84       new_last_accessed.ToInternalValue());
85   src_entry.set_metadata_edit_state(ResourceEntry::DIRTY);
86
87   FileError error = FILE_ERROR_FAILED;
88   base::PostTaskAndReplyWithResult(
89       blocking_task_runner(),
90       FROM_HERE,
91       base::Bind(&ResourceMetadata::RefreshEntry,
92                  base::Unretained(metadata()),
93                  src_entry),
94       google_apis::test_util::CreateCopyResultCallback(&error));
95   test_util::RunBlockingPoolTask();
96   EXPECT_EQ(FILE_ERROR_OK, error);
97
98   // Perform server side update.
99   error = FILE_ERROR_FAILED;
100   performer_->UpdateEntry(
101       src_entry.local_id(),
102       ClientContext(USER_INITIATED),
103       google_apis::test_util::CreateCopyResultCallback(&error));
104   test_util::RunBlockingPoolTask();
105   EXPECT_EQ(FILE_ERROR_OK, error);
106
107   // Verify the file is updated on the server.
108   google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
109   scoped_ptr<google_apis::ResourceEntry> gdata_entry;
110   fake_service()->GetResourceEntry(
111       src_entry.resource_id(),
112       google_apis::test_util::CreateCopyResultCallback(&gdata_error,
113                                                        &gdata_entry));
114   test_util::RunBlockingPoolTask();
115   EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
116   ASSERT_TRUE(gdata_entry);
117
118   EXPECT_EQ(src_entry.title(), gdata_entry->title());
119   EXPECT_EQ(new_last_modified, gdata_entry->updated_time());
120   EXPECT_EQ(new_last_accessed, gdata_entry->last_viewed_time());
121
122   const google_apis::Link* parent_link =
123       gdata_entry->GetLinkByType(google_apis::Link::LINK_PARENT);
124   ASSERT_TRUE(parent_link);
125   EXPECT_EQ(dest_entry.resource_id(),
126             util::ExtractResourceIdFromUrl(parent_link->href()));
127 }
128
129 // Tests updating metadata of a file with a non-dirty cache file.
130 TEST_F(EntryUpdatePerformerTest, UpdateEntry_WithNonDirtyCache) {
131   base::FilePath src_path(
132       FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
133
134   // Download the file content to prepare a non-dirty cache file.
135   file_system::DownloadOperation download_operation(
136       blocking_task_runner(), observer(), scheduler(), metadata(), cache(),
137       temp_dir());
138   FileError error = FILE_ERROR_FAILED;
139   base::FilePath cache_file_path;
140   scoped_ptr<ResourceEntry> src_entry;
141   download_operation.EnsureFileDownloadedByPath(
142       src_path,
143       ClientContext(USER_INITIATED),
144       GetFileContentInitializedCallback(),
145       google_apis::GetContentCallback(),
146       google_apis::test_util::CreateCopyResultCallback(
147           &error, &cache_file_path, &src_entry));
148   test_util::RunBlockingPoolTask();
149   EXPECT_EQ(FILE_ERROR_OK, error);
150   ASSERT_TRUE(src_entry);
151
152   // Update the entry locally.
153   src_entry->set_title("Updated" + src_entry->title());
154   src_entry->set_metadata_edit_state(ResourceEntry::DIRTY);
155
156   error = FILE_ERROR_FAILED;
157   base::PostTaskAndReplyWithResult(
158       blocking_task_runner(),
159       FROM_HERE,
160       base::Bind(&ResourceMetadata::RefreshEntry,
161                  base::Unretained(metadata()),
162                  *src_entry),
163       google_apis::test_util::CreateCopyResultCallback(&error));
164   test_util::RunBlockingPoolTask();
165   EXPECT_EQ(FILE_ERROR_OK, error);
166
167   // Perform server side update. This shouldn't fail. (crbug.com/358590)
168   error = FILE_ERROR_FAILED;
169   performer_->UpdateEntry(
170       src_entry->local_id(),
171       ClientContext(USER_INITIATED),
172       google_apis::test_util::CreateCopyResultCallback(&error));
173   test_util::RunBlockingPoolTask();
174   EXPECT_EQ(FILE_ERROR_OK, error);
175
176   // Verify the file is updated on the server.
177   google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
178   scoped_ptr<google_apis::ResourceEntry> gdata_entry;
179   fake_service()->GetResourceEntry(
180       src_entry->resource_id(),
181       google_apis::test_util::CreateCopyResultCallback(&gdata_error,
182                                                        &gdata_entry));
183   test_util::RunBlockingPoolTask();
184   EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
185   ASSERT_TRUE(gdata_entry);
186   EXPECT_EQ(src_entry->title(), gdata_entry->title());
187 }
188
189 TEST_F(EntryUpdatePerformerTest, UpdateEntry_NotFound) {
190   const std::string id = "this ID should result in NOT_FOUND";
191   FileError error = FILE_ERROR_FAILED;
192   performer_->UpdateEntry(
193       id, ClientContext(USER_INITIATED),
194       google_apis::test_util::CreateCopyResultCallback(&error));
195   test_util::RunBlockingPoolTask();
196   EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
197 }
198
199 TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdate) {
200   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
201   const std::string kResourceId("file:2_file_resource_id");
202
203   const std::string local_id = GetLocalId(kFilePath);
204   EXPECT_FALSE(local_id.empty());
205
206   const std::string kTestFileContent = "I'm being uploaded! Yay!";
207   EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
208
209   int64 original_changestamp =
210       fake_service()->about_resource().largest_change_id();
211
212   // The callback will be called upon completion of UpdateEntry().
213   FileError error = FILE_ERROR_FAILED;
214   performer_->UpdateEntry(
215       local_id,
216       ClientContext(USER_INITIATED),
217       google_apis::test_util::CreateCopyResultCallback(&error));
218   test_util::RunBlockingPoolTask();
219   EXPECT_EQ(FILE_ERROR_OK, error);
220
221   // Check that the server has received an update.
222   EXPECT_LT(original_changestamp,
223             fake_service()->about_resource().largest_change_id());
224
225   // Check that the file size is updated to that of the updated content.
226   google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
227   scoped_ptr<google_apis::ResourceEntry> server_entry;
228   fake_service()->GetResourceEntry(
229       kResourceId,
230       google_apis::test_util::CreateCopyResultCallback(&gdata_error,
231                                                        &server_entry));
232   test_util::RunBlockingPoolTask();
233   EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
234   EXPECT_EQ(static_cast<int64>(kTestFileContent.size()),
235             server_entry->file_size());
236
237   // Make sure that the cache is no longer dirty.
238   bool success = false;
239   FileCacheEntry cache_entry;
240   base::PostTaskAndReplyWithResult(
241       blocking_task_runner(),
242       FROM_HERE,
243       base::Bind(&FileCache::GetCacheEntry,
244                  base::Unretained(cache()),
245                  local_id,
246                  &cache_entry),
247       google_apis::test_util::CreateCopyResultCallback(&success));
248   test_util::RunBlockingPoolTask();
249   ASSERT_TRUE(success);
250   EXPECT_FALSE(cache_entry.is_dirty());
251 }
252
253 TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdateMd5Check) {
254   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
255   const std::string kResourceId("file:2_file_resource_id");
256
257   const std::string local_id = GetLocalId(kFilePath);
258   EXPECT_FALSE(local_id.empty());
259
260   const std::string kTestFileContent = "I'm being uploaded! Yay!";
261   EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
262
263   int64 original_changestamp =
264       fake_service()->about_resource().largest_change_id();
265
266   // The callback will be called upon completion of UpdateEntry().
267   FileError error = FILE_ERROR_FAILED;
268   performer_->UpdateEntry(
269       local_id,
270       ClientContext(USER_INITIATED),
271       google_apis::test_util::CreateCopyResultCallback(&error));
272   test_util::RunBlockingPoolTask();
273   EXPECT_EQ(FILE_ERROR_OK, error);
274
275   // Check that the server has received an update.
276   EXPECT_LT(original_changestamp,
277             fake_service()->about_resource().largest_change_id());
278
279   // Check that the file size is updated to that of the updated content.
280   google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR;
281   scoped_ptr<google_apis::ResourceEntry> server_entry;
282   fake_service()->GetResourceEntry(
283       kResourceId,
284       google_apis::test_util::CreateCopyResultCallback(&gdata_error,
285                                                        &server_entry));
286   test_util::RunBlockingPoolTask();
287   EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
288   EXPECT_EQ(static_cast<int64>(kTestFileContent.size()),
289             server_entry->file_size());
290
291   // Make sure that the cache is no longer dirty.
292   bool success = false;
293   FileCacheEntry cache_entry;
294   base::PostTaskAndReplyWithResult(
295       blocking_task_runner(),
296       FROM_HERE,
297       base::Bind(&FileCache::GetCacheEntry,
298                  base::Unretained(cache()),
299                  local_id,
300                  &cache_entry),
301       google_apis::test_util::CreateCopyResultCallback(&success));
302   test_util::RunBlockingPoolTask();
303   ASSERT_TRUE(success);
304   EXPECT_FALSE(cache_entry.is_dirty());
305
306   // Again mark the cache file dirty.
307   scoped_ptr<base::ScopedClosureRunner> file_closer;
308   error = FILE_ERROR_FAILED;
309   base::PostTaskAndReplyWithResult(
310       blocking_task_runner(),
311       FROM_HERE,
312       base::Bind(&FileCache::OpenForWrite,
313                  base::Unretained(cache()),
314                  local_id,
315                  &file_closer),
316       google_apis::test_util::CreateCopyResultCallback(&error));
317   test_util::RunBlockingPoolTask();
318   EXPECT_EQ(FILE_ERROR_OK, error);
319   file_closer.reset();
320
321   // And call UpdateEntry again.
322   // In this case, although the file is marked as dirty, but the content
323   // hasn't been changed. Thus, the actual uploading should be skipped.
324   original_changestamp = fake_service()->about_resource().largest_change_id();
325   error = FILE_ERROR_FAILED;
326   performer_->UpdateEntry(
327       local_id,
328       ClientContext(USER_INITIATED),
329       google_apis::test_util::CreateCopyResultCallback(&error));
330   test_util::RunBlockingPoolTask();
331   EXPECT_EQ(FILE_ERROR_OK, error);
332
333   EXPECT_EQ(original_changestamp,
334             fake_service()->about_resource().largest_change_id());
335
336   // Make sure that the cache is no longer dirty.
337   success = false;
338   base::PostTaskAndReplyWithResult(
339       blocking_task_runner(),
340       FROM_HERE,
341       base::Bind(&FileCache::GetCacheEntry,
342                  base::Unretained(cache()),
343                  local_id,
344                  &cache_entry),
345       google_apis::test_util::CreateCopyResultCallback(&success));
346   test_util::RunBlockingPoolTask();
347   ASSERT_TRUE(success);
348   EXPECT_FALSE(cache_entry.is_dirty());
349 }
350
351 TEST_F(EntryUpdatePerformerTest, UpdateEntry_OpenedForWrite) {
352   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
353   const std::string kResourceId("file:2_file_resource_id");
354
355   const std::string local_id = GetLocalId(kFilePath);
356   EXPECT_FALSE(local_id.empty());
357
358   const std::string kTestFileContent = "I'm being uploaded! Yay!";
359   EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
360
361   // Emulate a situation where someone is writing to the file.
362   scoped_ptr<base::ScopedClosureRunner> file_closer;
363   FileError error = FILE_ERROR_FAILED;
364   base::PostTaskAndReplyWithResult(
365       blocking_task_runner(),
366       FROM_HERE,
367       base::Bind(&FileCache::OpenForWrite,
368                  base::Unretained(cache()),
369                  local_id,
370                  &file_closer),
371       google_apis::test_util::CreateCopyResultCallback(&error));
372   test_util::RunBlockingPoolTask();
373   EXPECT_EQ(FILE_ERROR_OK, error);
374
375   // Update. This should not clear the dirty bit.
376   error = FILE_ERROR_FAILED;
377   performer_->UpdateEntry(
378       local_id,
379       ClientContext(USER_INITIATED),
380       google_apis::test_util::CreateCopyResultCallback(&error));
381   test_util::RunBlockingPoolTask();
382   EXPECT_EQ(FILE_ERROR_OK, error);
383
384   // Make sure that the cache is still dirty.
385   bool success = false;
386   FileCacheEntry cache_entry;
387   base::PostTaskAndReplyWithResult(
388       blocking_task_runner(),
389       FROM_HERE,
390       base::Bind(&FileCache::GetCacheEntry,
391                  base::Unretained(cache()),
392                  local_id,
393                  &cache_entry),
394       google_apis::test_util::CreateCopyResultCallback(&success));
395   test_util::RunBlockingPoolTask();
396   EXPECT_TRUE(success);
397   EXPECT_TRUE(cache_entry.is_dirty());
398
399   // Close the file.
400   file_closer.reset();
401
402   // Update. This should clear the dirty bit.
403   error = FILE_ERROR_FAILED;
404   performer_->UpdateEntry(
405       local_id,
406       ClientContext(USER_INITIATED),
407       google_apis::test_util::CreateCopyResultCallback(&error));
408   test_util::RunBlockingPoolTask();
409   EXPECT_EQ(FILE_ERROR_OK, error);
410
411   // Make sure that the cache is no longer dirty.
412   base::PostTaskAndReplyWithResult(
413       blocking_task_runner(),
414       FROM_HERE,
415       base::Bind(&FileCache::GetCacheEntry,
416                  base::Unretained(cache()),
417                  local_id,
418                  &cache_entry),
419       google_apis::test_util::CreateCopyResultCallback(&success));
420   test_util::RunBlockingPoolTask();
421   EXPECT_TRUE(success);
422   EXPECT_FALSE(cache_entry.is_dirty());
423 }
424
425 TEST_F(EntryUpdatePerformerTest, UpdateEntry_UploadNewFile) {
426   // Create a new file locally.
427   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt"));
428
429   ResourceEntry parent;
430   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent));
431
432   ResourceEntry entry;
433   entry.set_parent_local_id(parent.local_id());
434   entry.set_title(kFilePath.BaseName().AsUTF8Unsafe());
435   entry.mutable_file_specific_info()->set_content_mime_type("text/plain");
436   entry.set_metadata_edit_state(ResourceEntry::DIRTY);
437
438   FileError error = FILE_ERROR_FAILED;
439   std::string local_id;
440   base::PostTaskAndReplyWithResult(
441       blocking_task_runner(),
442       FROM_HERE,
443       base::Bind(&internal::ResourceMetadata::AddEntry,
444                  base::Unretained(metadata()),
445                  entry,
446                  &local_id),
447       google_apis::test_util::CreateCopyResultCallback(&error));
448   test_util::RunBlockingPoolTask();
449   EXPECT_EQ(FILE_ERROR_OK, error);
450
451   // Update. This should result in creating a new file on the server.
452   error = FILE_ERROR_FAILED;
453   performer_->UpdateEntry(
454       local_id,
455       ClientContext(USER_INITIATED),
456       google_apis::test_util::CreateCopyResultCallback(&error));
457   test_util::RunBlockingPoolTask();
458   EXPECT_EQ(FILE_ERROR_OK, error);
459
460   // The entry got a resource ID.
461   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
462   EXPECT_FALSE(entry.resource_id().empty());
463   EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state());
464
465   // Make sure that the cache is no longer dirty.
466   bool success = false;
467   FileCacheEntry cache_entry;
468   base::PostTaskAndReplyWithResult(
469       blocking_task_runner(),
470       FROM_HERE,
471       base::Bind(&FileCache::GetCacheEntry,
472                  base::Unretained(cache()),
473                  local_id,
474                  &cache_entry),
475       google_apis::test_util::CreateCopyResultCallback(&success));
476   test_util::RunBlockingPoolTask();
477   EXPECT_TRUE(success);
478   EXPECT_FALSE(cache_entry.is_dirty());
479
480   // Make sure that we really created a file.
481   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
482   scoped_ptr<google_apis::ResourceEntry> resource_entry;
483   fake_service()->GetResourceEntry(
484       entry.resource_id(),
485       google_apis::test_util::CreateCopyResultCallback(&status,
486                                                        &resource_entry));
487   test_util::RunBlockingPoolTask();
488   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
489   ASSERT_TRUE(resource_entry);
490   EXPECT_FALSE(resource_entry->is_folder());
491 }
492
493 TEST_F(EntryUpdatePerformerTest, UpdateEntry_NewFileOpendForWrite) {
494   // Create a new file locally.
495   const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt"));
496
497   ResourceEntry parent;
498   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent));
499
500   ResourceEntry entry;
501   entry.set_parent_local_id(parent.local_id());
502   entry.set_title(kFilePath.BaseName().AsUTF8Unsafe());
503   entry.mutable_file_specific_info()->set_content_mime_type("text/plain");
504   entry.set_metadata_edit_state(ResourceEntry::DIRTY);
505
506   FileError error = FILE_ERROR_FAILED;
507   std::string local_id;
508   base::PostTaskAndReplyWithResult(
509       blocking_task_runner(),
510       FROM_HERE,
511       base::Bind(&internal::ResourceMetadata::AddEntry,
512                  base::Unretained(metadata()),
513                  entry,
514                  &local_id),
515       google_apis::test_util::CreateCopyResultCallback(&error));
516   test_util::RunBlockingPoolTask();
517   EXPECT_EQ(FILE_ERROR_OK, error);
518
519   const std::string kTestFileContent = "This is a new file.";
520   EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
521
522   // Emulate a situation where someone is writing to the file.
523   scoped_ptr<base::ScopedClosureRunner> file_closer;
524   error = FILE_ERROR_FAILED;
525   base::PostTaskAndReplyWithResult(
526       blocking_task_runner(),
527       FROM_HERE,
528       base::Bind(&FileCache::OpenForWrite,
529                  base::Unretained(cache()),
530                  local_id,
531                  &file_closer),
532       google_apis::test_util::CreateCopyResultCallback(&error));
533   test_util::RunBlockingPoolTask();
534   EXPECT_EQ(FILE_ERROR_OK, error);
535
536   // Update, but no update is performed because the file is opened.
537   error = FILE_ERROR_FAILED;
538   performer_->UpdateEntry(
539       local_id,
540       ClientContext(USER_INITIATED),
541       google_apis::test_util::CreateCopyResultCallback(&error));
542   test_util::RunBlockingPoolTask();
543   EXPECT_EQ(FILE_ERROR_OK, error);
544
545   // The entry hasn't got a resource ID yet.
546   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
547   EXPECT_TRUE(entry.resource_id().empty());
548
549   // Close the file.
550   file_closer.reset();
551
552   // Update. This should result in creating a new file on the server.
553   error = FILE_ERROR_FAILED;
554   performer_->UpdateEntry(
555       local_id,
556       ClientContext(USER_INITIATED),
557       google_apis::test_util::CreateCopyResultCallback(&error));
558   test_util::RunBlockingPoolTask();
559   EXPECT_EQ(FILE_ERROR_OK, error);
560
561   // The entry got a resource ID.
562   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
563   EXPECT_FALSE(entry.resource_id().empty());
564   EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state());
565 }
566
567 TEST_F(EntryUpdatePerformerTest, UpdateEntry_CreateDirectory) {
568   // Create a new directory locally.
569   const base::FilePath kPath(FILE_PATH_LITERAL("drive/root/New Directory"));
570
571   ResourceEntry parent;
572   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath.DirName(), &parent));
573
574   ResourceEntry entry;
575   entry.set_parent_local_id(parent.local_id());
576   entry.set_title(kPath.BaseName().AsUTF8Unsafe());
577   entry.mutable_file_info()->set_is_directory(true);
578   entry.set_metadata_edit_state(ResourceEntry::DIRTY);
579
580   FileError error = FILE_ERROR_FAILED;
581   std::string local_id;
582   base::PostTaskAndReplyWithResult(
583       blocking_task_runner(),
584       FROM_HERE,
585       base::Bind(&internal::ResourceMetadata::AddEntry,
586                  base::Unretained(metadata()),
587                  entry,
588                  &local_id),
589       google_apis::test_util::CreateCopyResultCallback(&error));
590   test_util::RunBlockingPoolTask();
591   EXPECT_EQ(FILE_ERROR_OK, error);
592
593   // Update. This should result in creating a new directory on the server.
594   error = FILE_ERROR_FAILED;
595   performer_->UpdateEntry(
596       local_id,
597       ClientContext(USER_INITIATED),
598       google_apis::test_util::CreateCopyResultCallback(&error));
599   test_util::RunBlockingPoolTask();
600   EXPECT_EQ(FILE_ERROR_OK, error);
601
602   // The entry got a resource ID.
603   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath, &entry));
604   EXPECT_FALSE(entry.resource_id().empty());
605   EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state());
606
607   // Make sure that we really created a directory.
608   google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
609   scoped_ptr<google_apis::ResourceEntry> resource_entry;
610   fake_service()->GetResourceEntry(
611       entry.resource_id(),
612       google_apis::test_util::CreateCopyResultCallback(&status,
613                                                        &resource_entry));
614   test_util::RunBlockingPoolTask();
615   EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
616   ASSERT_TRUE(resource_entry);
617   EXPECT_TRUE(resource_entry->is_folder());
618 }
619
620 }  // namespace internal
621 }  // namespace drive