OLD | NEW |
| (Empty) |
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/files/file_util.h" | |
9 #include "base/md5.h" | |
10 #include "base/task_runner_util.h" | |
11 #include "components/drive/drive_api_util.h" | |
12 #include "components/drive/file_cache.h" | |
13 #include "components/drive/file_system/download_operation.h" | |
14 #include "components/drive/file_system/operation_test_base.h" | |
15 #include "components/drive/job_scheduler.h" | |
16 #include "components/drive/resource_metadata.h" | |
17 #include "components/drive/service/fake_drive_service.h" | |
18 #include "content/public/test/test_utils.h" | |
19 #include "google_apis/drive/drive_api_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 void SetUp() override { | |
29 OperationTestBase::SetUp(); | |
30 performer_.reset(new EntryUpdatePerformer(blocking_task_runner(), | |
31 delegate(), | |
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 content::RunAllBlockingPoolTasksUntilIdle(); | |
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 content::RunAllBlockingPoolTasksUntilIdle(); | |
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 content::RunAllBlockingPoolTasksUntilIdle(); | |
105 EXPECT_EQ(FILE_ERROR_OK, error); | |
106 | |
107 // Verify the file is updated on the server. | |
108 google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; | |
109 scoped_ptr<google_apis::FileResource> gdata_entry; | |
110 fake_service()->GetFileResource( | |
111 src_entry.resource_id(), | |
112 google_apis::test_util::CreateCopyResultCallback(&gdata_error, | |
113 &gdata_entry)); | |
114 content::RunAllBlockingPoolTasksUntilIdle(); | |
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->modified_date()); | |
120 EXPECT_EQ(new_last_accessed, gdata_entry->last_viewed_by_me_date()); | |
121 | |
122 ASSERT_FALSE(gdata_entry->parents().empty()); | |
123 EXPECT_EQ(dest_entry.resource_id(), gdata_entry->parents()[0].file_id()); | |
124 } | |
125 | |
126 TEST_F(EntryUpdatePerformerTest, UpdateEntry_SetProperties) { | |
127 base::FilePath entry_path( | |
128 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); | |
129 | |
130 ResourceEntry entry; | |
131 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(entry_path, &entry)); | |
132 | |
133 Property* const first_property = entry.mutable_new_properties()->Add(); | |
134 first_property->set_key("hello"); | |
135 first_property->set_value("world"); | |
136 first_property->set_visibility(Property_Visibility_PUBLIC); | |
137 | |
138 Property* const second_property = entry.mutable_new_properties()->Add(); | |
139 second_property->set_key("this"); | |
140 second_property->set_value("will-change"); | |
141 second_property->set_visibility(Property_Visibility_PUBLIC); | |
142 entry.set_metadata_edit_state(ResourceEntry::DIRTY); | |
143 | |
144 FileError error = FILE_ERROR_FAILED; | |
145 base::PostTaskAndReplyWithResult( | |
146 blocking_task_runner(), FROM_HERE, | |
147 base::Bind(&ResourceMetadata::RefreshEntry, base::Unretained(metadata()), | |
148 entry), | |
149 google_apis::test_util::CreateCopyResultCallback(&error)); | |
150 content::RunAllBlockingPoolTasksUntilIdle(); | |
151 EXPECT_EQ(FILE_ERROR_OK, error); | |
152 | |
153 // Perform server side update. | |
154 error = FILE_ERROR_FAILED; | |
155 performer_->UpdateEntry( | |
156 entry.local_id(), ClientContext(USER_INITIATED), | |
157 google_apis::test_util::CreateCopyResultCallback(&error)); | |
158 | |
159 // Add a new property during an update. | |
160 Property* const property = entry.mutable_new_properties()->Add(); | |
161 property->set_key("tokyo"); | |
162 property->set_value("kyoto"); | |
163 property->set_visibility(Property_Visibility_PUBLIC); | |
164 | |
165 // Modify an existing property during an update. | |
166 second_property->set_value("changed"); | |
167 | |
168 // Change the resource entry during an update. | |
169 base::PostTaskAndReplyWithResult( | |
170 blocking_task_runner(), FROM_HERE, | |
171 base::Bind(&ResourceMetadata::RefreshEntry, base::Unretained(metadata()), | |
172 entry), | |
173 google_apis::test_util::CreateCopyResultCallback(&error)); | |
174 | |
175 // Wait until the update is fully completed. | |
176 content::RunAllBlockingPoolTasksUntilIdle(); | |
177 EXPECT_EQ(FILE_ERROR_OK, error); | |
178 | |
179 // List of synced properties should be removed from the proto. | |
180 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(entry_path, &entry)); | |
181 ASSERT_EQ(2, entry.new_properties().size()); | |
182 EXPECT_EQ("changed", entry.new_properties().Get(0).value()); | |
183 EXPECT_EQ("tokyo", entry.new_properties().Get(1).key()); | |
184 } | |
185 | |
186 // Tests updating metadata of a file with a non-dirty cache file. | |
187 TEST_F(EntryUpdatePerformerTest, UpdateEntry_WithNonDirtyCache) { | |
188 base::FilePath src_path( | |
189 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); | |
190 | |
191 // Download the file content to prepare a non-dirty cache file. | |
192 file_system::DownloadOperation download_operation( | |
193 blocking_task_runner(), delegate(), scheduler(), metadata(), cache(), | |
194 temp_dir()); | |
195 FileError error = FILE_ERROR_FAILED; | |
196 base::FilePath cache_file_path; | |
197 scoped_ptr<ResourceEntry> src_entry; | |
198 download_operation.EnsureFileDownloadedByPath( | |
199 src_path, | |
200 ClientContext(USER_INITIATED), | |
201 GetFileContentInitializedCallback(), | |
202 google_apis::GetContentCallback(), | |
203 google_apis::test_util::CreateCopyResultCallback( | |
204 &error, &cache_file_path, &src_entry)); | |
205 content::RunAllBlockingPoolTasksUntilIdle(); | |
206 EXPECT_EQ(FILE_ERROR_OK, error); | |
207 ASSERT_TRUE(src_entry); | |
208 | |
209 // Update the entry locally. | |
210 src_entry->set_title("Updated" + src_entry->title()); | |
211 src_entry->set_metadata_edit_state(ResourceEntry::DIRTY); | |
212 | |
213 error = FILE_ERROR_FAILED; | |
214 base::PostTaskAndReplyWithResult( | |
215 blocking_task_runner(), | |
216 FROM_HERE, | |
217 base::Bind(&ResourceMetadata::RefreshEntry, | |
218 base::Unretained(metadata()), | |
219 *src_entry), | |
220 google_apis::test_util::CreateCopyResultCallback(&error)); | |
221 content::RunAllBlockingPoolTasksUntilIdle(); | |
222 EXPECT_EQ(FILE_ERROR_OK, error); | |
223 | |
224 // Perform server side update. This shouldn't fail. (crbug.com/358590) | |
225 error = FILE_ERROR_FAILED; | |
226 performer_->UpdateEntry( | |
227 src_entry->local_id(), | |
228 ClientContext(USER_INITIATED), | |
229 google_apis::test_util::CreateCopyResultCallback(&error)); | |
230 content::RunAllBlockingPoolTasksUntilIdle(); | |
231 EXPECT_EQ(FILE_ERROR_OK, error); | |
232 | |
233 // Verify the file is updated on the server. | |
234 google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; | |
235 scoped_ptr<google_apis::FileResource> gdata_entry; | |
236 fake_service()->GetFileResource( | |
237 src_entry->resource_id(), | |
238 google_apis::test_util::CreateCopyResultCallback(&gdata_error, | |
239 &gdata_entry)); | |
240 content::RunAllBlockingPoolTasksUntilIdle(); | |
241 EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); | |
242 ASSERT_TRUE(gdata_entry); | |
243 EXPECT_EQ(src_entry->title(), gdata_entry->title()); | |
244 } | |
245 | |
246 TEST_F(EntryUpdatePerformerTest, UpdateEntry_NotFound) { | |
247 const std::string id = "this ID should result in NOT_FOUND"; | |
248 FileError error = FILE_ERROR_FAILED; | |
249 performer_->UpdateEntry( | |
250 id, ClientContext(USER_INITIATED), | |
251 google_apis::test_util::CreateCopyResultCallback(&error)); | |
252 content::RunAllBlockingPoolTasksUntilIdle(); | |
253 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); | |
254 } | |
255 | |
256 TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdate) { | |
257 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); | |
258 const std::string kResourceId("2_file_resource_id"); | |
259 | |
260 const std::string local_id = GetLocalId(kFilePath); | |
261 EXPECT_FALSE(local_id.empty()); | |
262 | |
263 const std::string kTestFileContent = "I'm being uploaded! Yay!"; | |
264 EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); | |
265 | |
266 int64 original_changestamp = | |
267 fake_service()->about_resource().largest_change_id(); | |
268 | |
269 // The callback will be called upon completion of UpdateEntry(). | |
270 FileError error = FILE_ERROR_FAILED; | |
271 performer_->UpdateEntry( | |
272 local_id, | |
273 ClientContext(USER_INITIATED), | |
274 google_apis::test_util::CreateCopyResultCallback(&error)); | |
275 content::RunAllBlockingPoolTasksUntilIdle(); | |
276 EXPECT_EQ(FILE_ERROR_OK, error); | |
277 | |
278 // Check that the server has received an update. | |
279 EXPECT_LT(original_changestamp, | |
280 fake_service()->about_resource().largest_change_id()); | |
281 | |
282 // Check that the file size is updated to that of the updated content. | |
283 google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; | |
284 scoped_ptr<google_apis::FileResource> server_entry; | |
285 fake_service()->GetFileResource( | |
286 kResourceId, | |
287 google_apis::test_util::CreateCopyResultCallback(&gdata_error, | |
288 &server_entry)); | |
289 content::RunAllBlockingPoolTasksUntilIdle(); | |
290 EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); | |
291 EXPECT_EQ(static_cast<int64>(kTestFileContent.size()), | |
292 server_entry->file_size()); | |
293 | |
294 // Make sure that the cache is no longer dirty. | |
295 ResourceEntry entry; | |
296 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); | |
297 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); | |
298 } | |
299 | |
300 TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdateMd5Check) { | |
301 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); | |
302 const std::string kResourceId("2_file_resource_id"); | |
303 | |
304 const std::string local_id = GetLocalId(kFilePath); | |
305 EXPECT_FALSE(local_id.empty()); | |
306 | |
307 const std::string kTestFileContent = "I'm being uploaded! Yay!"; | |
308 EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); | |
309 | |
310 int64 original_changestamp = | |
311 fake_service()->about_resource().largest_change_id(); | |
312 | |
313 // The callback will be called upon completion of UpdateEntry(). | |
314 FileError error = FILE_ERROR_FAILED; | |
315 performer_->UpdateEntry( | |
316 local_id, | |
317 ClientContext(USER_INITIATED), | |
318 google_apis::test_util::CreateCopyResultCallback(&error)); | |
319 content::RunAllBlockingPoolTasksUntilIdle(); | |
320 EXPECT_EQ(FILE_ERROR_OK, error); | |
321 | |
322 // Check that the server has received an update. | |
323 EXPECT_LT(original_changestamp, | |
324 fake_service()->about_resource().largest_change_id()); | |
325 | |
326 // Check that the file size is updated to that of the updated content. | |
327 google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR; | |
328 scoped_ptr<google_apis::FileResource> server_entry; | |
329 fake_service()->GetFileResource( | |
330 kResourceId, | |
331 google_apis::test_util::CreateCopyResultCallback(&gdata_error, | |
332 &server_entry)); | |
333 content::RunAllBlockingPoolTasksUntilIdle(); | |
334 EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); | |
335 EXPECT_EQ(static_cast<int64>(kTestFileContent.size()), | |
336 server_entry->file_size()); | |
337 | |
338 // Make sure that the cache is no longer dirty. | |
339 ResourceEntry entry; | |
340 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); | |
341 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); | |
342 | |
343 // Again mark the cache file dirty. | |
344 scoped_ptr<base::ScopedClosureRunner> file_closer; | |
345 error = FILE_ERROR_FAILED; | |
346 base::PostTaskAndReplyWithResult( | |
347 blocking_task_runner(), | |
348 FROM_HERE, | |
349 base::Bind(&FileCache::OpenForWrite, | |
350 base::Unretained(cache()), | |
351 local_id, | |
352 &file_closer), | |
353 google_apis::test_util::CreateCopyResultCallback(&error)); | |
354 content::RunAllBlockingPoolTasksUntilIdle(); | |
355 EXPECT_EQ(FILE_ERROR_OK, error); | |
356 file_closer.reset(); | |
357 | |
358 // And call UpdateEntry again. | |
359 // In this case, although the file is marked as dirty, but the content | |
360 // hasn't been changed. Thus, the actual uploading should be skipped. | |
361 original_changestamp = fake_service()->about_resource().largest_change_id(); | |
362 error = FILE_ERROR_FAILED; | |
363 performer_->UpdateEntry( | |
364 local_id, | |
365 ClientContext(USER_INITIATED), | |
366 google_apis::test_util::CreateCopyResultCallback(&error)); | |
367 content::RunAllBlockingPoolTasksUntilIdle(); | |
368 EXPECT_EQ(FILE_ERROR_OK, error); | |
369 | |
370 EXPECT_EQ(original_changestamp, | |
371 fake_service()->about_resource().largest_change_id()); | |
372 | |
373 // Make sure that the cache is no longer dirty. | |
374 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); | |
375 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); | |
376 } | |
377 | |
378 TEST_F(EntryUpdatePerformerTest, UpdateEntry_OpenedForWrite) { | |
379 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); | |
380 const std::string kResourceId("2_file_resource_id"); | |
381 | |
382 const std::string local_id = GetLocalId(kFilePath); | |
383 EXPECT_FALSE(local_id.empty()); | |
384 | |
385 const std::string kTestFileContent = "I'm being uploaded! Yay!"; | |
386 EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); | |
387 | |
388 // Emulate a situation where someone is writing to the file. | |
389 scoped_ptr<base::ScopedClosureRunner> file_closer; | |
390 FileError error = FILE_ERROR_FAILED; | |
391 base::PostTaskAndReplyWithResult( | |
392 blocking_task_runner(), | |
393 FROM_HERE, | |
394 base::Bind(&FileCache::OpenForWrite, | |
395 base::Unretained(cache()), | |
396 local_id, | |
397 &file_closer), | |
398 google_apis::test_util::CreateCopyResultCallback(&error)); | |
399 content::RunAllBlockingPoolTasksUntilIdle(); | |
400 EXPECT_EQ(FILE_ERROR_OK, error); | |
401 | |
402 // Update. This should not 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 content::RunAllBlockingPoolTasksUntilIdle(); | |
409 EXPECT_EQ(FILE_ERROR_OK, error); | |
410 | |
411 // Make sure that the cache is still dirty. | |
412 ResourceEntry entry; | |
413 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); | |
414 EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); | |
415 | |
416 // Close the file. | |
417 file_closer.reset(); | |
418 | |
419 // Update. This should clear the dirty bit. | |
420 error = FILE_ERROR_FAILED; | |
421 performer_->UpdateEntry( | |
422 local_id, | |
423 ClientContext(USER_INITIATED), | |
424 google_apis::test_util::CreateCopyResultCallback(&error)); | |
425 content::RunAllBlockingPoolTasksUntilIdle(); | |
426 EXPECT_EQ(FILE_ERROR_OK, error); | |
427 | |
428 // Make sure that the cache is no longer dirty. | |
429 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); | |
430 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); | |
431 } | |
432 | |
433 TEST_F(EntryUpdatePerformerTest, UpdateEntry_UploadNewFile) { | |
434 // Create a new file locally. | |
435 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt")); | |
436 | |
437 ResourceEntry parent; | |
438 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent)); | |
439 | |
440 ResourceEntry entry; | |
441 entry.set_parent_local_id(parent.local_id()); | |
442 entry.set_title(kFilePath.BaseName().AsUTF8Unsafe()); | |
443 entry.mutable_file_specific_info()->set_content_mime_type("text/plain"); | |
444 entry.set_metadata_edit_state(ResourceEntry::DIRTY); | |
445 | |
446 FileError error = FILE_ERROR_FAILED; | |
447 std::string local_id; | |
448 base::PostTaskAndReplyWithResult( | |
449 blocking_task_runner(), | |
450 FROM_HERE, | |
451 base::Bind(&internal::ResourceMetadata::AddEntry, | |
452 base::Unretained(metadata()), | |
453 entry, | |
454 &local_id), | |
455 google_apis::test_util::CreateCopyResultCallback(&error)); | |
456 content::RunAllBlockingPoolTasksUntilIdle(); | |
457 EXPECT_EQ(FILE_ERROR_OK, error); | |
458 | |
459 // Update. This should result in creating a new file on the server. | |
460 error = FILE_ERROR_FAILED; | |
461 performer_->UpdateEntry( | |
462 local_id, | |
463 ClientContext(USER_INITIATED), | |
464 google_apis::test_util::CreateCopyResultCallback(&error)); | |
465 content::RunAllBlockingPoolTasksUntilIdle(); | |
466 EXPECT_EQ(FILE_ERROR_OK, error); | |
467 | |
468 // The entry got a resource ID. | |
469 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); | |
470 EXPECT_FALSE(entry.resource_id().empty()); | |
471 EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state()); | |
472 | |
473 // Make sure that the cache is no longer dirty. | |
474 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); | |
475 | |
476 // Make sure that we really created a file. | |
477 google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; | |
478 scoped_ptr<google_apis::FileResource> server_entry; | |
479 fake_service()->GetFileResource( | |
480 entry.resource_id(), | |
481 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); | |
482 content::RunAllBlockingPoolTasksUntilIdle(); | |
483 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); | |
484 ASSERT_TRUE(server_entry); | |
485 EXPECT_FALSE(server_entry->IsDirectory()); | |
486 } | |
487 | |
488 TEST_F(EntryUpdatePerformerTest, UpdateEntry_NewFileOpendForWrite) { | |
489 // Create a new file locally. | |
490 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt")); | |
491 | |
492 ResourceEntry parent; | |
493 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent)); | |
494 | |
495 ResourceEntry entry; | |
496 entry.set_parent_local_id(parent.local_id()); | |
497 entry.set_title(kFilePath.BaseName().AsUTF8Unsafe()); | |
498 entry.mutable_file_specific_info()->set_content_mime_type("text/plain"); | |
499 entry.set_metadata_edit_state(ResourceEntry::DIRTY); | |
500 | |
501 FileError error = FILE_ERROR_FAILED; | |
502 std::string local_id; | |
503 base::PostTaskAndReplyWithResult( | |
504 blocking_task_runner(), | |
505 FROM_HERE, | |
506 base::Bind(&internal::ResourceMetadata::AddEntry, | |
507 base::Unretained(metadata()), | |
508 entry, | |
509 &local_id), | |
510 google_apis::test_util::CreateCopyResultCallback(&error)); | |
511 content::RunAllBlockingPoolTasksUntilIdle(); | |
512 EXPECT_EQ(FILE_ERROR_OK, error); | |
513 | |
514 const std::string kTestFileContent = "This is a new file."; | |
515 EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); | |
516 | |
517 // Emulate a situation where someone is writing to the file. | |
518 scoped_ptr<base::ScopedClosureRunner> file_closer; | |
519 error = FILE_ERROR_FAILED; | |
520 base::PostTaskAndReplyWithResult( | |
521 blocking_task_runner(), | |
522 FROM_HERE, | |
523 base::Bind(&FileCache::OpenForWrite, | |
524 base::Unretained(cache()), | |
525 local_id, | |
526 &file_closer), | |
527 google_apis::test_util::CreateCopyResultCallback(&error)); | |
528 content::RunAllBlockingPoolTasksUntilIdle(); | |
529 EXPECT_EQ(FILE_ERROR_OK, error); | |
530 | |
531 // Update, but no update is performed because the file is opened. | |
532 error = FILE_ERROR_FAILED; | |
533 performer_->UpdateEntry( | |
534 local_id, | |
535 ClientContext(USER_INITIATED), | |
536 google_apis::test_util::CreateCopyResultCallback(&error)); | |
537 content::RunAllBlockingPoolTasksUntilIdle(); | |
538 EXPECT_EQ(FILE_ERROR_OK, error); | |
539 | |
540 // The entry hasn't got a resource ID yet. | |
541 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); | |
542 EXPECT_TRUE(entry.resource_id().empty()); | |
543 | |
544 // Close the file. | |
545 file_closer.reset(); | |
546 | |
547 // Update. This should result in creating a new file on the server. | |
548 error = FILE_ERROR_FAILED; | |
549 performer_->UpdateEntry( | |
550 local_id, | |
551 ClientContext(USER_INITIATED), | |
552 google_apis::test_util::CreateCopyResultCallback(&error)); | |
553 content::RunAllBlockingPoolTasksUntilIdle(); | |
554 EXPECT_EQ(FILE_ERROR_OK, error); | |
555 | |
556 // The entry got a resource ID. | |
557 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry)); | |
558 EXPECT_FALSE(entry.resource_id().empty()); | |
559 EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state()); | |
560 } | |
561 | |
562 TEST_F(EntryUpdatePerformerTest, UpdateEntry_CreateDirectory) { | |
563 // Create a new directory locally. | |
564 const base::FilePath kPath(FILE_PATH_LITERAL("drive/root/New Directory")); | |
565 | |
566 ResourceEntry parent; | |
567 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath.DirName(), &parent)); | |
568 | |
569 ResourceEntry entry; | |
570 entry.set_parent_local_id(parent.local_id()); | |
571 entry.set_title(kPath.BaseName().AsUTF8Unsafe()); | |
572 entry.mutable_file_info()->set_is_directory(true); | |
573 entry.set_metadata_edit_state(ResourceEntry::DIRTY); | |
574 | |
575 FileError error = FILE_ERROR_FAILED; | |
576 std::string local_id; | |
577 base::PostTaskAndReplyWithResult( | |
578 blocking_task_runner(), | |
579 FROM_HERE, | |
580 base::Bind(&internal::ResourceMetadata::AddEntry, | |
581 base::Unretained(metadata()), | |
582 entry, | |
583 &local_id), | |
584 google_apis::test_util::CreateCopyResultCallback(&error)); | |
585 content::RunAllBlockingPoolTasksUntilIdle(); | |
586 EXPECT_EQ(FILE_ERROR_OK, error); | |
587 | |
588 // Update. This should result in creating a new directory on the server. | |
589 error = FILE_ERROR_FAILED; | |
590 performer_->UpdateEntry( | |
591 local_id, | |
592 ClientContext(USER_INITIATED), | |
593 google_apis::test_util::CreateCopyResultCallback(&error)); | |
594 content::RunAllBlockingPoolTasksUntilIdle(); | |
595 EXPECT_EQ(FILE_ERROR_OK, error); | |
596 | |
597 // The entry got a resource ID. | |
598 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath, &entry)); | |
599 EXPECT_FALSE(entry.resource_id().empty()); | |
600 EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state()); | |
601 | |
602 // Make sure that we really created a directory. | |
603 google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR; | |
604 scoped_ptr<google_apis::FileResource> server_entry; | |
605 fake_service()->GetFileResource( | |
606 entry.resource_id(), | |
607 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); | |
608 content::RunAllBlockingPoolTasksUntilIdle(); | |
609 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); | |
610 ASSERT_TRUE(server_entry); | |
611 EXPECT_TRUE(server_entry->IsDirectory()); | |
612 } | |
613 | |
614 TEST_F(EntryUpdatePerformerTest, UpdateEntry_InsufficientPermission) { | |
615 base::FilePath src_path( | |
616 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); | |
617 | |
618 ResourceEntry src_entry; | |
619 EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry)); | |
620 | |
621 // Update local entry. | |
622 ResourceEntry updated_entry(src_entry); | |
623 updated_entry.set_title("Moved" + src_entry.title()); | |
624 updated_entry.set_metadata_edit_state(ResourceEntry::DIRTY); | |
625 | |
626 FileError error = FILE_ERROR_FAILED; | |
627 base::PostTaskAndReplyWithResult( | |
628 blocking_task_runner(), | |
629 FROM_HERE, | |
630 base::Bind(&ResourceMetadata::RefreshEntry, | |
631 base::Unretained(metadata()), | |
632 updated_entry), | |
633 google_apis::test_util::CreateCopyResultCallback(&error)); | |
634 content::RunAllBlockingPoolTasksUntilIdle(); | |
635 EXPECT_EQ(FILE_ERROR_OK, error); | |
636 | |
637 // Set user permission to forbid server side update. | |
638 EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_service()->SetUserPermission( | |
639 src_entry.resource_id(), google_apis::drive::PERMISSION_ROLE_READER)); | |
640 | |
641 // Try to perform update. | |
642 error = FILE_ERROR_FAILED; | |
643 performer_->UpdateEntry( | |
644 src_entry.local_id(), | |
645 ClientContext(USER_INITIATED), | |
646 google_apis::test_util::CreateCopyResultCallback(&error)); | |
647 content::RunAllBlockingPoolTasksUntilIdle(); | |
648 EXPECT_EQ(FILE_ERROR_OK, error); | |
649 | |
650 // This should result in reverting the local change. | |
651 ResourceEntry result_entry; | |
652 EXPECT_EQ(FILE_ERROR_OK, | |
653 GetLocalResourceEntryById(src_entry.local_id(), &result_entry)); | |
654 EXPECT_EQ(src_entry.title(), result_entry.title()); | |
655 } | |
656 | |
657 } // namespace internal | |
658 } // namespace drive | |
OLD | NEW |