OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 <string> | |
6 #include <vector> | |
7 | |
8 #include "base/bind.h" | |
9 #include "base/file_path.h" | |
10 #include "base/file_util.h" | |
11 #include "base/json/json_file_value_serializer.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/message_loop.h" | |
14 #include "base/path_service.h" | |
15 #include "base/scoped_temp_dir.h" | |
16 #include "base/stringprintf.h" | |
17 #include "base/threading/sequenced_worker_pool.h" | |
18 #include "base/values.h" | |
19 #include "chrome/browser/chromeos/cros/cros_library.h" | |
20 #include "chrome/browser/chromeos/gdata/drive.pb.h" | |
21 #include "chrome/browser/chromeos/gdata/drive_api_parser.h" | |
22 #include "chrome/browser/chromeos/gdata/drive_webapps_registry.h" | |
23 #include "chrome/browser/chromeos/gdata/gdata_file_system.h" | |
24 #include "chrome/browser/chromeos/gdata/gdata_test_util.h" | |
25 #include "chrome/browser/chromeos/gdata/gdata_uploader.h" | |
26 #include "chrome/browser/chromeos/gdata/gdata_util.h" | |
27 #include "chrome/browser/chromeos/gdata/mock_directory_change_observer.h" | |
28 #include "chrome/browser/chromeos/gdata/mock_drive_cache_observer.h" | |
29 #include "chrome/browser/chromeos/gdata/mock_drive_service.h" | |
30 #include "chrome/common/chrome_paths.h" | |
31 #include "chrome/test/base/testing_profile.h" | |
32 #include "content/public/browser/browser_thread.h" | |
33 #include "content/public/test/test_browser_thread.h" | |
34 #include "testing/gmock/include/gmock/gmock.h" | |
35 #include "testing/gtest/include/gtest/gtest.h" | |
36 | |
37 using ::testing::AtLeast; | |
38 using ::testing::Eq; | |
39 using ::testing::NotNull; | |
40 using ::testing::Return; | |
41 using ::testing::StrictMock; | |
42 using ::testing::_; | |
43 | |
44 namespace gdata { | |
45 namespace { | |
46 | |
47 const char kSymLinkToDevNull[] = "/dev/null"; | |
48 | |
49 const int64 kLotsOfSpace = kMinFreeSpace * 10; | |
50 | |
51 struct SearchResultPair { | |
52 const char* path; | |
53 const bool is_directory; | |
54 }; | |
55 | |
56 // Callback to GDataFileSystem::Search used in ContentSearch tests. | |
57 // Verifies returned vector of results. | |
58 void DriveSearchCallback( | |
59 MessageLoop* message_loop, | |
60 const SearchResultPair* expected_results, | |
61 size_t expected_results_size, | |
62 DriveFileError error, | |
63 const GURL& next_feed, | |
64 scoped_ptr<std::vector<SearchResultInfo> > results) { | |
65 ASSERT_TRUE(results.get()); | |
66 ASSERT_EQ(expected_results_size, results->size()); | |
67 | |
68 for (size_t i = 0; i < results->size(); i++) { | |
69 EXPECT_EQ(FilePath(expected_results[i].path), | |
70 results->at(i).path); | |
71 EXPECT_EQ(expected_results[i].is_directory, | |
72 results->at(i).is_directory); | |
73 } | |
74 | |
75 message_loop->Quit(); | |
76 } | |
77 | |
78 // Action used to set mock expectations for | |
79 // DriveServiceInterface::GetDocumentEntry(). | |
80 ACTION_P2(MockGetDocumentEntry, status, value) { | |
81 base::MessageLoopProxy::current()->PostTask(FROM_HERE, | |
82 base::Bind(arg1, status, base::Passed(value))); | |
83 } | |
84 | |
85 // Action used to set mock expectations for | |
86 // GDataUploaderInterface::UploadExistingFile(). | |
87 ACTION_P4(MockUploadExistingFile, | |
88 error, gdata_path, local_file_path, document_entry) { | |
89 scoped_ptr<UploadFileInfo> upload_file_info(new UploadFileInfo); | |
90 upload_file_info->gdata_path = gdata_path; | |
91 upload_file_info->file_path = local_file_path; | |
92 upload_file_info->entry.reset(document_entry); | |
93 base::MessageLoopProxy::current()->PostTask(FROM_HERE, | |
94 base::Bind(arg5, error, base::Passed(&upload_file_info))); | |
95 | |
96 const int kUploadId = 123; | |
97 return kUploadId; | |
98 } | |
99 | |
100 // Action used to set mock expectations for | |
101 // GDataFileSystem::CopyDocument(). | |
102 ACTION_P2(MockCopyDocument, status, value) { | |
103 base::MessageLoopProxy::current()->PostTask( | |
104 FROM_HERE, | |
105 base::Bind(arg2, status, base::Passed(value))); | |
106 } | |
107 | |
108 // Returns the absolute path for a test file stored under | |
109 // chrome/test/data/chromeos/gdata. | |
110 FilePath GetTestFilePath(const FilePath::StringType& base_name) { | |
111 FilePath path; | |
112 std::string error; | |
113 PathService::Get(chrome::DIR_TEST_DATA, &path); | |
114 path = path.AppendASCII("chromeos") | |
115 .AppendASCII("gdata") | |
116 .AppendASCII(base_name.c_str()); | |
117 EXPECT_TRUE(file_util::PathExists(path)) << | |
118 "Couldn't find " << path.value(); | |
119 return path; | |
120 } | |
121 | |
122 // Loads a test JSON file as a base::Value. | |
123 base::Value* LoadJSONFile(const std::string& base_name) { | |
124 FilePath path = GetTestFilePath(base_name); | |
125 | |
126 std::string error; | |
127 JSONFileValueSerializer serializer(path); | |
128 base::Value* value = serializer.Deserialize(NULL, &error); | |
129 EXPECT_TRUE(value) << | |
130 "Parse error " << path.value() << ": " << error; | |
131 return value; | |
132 } | |
133 | |
134 // Counts the number of files (not directories) in |entries|. | |
135 int CountFiles(const DriveEntryProtoVector& entries) { | |
136 int num_files = 0; | |
137 for (size_t i = 0; i < entries.size(); ++i) { | |
138 if (!entries[i].file_info().is_directory()) | |
139 ++num_files; | |
140 } | |
141 return num_files; | |
142 } | |
143 | |
144 } // namespace | |
145 | |
146 class MockFreeDiskSpaceGetter : public FreeDiskSpaceGetterInterface { | |
147 public: | |
148 virtual ~MockFreeDiskSpaceGetter() {} | |
149 MOCK_CONST_METHOD0(AmountOfFreeDiskSpace, int64()); | |
150 }; | |
151 | |
152 class MockGDataUploader : public GDataUploaderInterface { | |
153 public: | |
154 virtual ~MockGDataUploader() {} | |
155 // This function is not mockable by gmock. | |
156 virtual int UploadNewFile( | |
157 scoped_ptr<UploadFileInfo> upload_file_info) OVERRIDE { | |
158 // Set a document entry for an uploaded file. | |
159 // Used for TransferFileFromLocalToRemote_RegularFile test. | |
160 scoped_ptr<base::Value> value(LoadJSONFile("uploaded_file.json")); | |
161 scoped_ptr<DocumentEntry> document_entry( | |
162 DocumentEntry::ExtractAndParse(*value)); | |
163 upload_file_info->entry = document_entry.Pass(); | |
164 | |
165 // Run the completion callback. | |
166 const UploadFileInfo::UploadCompletionCallback callback = | |
167 upload_file_info->completion_callback; | |
168 if (!callback.is_null()) | |
169 callback.Run(DRIVE_FILE_OK, upload_file_info.Pass()); | |
170 | |
171 const int kUploadId = 123; | |
172 return kUploadId; | |
173 } | |
174 | |
175 // This function is not mockable by gmock. | |
176 virtual int StreamExistingFile( | |
177 scoped_ptr<UploadFileInfo> upload_file_info) OVERRIDE { return 0; } | |
178 | |
179 MOCK_METHOD6(UploadExistingFile, | |
180 int(const GURL& upload_location, | |
181 const FilePath& gdata_file_path, | |
182 const FilePath& local_file_path, | |
183 int64 file_size, | |
184 const std::string& content_type, | |
185 const UploadFileInfo::UploadCompletionCallback& callback)); | |
186 | |
187 MOCK_METHOD2(UpdateUpload, void(int upload_id, | |
188 content::DownloadItem* download)); | |
189 MOCK_CONST_METHOD1(GetUploadedBytes, int64(int upload_id)); | |
190 }; | |
191 | |
192 class MockDriveWebAppsRegistry : public DriveWebAppsRegistryInterface { | |
193 public: | |
194 virtual ~MockDriveWebAppsRegistry() {} | |
195 | |
196 MOCK_METHOD3(GetWebAppsForFile, void(const FilePath& file, | |
197 const std::string& mime_type, | |
198 ScopedVector<DriveWebAppInfo>* apps)); | |
199 MOCK_METHOD1(GetExtensionsForWebStoreApp, | |
200 std::set<std::string>(const std::string& web_store_id)); | |
201 MOCK_METHOD1(UpdateFromFeed, void(const AccountMetadataFeed& metadata)); | |
202 MOCK_METHOD1(UpdateFromApplicationList, void(const AppList& applist)); | |
203 }; | |
204 | |
205 class GDataFileSystemTest : public testing::Test { | |
206 protected: | |
207 GDataFileSystemTest() | |
208 : ui_thread_(content::BrowserThread::UI, &message_loop_), | |
209 io_thread_(content::BrowserThread::IO), | |
210 cache_(NULL), | |
211 file_system_(NULL), | |
212 mock_drive_service_(NULL), | |
213 mock_webapps_registry_(NULL), | |
214 num_callback_invocations_(0), | |
215 expected_error_(DRIVE_FILE_OK), | |
216 expected_cache_state_(0), | |
217 expected_sub_dir_type_(DriveCache::CACHE_TYPE_META), | |
218 expected_success_(true), | |
219 expect_outgoing_symlink_(false), | |
220 root_feed_changestamp_(0) { | |
221 } | |
222 | |
223 virtual void SetUp() OVERRIDE { | |
224 chromeos::CrosLibrary::Initialize(true /* use_stub */); | |
225 io_thread_.StartIOThread(); | |
226 | |
227 profile_.reset(new TestingProfile); | |
228 | |
229 callback_helper_ = new CallbackHelper; | |
230 | |
231 // Allocate and keep a pointer to the mock, and inject it into the | |
232 // GDataFileSystem object, which will own the mock object. | |
233 mock_drive_service_ = new StrictMock<MockDriveService>; | |
234 | |
235 EXPECT_CALL(*mock_drive_service_, Initialize(profile_.get())).Times(1); | |
236 | |
237 // Likewise, this will be owned by GDataFileSystem. | |
238 mock_free_disk_space_checker_ = new StrictMock<MockFreeDiskSpaceGetter>; | |
239 SetFreeDiskSpaceGetterForTesting(mock_free_disk_space_checker_); | |
240 | |
241 scoped_refptr<base::SequencedWorkerPool> pool = | |
242 content::BrowserThread::GetBlockingPool(); | |
243 blocking_task_runner_ = | |
244 pool->GetSequencedTaskRunner(pool->GetSequenceToken()); | |
245 | |
246 cache_ = DriveCache::CreateDriveCacheOnUIThread( | |
247 DriveCache::GetCacheRootPath(profile_.get()), blocking_task_runner_); | |
248 | |
249 mock_uploader_.reset(new StrictMock<MockGDataUploader>); | |
250 mock_webapps_registry_.reset(new StrictMock<MockDriveWebAppsRegistry>); | |
251 | |
252 ASSERT_FALSE(file_system_); | |
253 file_system_ = new GDataFileSystem(profile_.get(), | |
254 cache_, | |
255 mock_drive_service_, | |
256 mock_uploader_.get(), | |
257 mock_webapps_registry_.get(), | |
258 blocking_task_runner_); | |
259 | |
260 mock_cache_observer_.reset(new StrictMock<MockDriveCacheObserver>); | |
261 cache_->AddObserver(mock_cache_observer_.get()); | |
262 | |
263 mock_directory_observer_.reset(new StrictMock<MockDirectoryChangeObserver>); | |
264 file_system_->AddObserver(mock_directory_observer_.get()); | |
265 | |
266 file_system_->Initialize(); | |
267 cache_->RequestInitializeOnUIThreadForTesting(); | |
268 test_util::RunBlockingPoolTask(); | |
269 } | |
270 | |
271 virtual void TearDown() OVERRIDE { | |
272 ASSERT_TRUE(file_system_); | |
273 EXPECT_CALL(*mock_drive_service_, CancelAll()).Times(1); | |
274 delete file_system_; | |
275 file_system_ = NULL; | |
276 delete mock_drive_service_; | |
277 mock_drive_service_ = NULL; | |
278 SetFreeDiskSpaceGetterForTesting(NULL); | |
279 cache_->DestroyOnUIThread(); | |
280 // The cache destruction requires to post a task to the blocking pool. | |
281 test_util::RunBlockingPoolTask(); | |
282 | |
283 profile_.reset(NULL); | |
284 chromeos::CrosLibrary::Shutdown(); | |
285 } | |
286 | |
287 // Loads test json file as root ("/drive") element. | |
288 void LoadRootFeedDocument(const std::string& filename) { | |
289 LoadChangeFeed(filename, 0); | |
290 } | |
291 | |
292 void LoadChangeFeed(const std::string& filename, | |
293 int largest_changestamp) { | |
294 std::string error; | |
295 scoped_ptr<Value> document(LoadJSONFile(filename)); | |
296 ASSERT_TRUE(document.get()); | |
297 ASSERT_TRUE(document->GetType() == Value::TYPE_DICTIONARY); | |
298 scoped_ptr<DocumentFeed> document_feed( | |
299 DocumentFeed::ExtractAndParse(*document)); | |
300 ASSERT_TRUE(document_feed.get()); | |
301 std::vector<DocumentFeed*> feed_list; | |
302 feed_list.push_back(document_feed.get()); | |
303 ASSERT_TRUE(UpdateContent(feed_list, largest_changestamp)); | |
304 } | |
305 | |
306 void AddDirectoryFromFile(const FilePath& directory_path, | |
307 const std::string& filename) { | |
308 std::string error; | |
309 scoped_ptr<Value> atom(LoadJSONFile(filename)); | |
310 ASSERT_TRUE(atom.get()); | |
311 ASSERT_TRUE(atom->GetType() == Value::TYPE_DICTIONARY); | |
312 | |
313 DictionaryValue* dict_value = NULL; | |
314 Value* entry_value = NULL; | |
315 ASSERT_TRUE(atom->GetAsDictionary(&dict_value)); | |
316 ASSERT_TRUE(dict_value->Get("entry", &entry_value)); | |
317 | |
318 DictionaryValue* entry_dict = NULL; | |
319 ASSERT_TRUE(entry_value->GetAsDictionary(&entry_dict)); | |
320 | |
321 // Tweak entry title to match the last segment of the directory path | |
322 // (new directory name). | |
323 std::vector<FilePath::StringType> dir_parts; | |
324 directory_path.GetComponents(&dir_parts); | |
325 entry_dict->SetString("title.$t", dir_parts[dir_parts.size() - 1]); | |
326 | |
327 ASSERT_EQ(file_system_->AddNewDirectory(directory_path.DirName(), | |
328 entry_value), | |
329 DRIVE_FILE_OK) | |
330 << "Failed adding " | |
331 << directory_path.DirName().value(); | |
332 } | |
333 | |
334 // Updates the content of directory under |directory_path| with parsed feed | |
335 // |value|. | |
336 bool UpdateContent(const std::vector<DocumentFeed*>& list, | |
337 int largest_changestamp) { | |
338 GURL unused; | |
339 return file_system_->UpdateFromFeedForTesting( | |
340 list, | |
341 largest_changestamp, | |
342 root_feed_changestamp_++) == DRIVE_FILE_OK; | |
343 } | |
344 | |
345 bool RemoveEntry(const FilePath& file_path) { | |
346 return file_system_->RemoveEntryAndCacheLocally(file_path) == | |
347 DRIVE_FILE_OK; | |
348 } | |
349 | |
350 FilePath GetCachePathForFile(const std::string& resource_id, | |
351 const std::string& md5) { | |
352 return cache_->GetCacheFilePath(resource_id, | |
353 md5, | |
354 DriveCache::CACHE_TYPE_TMP, | |
355 DriveCache::CACHED_FILE_FROM_SERVER); | |
356 } | |
357 | |
358 // Gets entry info by path synchronously. | |
359 scoped_ptr<DriveEntryProto> GetEntryInfoByPathSync( | |
360 const FilePath& file_path) { | |
361 file_system_->GetEntryInfoByPath( | |
362 file_path, | |
363 base::Bind(&CallbackHelper::GetEntryInfoCallback, | |
364 callback_helper_.get())); | |
365 test_util::RunBlockingPoolTask(); | |
366 | |
367 return callback_helper_->entry_proto_.Pass(); | |
368 } | |
369 | |
370 // Gets directory info by path synchronously. | |
371 scoped_ptr<DriveEntryProtoVector> ReadDirectoryByPathSync( | |
372 const FilePath& file_path) { | |
373 file_system_->ReadDirectoryByPath( | |
374 file_path, | |
375 base::Bind(&CallbackHelper::ReadDirectoryCallback, | |
376 callback_helper_.get())); | |
377 test_util::RunBlockingPoolTask(); | |
378 | |
379 return callback_helper_->directory_entries_.Pass(); | |
380 } | |
381 | |
382 // Returns true if an entry exists at |file_path|. | |
383 bool EntryExists(const FilePath& file_path) { | |
384 return GetEntryInfoByPathSync(file_path).get(); | |
385 } | |
386 | |
387 | |
388 // Gets the resource ID of |file_path|. Returns an empty string if not found. | |
389 std::string GetResourceIdByPath(const FilePath& file_path) { | |
390 scoped_ptr<DriveEntryProto> entry_proto = | |
391 GetEntryInfoByPathSync(file_path); | |
392 if (entry_proto.get()) | |
393 return entry_proto->resource_id(); | |
394 else | |
395 return ""; | |
396 } | |
397 | |
398 // Helper function to call GetCacheEntry from origin thread. | |
399 bool GetCacheEntryFromOriginThread(const std::string& resource_id, | |
400 const std::string& md5, | |
401 DriveCacheEntry* cache_entry) { | |
402 bool result = false; | |
403 blocking_task_runner_->PostTask( | |
404 FROM_HERE, | |
405 base::Bind(&GDataFileSystemTest::GetCacheEntryFromOriginThreadInternal, | |
406 base::Unretained(this), | |
407 resource_id, | |
408 md5, | |
409 cache_entry, | |
410 &result)); | |
411 test_util::RunBlockingPoolTask(); | |
412 return result; | |
413 } | |
414 | |
415 // Used to implement GetCacheEntry. | |
416 void GetCacheEntryFromOriginThreadInternal( | |
417 const std::string& resource_id, | |
418 const std::string& md5, | |
419 DriveCacheEntry* cache_entry, | |
420 bool* result) { | |
421 *result = cache_->GetCacheEntry(resource_id, md5, cache_entry); | |
422 } | |
423 | |
424 // Returns true if the cache entry exists for the given resource ID and MD5. | |
425 bool CacheEntryExists(const std::string& resource_id, | |
426 const std::string& md5) { | |
427 DriveCacheEntry cache_entry; | |
428 return GetCacheEntryFromOriginThread(resource_id, md5, &cache_entry); | |
429 } | |
430 | |
431 // Returns true if the cache file exists for the given resource ID and MD5. | |
432 bool CacheFileExists(const std::string& resource_id, | |
433 const std::string& md5) { | |
434 const FilePath file_path = cache_->GetCacheFilePath( | |
435 resource_id, | |
436 md5, | |
437 DriveCache::CACHE_TYPE_TMP, | |
438 DriveCache::CACHED_FILE_FROM_SERVER); | |
439 return file_util::PathExists(file_path); | |
440 } | |
441 | |
442 void TestStoreToCache( | |
443 const std::string& resource_id, | |
444 const std::string& md5, | |
445 const FilePath& source_path, | |
446 DriveFileError expected_error, | |
447 int expected_cache_state, | |
448 DriveCache::CacheSubDirectoryType expected_sub_dir_type) { | |
449 expected_error_ = expected_error; | |
450 expected_cache_state_ = expected_cache_state; | |
451 expected_sub_dir_type_ = expected_sub_dir_type; | |
452 | |
453 cache_->StoreOnUIThread( | |
454 resource_id, md5, source_path, | |
455 DriveCache::FILE_OPERATION_COPY, | |
456 base::Bind(&GDataFileSystemTest::VerifyCacheFileState, | |
457 base::Unretained(this))); | |
458 | |
459 test_util::RunBlockingPoolTask(); | |
460 } | |
461 | |
462 void TestPin( | |
463 const std::string& resource_id, | |
464 const std::string& md5, | |
465 DriveFileError expected_error, | |
466 int expected_cache_state, | |
467 DriveCache::CacheSubDirectoryType expected_sub_dir_type) { | |
468 expected_error_ = expected_error; | |
469 expected_cache_state_ = expected_cache_state; | |
470 expected_sub_dir_type_ = expected_sub_dir_type; | |
471 | |
472 cache_->PinOnUIThread( | |
473 resource_id, md5, | |
474 base::Bind(&GDataFileSystemTest::VerifyCacheFileState, | |
475 base::Unretained(this))); | |
476 | |
477 test_util::RunBlockingPoolTask(); | |
478 } | |
479 | |
480 void TestMarkDirty( | |
481 const std::string& resource_id, | |
482 const std::string& md5, | |
483 DriveFileError expected_error, | |
484 int expected_cache_state, | |
485 DriveCache::CacheSubDirectoryType expected_sub_dir_type) { | |
486 expected_error_ = expected_error; | |
487 expected_cache_state_ = expected_cache_state; | |
488 expected_sub_dir_type_ = expected_sub_dir_type; | |
489 expect_outgoing_symlink_ = false; | |
490 | |
491 cache_->MarkDirtyOnUIThread( | |
492 resource_id, md5, | |
493 base::Bind(&GDataFileSystemTest::VerifyMarkDirty, | |
494 base::Unretained(this))); | |
495 | |
496 test_util::RunBlockingPoolTask(); | |
497 } | |
498 | |
499 void VerifyMarkDirty(DriveFileError error, | |
500 const std::string& resource_id, | |
501 const std::string& md5, | |
502 const FilePath& cache_file_path) { | |
503 VerifyCacheFileState(error, resource_id, md5); | |
504 | |
505 // Verify filename of |cache_file_path|. | |
506 if (error == DRIVE_FILE_OK) { | |
507 FilePath base_name = cache_file_path.BaseName(); | |
508 EXPECT_EQ(util::EscapeCacheFileName(resource_id) + | |
509 FilePath::kExtensionSeparator + | |
510 "local", | |
511 base_name.value()); | |
512 } else { | |
513 EXPECT_TRUE(cache_file_path.empty()); | |
514 } | |
515 } | |
516 | |
517 void TestCommitDirty( | |
518 const std::string& resource_id, | |
519 const std::string& md5, | |
520 DriveFileError expected_error, | |
521 int expected_cache_state, | |
522 DriveCache::CacheSubDirectoryType expected_sub_dir_type) { | |
523 expected_error_ = expected_error; | |
524 expected_cache_state_ = expected_cache_state; | |
525 expected_sub_dir_type_ = expected_sub_dir_type; | |
526 expect_outgoing_symlink_ = true; | |
527 | |
528 cache_->CommitDirtyOnUIThread( | |
529 resource_id, md5, | |
530 base::Bind(&GDataFileSystemTest::VerifyCacheFileState, | |
531 base::Unretained(this))); | |
532 | |
533 test_util::RunBlockingPoolTask(); | |
534 } | |
535 | |
536 // Verify the file identified by |resource_id| and |md5| is in the expected | |
537 // cache state after |OpenFile|, that is, marked dirty and has no outgoing | |
538 // symlink, etc. | |
539 void VerifyCacheStateAfterOpenFile(DriveFileError error, | |
540 const std::string& resource_id, | |
541 const std::string& md5, | |
542 const FilePath& cache_file_path) { | |
543 expected_error_ = DRIVE_FILE_OK; | |
544 expected_cache_state_ = (test_util::TEST_CACHE_STATE_PRESENT | | |
545 test_util::TEST_CACHE_STATE_DIRTY | | |
546 test_util::TEST_CACHE_STATE_PERSISTENT); | |
547 expected_sub_dir_type_ = DriveCache::CACHE_TYPE_PERSISTENT; | |
548 expect_outgoing_symlink_ = false; | |
549 VerifyMarkDirty(error, resource_id, md5, cache_file_path); | |
550 } | |
551 | |
552 // Verify the file identified by |resource_id| and |md5| is in the expected | |
553 // cache state after |CloseFile|, that is, marked dirty and has an outgoing | |
554 // symlink, etc. | |
555 void VerifyCacheStateAfterCloseFile(DriveFileError error, | |
556 const std::string& resource_id, | |
557 const std::string& md5) { | |
558 expected_error_ = DRIVE_FILE_OK; | |
559 expected_cache_state_ = (test_util::TEST_CACHE_STATE_PRESENT | | |
560 test_util::TEST_CACHE_STATE_DIRTY | | |
561 test_util::TEST_CACHE_STATE_PERSISTENT); | |
562 expected_sub_dir_type_ = DriveCache::CACHE_TYPE_PERSISTENT; | |
563 expect_outgoing_symlink_ = true; | |
564 VerifyCacheFileState(error, resource_id, md5); | |
565 } | |
566 | |
567 void VerifyCacheFileState(DriveFileError error, | |
568 const std::string& resource_id, | |
569 const std::string& md5) { | |
570 ++num_callback_invocations_; | |
571 | |
572 EXPECT_EQ(expected_error_, error); | |
573 | |
574 // Verify cache map. | |
575 DriveCacheEntry cache_entry; | |
576 const bool cache_entry_found = | |
577 GetCacheEntryFromOriginThread(resource_id, md5, &cache_entry); | |
578 if (test_util::ToCacheEntry(expected_cache_state_).is_present() || | |
579 test_util::ToCacheEntry(expected_cache_state_).is_pinned()) { | |
580 ASSERT_TRUE(cache_entry_found); | |
581 EXPECT_TRUE(test_util::CacheStatesEqual( | |
582 test_util::ToCacheEntry(expected_cache_state_), | |
583 cache_entry)); | |
584 EXPECT_EQ(expected_sub_dir_type_, | |
585 DriveCache::GetSubDirectoryType(cache_entry)); | |
586 } else { | |
587 EXPECT_FALSE(cache_entry_found); | |
588 } | |
589 | |
590 // Verify actual cache file. | |
591 FilePath dest_path = cache_->GetCacheFilePath( | |
592 resource_id, | |
593 md5, | |
594 test_util::ToCacheEntry(expected_cache_state_).is_pinned() || | |
595 test_util::ToCacheEntry(expected_cache_state_).is_dirty() ? | |
596 DriveCache::CACHE_TYPE_PERSISTENT : | |
597 DriveCache::CACHE_TYPE_TMP, | |
598 test_util::ToCacheEntry(expected_cache_state_).is_dirty() ? | |
599 DriveCache::CACHED_FILE_LOCALLY_MODIFIED : | |
600 DriveCache::CACHED_FILE_FROM_SERVER); | |
601 bool exists = file_util::PathExists(dest_path); | |
602 if (test_util::ToCacheEntry(expected_cache_state_).is_present()) | |
603 EXPECT_TRUE(exists); | |
604 else | |
605 EXPECT_FALSE(exists); | |
606 | |
607 // Verify symlink in pinned dir. | |
608 FilePath symlink_path = cache_->GetCacheFilePath( | |
609 resource_id, | |
610 std::string(), | |
611 DriveCache::CACHE_TYPE_PINNED, | |
612 DriveCache::CACHED_FILE_FROM_SERVER); | |
613 // Check that pin symlink exists, without dereferencing to target path. | |
614 exists = file_util::IsLink(symlink_path); | |
615 if (test_util::ToCacheEntry(expected_cache_state_).is_pinned()) { | |
616 EXPECT_TRUE(exists); | |
617 FilePath target_path; | |
618 EXPECT_TRUE(file_util::ReadSymbolicLink(symlink_path, &target_path)); | |
619 if (test_util::ToCacheEntry(expected_cache_state_).is_present()) | |
620 EXPECT_EQ(dest_path, target_path); | |
621 else | |
622 EXPECT_EQ(kSymLinkToDevNull, target_path.value()); | |
623 } else { | |
624 EXPECT_FALSE(exists); | |
625 } | |
626 | |
627 // Verify symlink in outgoing dir. | |
628 symlink_path = cache_->GetCacheFilePath( | |
629 resource_id, | |
630 std::string(), | |
631 DriveCache::CACHE_TYPE_OUTGOING, | |
632 DriveCache::CACHED_FILE_FROM_SERVER); | |
633 // Check that outgoing symlink exists, without dereferencing to target path. | |
634 exists = file_util::IsLink(symlink_path); | |
635 if (expect_outgoing_symlink_ && | |
636 test_util::ToCacheEntry(expected_cache_state_).is_dirty()) { | |
637 EXPECT_TRUE(exists); | |
638 FilePath target_path; | |
639 EXPECT_TRUE(file_util::ReadSymbolicLink(symlink_path, &target_path)); | |
640 EXPECT_TRUE(target_path.value() != kSymLinkToDevNull); | |
641 if (test_util::ToCacheEntry(expected_cache_state_).is_present()) | |
642 EXPECT_EQ(dest_path, target_path); | |
643 } else { | |
644 EXPECT_FALSE(exists); | |
645 } | |
646 } | |
647 | |
648 void SetExpectationsForGetDocumentEntry(scoped_ptr<base::Value>* document, | |
649 const std::string& resource_id) { | |
650 EXPECT_CALL(*mock_drive_service_, GetDocumentEntry(resource_id, _)) | |
651 .WillOnce(MockGetDocumentEntry(gdata::HTTP_SUCCESS, document)); | |
652 } | |
653 | |
654 // Loads serialized proto file from GCache, and makes sure the root | |
655 // filesystem has a root at 'drive' | |
656 void TestLoadMetadataFromCache() { | |
657 file_system_->LoadRootFeedFromCacheForTesting(); | |
658 test_util::RunBlockingPoolTask(); | |
659 } | |
660 | |
661 // Creates a proto file representing a filesystem with directories: | |
662 // drive, drive/Dir1, drive/Dir1/SubDir2 | |
663 // and files | |
664 // drive/File1, drive/Dir1/File2, drive/Dir1/SubDir2/File3. | |
665 // Sets the changestamp to 654321, equal to that of "account_metadata.json" | |
666 // test data, indicating the cache is holding the latest file system info. | |
667 void SaveTestFileSystem() { | |
668 DriveRootDirectoryProto root; | |
669 root.set_version(kProtoVersion); | |
670 root.set_largest_changestamp(654321); | |
671 DriveDirectoryProto* root_dir = root.mutable_gdata_directory(); | |
672 DriveEntryProto* dir_base = root_dir->mutable_gdata_entry(); | |
673 PlatformFileInfoProto* platform_info = dir_base->mutable_file_info(); | |
674 dir_base->set_title("drive"); | |
675 dir_base->set_resource_id(kDriveRootDirectoryResourceId); | |
676 dir_base->set_upload_url("http://resumable-create-media/1"); | |
677 platform_info->set_is_directory(true); | |
678 | |
679 // drive/File1 | |
680 DriveEntryProto* file = root_dir->add_child_files(); | |
681 file->set_title("File1"); | |
682 file->set_resource_id("resource_id:File1"); | |
683 file->set_upload_url("http://resumable-edit-media/1"); | |
684 file->mutable_file_specific_info()->set_file_md5("md5"); | |
685 platform_info = file->mutable_file_info(); | |
686 platform_info->set_is_directory(false); | |
687 platform_info->set_size(1048576); | |
688 | |
689 // drive/Dir1 | |
690 DriveDirectoryProto* dir1 = root_dir->add_child_directories(); | |
691 dir_base = dir1->mutable_gdata_entry(); | |
692 dir_base->set_title("Dir1"); | |
693 dir_base->set_resource_id("resource_id:Dir1"); | |
694 dir_base->set_upload_url("http://resumable-create-media/2"); | |
695 platform_info = dir_base->mutable_file_info(); | |
696 platform_info->set_is_directory(true); | |
697 | |
698 // drive/Dir1/File2 | |
699 file = dir1->add_child_files(); | |
700 file->set_title("File2"); | |
701 file->set_resource_id("resource_id:File2"); | |
702 file->set_upload_url("http://resumable-edit-media/2"); | |
703 file->mutable_file_specific_info()->set_file_md5("md5"); | |
704 platform_info = file->mutable_file_info(); | |
705 platform_info->set_is_directory(false); | |
706 platform_info->set_size(555); | |
707 | |
708 // drive/Dir1/SubDir2 | |
709 DriveDirectoryProto* dir2 = dir1->add_child_directories(); | |
710 dir_base = dir2->mutable_gdata_entry(); | |
711 dir_base->set_title("SubDir2"); | |
712 dir_base->set_resource_id("resource_id:SubDir2"); | |
713 dir_base->set_upload_url("http://resumable-create-media/3"); | |
714 platform_info = dir_base->mutable_file_info(); | |
715 platform_info->set_is_directory(true); | |
716 | |
717 // drive/Dir1/SubDir2/File3 | |
718 file = dir2->add_child_files(); | |
719 file->set_title("File3"); | |
720 file->set_resource_id("resource_id:File3"); | |
721 file->set_upload_url("http://resumable-edit-media/3"); | |
722 file->mutable_file_specific_info()->set_file_md5("md5"); | |
723 platform_info = file->mutable_file_info(); | |
724 platform_info->set_is_directory(false); | |
725 platform_info->set_size(12345); | |
726 | |
727 // Write this proto out to GCache/vi/meta/file_system.pb | |
728 std::string serialized_proto; | |
729 ASSERT_TRUE(root.SerializeToString(&serialized_proto)); | |
730 ASSERT_TRUE(!serialized_proto.empty()); | |
731 | |
732 FilePath cache_dir_path = profile_->GetPath().Append( | |
733 FILE_PATH_LITERAL("GCache/v1/meta/")); | |
734 ASSERT_TRUE(file_util::CreateDirectory(cache_dir_path)); | |
735 const int file_size = static_cast<int>(serialized_proto.length()); | |
736 ASSERT_EQ(file_util::WriteFile(cache_dir_path.Append("file_system.pb"), | |
737 serialized_proto.data(), file_size), file_size); | |
738 } | |
739 | |
740 // Verifies that |file_path| is a valid JSON file for the hosted document | |
741 // associated with |entry| (i.e. |url| and |resource_id| match). | |
742 void VerifyHostedDocumentJSONFile(const DriveEntryProto& entry_proto, | |
743 const FilePath& file_path) { | |
744 std::string error; | |
745 JSONFileValueSerializer serializer(file_path); | |
746 scoped_ptr<Value> value(serializer.Deserialize(NULL, &error)); | |
747 ASSERT_TRUE(value.get()) << "Parse error " << file_path.value() | |
748 << ": " << error; | |
749 DictionaryValue* dict_value = NULL; | |
750 ASSERT_TRUE(value->GetAsDictionary(&dict_value)); | |
751 | |
752 std::string edit_url, resource_id; | |
753 EXPECT_TRUE(dict_value->GetString("url", &edit_url)); | |
754 EXPECT_TRUE(dict_value->GetString("resource_id", &resource_id)); | |
755 | |
756 EXPECT_EQ(entry_proto.file_specific_info().alternate_url(), | |
757 edit_url); | |
758 EXPECT_EQ(entry_proto.resource_id(), resource_id); | |
759 } | |
760 | |
761 // This is used as a helper for registering callbacks that need to be | |
762 // RefCountedThreadSafe, and a place where we can fetch results from various | |
763 // operations. | |
764 class CallbackHelper | |
765 : public base::RefCountedThreadSafe<CallbackHelper> { | |
766 public: | |
767 CallbackHelper() | |
768 : last_error_(DRIVE_FILE_OK), | |
769 quota_bytes_total_(0), | |
770 quota_bytes_used_(0), | |
771 entry_proto_(NULL) {} | |
772 | |
773 virtual void GetFileCallback(DriveFileError error, | |
774 const FilePath& file_path, | |
775 const std::string& mime_type, | |
776 DriveFileType file_type) { | |
777 last_error_ = error; | |
778 download_path_ = file_path; | |
779 mime_type_ = mime_type; | |
780 file_type_ = file_type; | |
781 } | |
782 | |
783 virtual void FileOperationCallback(DriveFileError error) { | |
784 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
785 | |
786 last_error_ = error; | |
787 } | |
788 | |
789 virtual void GetAvailableSpaceCallback(DriveFileError error, | |
790 int64 bytes_total, | |
791 int64 bytes_used) { | |
792 last_error_ = error; | |
793 quota_bytes_total_ = bytes_total; | |
794 quota_bytes_used_ = bytes_used; | |
795 } | |
796 | |
797 virtual void OpenFileCallback(DriveFileError error, | |
798 const FilePath& file_path) { | |
799 last_error_ = error; | |
800 opened_file_path_ = file_path; | |
801 MessageLoop::current()->Quit(); | |
802 } | |
803 | |
804 virtual void CloseFileCallback(DriveFileError error) { | |
805 last_error_ = error; | |
806 MessageLoop::current()->Quit(); | |
807 } | |
808 | |
809 virtual void GetEntryInfoCallback( | |
810 DriveFileError error, | |
811 scoped_ptr<DriveEntryProto> entry_proto) { | |
812 last_error_ = error; | |
813 entry_proto_ = entry_proto.Pass(); | |
814 } | |
815 | |
816 virtual void ReadDirectoryCallback( | |
817 DriveFileError error, | |
818 bool /* hide_hosted_documents */, | |
819 scoped_ptr<DriveEntryProtoVector> entries) { | |
820 last_error_ = error; | |
821 directory_entries_ = entries.Pass(); | |
822 } | |
823 | |
824 DriveFileError last_error_; | |
825 FilePath download_path_; | |
826 FilePath opened_file_path_; | |
827 std::string mime_type_; | |
828 DriveFileType file_type_; | |
829 int64 quota_bytes_total_; | |
830 int64 quota_bytes_used_; | |
831 scoped_ptr<DriveEntryProto> entry_proto_; | |
832 scoped_ptr<DriveEntryProtoVector> directory_entries_; | |
833 | |
834 protected: | |
835 virtual ~CallbackHelper() {} | |
836 | |
837 private: | |
838 friend class base::RefCountedThreadSafe<CallbackHelper>; | |
839 }; | |
840 | |
841 MessageLoopForUI message_loop_; | |
842 // The order of the test threads is important, do not change the order. | |
843 // See also content/browser/browser_thread_impl.cc. | |
844 content::TestBrowserThread ui_thread_; | |
845 content::TestBrowserThread io_thread_; | |
846 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; | |
847 scoped_ptr<TestingProfile> profile_; | |
848 scoped_refptr<CallbackHelper> callback_helper_; | |
849 DriveCache* cache_; | |
850 scoped_ptr<StrictMock<MockGDataUploader> > mock_uploader_; | |
851 GDataFileSystem* file_system_; | |
852 StrictMock<MockDriveService>* mock_drive_service_; | |
853 scoped_ptr<StrictMock<MockDriveWebAppsRegistry> > mock_webapps_registry_; | |
854 StrictMock<MockFreeDiskSpaceGetter>* mock_free_disk_space_checker_; | |
855 scoped_ptr<StrictMock<MockDriveCacheObserver> > mock_cache_observer_; | |
856 scoped_ptr<StrictMock<MockDirectoryChangeObserver> > mock_directory_observer_; | |
857 | |
858 int num_callback_invocations_; | |
859 DriveFileError expected_error_; | |
860 int expected_cache_state_; | |
861 DriveCache::CacheSubDirectoryType expected_sub_dir_type_; | |
862 bool expected_success_; | |
863 bool expect_outgoing_symlink_; | |
864 std::string expected_file_extension_; | |
865 int root_feed_changestamp_; | |
866 static bool cros_initialized_; | |
867 }; | |
868 | |
869 bool GDataFileSystemTest::cros_initialized_ = false; | |
870 | |
871 void AsyncInitializationCallback( | |
872 int* counter, | |
873 int expected_counter, | |
874 const FilePath& expected_file_path, | |
875 MessageLoop* message_loop, | |
876 DriveFileError error, | |
877 scoped_ptr<DriveEntryProto> entry_proto) { | |
878 ASSERT_EQ(DRIVE_FILE_OK, error); | |
879 ASSERT_TRUE(entry_proto.get()); | |
880 ASSERT_TRUE(entry_proto->file_info().is_directory()); | |
881 EXPECT_EQ(expected_file_path.value(), entry_proto->base_name()); | |
882 | |
883 (*counter)++; | |
884 if (*counter >= expected_counter) | |
885 message_loop->Quit(); | |
886 } | |
887 | |
888 TEST_F(GDataFileSystemTest, DuplicatedAsyncInitialization) { | |
889 int counter = 0; | |
890 GetEntryInfoCallback callback = base::Bind( | |
891 &AsyncInitializationCallback, | |
892 &counter, | |
893 2, | |
894 FilePath(FILE_PATH_LITERAL("drive")), | |
895 &message_loop_); | |
896 | |
897 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)).Times(1); | |
898 EXPECT_CALL(*mock_drive_service_, | |
899 GetDocuments(Eq(GURL()), _, _, _, _)).Times(1); | |
900 | |
901 EXPECT_CALL(*mock_webapps_registry_, UpdateFromFeed(_)).Times(1); | |
902 | |
903 file_system_->GetEntryInfoByPath( | |
904 FilePath(FILE_PATH_LITERAL("drive")), callback); | |
905 file_system_->GetEntryInfoByPath( | |
906 FilePath(FILE_PATH_LITERAL("drive")), callback); | |
907 message_loop_.Run(); // Wait to get our result | |
908 EXPECT_EQ(2, counter); | |
909 } | |
910 | |
911 TEST_F(GDataFileSystemTest, SearchRootDirectory) { | |
912 LoadRootFeedDocument("root_feed.json"); | |
913 | |
914 const FilePath kFilePath = FilePath(FILE_PATH_LITERAL("drive")); | |
915 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync( | |
916 FilePath(FILE_PATH_LITERAL(kFilePath))); | |
917 ASSERT_TRUE(entry.get()); | |
918 EXPECT_EQ(kDriveRootDirectoryResourceId, entry->resource_id()); | |
919 } | |
920 | |
921 TEST_F(GDataFileSystemTest, SearchExistingFile) { | |
922 LoadRootFeedDocument("root_feed.json"); | |
923 | |
924 const FilePath kFilePath = FilePath( | |
925 FILE_PATH_LITERAL("drive/File 1.txt")); | |
926 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
927 ASSERT_TRUE(entry.get()); | |
928 EXPECT_EQ("file:2_file_resource_id", entry->resource_id()); | |
929 } | |
930 | |
931 TEST_F(GDataFileSystemTest, SearchExistingDocument) { | |
932 LoadRootFeedDocument("root_feed.json"); | |
933 | |
934 const FilePath kFilePath = FilePath( | |
935 FILE_PATH_LITERAL("drive/Document 1.gdoc")); | |
936 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
937 ASSERT_TRUE(entry.get()); | |
938 EXPECT_EQ("document:5_document_resource_id", entry->resource_id()); | |
939 } | |
940 | |
941 TEST_F(GDataFileSystemTest, SearchNonExistingFile) { | |
942 LoadRootFeedDocument("root_feed.json"); | |
943 | |
944 const FilePath kFilePath = FilePath( | |
945 FILE_PATH_LITERAL("drive/nonexisting.file")); | |
946 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
947 ASSERT_FALSE(entry.get()); | |
948 } | |
949 | |
950 TEST_F(GDataFileSystemTest, SearchEncodedFileNames) { | |
951 LoadRootFeedDocument("root_feed.json"); | |
952 | |
953 const FilePath kFilePath1 = FilePath( | |
954 FILE_PATH_LITERAL("drive/Slash / in file 1.txt")); | |
955 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath1); | |
956 ASSERT_FALSE(entry.get()); | |
957 | |
958 const FilePath kFilePath2 = FilePath::FromUTF8Unsafe( | |
959 "drive/Slash \xE2\x88\x95 in file 1.txt"); | |
960 entry = GetEntryInfoByPathSync(kFilePath2); | |
961 ASSERT_TRUE(entry.get()); | |
962 EXPECT_EQ("file:slash_file_resource_id", entry->resource_id()); | |
963 | |
964 const FilePath kFilePath3 = FilePath::FromUTF8Unsafe( | |
965 "drive/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt"); | |
966 entry = GetEntryInfoByPathSync(kFilePath3); | |
967 ASSERT_TRUE(entry.get()); | |
968 EXPECT_EQ("file:slash_subdir_file", entry->resource_id()); | |
969 } | |
970 | |
971 TEST_F(GDataFileSystemTest, SearchEncodedFileNamesLoadingRoot) { | |
972 LoadRootFeedDocument("root_feed.json"); | |
973 | |
974 const FilePath kFilePath1 = FilePath( | |
975 FILE_PATH_LITERAL("drive/Slash / in file 1.txt")); | |
976 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath1); | |
977 ASSERT_FALSE(entry.get()); | |
978 | |
979 const FilePath kFilePath2 = FilePath::FromUTF8Unsafe( | |
980 "drive/Slash \xE2\x88\x95 in file 1.txt"); | |
981 entry = GetEntryInfoByPathSync(kFilePath2); | |
982 ASSERT_TRUE(entry.get()); | |
983 EXPECT_EQ("file:slash_file_resource_id", entry->resource_id()); | |
984 | |
985 const FilePath kFilePath3 = FilePath::FromUTF8Unsafe( | |
986 "drive/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt"); | |
987 entry = GetEntryInfoByPathSync(kFilePath3); | |
988 ASSERT_TRUE(entry.get()); | |
989 EXPECT_EQ("file:slash_subdir_file", entry->resource_id()); | |
990 } | |
991 | |
992 TEST_F(GDataFileSystemTest, SearchDuplicateNames) { | |
993 LoadRootFeedDocument("root_feed.json"); | |
994 | |
995 const FilePath kFilePath1 = FilePath( | |
996 FILE_PATH_LITERAL("drive/Duplicate Name.txt")); | |
997 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath1); | |
998 ASSERT_TRUE(entry.get()); | |
999 EXPECT_EQ("file:3_file_resource_id", entry->resource_id()); | |
1000 | |
1001 const FilePath kFilePath2 = FilePath( | |
1002 FILE_PATH_LITERAL("drive/Duplicate Name (2).txt")); | |
1003 entry = GetEntryInfoByPathSync(kFilePath2); | |
1004 ASSERT_TRUE(entry.get()); | |
1005 EXPECT_EQ("file:4_file_resource_id", entry->resource_id()); | |
1006 } | |
1007 | |
1008 TEST_F(GDataFileSystemTest, SearchExistingDirectory) { | |
1009 LoadRootFeedDocument("root_feed.json"); | |
1010 | |
1011 const FilePath kFilePath = FilePath( | |
1012 FILE_PATH_LITERAL("drive/Directory 1")); | |
1013 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
1014 ASSERT_TRUE(entry.get()); | |
1015 ASSERT_EQ("folder:1_folder_resource_id", entry->resource_id()); | |
1016 } | |
1017 | |
1018 TEST_F(GDataFileSystemTest, SearchInSubdir) { | |
1019 LoadRootFeedDocument("root_feed.json"); | |
1020 | |
1021 const FilePath kFilePath = FilePath( | |
1022 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
1023 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
1024 ASSERT_TRUE(entry.get()); | |
1025 ASSERT_EQ("file:subdirectory_file_1_id", entry->resource_id()); | |
1026 } | |
1027 | |
1028 // Check the reconstruction of the directory structure from only the root feed. | |
1029 TEST_F(GDataFileSystemTest, SearchInSubSubdir) { | |
1030 LoadRootFeedDocument("root_feed.json"); | |
1031 | |
1032 const FilePath kFilePath = FilePath( | |
1033 FILE_PATH_LITERAL("drive/Directory 1/Sub Directory Folder/" | |
1034 "Sub Sub Directory Folder")); | |
1035 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
1036 ASSERT_TRUE(entry.get()); | |
1037 ASSERT_EQ("folder:sub_sub_directory_folder_id", entry->resource_id()); | |
1038 } | |
1039 | |
1040 TEST_F(GDataFileSystemTest, FilePathTests) { | |
1041 LoadRootFeedDocument("root_feed.json"); | |
1042 | |
1043 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/File 1.txt")))); | |
1044 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/Directory 1")))); | |
1045 EXPECT_TRUE(EntryExists( | |
1046 FilePath( | |
1047 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")))); | |
1048 } | |
1049 | |
1050 TEST_F(GDataFileSystemTest, ChangeFeed_AddAndDeleteFileInRoot) { | |
1051 int latest_changelog = 0; | |
1052 LoadRootFeedDocument("root_feed.json"); | |
1053 | |
1054 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1055 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(2); | |
1056 | |
1057 LoadChangeFeed("delta_file_added_in_root.json", ++latest_changelog); | |
1058 EXPECT_TRUE( | |
1059 EntryExists(FilePath(FILE_PATH_LITERAL("drive/Added file.gdoc")))); | |
1060 | |
1061 LoadChangeFeed("delta_file_deleted_in_root.json", ++latest_changelog); | |
1062 EXPECT_FALSE( | |
1063 EntryExists(FilePath(FILE_PATH_LITERAL("drive/Added file.gdoc")))); | |
1064 } | |
1065 | |
1066 | |
1067 TEST_F(GDataFileSystemTest, ChangeFeed_AddAndDeleteFileFromExistingDirectory) { | |
1068 int latest_changelog = 0; | |
1069 LoadRootFeedDocument("root_feed.json"); | |
1070 | |
1071 EXPECT_TRUE(EntryExists(FilePath( | |
1072 FILE_PATH_LITERAL("drive/Directory 1")))); | |
1073 | |
1074 // Add file to an existing directory. | |
1075 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1076 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1077 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1078 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
1079 LoadChangeFeed("delta_file_added_in_directory.json", ++latest_changelog); | |
1080 EXPECT_TRUE(EntryExists(FilePath( | |
1081 FILE_PATH_LITERAL("drive/Directory 1/Added file.gdoc")))); | |
1082 | |
1083 // Remove that file from the directory. | |
1084 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1085 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
1086 LoadChangeFeed("delta_file_deleted_in_directory.json", ++latest_changelog); | |
1087 EXPECT_TRUE(EntryExists(FilePath( | |
1088 FILE_PATH_LITERAL("drive/Directory 1")))); | |
1089 EXPECT_FALSE(EntryExists(FilePath( | |
1090 FILE_PATH_LITERAL("drive/Directory 1/Added file.gdoc")))); | |
1091 } | |
1092 | |
1093 TEST_F(GDataFileSystemTest, ChangeFeed_AddFileToNewDirectory) { | |
1094 int latest_changelog = 0; | |
1095 LoadRootFeedDocument("root_feed.json"); | |
1096 // Add file to a new directory. | |
1097 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1098 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1099 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1100 Eq(FilePath(FILE_PATH_LITERAL("drive/New Directory"))))).Times(1); | |
1101 | |
1102 LoadChangeFeed("delta_file_added_in_new_directory.json", ++latest_changelog); | |
1103 | |
1104 EXPECT_TRUE(EntryExists(FilePath( | |
1105 FILE_PATH_LITERAL("drive/New Directory")))); | |
1106 EXPECT_TRUE(EntryExists(FilePath( | |
1107 FILE_PATH_LITERAL("drive/New Directory/File in new dir.gdoc")))); | |
1108 } | |
1109 | |
1110 TEST_F(GDataFileSystemTest, ChangeFeed_AddFileToNewButDeletedDirectory) { | |
1111 int latest_changelog = 0; | |
1112 LoadRootFeedDocument("root_feed.json"); | |
1113 | |
1114 // This feed contains thw following updates: | |
1115 // 1) A new PDF file is added to a new directory | |
1116 // 2) but the new directory is marked "deleted" (i.e. moved to Trash) | |
1117 // Hence, the PDF file should be just ignored. | |
1118 LoadChangeFeed("delta_file_added_in_new_but_deleted_directory.json", | |
1119 ++latest_changelog); | |
1120 } | |
1121 | |
1122 TEST_F(GDataFileSystemTest, ChangeFeed_DirectoryMovedFromRootToDirectory) { | |
1123 int latest_changelog = 0; | |
1124 LoadRootFeedDocument("root_feed.json"); | |
1125 | |
1126 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1127 "drive/Directory 2")))); | |
1128 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1129 "drive/Directory 1")))); | |
1130 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1131 "drive/Directory 1/SubDirectory File 1.txt")))); | |
1132 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1133 "drive/Directory 1/Sub Directory Folder")))); | |
1134 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1135 "drive/Directory 1/Sub Directory Folder/Sub Sub Directory Folder")))); | |
1136 | |
1137 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1138 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1139 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1140 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 2"))))).Times(1); | |
1141 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1142 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 2/Directory 1"))))) | |
1143 .Times(1); | |
1144 LoadChangeFeed("delta_dir_moved_from_root_to_directory.json", | |
1145 ++latest_changelog); | |
1146 | |
1147 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1148 "drive/Directory 2")))); | |
1149 EXPECT_FALSE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1150 "drive/Directory 1")))); | |
1151 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1152 "drive/Directory 2/Directory 1")))); | |
1153 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1154 "drive/Directory 2/Directory 1/SubDirectory File 1.txt")))); | |
1155 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1156 "drive/Directory 2/Directory 1/Sub Directory Folder")))); | |
1157 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1158 "drive/Directory 2/Directory 1/Sub Directory Folder/" | |
1159 "Sub Sub Directory Folder")))); | |
1160 } | |
1161 | |
1162 TEST_F(GDataFileSystemTest, ChangeFeed_FileMovedFromDirectoryToRoot) { | |
1163 int latest_changelog = 0; | |
1164 LoadRootFeedDocument("root_feed.json"); | |
1165 | |
1166 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1167 "drive/Directory 1")))); | |
1168 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1169 "drive/Directory 1/Sub Directory Folder")))); | |
1170 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1171 "drive/Directory 1/Sub Directory Folder/Sub Sub Directory Folder")))); | |
1172 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1173 "drive/Directory 1/SubDirectory File 1.txt")))); | |
1174 | |
1175 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1176 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1177 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1178 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
1179 LoadChangeFeed("delta_file_moved_from_directory_to_root.json", | |
1180 ++latest_changelog); | |
1181 | |
1182 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1183 "drive/Directory 1")))); | |
1184 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1185 "drive/Directory 1/Sub Directory Folder")))); | |
1186 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1187 "drive/Directory 1/Sub Directory Folder/Sub Sub Directory Folder")))); | |
1188 EXPECT_FALSE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1189 "drive/Directory 1/SubDirectory File 1.txt")))); | |
1190 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1191 "drive/SubDirectory File 1.txt")))); | |
1192 } | |
1193 | |
1194 TEST_F(GDataFileSystemTest, ChangeFeed_FileRenamedInDirectory) { | |
1195 int latest_changelog = 0; | |
1196 LoadRootFeedDocument("root_feed.json"); | |
1197 | |
1198 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1199 "drive/Directory 1")))); | |
1200 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1201 "drive/Directory 1/SubDirectory File 1.txt")))); | |
1202 | |
1203 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1204 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1205 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1206 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
1207 LoadChangeFeed("delta_file_renamed_in_directory.json", | |
1208 ++latest_changelog); | |
1209 | |
1210 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1211 "drive/Directory 1")))); | |
1212 EXPECT_FALSE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1213 "drive/Directory 1/SubDirectory File 1.txt")))); | |
1214 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
1215 "drive/Directory 1/New SubDirectory File 1.txt")))); | |
1216 } | |
1217 | |
1218 TEST_F(GDataFileSystemTest, CachedFeedLoading) { | |
1219 SaveTestFileSystem(); | |
1220 TestLoadMetadataFromCache(); | |
1221 | |
1222 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/File1")))); | |
1223 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/Dir1")))); | |
1224 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/Dir1/File2")))); | |
1225 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/Dir1/SubDir2")))); | |
1226 EXPECT_TRUE(EntryExists( | |
1227 FilePath(FILE_PATH_LITERAL("drive/Dir1/SubDir2/File3")))); | |
1228 } | |
1229 | |
1230 TEST_F(GDataFileSystemTest, CachedFeadLoadingThenServerFeedLoading) { | |
1231 SaveTestFileSystem(); | |
1232 | |
1233 // SaveTestFileSystem and "account_metadata.json" have the same changestamp, | |
1234 // so no request for new feeds (i.e., call to GetDocuments) should happen. | |
1235 mock_drive_service_->set_account_metadata( | |
1236 LoadJSONFile("account_metadata.json")); | |
1237 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)).Times(1); | |
1238 EXPECT_CALL(*mock_webapps_registry_, UpdateFromFeed(_)).Times(1); | |
1239 EXPECT_CALL(*mock_drive_service_, GetDocuments(_, _, _, _, _)).Times(0); | |
1240 | |
1241 // Kicks loading of cached file system and query for server update. | |
1242 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/File1")))); | |
1243 | |
1244 // Since the file system has verified that it holds the latest snapshot, | |
1245 // it should change its state to FROM_SERVER, which admits periodic refresh. | |
1246 // To test it, call CheckForUpdates and verify it does try to check updates. | |
1247 mock_drive_service_->set_account_metadata( | |
1248 LoadJSONFile("account_metadata.json")); | |
1249 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)).Times(1); | |
1250 EXPECT_CALL(*mock_webapps_registry_, UpdateFromFeed(_)).Times(1); | |
1251 | |
1252 file_system_->CheckForUpdates(); | |
1253 test_util::RunBlockingPoolTask(); | |
1254 } | |
1255 | |
1256 TEST_F(GDataFileSystemTest, TransferFileFromLocalToRemote_RegularFile) { | |
1257 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
1258 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
1259 | |
1260 LoadRootFeedDocument("root_feed.json"); | |
1261 | |
1262 // We'll add a file to the Drive root directory. | |
1263 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1264 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1265 | |
1266 FileOperationCallback callback = | |
1267 base::Bind(&CallbackHelper::FileOperationCallback, | |
1268 callback_helper_.get()); | |
1269 | |
1270 // Prepare a local file. | |
1271 ScopedTempDir temp_dir; | |
1272 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
1273 const FilePath local_src_file_path = temp_dir.path().Append("local.txt"); | |
1274 const std::string kContent = "hello"; | |
1275 file_util::WriteFile(local_src_file_path, kContent.data(), kContent.size()); | |
1276 | |
1277 // Confirm that the remote file does not exist. | |
1278 const FilePath remote_dest_file_path(FILE_PATH_LITERAL("drive/remote.txt")); | |
1279 EXPECT_FALSE(EntryExists(remote_dest_file_path)); | |
1280 | |
1281 // Transfer the local file to Drive. | |
1282 file_system_->TransferFileFromLocalToRemote( | |
1283 local_src_file_path, remote_dest_file_path, callback); | |
1284 test_util::RunBlockingPoolTask(); | |
1285 | |
1286 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
1287 | |
1288 // Now the remote file should exist. | |
1289 EXPECT_TRUE(EntryExists(remote_dest_file_path)); | |
1290 } | |
1291 | |
1292 TEST_F(GDataFileSystemTest, TransferFileFromLocalToRemote_HostedDocument) { | |
1293 LoadRootFeedDocument("root_feed.json"); | |
1294 | |
1295 // Prepare a local file, which is a json file of a hosted document, which | |
1296 // matches "Document 1" in root_feed.json. | |
1297 ScopedTempDir temp_dir; | |
1298 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
1299 const FilePath local_src_file_path = temp_dir.path().Append("local.gdoc"); | |
1300 const std::string kEditUrl = | |
1301 "https://3_document_self_link/document:5_document_resource_id"; | |
1302 const std::string kResourceId = "document:5_document_resource_id"; | |
1303 const std::string kContent = | |
1304 base::StringPrintf("{\"url\": \"%s\", \"resource_id\": \"%s\"}", | |
1305 kEditUrl.c_str(), kResourceId.c_str()); | |
1306 file_util::WriteFile(local_src_file_path, kContent.data(), kContent.size()); | |
1307 | |
1308 // Confirm that the remote file does not exist. | |
1309 const FilePath remote_dest_file_path( | |
1310 FILE_PATH_LITERAL("drive/Directory 1/Document 1.gdoc")); | |
1311 EXPECT_FALSE(EntryExists(remote_dest_file_path)); | |
1312 | |
1313 // We'll add a file to "Directory 1" directory on Drive. | |
1314 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1315 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
1316 | |
1317 // We'll copy a hosted document using CopyDocument. | |
1318 // ".gdoc" suffix should be stripped when copying. | |
1319 scoped_ptr<base::Value> document(LoadJSONFile("uploaded_document.json")); | |
1320 EXPECT_CALL(*mock_drive_service_, | |
1321 CopyDocument(kResourceId, | |
1322 FILE_PATH_LITERAL("Document 1"), | |
1323 _)) | |
1324 .WillOnce(MockCopyDocument(gdata::HTTP_SUCCESS, &document)); | |
1325 // We'll then add the hosted document to the destination directory. | |
1326 EXPECT_CALL(*mock_drive_service_, | |
1327 AddResourceToDirectory(_, _, _)).Times(1); | |
1328 | |
1329 FileOperationCallback callback = | |
1330 base::Bind(&CallbackHelper::FileOperationCallback, | |
1331 callback_helper_.get()); | |
1332 | |
1333 // Transfer the local file to Drive. | |
1334 file_system_->TransferFileFromLocalToRemote( | |
1335 local_src_file_path, remote_dest_file_path, callback); | |
1336 test_util::RunBlockingPoolTask(); | |
1337 | |
1338 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
1339 | |
1340 // Now the remote file should exist. | |
1341 EXPECT_TRUE(EntryExists(remote_dest_file_path)); | |
1342 } | |
1343 | |
1344 TEST_F(GDataFileSystemTest, TransferFileFromRemoteToLocal_RegularFile) { | |
1345 LoadRootFeedDocument("root_feed.json"); | |
1346 | |
1347 FileOperationCallback callback = | |
1348 base::Bind(&CallbackHelper::FileOperationCallback, | |
1349 callback_helper_.get()); | |
1350 | |
1351 ScopedTempDir temp_dir; | |
1352 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
1353 FilePath local_dest_file_path = temp_dir.path().Append("local_copy.txt"); | |
1354 | |
1355 FilePath remote_src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
1356 scoped_ptr<DriveEntryProto> file = GetEntryInfoByPathSync( | |
1357 remote_src_file_path); | |
1358 FilePath cache_file = GetCachePathForFile( | |
1359 file->resource_id(), | |
1360 file->file_specific_info().file_md5()); | |
1361 const int64 file_size = file->file_info().size(); | |
1362 | |
1363 // Pretend we have enough space. | |
1364 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
1365 .Times(2).WillRepeatedly(Return(file_size + kMinFreeSpace)); | |
1366 | |
1367 const std::string remote_src_file_data = "Test file data"; | |
1368 mock_drive_service_->set_file_data(new std::string(remote_src_file_data)); | |
1369 | |
1370 // Before Download starts metadata from server will be fetched. | |
1371 // We will read content url from the result. | |
1372 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
1373 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
1374 | |
1375 // The file is obtained with the mock DriveService. | |
1376 EXPECT_CALL(*mock_drive_service_, | |
1377 DownloadFile(remote_src_file_path, | |
1378 cache_file, | |
1379 GURL("https://file_content_url_changed/"), | |
1380 _, _)) | |
1381 .Times(1); | |
1382 | |
1383 file_system_->TransferFileFromRemoteToLocal( | |
1384 remote_src_file_path, local_dest_file_path, callback); | |
1385 test_util::RunBlockingPoolTask(); | |
1386 | |
1387 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
1388 | |
1389 std::string cache_file_data; | |
1390 EXPECT_TRUE(file_util::ReadFileToString(cache_file, &cache_file_data)); | |
1391 EXPECT_EQ(remote_src_file_data, cache_file_data); | |
1392 | |
1393 std::string local_dest_file_data; | |
1394 EXPECT_TRUE(file_util::ReadFileToString(local_dest_file_path, | |
1395 &local_dest_file_data)); | |
1396 EXPECT_EQ(remote_src_file_data, local_dest_file_data); | |
1397 } | |
1398 | |
1399 TEST_F(GDataFileSystemTest, TransferFileFromRemoteToLocal_HostedDocument) { | |
1400 LoadRootFeedDocument("root_feed.json"); | |
1401 | |
1402 FileOperationCallback callback = | |
1403 base::Bind(&CallbackHelper::FileOperationCallback, | |
1404 callback_helper_.get()); | |
1405 | |
1406 ScopedTempDir temp_dir; | |
1407 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
1408 FilePath local_dest_file_path = temp_dir.path().Append("local_copy.txt"); | |
1409 FilePath remote_src_file_path(FILE_PATH_LITERAL("drive/Document 1.gdoc")); | |
1410 file_system_->TransferFileFromRemoteToLocal( | |
1411 remote_src_file_path, local_dest_file_path, callback); | |
1412 test_util::RunBlockingPoolTask(); | |
1413 | |
1414 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
1415 | |
1416 scoped_ptr<DriveEntryProto> entry_proto = GetEntryInfoByPathSync( | |
1417 remote_src_file_path); | |
1418 ASSERT_TRUE(entry_proto.get()); | |
1419 VerifyHostedDocumentJSONFile(*entry_proto, local_dest_file_path); | |
1420 } | |
1421 | |
1422 TEST_F(GDataFileSystemTest, CopyNotExistingFile) { | |
1423 FilePath src_file_path(FILE_PATH_LITERAL("drive/Dummy file.txt")); | |
1424 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Test.log")); | |
1425 | |
1426 LoadRootFeedDocument("root_feed.json"); | |
1427 | |
1428 EXPECT_FALSE(EntryExists(src_file_path)); | |
1429 | |
1430 FileOperationCallback callback = | |
1431 base::Bind(&CallbackHelper::FileOperationCallback, | |
1432 callback_helper_.get()); | |
1433 | |
1434 file_system_->Copy(src_file_path, dest_file_path, callback); | |
1435 test_util::RunBlockingPoolTask(); | |
1436 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
1437 | |
1438 EXPECT_FALSE(EntryExists(src_file_path)); | |
1439 EXPECT_FALSE(EntryExists(dest_file_path)); | |
1440 } | |
1441 | |
1442 TEST_F(GDataFileSystemTest, CopyFileToNonExistingDirectory) { | |
1443 FilePath src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
1444 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Dummy")); | |
1445 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Dummy/Test.log")); | |
1446 | |
1447 LoadRootFeedDocument("root_feed.json"); | |
1448 | |
1449 ASSERT_TRUE(EntryExists(src_file_path)); | |
1450 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
1451 src_file_path); | |
1452 ASSERT_TRUE(src_entry_proto.get()); | |
1453 std::string src_file_path_resource_id = | |
1454 src_entry_proto->resource_id(); | |
1455 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
1456 | |
1457 EXPECT_FALSE(EntryExists(dest_parent_path)); | |
1458 | |
1459 FileOperationCallback callback = | |
1460 base::Bind(&CallbackHelper::FileOperationCallback, | |
1461 callback_helper_.get()); | |
1462 | |
1463 file_system_->Move(src_file_path, dest_file_path, callback); | |
1464 test_util::RunBlockingPoolTask(); | |
1465 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
1466 | |
1467 EXPECT_TRUE(EntryExists(src_file_path)); | |
1468 EXPECT_FALSE(EntryExists(dest_parent_path)); | |
1469 EXPECT_FALSE(EntryExists(dest_file_path)); | |
1470 } | |
1471 | |
1472 // Test the case where the parent of |dest_file_path| is an existing file, | |
1473 // not a directory. | |
1474 TEST_F(GDataFileSystemTest, CopyFileToInvalidPath) { | |
1475 FilePath src_file_path(FILE_PATH_LITERAL("drive/Document 1.gdoc")); | |
1476 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Duplicate Name.txt")); | |
1477 FilePath dest_file_path(FILE_PATH_LITERAL( | |
1478 "drive/Duplicate Name.txt/Document 1.gdoc")); | |
1479 | |
1480 LoadRootFeedDocument("root_feed.json"); | |
1481 | |
1482 ASSERT_TRUE(EntryExists(src_file_path)); | |
1483 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
1484 src_file_path); | |
1485 ASSERT_TRUE(src_entry_proto.get()); | |
1486 std::string src_file_resource_id = | |
1487 src_entry_proto->resource_id(); | |
1488 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
1489 | |
1490 ASSERT_TRUE(EntryExists(dest_parent_path)); | |
1491 scoped_ptr<DriveEntryProto> dest_entry_proto = GetEntryInfoByPathSync( | |
1492 dest_parent_path); | |
1493 ASSERT_TRUE(dest_entry_proto.get()); | |
1494 | |
1495 FileOperationCallback callback = | |
1496 base::Bind(&CallbackHelper::FileOperationCallback, | |
1497 callback_helper_.get()); | |
1498 | |
1499 file_system_->Copy(src_file_path, dest_file_path, callback); | |
1500 test_util::RunBlockingPoolTask(); | |
1501 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_A_DIRECTORY, | |
1502 callback_helper_->last_error_); | |
1503 | |
1504 EXPECT_TRUE(EntryExists(src_file_path)); | |
1505 EXPECT_TRUE(EntryExists(src_file_path)); | |
1506 EXPECT_TRUE(EntryExists(dest_parent_path)); | |
1507 | |
1508 EXPECT_FALSE(EntryExists(dest_file_path)); | |
1509 } | |
1510 | |
1511 TEST_F(GDataFileSystemTest, RenameFile) { | |
1512 const FilePath src_file_path( | |
1513 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
1514 const FilePath src_parent_path(FILE_PATH_LITERAL("drive/Directory 1")); | |
1515 const FilePath dest_file_path( | |
1516 FILE_PATH_LITERAL("drive/Directory 1/Test.log")); | |
1517 | |
1518 LoadRootFeedDocument("root_feed.json"); | |
1519 | |
1520 ASSERT_TRUE(EntryExists(src_file_path)); | |
1521 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
1522 src_file_path); | |
1523 ASSERT_TRUE(src_entry_proto.get()); | |
1524 std::string src_file_resource_id = | |
1525 src_entry_proto->resource_id(); | |
1526 | |
1527 EXPECT_CALL(*mock_drive_service_, | |
1528 RenameResource(GURL(src_entry_proto->edit_url()), | |
1529 FILE_PATH_LITERAL("Test.log"), _)); | |
1530 | |
1531 FileOperationCallback callback = | |
1532 base::Bind(&CallbackHelper::FileOperationCallback, | |
1533 callback_helper_.get()); | |
1534 | |
1535 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1536 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
1537 | |
1538 file_system_->Move(src_file_path, dest_file_path, callback); | |
1539 test_util::RunBlockingPoolTask(); | |
1540 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
1541 | |
1542 EXPECT_FALSE(EntryExists(src_file_path)); | |
1543 EXPECT_TRUE(EntryExists(dest_file_path)); | |
1544 EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path)); | |
1545 } | |
1546 | |
1547 TEST_F(GDataFileSystemTest, MoveFileFromRootToSubDirectory) { | |
1548 FilePath src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
1549 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Directory 1")); | |
1550 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Directory 1/Test.log")); | |
1551 | |
1552 LoadRootFeedDocument("root_feed.json"); | |
1553 | |
1554 ASSERT_TRUE(EntryExists(src_file_path)); | |
1555 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
1556 src_file_path); | |
1557 ASSERT_TRUE(src_entry_proto.get()); | |
1558 std::string src_file_resource_id = | |
1559 src_entry_proto->resource_id(); | |
1560 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
1561 | |
1562 ASSERT_TRUE(EntryExists(dest_parent_path)); | |
1563 scoped_ptr<DriveEntryProto> dest_parent_proto = GetEntryInfoByPathSync( | |
1564 dest_parent_path); | |
1565 ASSERT_TRUE(dest_parent_proto.get()); | |
1566 ASSERT_TRUE(dest_parent_proto->file_info().is_directory()); | |
1567 EXPECT_FALSE(dest_parent_proto->content_url().empty()); | |
1568 | |
1569 EXPECT_CALL(*mock_drive_service_, | |
1570 RenameResource(GURL(src_entry_proto->edit_url()), | |
1571 FILE_PATH_LITERAL("Test.log"), _)); | |
1572 EXPECT_CALL(*mock_drive_service_, | |
1573 AddResourceToDirectory( | |
1574 GURL(dest_parent_proto->content_url()), | |
1575 GURL(src_entry_proto->edit_url()), _)); | |
1576 | |
1577 FileOperationCallback callback = | |
1578 base::Bind(&CallbackHelper::FileOperationCallback, | |
1579 callback_helper_.get()); | |
1580 | |
1581 // Expect notification for both source and destination directories. | |
1582 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1583 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1584 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1585 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
1586 | |
1587 file_system_->Move(src_file_path, dest_file_path, callback); | |
1588 test_util::RunBlockingPoolTask(); | |
1589 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
1590 | |
1591 EXPECT_FALSE(EntryExists(src_file_path)); | |
1592 EXPECT_TRUE(EntryExists(dest_file_path)); | |
1593 EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path)); | |
1594 } | |
1595 | |
1596 TEST_F(GDataFileSystemTest, MoveFileFromSubDirectoryToRoot) { | |
1597 FilePath src_parent_path(FILE_PATH_LITERAL("drive/Directory 1")); | |
1598 FilePath src_file_path( | |
1599 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
1600 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Test.log")); | |
1601 | |
1602 LoadRootFeedDocument("root_feed.json"); | |
1603 | |
1604 ASSERT_TRUE(EntryExists(src_file_path)); | |
1605 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
1606 src_file_path); | |
1607 ASSERT_TRUE(src_entry_proto.get()); | |
1608 std::string src_file_resource_id = | |
1609 src_entry_proto->resource_id(); | |
1610 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
1611 | |
1612 ASSERT_TRUE(EntryExists(src_parent_path)); | |
1613 scoped_ptr<DriveEntryProto> src_parent_proto = GetEntryInfoByPathSync( | |
1614 src_parent_path); | |
1615 ASSERT_TRUE(src_parent_proto.get()); | |
1616 ASSERT_TRUE(src_parent_proto->file_info().is_directory()); | |
1617 EXPECT_FALSE(src_parent_proto->content_url().empty()); | |
1618 | |
1619 EXPECT_CALL(*mock_drive_service_, | |
1620 RenameResource(GURL(src_entry_proto->edit_url()), | |
1621 FILE_PATH_LITERAL("Test.log"), _)); | |
1622 EXPECT_CALL(*mock_drive_service_, | |
1623 RemoveResourceFromDirectory( | |
1624 GURL(src_parent_proto->content_url()), | |
1625 GURL(src_entry_proto->edit_url()), | |
1626 src_file_resource_id, _)); | |
1627 | |
1628 FileOperationCallback callback = | |
1629 base::Bind(&CallbackHelper::FileOperationCallback, | |
1630 callback_helper_.get()); | |
1631 | |
1632 // Expect notification for both source and destination directories. | |
1633 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1634 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1635 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1636 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
1637 | |
1638 file_system_->Move(src_file_path, dest_file_path, callback); | |
1639 test_util::RunBlockingPoolTask(); | |
1640 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
1641 | |
1642 EXPECT_FALSE(EntryExists(src_file_path)); | |
1643 ASSERT_TRUE(EntryExists(dest_file_path)); | |
1644 EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path)); | |
1645 } | |
1646 | |
1647 TEST_F(GDataFileSystemTest, MoveFileBetweenSubDirectories) { | |
1648 FilePath src_parent_path(FILE_PATH_LITERAL("drive/Directory 1")); | |
1649 FilePath src_file_path( | |
1650 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
1651 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/New Folder 1")); | |
1652 FilePath dest_file_path(FILE_PATH_LITERAL("drive/New Folder 1/Test.log")); | |
1653 FilePath interim_file_path(FILE_PATH_LITERAL("drive/Test.log")); | |
1654 | |
1655 LoadRootFeedDocument("root_feed.json"); | |
1656 | |
1657 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1658 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1659 | |
1660 AddDirectoryFromFile(dest_parent_path, "directory_entry_atom.json"); | |
1661 | |
1662 ASSERT_TRUE(EntryExists(src_file_path)); | |
1663 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
1664 src_file_path); | |
1665 ASSERT_TRUE(src_entry_proto.get()); | |
1666 std::string src_file_resource_id = | |
1667 src_entry_proto->resource_id(); | |
1668 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
1669 | |
1670 ASSERT_TRUE(EntryExists(src_parent_path)); | |
1671 scoped_ptr<DriveEntryProto> src_parent_proto = GetEntryInfoByPathSync( | |
1672 src_parent_path); | |
1673 ASSERT_TRUE(src_parent_proto.get()); | |
1674 ASSERT_TRUE(src_parent_proto->file_info().is_directory()); | |
1675 EXPECT_FALSE(src_parent_proto->content_url().empty()); | |
1676 | |
1677 ASSERT_TRUE(EntryExists(dest_parent_path)); | |
1678 scoped_ptr<DriveEntryProto> dest_parent_proto = GetEntryInfoByPathSync( | |
1679 dest_parent_path); | |
1680 ASSERT_TRUE(dest_parent_proto.get()); | |
1681 ASSERT_TRUE(dest_parent_proto->file_info().is_directory()); | |
1682 EXPECT_FALSE(dest_parent_proto->content_url().empty()); | |
1683 | |
1684 EXPECT_FALSE(EntryExists(interim_file_path)); | |
1685 | |
1686 EXPECT_CALL(*mock_drive_service_, | |
1687 RenameResource(GURL(src_entry_proto->edit_url()), | |
1688 FILE_PATH_LITERAL("Test.log"), _)); | |
1689 EXPECT_CALL(*mock_drive_service_, | |
1690 RemoveResourceFromDirectory( | |
1691 GURL(src_parent_proto->content_url()), | |
1692 GURL(src_entry_proto->edit_url()), | |
1693 src_file_resource_id, _)); | |
1694 EXPECT_CALL(*mock_drive_service_, | |
1695 AddResourceToDirectory( | |
1696 GURL(dest_parent_proto->content_url()), | |
1697 GURL(src_entry_proto->edit_url()), | |
1698 _)); | |
1699 | |
1700 FileOperationCallback callback = | |
1701 base::Bind(&CallbackHelper::FileOperationCallback, | |
1702 callback_helper_.get()); | |
1703 | |
1704 // Expect notification for both source and destination directories plus | |
1705 // interim file path. | |
1706 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1707 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
1708 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1709 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1710 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1711 Eq(FilePath(FILE_PATH_LITERAL("drive/New Folder 1"))))).Times(1); | |
1712 | |
1713 file_system_->Move(src_file_path, dest_file_path, callback); | |
1714 test_util::RunBlockingPoolTask(); | |
1715 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
1716 | |
1717 EXPECT_FALSE(EntryExists(src_file_path)); | |
1718 EXPECT_FALSE(EntryExists(interim_file_path)); | |
1719 | |
1720 EXPECT_FALSE(EntryExists(src_file_path)); | |
1721 EXPECT_TRUE(EntryExists(dest_file_path)); | |
1722 EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path)); | |
1723 } | |
1724 | |
1725 TEST_F(GDataFileSystemTest, MoveNotExistingFile) { | |
1726 FilePath src_file_path(FILE_PATH_LITERAL("drive/Dummy file.txt")); | |
1727 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Test.log")); | |
1728 | |
1729 LoadRootFeedDocument("root_feed.json"); | |
1730 | |
1731 EXPECT_FALSE(EntryExists(src_file_path)); | |
1732 | |
1733 FileOperationCallback callback = | |
1734 base::Bind(&CallbackHelper::FileOperationCallback, | |
1735 callback_helper_.get()); | |
1736 | |
1737 file_system_->Move(src_file_path, dest_file_path, callback); | |
1738 test_util::RunBlockingPoolTask(); | |
1739 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
1740 | |
1741 EXPECT_FALSE(EntryExists(src_file_path)); | |
1742 EXPECT_FALSE(EntryExists(dest_file_path)); | |
1743 } | |
1744 | |
1745 TEST_F(GDataFileSystemTest, MoveFileToNonExistingDirectory) { | |
1746 FilePath src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
1747 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Dummy")); | |
1748 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Dummy/Test.log")); | |
1749 | |
1750 LoadRootFeedDocument("root_feed.json"); | |
1751 | |
1752 ASSERT_TRUE(EntryExists(src_file_path)); | |
1753 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
1754 src_file_path); | |
1755 ASSERT_TRUE(src_entry_proto.get()); | |
1756 std::string src_file_resource_id = | |
1757 src_entry_proto->resource_id(); | |
1758 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
1759 | |
1760 EXPECT_FALSE(EntryExists(dest_parent_path)); | |
1761 | |
1762 FileOperationCallback callback = | |
1763 base::Bind(&CallbackHelper::FileOperationCallback, | |
1764 callback_helper_.get()); | |
1765 | |
1766 file_system_->Move(src_file_path, dest_file_path, callback); | |
1767 test_util::RunBlockingPoolTask(); | |
1768 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
1769 | |
1770 | |
1771 EXPECT_FALSE(EntryExists(dest_parent_path)); | |
1772 EXPECT_FALSE(EntryExists(dest_file_path)); | |
1773 } | |
1774 | |
1775 // Test the case where the parent of |dest_file_path| is a existing file, | |
1776 // not a directory. | |
1777 TEST_F(GDataFileSystemTest, MoveFileToInvalidPath) { | |
1778 FilePath src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
1779 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Duplicate Name.txt")); | |
1780 FilePath dest_file_path(FILE_PATH_LITERAL( | |
1781 "drive/Duplicate Name.txt/Test.log")); | |
1782 | |
1783 LoadRootFeedDocument("root_feed.json"); | |
1784 | |
1785 ASSERT_TRUE(EntryExists(src_file_path)); | |
1786 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
1787 src_file_path); | |
1788 ASSERT_TRUE(src_entry_proto.get()); | |
1789 std::string src_file_resource_id = | |
1790 src_entry_proto->resource_id(); | |
1791 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
1792 | |
1793 ASSERT_TRUE(EntryExists(dest_parent_path)); | |
1794 scoped_ptr<DriveEntryProto> dest_parent_proto = GetEntryInfoByPathSync( | |
1795 dest_parent_path); | |
1796 ASSERT_TRUE(dest_parent_proto.get()); | |
1797 | |
1798 FileOperationCallback callback = | |
1799 base::Bind(&CallbackHelper::FileOperationCallback, | |
1800 callback_helper_.get()); | |
1801 | |
1802 file_system_->Move(src_file_path, dest_file_path, callback); | |
1803 test_util::RunBlockingPoolTask(); | |
1804 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_A_DIRECTORY, | |
1805 callback_helper_->last_error_); | |
1806 | |
1807 EXPECT_TRUE(EntryExists(src_file_path)); | |
1808 EXPECT_TRUE(EntryExists(dest_parent_path)); | |
1809 EXPECT_FALSE(EntryExists(dest_file_path)); | |
1810 } | |
1811 | |
1812 TEST_F(GDataFileSystemTest, RemoveEntries) { | |
1813 LoadRootFeedDocument("root_feed.json"); | |
1814 | |
1815 FilePath nonexisting_file(FILE_PATH_LITERAL("drive/Dummy file.txt")); | |
1816 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
1817 FilePath dir_in_root(FILE_PATH_LITERAL("drive/Directory 1")); | |
1818 FilePath file_in_subdir( | |
1819 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
1820 | |
1821 ASSERT_TRUE(EntryExists(file_in_root)); | |
1822 scoped_ptr<DriveEntryProto> file_in_root_proto = GetEntryInfoByPathSync( | |
1823 file_in_root); | |
1824 ASSERT_TRUE(file_in_root_proto.get()); | |
1825 | |
1826 ASSERT_TRUE(EntryExists(dir_in_root)); | |
1827 scoped_ptr<DriveEntryProto> dir_in_root_proto = GetEntryInfoByPathSync( | |
1828 dir_in_root); | |
1829 ASSERT_TRUE(dir_in_root_proto.get()); | |
1830 ASSERT_TRUE(dir_in_root_proto->file_info().is_directory()); | |
1831 | |
1832 ASSERT_TRUE(EntryExists(file_in_subdir)); | |
1833 scoped_ptr<DriveEntryProto> file_in_subdir_proto = GetEntryInfoByPathSync( | |
1834 file_in_subdir); | |
1835 ASSERT_TRUE(file_in_subdir_proto.get()); | |
1836 | |
1837 // Once for file in root and once for file... | |
1838 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1839 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(2); | |
1840 | |
1841 // Remove first file in root. | |
1842 EXPECT_TRUE(RemoveEntry(file_in_root)); | |
1843 EXPECT_FALSE(EntryExists(file_in_root)); | |
1844 EXPECT_TRUE(EntryExists(dir_in_root)); | |
1845 EXPECT_TRUE(EntryExists(file_in_subdir)); | |
1846 | |
1847 // Remove directory. | |
1848 EXPECT_TRUE(RemoveEntry(dir_in_root)); | |
1849 EXPECT_FALSE(EntryExists(file_in_root)); | |
1850 EXPECT_FALSE(EntryExists(dir_in_root)); | |
1851 EXPECT_FALSE(EntryExists(file_in_subdir)); | |
1852 | |
1853 // Try removing file in already removed subdirectory. | |
1854 EXPECT_FALSE(RemoveEntry(file_in_subdir)); | |
1855 | |
1856 // Try removing non-existing file. | |
1857 EXPECT_FALSE(RemoveEntry(nonexisting_file)); | |
1858 | |
1859 // Try removing root file element. | |
1860 EXPECT_FALSE(RemoveEntry(FilePath(FILE_PATH_LITERAL("drive")))); | |
1861 | |
1862 // Need this to ensure OnDirectoryChanged() is run. | |
1863 test_util::RunBlockingPoolTask(); | |
1864 } | |
1865 | |
1866 TEST_F(GDataFileSystemTest, CreateDirectory) { | |
1867 LoadRootFeedDocument("root_feed.json"); | |
1868 | |
1869 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1870 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1871 | |
1872 // Create directory in root. | |
1873 FilePath dir_path(FILE_PATH_LITERAL("drive/New Folder 1")); | |
1874 EXPECT_FALSE(EntryExists(dir_path)); | |
1875 AddDirectoryFromFile(dir_path, "directory_entry_atom.json"); | |
1876 EXPECT_TRUE(EntryExists(dir_path)); | |
1877 | |
1878 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1879 Eq(FilePath(FILE_PATH_LITERAL("drive/New Folder 1"))))).Times(1); | |
1880 | |
1881 // Create directory in a sub directory. | |
1882 FilePath subdir_path(FILE_PATH_LITERAL("drive/New Folder 1/New Folder 2")); | |
1883 EXPECT_FALSE(EntryExists(subdir_path)); | |
1884 AddDirectoryFromFile(subdir_path, "directory_entry_atom2.json"); | |
1885 EXPECT_TRUE(EntryExists(subdir_path)); | |
1886 } | |
1887 | |
1888 TEST_F(GDataFileSystemTest, FindFirstMissingParentDirectory) { | |
1889 LoadRootFeedDocument("root_feed.json"); | |
1890 | |
1891 GURL last_dir_content_url; | |
1892 FilePath first_missing_parent_path; | |
1893 | |
1894 // Create directory in root. | |
1895 FilePath dir_path(FILE_PATH_LITERAL("drive/New Folder 1")); | |
1896 EXPECT_EQ( | |
1897 GDataFileSystem::FOUND_MISSING, | |
1898 file_system_->FindFirstMissingParentDirectory(dir_path, | |
1899 &last_dir_content_url, | |
1900 &first_missing_parent_path)); | |
1901 EXPECT_EQ(FilePath(FILE_PATH_LITERAL("drive/New Folder 1")), | |
1902 first_missing_parent_path); | |
1903 EXPECT_TRUE(last_dir_content_url.is_empty()); // root directory. | |
1904 | |
1905 // Missing folders in subdir of an existing folder. | |
1906 FilePath dir_path2(FILE_PATH_LITERAL("drive/Directory 1/New Folder 2")); | |
1907 EXPECT_EQ( | |
1908 GDataFileSystem::FOUND_MISSING, | |
1909 file_system_->FindFirstMissingParentDirectory(dir_path2, | |
1910 &last_dir_content_url, | |
1911 &first_missing_parent_path)); | |
1912 EXPECT_EQ(FilePath(FILE_PATH_LITERAL("drive/Directory 1/New Folder 2")), | |
1913 first_missing_parent_path); | |
1914 EXPECT_FALSE(last_dir_content_url.is_empty()); // non-root directory. | |
1915 | |
1916 // Missing two folders on the path. | |
1917 FilePath dir_path3 = dir_path2.Append(FILE_PATH_LITERAL("Another Folder")); | |
1918 EXPECT_EQ( | |
1919 GDataFileSystem::FOUND_MISSING, | |
1920 file_system_->FindFirstMissingParentDirectory(dir_path3, | |
1921 &last_dir_content_url, | |
1922 &first_missing_parent_path)); | |
1923 EXPECT_EQ(FilePath(FILE_PATH_LITERAL("drive/Directory 1/New Folder 2")), | |
1924 first_missing_parent_path); | |
1925 EXPECT_FALSE(last_dir_content_url.is_empty()); // non-root directory. | |
1926 | |
1927 // Folders on top of an existing file. | |
1928 EXPECT_EQ( | |
1929 GDataFileSystem::FOUND_INVALID, | |
1930 file_system_->FindFirstMissingParentDirectory( | |
1931 FilePath(FILE_PATH_LITERAL("drive/File 1.txt/BadDir")), | |
1932 &last_dir_content_url, | |
1933 &first_missing_parent_path)); | |
1934 | |
1935 // Existing folder. | |
1936 EXPECT_EQ( | |
1937 GDataFileSystem::DIRECTORY_ALREADY_PRESENT, | |
1938 file_system_->FindFirstMissingParentDirectory( | |
1939 FilePath(FILE_PATH_LITERAL("drive/Directory 1")), | |
1940 &last_dir_content_url, | |
1941 &first_missing_parent_path)); | |
1942 } | |
1943 | |
1944 // Create a directory through the document service | |
1945 TEST_F(GDataFileSystemTest, CreateDirectoryWithService) { | |
1946 LoadRootFeedDocument("root_feed.json"); | |
1947 EXPECT_CALL(*mock_drive_service_, | |
1948 CreateDirectory(_, "Sample Directory Title", _)).Times(1); | |
1949 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
1950 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
1951 | |
1952 // Set last error so it's not a valid error code. | |
1953 callback_helper_->last_error_ = static_cast<DriveFileError>(1); | |
1954 file_system_->CreateDirectory( | |
1955 FilePath(FILE_PATH_LITERAL("drive/Sample Directory Title")), | |
1956 false, // is_exclusive | |
1957 true, // is_recursive | |
1958 base::Bind(&CallbackHelper::FileOperationCallback, | |
1959 callback_helper_.get())); | |
1960 test_util::RunBlockingPoolTask(); | |
1961 // TODO(gspencer): Uncomment this when we get a blob that | |
1962 // works that can be returned from the mock. | |
1963 // EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
1964 } | |
1965 | |
1966 TEST_F(GDataFileSystemTest, GetFileByPath_FromGData_EnoughSpace) { | |
1967 LoadRootFeedDocument("root_feed.json"); | |
1968 | |
1969 GetFileCallback callback = | |
1970 base::Bind(&CallbackHelper::GetFileCallback, | |
1971 callback_helper_.get()); | |
1972 | |
1973 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
1974 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
1975 FilePath downloaded_file = GetCachePathForFile( | |
1976 entry_proto->resource_id(), | |
1977 entry_proto->file_specific_info().file_md5()); | |
1978 const int64 file_size = entry_proto->file_info().size(); | |
1979 | |
1980 // Pretend we have enough space. | |
1981 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
1982 .Times(2).WillRepeatedly(Return(file_size + kMinFreeSpace)); | |
1983 | |
1984 // Before Download starts metadata from server will be fetched. | |
1985 // We will read content url from the result. | |
1986 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
1987 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
1988 | |
1989 // The file is obtained with the mock DriveService. | |
1990 EXPECT_CALL(*mock_drive_service_, | |
1991 DownloadFile(file_in_root, | |
1992 downloaded_file, | |
1993 GURL("https://file_content_url_changed/"), | |
1994 _, _)) | |
1995 .Times(1); | |
1996 | |
1997 file_system_->GetFileByPath(file_in_root, callback, | |
1998 GetContentCallback()); | |
1999 test_util::RunBlockingPoolTask(); | |
2000 | |
2001 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
2002 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
2003 EXPECT_EQ(downloaded_file.value(), | |
2004 callback_helper_->download_path_.value()); | |
2005 } | |
2006 | |
2007 TEST_F(GDataFileSystemTest, GetFileByPath_FromGData_NoSpaceAtAll) { | |
2008 LoadRootFeedDocument("root_feed.json"); | |
2009 | |
2010 GetFileCallback callback = | |
2011 base::Bind(&CallbackHelper::GetFileCallback, | |
2012 callback_helper_.get()); | |
2013 | |
2014 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
2015 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
2016 FilePath downloaded_file = GetCachePathForFile( | |
2017 entry_proto->resource_id(), | |
2018 entry_proto->file_specific_info().file_md5()); | |
2019 | |
2020 // Pretend we have no space at all. | |
2021 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
2022 .Times(2).WillRepeatedly(Return(0)); | |
2023 | |
2024 // Before Download starts metadata from server will be fetched. | |
2025 // We will read content url from the result. | |
2026 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
2027 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
2028 | |
2029 // The file is not obtained with the mock DriveService, because of no space. | |
2030 EXPECT_CALL(*mock_drive_service_, | |
2031 DownloadFile(file_in_root, | |
2032 downloaded_file, | |
2033 GURL("https://file_content_url_changed/"), | |
2034 _, _)) | |
2035 .Times(0); | |
2036 | |
2037 file_system_->GetFileByPath(file_in_root, callback, | |
2038 GetContentCallback()); | |
2039 test_util::RunBlockingPoolTask(); | |
2040 | |
2041 EXPECT_EQ(DRIVE_FILE_ERROR_NO_SPACE, | |
2042 callback_helper_->last_error_); | |
2043 } | |
2044 | |
2045 TEST_F(GDataFileSystemTest, GetFileByPath_FromGData_NoEnoughSpaceButCanFreeUp) { | |
2046 LoadRootFeedDocument("root_feed.json"); | |
2047 | |
2048 GetFileCallback callback = | |
2049 base::Bind(&CallbackHelper::GetFileCallback, | |
2050 callback_helper_.get()); | |
2051 | |
2052 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
2053 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
2054 FilePath downloaded_file = GetCachePathForFile( | |
2055 entry_proto->resource_id(), | |
2056 entry_proto->file_specific_info().file_md5()); | |
2057 const int64 file_size = entry_proto->file_info().size(); | |
2058 | |
2059 // Pretend we have no space first (checked before downloading a file), | |
2060 // but then start reporting we have space. This is to emulate that | |
2061 // the disk space was freed up by removing temporary files. | |
2062 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
2063 .WillOnce(Return(file_size + kMinFreeSpace)) | |
2064 .WillOnce(Return(0)) | |
2065 .WillOnce(Return(file_size + kMinFreeSpace)) | |
2066 .WillOnce(Return(file_size + kMinFreeSpace)); | |
2067 | |
2068 // Store something in the temporary cache directory. | |
2069 TestStoreToCache("<resource_id>", | |
2070 "<md5>", | |
2071 GetTestFilePath("root_feed.json"), | |
2072 DRIVE_FILE_OK, | |
2073 test_util::TEST_CACHE_STATE_PRESENT, | |
2074 DriveCache::CACHE_TYPE_TMP); | |
2075 ASSERT_TRUE(CacheEntryExists("<resource_id>", "<md5>")); | |
2076 ASSERT_TRUE(CacheFileExists("<resource_id>", "<md5>")); | |
2077 | |
2078 // Before Download starts metadata from server will be fetched. | |
2079 // We will read content url from the result. | |
2080 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
2081 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
2082 | |
2083 // The file is obtained with the mock DriveService, because of we freed up the | |
2084 // space. | |
2085 EXPECT_CALL(*mock_drive_service_, | |
2086 DownloadFile(file_in_root, | |
2087 downloaded_file, | |
2088 GURL("https://file_content_url_changed/"), | |
2089 _, _)) | |
2090 .Times(1); | |
2091 | |
2092 file_system_->GetFileByPath(file_in_root, callback, | |
2093 GetContentCallback()); | |
2094 test_util::RunBlockingPoolTask(); | |
2095 | |
2096 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
2097 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
2098 EXPECT_EQ(downloaded_file.value(), | |
2099 callback_helper_->download_path_.value()); | |
2100 | |
2101 // The file should be removed in order to free up space, and the cache | |
2102 // entry should also be removed. | |
2103 ASSERT_FALSE(CacheEntryExists("<resource_id>", "<md5>")); | |
2104 ASSERT_FALSE(CacheFileExists("<resource_id>", "<md5>")); | |
2105 } | |
2106 | |
2107 TEST_F(GDataFileSystemTest, GetFileByPath_FromGData_EnoughSpaceButBecomeFull) { | |
2108 LoadRootFeedDocument("root_feed.json"); | |
2109 | |
2110 GetFileCallback callback = | |
2111 base::Bind(&CallbackHelper::GetFileCallback, | |
2112 callback_helper_.get()); | |
2113 | |
2114 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
2115 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
2116 FilePath downloaded_file = GetCachePathForFile( | |
2117 entry_proto->resource_id(), | |
2118 entry_proto->file_specific_info().file_md5()); | |
2119 const int64 file_size = entry_proto->file_info().size(); | |
2120 | |
2121 // Pretend we have enough space first (checked before downloading a file), | |
2122 // but then start reporting we have not enough space. This is to emulate that | |
2123 // the disk space becomes full after the file is downloaded for some reason | |
2124 // (ex. the actual file was larger than the expected size). | |
2125 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
2126 .WillOnce(Return(file_size + kMinFreeSpace)) | |
2127 .WillOnce(Return(kMinFreeSpace - 1)) | |
2128 .WillOnce(Return(kMinFreeSpace - 1)); | |
2129 | |
2130 // Before Download starts metadata from server will be fetched. | |
2131 // We will read content url from the result. | |
2132 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
2133 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
2134 | |
2135 // The file is obtained with the mock DriveService. | |
2136 EXPECT_CALL(*mock_drive_service_, | |
2137 DownloadFile(file_in_root, | |
2138 downloaded_file, | |
2139 GURL("https://file_content_url_changed/"), | |
2140 _, _)) | |
2141 .Times(1); | |
2142 | |
2143 file_system_->GetFileByPath(file_in_root, callback, | |
2144 GetContentCallback()); | |
2145 test_util::RunBlockingPoolTask(); | |
2146 | |
2147 EXPECT_EQ(DRIVE_FILE_ERROR_NO_SPACE, | |
2148 callback_helper_->last_error_); | |
2149 } | |
2150 | |
2151 TEST_F(GDataFileSystemTest, GetFileByPath_FromCache) { | |
2152 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
2153 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
2154 | |
2155 LoadRootFeedDocument("root_feed.json"); | |
2156 | |
2157 GetFileCallback callback = | |
2158 base::Bind(&CallbackHelper::GetFileCallback, | |
2159 callback_helper_.get()); | |
2160 | |
2161 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
2162 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
2163 FilePath downloaded_file = GetCachePathForFile( | |
2164 entry_proto->resource_id(), | |
2165 entry_proto->file_specific_info().file_md5()); | |
2166 | |
2167 // Store something as cached version of this file. | |
2168 TestStoreToCache(entry_proto->resource_id(), | |
2169 entry_proto->file_specific_info().file_md5(), | |
2170 GetTestFilePath("root_feed.json"), | |
2171 DRIVE_FILE_OK, | |
2172 test_util::TEST_CACHE_STATE_PRESENT, | |
2173 DriveCache::CACHE_TYPE_TMP); | |
2174 | |
2175 // Make sure we don't fetch metadata for downloading file. | |
2176 EXPECT_CALL(*mock_drive_service_, GetDocumentEntry(_, _)).Times(0); | |
2177 | |
2178 // Make sure we don't call downloads at all. | |
2179 EXPECT_CALL(*mock_drive_service_, | |
2180 DownloadFile(file_in_root, | |
2181 downloaded_file, | |
2182 GURL("https://file_content_url_changed/"), | |
2183 _, _)) | |
2184 .Times(0); | |
2185 | |
2186 file_system_->GetFileByPath(file_in_root, callback, | |
2187 GetContentCallback()); | |
2188 test_util::RunBlockingPoolTask(); | |
2189 | |
2190 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
2191 EXPECT_EQ(downloaded_file.value(), | |
2192 callback_helper_->download_path_.value()); | |
2193 } | |
2194 | |
2195 TEST_F(GDataFileSystemTest, GetFileByPath_HostedDocument) { | |
2196 LoadRootFeedDocument("root_feed.json"); | |
2197 | |
2198 GetFileCallback callback = | |
2199 base::Bind(&CallbackHelper::GetFileCallback, | |
2200 callback_helper_.get()); | |
2201 | |
2202 FilePath file_in_root(FILE_PATH_LITERAL("drive/Document 1.gdoc")); | |
2203 scoped_ptr<DriveEntryProto> src_entry_proto = | |
2204 GetEntryInfoByPathSync(file_in_root); | |
2205 ASSERT_TRUE(src_entry_proto.get()); | |
2206 | |
2207 file_system_->GetFileByPath(file_in_root, callback, | |
2208 GetContentCallback()); | |
2209 test_util::RunBlockingPoolTask(); | |
2210 | |
2211 EXPECT_EQ(HOSTED_DOCUMENT, callback_helper_->file_type_); | |
2212 EXPECT_FALSE(callback_helper_->download_path_.empty()); | |
2213 | |
2214 ASSERT_TRUE(src_entry_proto.get()); | |
2215 VerifyHostedDocumentJSONFile(*src_entry_proto, | |
2216 callback_helper_->download_path_); | |
2217 } | |
2218 | |
2219 TEST_F(GDataFileSystemTest, GetFileByResourceId) { | |
2220 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
2221 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
2222 | |
2223 LoadRootFeedDocument("root_feed.json"); | |
2224 | |
2225 GetFileCallback callback = | |
2226 base::Bind(&CallbackHelper::GetFileCallback, | |
2227 callback_helper_.get()); | |
2228 | |
2229 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
2230 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
2231 FilePath downloaded_file = GetCachePathForFile( | |
2232 entry_proto->resource_id(), | |
2233 entry_proto->file_specific_info().file_md5()); | |
2234 | |
2235 // Before Download starts metadata from server will be fetched. | |
2236 // We will read content url from the result. | |
2237 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
2238 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
2239 | |
2240 // The file is obtained with the mock DriveService, because it's not stored in | |
2241 // the cache. | |
2242 EXPECT_CALL(*mock_drive_service_, | |
2243 DownloadFile(file_in_root, | |
2244 downloaded_file, | |
2245 GURL("https://file_content_url_changed/"), | |
2246 _, _)) | |
2247 .Times(1); | |
2248 | |
2249 file_system_->GetFileByResourceId(entry_proto->resource_id(), | |
2250 callback, | |
2251 GetContentCallback()); | |
2252 test_util::RunBlockingPoolTask(); | |
2253 | |
2254 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
2255 EXPECT_EQ(downloaded_file.value(), | |
2256 callback_helper_->download_path_.value()); | |
2257 } | |
2258 | |
2259 TEST_F(GDataFileSystemTest, GetFileByResourceId_FromCache) { | |
2260 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
2261 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
2262 | |
2263 LoadRootFeedDocument("root_feed.json"); | |
2264 | |
2265 GetFileCallback callback = | |
2266 base::Bind(&CallbackHelper::GetFileCallback, | |
2267 callback_helper_.get()); | |
2268 | |
2269 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
2270 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
2271 FilePath downloaded_file = GetCachePathForFile( | |
2272 entry_proto->resource_id(), | |
2273 entry_proto->file_specific_info().file_md5()); | |
2274 | |
2275 // Store something as cached version of this file. | |
2276 TestStoreToCache(entry_proto->resource_id(), | |
2277 entry_proto->file_specific_info().file_md5(), | |
2278 GetTestFilePath("root_feed.json"), | |
2279 DRIVE_FILE_OK, | |
2280 test_util::TEST_CACHE_STATE_PRESENT, | |
2281 DriveCache::CACHE_TYPE_TMP); | |
2282 | |
2283 // The file is obtained from the cache. | |
2284 // Make sure we don't call downloads at all. | |
2285 EXPECT_CALL(*mock_drive_service_, DownloadFile(_, _, _, _, _)) | |
2286 .Times(0); | |
2287 | |
2288 file_system_->GetFileByResourceId(entry_proto->resource_id(), | |
2289 callback, | |
2290 GetContentCallback()); | |
2291 test_util::RunBlockingPoolTask(); | |
2292 | |
2293 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
2294 EXPECT_EQ(downloaded_file.value(), | |
2295 callback_helper_->download_path_.value()); | |
2296 } | |
2297 | |
2298 TEST_F(GDataFileSystemTest, UpdateFileByResourceId_PersistentFile) { | |
2299 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
2300 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
2301 | |
2302 LoadRootFeedDocument("root_feed.json"); | |
2303 | |
2304 // This is a file defined in root_feed.json. | |
2305 const FilePath kFilePath(FILE_PATH_LITERAL("drive/File 1.txt")); | |
2306 const std::string kResourceId("file:2_file_resource_id"); | |
2307 const std::string kMd5("3b4382ebefec6e743578c76bbd0575ce"); | |
2308 | |
2309 // Pin the file so it'll be store in "persistent" directory. | |
2310 EXPECT_CALL(*mock_cache_observer_, OnCachePinned(kResourceId, kMd5)).Times(1); | |
2311 TestPin(kResourceId, | |
2312 kMd5, | |
2313 DRIVE_FILE_OK, | |
2314 test_util::TEST_CACHE_STATE_PINNED, | |
2315 DriveCache::CACHE_TYPE_TMP); | |
2316 | |
2317 // First store a file to cache. A cache file will be created at: | |
2318 // GCache/v1/persistent/<kResourceId>.<kMd5> | |
2319 const FilePath original_cache_file_path = | |
2320 DriveCache::GetCacheRootPath(profile_.get()) | |
2321 .AppendASCII("persistent") | |
2322 .AppendASCII(kResourceId + "." + kMd5); | |
2323 TestStoreToCache(kResourceId, | |
2324 kMd5, | |
2325 GetTestFilePath("root_feed.json"), // Anything works. | |
2326 DRIVE_FILE_OK, | |
2327 test_util::TEST_CACHE_STATE_PRESENT | | |
2328 test_util::TEST_CACHE_STATE_PINNED | | |
2329 test_util::TEST_CACHE_STATE_PERSISTENT, | |
2330 DriveCache::CACHE_TYPE_PERSISTENT); | |
2331 ASSERT_TRUE(file_util::PathExists(original_cache_file_path)); | |
2332 | |
2333 // Add the dirty bit. The cache file will be renamed to | |
2334 // GCache/v1/persistent/<kResourceId>.local | |
2335 TestMarkDirty(kResourceId, | |
2336 kMd5, | |
2337 DRIVE_FILE_OK, | |
2338 test_util::TEST_CACHE_STATE_PRESENT | | |
2339 test_util::TEST_CACHE_STATE_PINNED | | |
2340 test_util::TEST_CACHE_STATE_DIRTY | | |
2341 test_util::TEST_CACHE_STATE_PERSISTENT, | |
2342 DriveCache::CACHE_TYPE_PERSISTENT); | |
2343 const FilePath dirty_cache_file_path = | |
2344 DriveCache::GetCacheRootPath(profile_.get()) | |
2345 .AppendASCII("persistent") | |
2346 .AppendASCII(kResourceId + ".local"); | |
2347 ASSERT_FALSE(file_util::PathExists(original_cache_file_path)); | |
2348 ASSERT_TRUE(file_util::PathExists(dirty_cache_file_path)); | |
2349 | |
2350 // Modify the cached file. | |
2351 const std::string kDummyCacheContent("modification to the cache"); | |
2352 ASSERT_TRUE(file_util::WriteFile(dirty_cache_file_path, | |
2353 kDummyCacheContent.c_str(), | |
2354 kDummyCacheContent.size())); | |
2355 | |
2356 // Commit the dirty bit. The cache file name remains the same | |
2357 // but a symlink will be created at: | |
2358 // GCache/v1/outgoing/<kResourceId> | |
2359 EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(kResourceId)).Times(1); | |
2360 TestCommitDirty(kResourceId, | |
2361 kMd5, | |
2362 DRIVE_FILE_OK, | |
2363 test_util::TEST_CACHE_STATE_PRESENT | | |
2364 test_util::TEST_CACHE_STATE_PINNED | | |
2365 test_util::TEST_CACHE_STATE_DIRTY | | |
2366 test_util::TEST_CACHE_STATE_PERSISTENT, | |
2367 DriveCache::CACHE_TYPE_PERSISTENT); | |
2368 const FilePath outgoing_symlink_path = | |
2369 DriveCache::GetCacheRootPath(profile_.get()) | |
2370 .AppendASCII("outgoing") | |
2371 .AppendASCII(kResourceId); | |
2372 ASSERT_TRUE(file_util::PathExists(dirty_cache_file_path)); | |
2373 ASSERT_TRUE(file_util::PathExists(outgoing_symlink_path)); | |
2374 | |
2375 // Create a DocumentEntry, which is needed to mock | |
2376 // GDataUploaderInterface::UploadExistingFile(). | |
2377 // TODO(satorux): This should be cleaned up. crbug.com/134240. | |
2378 DocumentEntry* document_entry = NULL; | |
2379 scoped_ptr<base::Value> value(LoadJSONFile("root_feed.json")); | |
2380 ASSERT_TRUE(value.get()); | |
2381 base::DictionaryValue* as_dict = NULL; | |
2382 base::ListValue* entry_list = NULL; | |
2383 if (value->GetAsDictionary(&as_dict) && | |
2384 as_dict->GetList("feed.entry", &entry_list)) { | |
2385 for (size_t i = 0; i < entry_list->GetSize(); ++i) { | |
2386 base::DictionaryValue* entry = NULL; | |
2387 std::string resource_id; | |
2388 if (entry_list->GetDictionary(i, &entry) && | |
2389 entry->GetString("gd$resourceId.$t", &resource_id) && | |
2390 resource_id == kResourceId) { | |
2391 // This will be deleted by UploadExistingFile(). | |
2392 document_entry = DocumentEntry::CreateFrom(*entry); | |
2393 } | |
2394 } | |
2395 } | |
2396 ASSERT_TRUE(document_entry); | |
2397 | |
2398 // The mock uploader will be used to simulate a file upload. | |
2399 EXPECT_CALL(*mock_uploader_, UploadExistingFile( | |
2400 GURL("https://file_link_resumable_edit_media/"), | |
2401 kFilePath, | |
2402 dirty_cache_file_path, | |
2403 kDummyCacheContent.size(), // The size after modification must be used. | |
2404 "audio/mpeg", | |
2405 _)) // callback | |
2406 .WillOnce(MockUploadExistingFile( | |
2407 DRIVE_FILE_OK, | |
2408 FilePath::FromUTF8Unsafe("drive/File1"), | |
2409 dirty_cache_file_path, | |
2410 document_entry)); | |
2411 | |
2412 // We'll notify the directory change to the observer upon completion. | |
2413 EXPECT_CALL(*mock_directory_observer_, | |
2414 OnDirectoryChanged(Eq(FilePath(kDriveRootDirectory)))).Times(1); | |
2415 | |
2416 // The callback will be called upon completion of | |
2417 // UpdateFileByResourceId(). | |
2418 FileOperationCallback callback = | |
2419 base::Bind(&CallbackHelper::FileOperationCallback, | |
2420 callback_helper_.get()); | |
2421 | |
2422 // Check the number of files in the root directory. We'll compare the | |
2423 // number after updating a file. | |
2424 scoped_ptr<DriveEntryProtoVector> root_directory_entries( | |
2425 ReadDirectoryByPathSync(FilePath::FromUTF8Unsafe("drive"))); | |
2426 ASSERT_TRUE(root_directory_entries.get()); | |
2427 const int num_files_in_root = CountFiles(*root_directory_entries); | |
2428 | |
2429 file_system_->UpdateFileByResourceId(kResourceId, callback); | |
2430 test_util::RunBlockingPoolTask(); | |
2431 | |
2432 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
2433 // Make sure that the number of files did not change (i.e. we updated an | |
2434 // existing file, rather than adding a new file. The number of files | |
2435 // increases if we don't handle the file update right). | |
2436 EXPECT_EQ(num_files_in_root, CountFiles(*root_directory_entries)); | |
2437 // After the file is updated, the dirty bit is cleared, hence the symlink | |
2438 // should be gone. | |
2439 ASSERT_FALSE(file_util::PathExists(outgoing_symlink_path)); | |
2440 } | |
2441 | |
2442 TEST_F(GDataFileSystemTest, UpdateFileByResourceId_NonexistentFile) { | |
2443 LoadRootFeedDocument("root_feed.json"); | |
2444 | |
2445 // This is nonexistent in root_feed.json. | |
2446 const FilePath kFilePath(FILE_PATH_LITERAL("drive/Nonexistent.txt")); | |
2447 const std::string kResourceId("file:nonexistent_resource_id"); | |
2448 const std::string kMd5("nonexistent_md5"); | |
2449 | |
2450 // The callback will be called upon completion of | |
2451 // UpdateFileByResourceId(). | |
2452 FileOperationCallback callback = | |
2453 base::Bind(&CallbackHelper::FileOperationCallback, | |
2454 callback_helper_.get()); | |
2455 | |
2456 file_system_->UpdateFileByResourceId(kResourceId, callback); | |
2457 test_util::RunBlockingPoolTask(); | |
2458 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
2459 } | |
2460 | |
2461 TEST_F(GDataFileSystemTest, ContentSearch) { | |
2462 LoadRootFeedDocument("root_feed.json"); | |
2463 | |
2464 mock_drive_service_->set_search_result("search_result_feed.json"); | |
2465 | |
2466 EXPECT_CALL(*mock_drive_service_, GetDocuments(Eq(GURL()), _, "foo", _, _)) | |
2467 .Times(1); | |
2468 | |
2469 const SearchResultPair kExpectedResults[] = { | |
2470 { "drive/Directory 1/SubDirectory File 1.txt", false }, | |
2471 { "drive/Directory 1", true } | |
2472 }; | |
2473 | |
2474 SearchCallback callback = base::Bind(&DriveSearchCallback, | |
2475 &message_loop_, kExpectedResults, ARRAYSIZE_UNSAFE(kExpectedResults)); | |
2476 | |
2477 file_system_->Search("foo", GURL(), callback); | |
2478 message_loop_.Run(); // Wait to get our result. | |
2479 } | |
2480 | |
2481 TEST_F(GDataFileSystemTest, ContentSearchWithNewEntry) { | |
2482 LoadRootFeedDocument("root_feed.json"); | |
2483 | |
2484 // Search result returning two entries "Directory 1/" and | |
2485 // "Directory 1/SubDirectory Newly Added File.txt". The latter is not | |
2486 // contained in the root feed. | |
2487 mock_drive_service_->set_search_result( | |
2488 "search_result_with_new_entry_feed.json"); | |
2489 | |
2490 EXPECT_CALL(*mock_drive_service_, GetDocuments(Eq(GURL()), _, "foo", _, _)) | |
2491 .Times(1); | |
2492 | |
2493 // As the result of the first Search(), only entries in the current file | |
2494 // system snapshot are expected to be returned. | |
2495 const SearchResultPair kExpectedResults[] = { | |
2496 { "drive/Directory 1", true } | |
2497 }; | |
2498 | |
2499 // At the same time, unknown entry should trigger delta feed request. | |
2500 // This will cause notification to observers (e.g., File Browser) so that | |
2501 // they can request search again. | |
2502 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)).Times(1); | |
2503 EXPECT_CALL(*mock_drive_service_, GetDocuments(Eq(GURL()), _, "", _, _)) | |
2504 .Times(1); | |
2505 EXPECT_CALL(*mock_webapps_registry_, UpdateFromFeed(_)).Times(1); | |
2506 | |
2507 SearchCallback callback = base::Bind(&DriveSearchCallback, | |
2508 &message_loop_, kExpectedResults, ARRAYSIZE_UNSAFE(kExpectedResults)); | |
2509 | |
2510 file_system_->Search("foo", GURL(), callback); | |
2511 message_loop_.Run(); // Wait to get our result. | |
2512 } | |
2513 | |
2514 TEST_F(GDataFileSystemTest, ContentSearchEmptyResult) { | |
2515 LoadRootFeedDocument("root_feed.json"); | |
2516 | |
2517 mock_drive_service_->set_search_result("empty_feed.json"); | |
2518 | |
2519 EXPECT_CALL(*mock_drive_service_, GetDocuments(Eq(GURL()), _, "foo", _, _)) | |
2520 .Times(1); | |
2521 | |
2522 const SearchResultPair* expected_results = NULL; | |
2523 | |
2524 SearchCallback callback = base::Bind(&DriveSearchCallback, | |
2525 &message_loop_, expected_results, 0u); | |
2526 | |
2527 file_system_->Search("foo", GURL(), callback); | |
2528 message_loop_.Run(); // Wait to get our result. | |
2529 } | |
2530 | |
2531 TEST_F(GDataFileSystemTest, GetAvailableSpace) { | |
2532 GetAvailableSpaceCallback callback = | |
2533 base::Bind(&CallbackHelper::GetAvailableSpaceCallback, | |
2534 callback_helper_.get()); | |
2535 | |
2536 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)); | |
2537 | |
2538 file_system_->GetAvailableSpace(callback); | |
2539 test_util::RunBlockingPoolTask(); | |
2540 EXPECT_EQ(GG_LONGLONG(6789012345), callback_helper_->quota_bytes_used_); | |
2541 EXPECT_EQ(GG_LONGLONG(9876543210), callback_helper_->quota_bytes_total_); | |
2542 } | |
2543 | |
2544 TEST_F(GDataFileSystemTest, RequestDirectoryRefresh) { | |
2545 LoadRootFeedDocument("root_feed.json"); | |
2546 | |
2547 // We'll fetch documents in the root directory with its resource ID. | |
2548 EXPECT_CALL(*mock_drive_service_, | |
2549 GetDocuments(Eq(GURL()), _, _, kDriveRootDirectoryResourceId, _)) | |
2550 .Times(1); | |
2551 // We'll notify the directory change to the observer. | |
2552 EXPECT_CALL(*mock_directory_observer_, | |
2553 OnDirectoryChanged(Eq(FilePath(kDriveRootDirectory)))).Times(1); | |
2554 | |
2555 file_system_->RequestDirectoryRefresh(FilePath(kDriveRootDirectory)); | |
2556 test_util::RunBlockingPoolTask(); | |
2557 } | |
2558 | |
2559 TEST_F(GDataFileSystemTest, OpenAndCloseFile) { | |
2560 LoadRootFeedDocument("root_feed.json"); | |
2561 | |
2562 OpenFileCallback callback = | |
2563 base::Bind(&CallbackHelper::OpenFileCallback, | |
2564 callback_helper_.get()); | |
2565 FileOperationCallback close_file_callback = | |
2566 base::Bind(&CallbackHelper::CloseFileCallback, | |
2567 callback_helper_.get()); | |
2568 | |
2569 const FilePath kFileInRoot(FILE_PATH_LITERAL("drive/File 1.txt")); | |
2570 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(kFileInRoot)); | |
2571 FilePath downloaded_file = GetCachePathForFile( | |
2572 entry_proto->resource_id(), | |
2573 entry_proto->file_specific_info().file_md5()); | |
2574 const int64 file_size = entry_proto->file_info().size(); | |
2575 const std::string& file_resource_id = | |
2576 entry_proto->resource_id(); | |
2577 const std::string& file_md5 = entry_proto->file_specific_info().file_md5(); | |
2578 | |
2579 // A dirty file is created on close. | |
2580 EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(file_resource_id)) | |
2581 .Times(1); | |
2582 | |
2583 // Pretend we have enough space. | |
2584 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
2585 .Times(2).WillRepeatedly(Return(file_size + kMinFreeSpace)); | |
2586 | |
2587 const std::string kExpectedFileData = "test file data"; | |
2588 mock_drive_service_->set_file_data(new std::string(kExpectedFileData)); | |
2589 | |
2590 // Before Download starts metadata from server will be fetched. | |
2591 // We will read content url from the result. | |
2592 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
2593 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
2594 | |
2595 // The file is obtained with the mock DriveService. | |
2596 EXPECT_CALL(*mock_drive_service_, | |
2597 DownloadFile(kFileInRoot, | |
2598 downloaded_file, | |
2599 GURL("https://file_content_url_changed/"), | |
2600 _, _)) | |
2601 .Times(1); | |
2602 | |
2603 // Open kFileInRoot ("drive/File 1.txt"). | |
2604 file_system_->OpenFile(kFileInRoot, callback); | |
2605 message_loop_.Run(); | |
2606 const FilePath opened_file_path = callback_helper_->opened_file_path_; | |
2607 | |
2608 // Verify that the file was properly opened. | |
2609 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
2610 | |
2611 // Try to open the already opened file. | |
2612 file_system_->OpenFile(kFileInRoot, callback); | |
2613 message_loop_.Run(); | |
2614 | |
2615 // It must fail. | |
2616 EXPECT_EQ(DRIVE_FILE_ERROR_IN_USE, callback_helper_->last_error_); | |
2617 | |
2618 // Verify that the file contents match the expected contents. | |
2619 std::string cache_file_data; | |
2620 EXPECT_TRUE(file_util::ReadFileToString(opened_file_path, &cache_file_data)); | |
2621 EXPECT_EQ(kExpectedFileData, cache_file_data); | |
2622 | |
2623 // Verify that the cache state was changed as expected. | |
2624 VerifyCacheStateAfterOpenFile(DRIVE_FILE_OK, | |
2625 file_resource_id, | |
2626 file_md5, | |
2627 opened_file_path); | |
2628 | |
2629 // Close kFileInRoot ("drive/File 1.txt"). | |
2630 file_system_->CloseFile(kFileInRoot, close_file_callback); | |
2631 message_loop_.Run(); | |
2632 | |
2633 // Verify that the file was properly closed. | |
2634 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
2635 | |
2636 // Verify that the cache state was changed as expected. | |
2637 VerifyCacheStateAfterCloseFile(DRIVE_FILE_OK, | |
2638 file_resource_id, | |
2639 file_md5); | |
2640 | |
2641 // Try to close the same file twice. | |
2642 file_system_->CloseFile(kFileInRoot, close_file_callback); | |
2643 message_loop_.Run(); | |
2644 | |
2645 // It must fail. | |
2646 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
2647 } | |
2648 | |
2649 } // namespace gdata | |
OLD | NEW |