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 "chrome/browser/chromeos/drive/file_system.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/file_util.h"
12 #include "base/files/file_path.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/prefs/testing_pref_service.h"
17 #include "base/run_loop.h"
18 #include "chrome/browser/chromeos/drive/change_list_loader.h"
19 #include "chrome/browser/chromeos/drive/drive.pb.h"
20 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
21 #include "chrome/browser/chromeos/drive/file_system_observer.h"
22 #include "chrome/browser/chromeos/drive/file_system_util.h"
23 #include "chrome/browser/chromeos/drive/job_scheduler.h"
24 #include "chrome/browser/chromeos/drive/sync_client.h"
25 #include "chrome/browser/chromeos/drive/test_util.h"
26 #include "chrome/browser/drive/drive_api_util.h"
27 #include "chrome/browser/drive/event_logger.h"
28 #include "chrome/browser/drive/fake_drive_service.h"
29 #include "chrome/browser/drive/test_util.h"
30 #include "content/public/test/test_browser_thread_bundle.h"
31 #include "google_apis/drive/drive_api_parser.h"
32 #include "google_apis/drive/test_util.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34
35 namespace drive {
36 namespace {
37
38 // Counts the number of invocation, and if it increased up to |expected_counter|
39 // quits the current message loop by calling |quit|.
AsyncInitializationCallback(int * counter,int expected_counter,const base::Closure & quit,FileError error,scoped_ptr<ResourceEntry> entry)40 void AsyncInitializationCallback(
41 int* counter, int expected_counter, const base::Closure& quit,
42 FileError error, scoped_ptr<ResourceEntry> entry) {
43 if (error != FILE_ERROR_OK || !entry) {
44 // If we hit an error case, quit the message loop immediately.
45 // Then the expectation in the test case can find it because the actual
46 // value of |counter| is different from the expected one.
47 quit.Run();
48 return;
49 }
50
51 (*counter)++;
52 if (*counter >= expected_counter)
53 quit.Run();
54 }
55
56 // This class is used to record directory changes and examine them later.
57 class MockDirectoryChangeObserver : public FileSystemObserver {
58 public:
MockDirectoryChangeObserver()59 MockDirectoryChangeObserver() {}
~MockDirectoryChangeObserver()60 virtual ~MockDirectoryChangeObserver() {}
61
62 // FileSystemObserver overrides.
OnDirectoryChanged(const base::FilePath & directory_path)63 virtual void OnDirectoryChanged(
64 const base::FilePath& directory_path) OVERRIDE {
65 changed_directories_.push_back(directory_path);
66 }
67
changed_directories() const68 const std::vector<base::FilePath>& changed_directories() const {
69 return changed_directories_;
70 }
71
72 private:
73 std::vector<base::FilePath> changed_directories_;
74 DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver);
75 };
76
77 } // namespace
78
79 class FileSystemTest : public testing::Test {
80 protected:
SetUp()81 virtual void SetUp() OVERRIDE {
82 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
83 pref_service_.reset(new TestingPrefServiceSimple);
84 test_util::RegisterDrivePrefs(pref_service_->registry());
85
86 logger_.reset(new EventLogger);
87 fake_drive_service_.reset(new FakeDriveService);
88 test_util::SetUpTestEntries(fake_drive_service_.get());
89
90 fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
91
92 scheduler_.reset(new JobScheduler(pref_service_.get(),
93 logger_.get(),
94 fake_drive_service_.get(),
95 base::MessageLoopProxy::current().get()));
96
97 mock_directory_observer_.reset(new MockDirectoryChangeObserver);
98
99 SetUpResourceMetadataAndFileSystem();
100 }
101
SetUpResourceMetadataAndFileSystem()102 void SetUpResourceMetadataAndFileSystem() {
103 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
104 ASSERT_TRUE(base::CreateDirectory(metadata_dir));
105 metadata_storage_.reset(new internal::ResourceMetadataStorage(
106 metadata_dir, base::MessageLoopProxy::current().get()));
107 ASSERT_TRUE(metadata_storage_->Initialize());
108
109 const base::FilePath cache_dir = temp_dir_.path().AppendASCII("files");
110 ASSERT_TRUE(base::CreateDirectory(cache_dir));
111 cache_.reset(new internal::FileCache(
112 metadata_storage_.get(),
113 cache_dir,
114 base::MessageLoopProxy::current().get(),
115 fake_free_disk_space_getter_.get()));
116 ASSERT_TRUE(cache_->Initialize());
117
118 resource_metadata_.reset(new internal::ResourceMetadata(
119 metadata_storage_.get(), cache_.get(),
120 base::MessageLoopProxy::current()));
121 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
122
123 const base::FilePath temp_file_dir = temp_dir_.path().AppendASCII("tmp");
124 ASSERT_TRUE(base::CreateDirectory(temp_file_dir));
125 file_system_.reset(new FileSystem(
126 pref_service_.get(),
127 logger_.get(),
128 cache_.get(),
129 fake_drive_service_.get(),
130 scheduler_.get(),
131 resource_metadata_.get(),
132 base::MessageLoopProxy::current().get(),
133 temp_file_dir));
134 file_system_->AddObserver(mock_directory_observer_.get());
135
136 // Disable delaying so that the sync starts immediately.
137 file_system_->sync_client_for_testing()->set_delay_for_testing(
138 base::TimeDelta::FromSeconds(0));
139 }
140
141 // Loads the full resource list via FakeDriveService.
LoadFullResourceList()142 bool LoadFullResourceList() {
143 FileError error = FILE_ERROR_FAILED;
144 file_system_->change_list_loader_for_testing()->LoadIfNeeded(
145 google_apis::test_util::CreateCopyResultCallback(&error));
146 test_util::RunBlockingPoolTask();
147 return error == FILE_ERROR_OK;
148 }
149
150 // Gets resource entry by path synchronously.
GetResourceEntrySync(const base::FilePath & file_path)151 scoped_ptr<ResourceEntry> GetResourceEntrySync(
152 const base::FilePath& file_path) {
153 FileError error = FILE_ERROR_FAILED;
154 scoped_ptr<ResourceEntry> entry;
155 file_system_->GetResourceEntry(
156 file_path,
157 google_apis::test_util::CreateCopyResultCallback(&error, &entry));
158 test_util::RunBlockingPoolTask();
159
160 return entry.Pass();
161 }
162
163 // Gets directory info by path synchronously.
ReadDirectorySync(const base::FilePath & file_path)164 scoped_ptr<ResourceEntryVector> ReadDirectorySync(
165 const base::FilePath& file_path) {
166 FileError error = FILE_ERROR_FAILED;
167 scoped_ptr<ResourceEntryVector> entries(new ResourceEntryVector);
168 file_system_->ReadDirectory(
169 file_path,
170 base::Bind(&AccumulateReadDirectoryResult, entries.get()),
171 google_apis::test_util::CreateCopyResultCallback(&error));
172 test_util::RunBlockingPoolTask();
173 if (error != FILE_ERROR_OK)
174 entries.reset();
175 return entries.Pass();
176 }
177
178 // Used to implement ReadDirectorySync().
AccumulateReadDirectoryResult(ResourceEntryVector * out_entries,scoped_ptr<ResourceEntryVector> entries)179 static void AccumulateReadDirectoryResult(
180 ResourceEntryVector* out_entries,
181 scoped_ptr<ResourceEntryVector> entries) {
182 ASSERT_TRUE(entries);
183 out_entries->insert(out_entries->end(), entries->begin(), entries->end());
184 }
185
186 // Returns true if an entry exists at |file_path|.
EntryExists(const base::FilePath & file_path)187 bool EntryExists(const base::FilePath& file_path) {
188 return GetResourceEntrySync(file_path);
189 }
190
191 // Flag for specifying the timestamp of the test filesystem cache.
192 enum SetUpTestFileSystemParam {
193 USE_OLD_TIMESTAMP,
194 USE_SERVER_TIMESTAMP,
195 };
196
197 // Sets up a filesystem with directories: drive/root, drive/root/Dir1,
198 // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2,
199 // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets
200 // the changestamp to that of FakeDriveService, indicating the cache is
201 // holding the latest file system info.
SetUpTestFileSystem(SetUpTestFileSystemParam param)202 void SetUpTestFileSystem(SetUpTestFileSystemParam param) {
203 // Destroy the existing resource metadata to close DB.
204 resource_metadata_.reset();
205
206 const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta");
207 ASSERT_TRUE(base::CreateDirectory(metadata_dir));
208 scoped_ptr<internal::ResourceMetadataStorage,
209 test_util::DestroyHelperForTests> metadata_storage(
210 new internal::ResourceMetadataStorage(
211 metadata_dir, base::MessageLoopProxy::current().get()));
212
213 const base::FilePath cache_dir = temp_dir_.path().AppendASCII("files");
214 scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache(
215 new internal::FileCache(metadata_storage.get(),
216 cache_dir,
217 base::MessageLoopProxy::current().get(),
218 fake_free_disk_space_getter_.get()));
219
220 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
221 resource_metadata(new internal::ResourceMetadata(
222 metadata_storage_.get(), cache.get(),
223 base::MessageLoopProxy::current()));
224
225 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->Initialize());
226
227 const int64 changestamp = param == USE_SERVER_TIMESTAMP ?
228 fake_drive_service_->about_resource().largest_change_id() : 1;
229 ASSERT_EQ(FILE_ERROR_OK,
230 resource_metadata->SetLargestChangestamp(changestamp));
231
232 // drive/root
233 ResourceEntry root;
234 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetResourceEntryByPath(
235 util::GetDriveMyDriveRootPath(), &root));
236 root.set_resource_id(fake_drive_service_->GetRootResourceId());
237 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->RefreshEntry(root));
238
239 std::string local_id;
240
241 // drive/root/File1
242 ResourceEntry file1;
243 file1.set_title("File1");
244 file1.set_resource_id("resource_id:File1");
245 file1.set_parent_local_id(root.local_id());
246 file1.mutable_file_specific_info()->set_md5("md5");
247 file1.mutable_file_info()->set_is_directory(false);
248 file1.mutable_file_info()->set_size(1048576);
249 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file1, &local_id));
250
251 // drive/root/Dir1
252 ResourceEntry dir1;
253 dir1.set_title("Dir1");
254 dir1.set_resource_id("resource_id:Dir1");
255 dir1.set_parent_local_id(root.local_id());
256 dir1.mutable_file_info()->set_is_directory(true);
257 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir1, &local_id));
258 const std::string dir1_local_id = local_id;
259
260 // drive/root/Dir1/File2
261 ResourceEntry file2;
262 file2.set_title("File2");
263 file2.set_resource_id("resource_id:File2");
264 file2.set_parent_local_id(dir1_local_id);
265 file2.mutable_file_specific_info()->set_md5("md5");
266 file2.mutable_file_info()->set_is_directory(false);
267 file2.mutable_file_info()->set_size(555);
268 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file2, &local_id));
269
270 // drive/root/Dir1/SubDir2
271 ResourceEntry dir2;
272 dir2.set_title("SubDir2");
273 dir2.set_resource_id("resource_id:SubDir2");
274 dir2.set_parent_local_id(dir1_local_id);
275 dir2.mutable_file_info()->set_is_directory(true);
276 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir2, &local_id));
277 const std::string dir2_local_id = local_id;
278
279 // drive/root/Dir1/SubDir2/File3
280 ResourceEntry file3;
281 file3.set_title("File3");
282 file3.set_resource_id("resource_id:File3");
283 file3.set_parent_local_id(dir2_local_id);
284 file3.mutable_file_specific_info()->set_md5("md5");
285 file3.mutable_file_info()->set_is_directory(false);
286 file3.mutable_file_info()->set_size(12345);
287 ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file3, &local_id));
288
289 // Recreate resource metadata.
290 SetUpResourceMetadataAndFileSystem();
291 }
292
293 content::TestBrowserThreadBundle thread_bundle_;
294 base::ScopedTempDir temp_dir_;
295 // We don't use TestingProfile::GetPrefs() in favor of having less
296 // dependencies to Profile in general.
297 scoped_ptr<TestingPrefServiceSimple> pref_service_;
298
299 scoped_ptr<EventLogger> logger_;
300 scoped_ptr<FakeDriveService> fake_drive_service_;
301 scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
302 scoped_ptr<JobScheduler> scheduler_;
303 scoped_ptr<MockDirectoryChangeObserver> mock_directory_observer_;
304
305 scoped_ptr<internal::ResourceMetadataStorage,
306 test_util::DestroyHelperForTests> metadata_storage_;
307 scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
308 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
309 resource_metadata_;
310 scoped_ptr<FileSystem> file_system_;
311 };
312
TEST_F(FileSystemTest,Copy)313 TEST_F(FileSystemTest, Copy) {
314 base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
315 base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Copied.txt"));
316 EXPECT_TRUE(GetResourceEntrySync(src_file_path));
317 EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
318
319 FileError error = FILE_ERROR_FAILED;
320 file_system_->Copy(src_file_path,
321 dest_file_path,
322 false, // preserve_last_modified,
323 google_apis::test_util::CreateCopyResultCallback(&error));
324 test_util::RunBlockingPoolTask();
325 EXPECT_EQ(FILE_ERROR_OK, error);
326
327 // Entry is added on the server.
328 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
329 ASSERT_TRUE(entry);
330
331 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
332 scoped_ptr<google_apis::FileResource> server_entry;
333 fake_drive_service_->GetFileResource(
334 entry->resource_id(),
335 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
336 test_util::RunBlockingPoolTask();
337 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
338 ASSERT_TRUE(server_entry);
339 EXPECT_EQ(entry->title(), server_entry->title());
340 EXPECT_FALSE(server_entry->IsDirectory());
341 }
342
TEST_F(FileSystemTest,Move)343 TEST_F(FileSystemTest, Move) {
344 base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
345 base::FilePath dest_file_path(
346 FILE_PATH_LITERAL("drive/root/Directory 1/Moved.txt"));
347 EXPECT_TRUE(GetResourceEntrySync(src_file_path));
348 EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
349 scoped_ptr<ResourceEntry> parent =
350 GetResourceEntrySync(dest_file_path.DirName());
351 ASSERT_TRUE(parent);
352
353 FileError error = FILE_ERROR_FAILED;
354 file_system_->Move(src_file_path,
355 dest_file_path,
356 google_apis::test_util::CreateCopyResultCallback(&error));
357 test_util::RunBlockingPoolTask();
358 EXPECT_EQ(FILE_ERROR_OK, error);
359
360 // Entry is moved on the server.
361 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
362 ASSERT_TRUE(entry);
363
364 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
365 scoped_ptr<google_apis::FileResource> server_entry;
366 fake_drive_service_->GetFileResource(
367 entry->resource_id(),
368 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
369 test_util::RunBlockingPoolTask();
370 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
371 ASSERT_TRUE(server_entry);
372 EXPECT_EQ(entry->title(), server_entry->title());
373
374 ASSERT_FALSE(server_entry->parents().empty());
375 EXPECT_EQ(parent->resource_id(), server_entry->parents()[0].file_id());
376 }
377
TEST_F(FileSystemTest,Remove)378 TEST_F(FileSystemTest, Remove) {
379 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
380 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
381 ASSERT_TRUE(entry);
382
383 FileError error = FILE_ERROR_FAILED;
384 file_system_->Remove(
385 file_path,
386 false, // is_resursive
387 google_apis::test_util::CreateCopyResultCallback(&error));
388 test_util::RunBlockingPoolTask();
389 EXPECT_EQ(FILE_ERROR_OK, error);
390
391 // Entry is removed on the server.
392 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
393 scoped_ptr<google_apis::FileResource> server_entry;
394 fake_drive_service_->GetFileResource(
395 entry->resource_id(),
396 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
397 test_util::RunBlockingPoolTask();
398 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
399 ASSERT_TRUE(server_entry);
400 EXPECT_TRUE(server_entry->labels().is_trashed());
401 }
402
TEST_F(FileSystemTest,CreateDirectory)403 TEST_F(FileSystemTest, CreateDirectory) {
404 base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory"));
405 EXPECT_FALSE(GetResourceEntrySync(directory_path));
406
407 FileError error = FILE_ERROR_FAILED;
408 file_system_->CreateDirectory(
409 directory_path,
410 true, // is_exclusive
411 false, // is_recursive
412 google_apis::test_util::CreateCopyResultCallback(&error));
413 test_util::RunBlockingPoolTask();
414 EXPECT_EQ(FILE_ERROR_OK, error);
415
416 // Directory is created on the server.
417 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(directory_path);
418 ASSERT_TRUE(entry);
419
420 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
421 scoped_ptr<google_apis::FileResource> server_entry;
422 fake_drive_service_->GetFileResource(
423 entry->resource_id(),
424 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
425 test_util::RunBlockingPoolTask();
426 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
427 ASSERT_TRUE(server_entry);
428 EXPECT_EQ(entry->title(), server_entry->title());
429 EXPECT_TRUE(server_entry->IsDirectory());
430 }
431
TEST_F(FileSystemTest,CreateFile)432 TEST_F(FileSystemTest, CreateFile) {
433 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt"));
434 EXPECT_FALSE(GetResourceEntrySync(file_path));
435
436 FileError error = FILE_ERROR_FAILED;
437 file_system_->CreateFile(
438 file_path,
439 true, // is_exclusive
440 "text/plain",
441 google_apis::test_util::CreateCopyResultCallback(&error));
442 test_util::RunBlockingPoolTask();
443 EXPECT_EQ(FILE_ERROR_OK, error);
444
445 // File is created on the server.
446 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
447 ASSERT_TRUE(entry);
448
449 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
450 scoped_ptr<google_apis::FileResource> server_entry;
451 fake_drive_service_->GetFileResource(
452 entry->resource_id(),
453 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
454 test_util::RunBlockingPoolTask();
455 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
456 ASSERT_TRUE(server_entry);
457 EXPECT_EQ(entry->title(), server_entry->title());
458 EXPECT_FALSE(server_entry->IsDirectory());
459 }
460
TEST_F(FileSystemTest,TouchFile)461 TEST_F(FileSystemTest, TouchFile) {
462 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
463 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
464 ASSERT_TRUE(entry);
465
466 base::Time last_accessed =
467 base::Time::FromInternalValue(entry->file_info().last_accessed()) +
468 base::TimeDelta::FromSeconds(1);
469 base::Time last_modified =
470 base::Time::FromInternalValue(entry->file_info().last_modified()) +
471 base::TimeDelta::FromSeconds(1);
472
473 FileError error = FILE_ERROR_FAILED;
474 file_system_->TouchFile(
475 file_path,
476 last_accessed,
477 last_modified,
478 google_apis::test_util::CreateCopyResultCallback(&error));
479 test_util::RunBlockingPoolTask();
480 EXPECT_EQ(FILE_ERROR_OK, error);
481
482 // File is touched on the server.
483 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
484 scoped_ptr<google_apis::FileResource> server_entry;
485 fake_drive_service_->GetFileResource(
486 entry->resource_id(),
487 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
488 test_util::RunBlockingPoolTask();
489 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
490 ASSERT_TRUE(server_entry);
491 EXPECT_EQ(last_accessed, server_entry->last_viewed_by_me_date());
492 EXPECT_EQ(last_modified, server_entry->modified_date());
493 }
494
TEST_F(FileSystemTest,TruncateFile)495 TEST_F(FileSystemTest, TruncateFile) {
496 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
497 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
498 ASSERT_TRUE(entry);
499
500 const int64 kLength = entry->file_info().size() + 100;
501
502 FileError error = FILE_ERROR_FAILED;
503 file_system_->TruncateFile(
504 file_path,
505 kLength,
506 google_apis::test_util::CreateCopyResultCallback(&error));
507 test_util::RunBlockingPoolTask();
508 EXPECT_EQ(FILE_ERROR_OK, error);
509
510 // File is touched on the server.
511 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR;
512 scoped_ptr<google_apis::FileResource> server_entry;
513 fake_drive_service_->GetFileResource(
514 entry->resource_id(),
515 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
516 test_util::RunBlockingPoolTask();
517 EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
518 ASSERT_TRUE(server_entry);
519 EXPECT_EQ(kLength, server_entry->file_size());
520 }
521
TEST_F(FileSystemTest,DuplicatedAsyncInitialization)522 TEST_F(FileSystemTest, DuplicatedAsyncInitialization) {
523 base::RunLoop loop;
524
525 int counter = 0;
526 const GetResourceEntryCallback& callback = base::Bind(
527 &AsyncInitializationCallback, &counter, 2, loop.QuitClosure());
528
529 file_system_->GetResourceEntry(
530 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
531 file_system_->GetResourceEntry(
532 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
533 loop.Run(); // Wait to get our result
534 EXPECT_EQ(2, counter);
535
536 EXPECT_EQ(1, fake_drive_service_->file_list_load_count());
537 }
538
TEST_F(FileSystemTest,GetGrandRootEntry)539 TEST_F(FileSystemTest, GetGrandRootEntry) {
540 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive"));
541 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
542 ASSERT_TRUE(entry);
543 EXPECT_EQ(util::kDriveGrandRootLocalId, entry->local_id());
544 }
545
TEST_F(FileSystemTest,GetOtherDirEntry)546 TEST_F(FileSystemTest, GetOtherDirEntry) {
547 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other"));
548 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
549 ASSERT_TRUE(entry);
550 EXPECT_EQ(util::kDriveOtherDirLocalId, entry->local_id());
551 }
552
TEST_F(FileSystemTest,GetMyDriveRoot)553 TEST_F(FileSystemTest, GetMyDriveRoot) {
554 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
555 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
556 ASSERT_TRUE(entry);
557 EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
558
559 // After "fast fetch" is done, full resource list is fetched.
560 EXPECT_EQ(1, fake_drive_service_->file_list_load_count());
561 }
562
TEST_F(FileSystemTest,GetExistingFile)563 TEST_F(FileSystemTest, GetExistingFile) {
564 // Simulate the situation that full feed fetching takes very long time,
565 // to test the recursive "fast fetch" feature is properly working.
566 fake_drive_service_->set_never_return_all_file_list(true);
567
568 const base::FilePath kFilePath(
569 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
570 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
571 ASSERT_TRUE(entry);
572 EXPECT_EQ("file:subdirectory_file_1_id", entry->resource_id());
573
574 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
575 EXPECT_EQ(2, fake_drive_service_->directory_load_count());
576 EXPECT_EQ(1, fake_drive_service_->blocked_file_list_load_count());
577 }
578
TEST_F(FileSystemTest,GetExistingDocument)579 TEST_F(FileSystemTest, GetExistingDocument) {
580 const base::FilePath kFilePath(
581 FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
582 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
583 ASSERT_TRUE(entry);
584 EXPECT_EQ("document:5_document_resource_id", entry->resource_id());
585 }
586
TEST_F(FileSystemTest,GetNonExistingFile)587 TEST_F(FileSystemTest, GetNonExistingFile) {
588 const base::FilePath kFilePath(
589 FILE_PATH_LITERAL("drive/root/nonexisting.file"));
590 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
591 EXPECT_FALSE(entry);
592 }
593
TEST_F(FileSystemTest,GetInSubSubdir)594 TEST_F(FileSystemTest, GetInSubSubdir) {
595 const base::FilePath kFilePath(
596 FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/"
597 "Sub Sub Directory Folder"));
598 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
599 ASSERT_TRUE(entry);
600 ASSERT_EQ("folder:sub_sub_directory_folder_id", entry->resource_id());
601 }
602
TEST_F(FileSystemTest,GetOrphanFile)603 TEST_F(FileSystemTest, GetOrphanFile) {
604 ASSERT_TRUE(LoadFullResourceList());
605
606 // Entry without parents are placed under "drive/other".
607 const base::FilePath kFilePath(
608 FILE_PATH_LITERAL("drive/other/Orphan File 1.txt"));
609 scoped_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
610 ASSERT_TRUE(entry);
611 EXPECT_EQ("file:1_orphanfile_resource_id", entry->resource_id());
612 }
613
TEST_F(FileSystemTest,ReadDirectory_Root)614 TEST_F(FileSystemTest, ReadDirectory_Root) {
615 // ReadDirectory() should kick off the resource list loading.
616 scoped_ptr<ResourceEntryVector> entries(
617 ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive")));
618 // The root directory should be read correctly.
619 ASSERT_TRUE(entries);
620 ASSERT_EQ(3U, entries->size());
621
622 // The found three directories should be /drive/root, /drive/other and
623 // /drive/trash.
624 std::set<base::FilePath> found;
625 for (size_t i = 0; i < entries->size(); ++i)
626 found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
627 EXPECT_EQ(3U, found.size());
628 EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveMyDriveRootDirName)));
629 EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveOtherDirName)));
630 EXPECT_EQ(1U, found.count(base::FilePath(util::kDriveTrashDirName)));
631 }
632
TEST_F(FileSystemTest,ReadDirectory_NonRootDirectory)633 TEST_F(FileSystemTest, ReadDirectory_NonRootDirectory) {
634 // ReadDirectory() should kick off the resource list loading.
635 scoped_ptr<ResourceEntryVector> entries(
636 ReadDirectorySync(
637 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
638 // The non root directory should also be read correctly.
639 // There was a bug (crbug.com/181487), which broke this behavior.
640 // Make sure this is fixed.
641 ASSERT_TRUE(entries);
642 EXPECT_EQ(3U, entries->size());
643 }
644
TEST_F(FileSystemTest,LoadFileSystemFromUpToDateCache)645 TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) {
646 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
647
648 // Kicks loading of cached file system and query for server update.
649 EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
650
651 // SetUpTestFileSystem and FakeDriveService have the same
652 // changestamp (i.e. the local metadata is up-to-date), so no request for
653 // new resource list (i.e., call to GetResourceList) should happen.
654 EXPECT_EQ(0, fake_drive_service_->file_list_load_count());
655
656 // Since the file system has verified that it holds the latest snapshot,
657 // it should change its state to "loaded", which admits periodic refresh.
658 // To test it, call CheckForUpdates and verify it does try to check updates.
659 const int about_resource_load_count_before =
660 fake_drive_service_->about_resource_load_count();
661 file_system_->CheckForUpdates();
662 test_util::RunBlockingPoolTask();
663 EXPECT_LT(about_resource_load_count_before,
664 fake_drive_service_->about_resource_load_count());
665 }
666
TEST_F(FileSystemTest,LoadFileSystemFromCacheWhileOffline)667 TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) {
668 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
669
670 // Make GetResourceList fail for simulating offline situation. This will
671 // leave the file system "loaded from cache, but not synced with server"
672 // state.
673 fake_drive_service_->set_offline(true);
674
675 // Load the root.
676 EXPECT_TRUE(ReadDirectorySync(util::GetDriveGrandRootPath()));
677 // Loading of about resource should not happen as it's offline.
678 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
679
680 // Load "My Drive".
681 EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
682 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
683
684 // Tests that cached data can be loaded even if the server is not reachable.
685 EXPECT_TRUE(EntryExists(base::FilePath(
686 FILE_PATH_LITERAL("drive/root/File1"))));
687 EXPECT_TRUE(EntryExists(base::FilePath(
688 FILE_PATH_LITERAL("drive/root/Dir1"))));
689 EXPECT_TRUE(EntryExists(base::FilePath(
690 FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
691 EXPECT_TRUE(EntryExists(base::FilePath(
692 FILE_PATH_LITERAL("drive/root/Dir1/SubDir2"))));
693 EXPECT_TRUE(EntryExists(base::FilePath(
694 FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"))));
695
696 // Since the file system has at least succeeded to load cached snapshot,
697 // the file system should be able to start periodic refresh.
698 // To test it, call CheckForUpdates and verify it does try to check
699 // updates, which will cause directory changes.
700 fake_drive_service_->set_offline(false);
701
702 file_system_->CheckForUpdates();
703
704 test_util::RunBlockingPoolTask();
705 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
706 EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
707
708 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
709 }
710
TEST_F(FileSystemTest,ReadDirectoryWhileRefreshing)711 TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) {
712 // Use old timestamp so the fast fetch will be performed.
713 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
714
715 // The list of resources in "drive/root/Dir1" should be fetched.
716 EXPECT_TRUE(ReadDirectorySync(base::FilePath(
717 FILE_PATH_LITERAL("drive/root/Dir1"))));
718 EXPECT_EQ(1, fake_drive_service_->directory_load_count());
719
720 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
721 }
722
TEST_F(FileSystemTest,GetResourceEntryNonExistentWhileRefreshing)723 TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
724 // Use old timestamp so the fast fetch will be performed.
725 ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
726
727 // If an entry is not found, parent directory's resource list is fetched.
728 EXPECT_FALSE(GetResourceEntrySync(base::FilePath(
729 FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
730 EXPECT_EQ(1, fake_drive_service_->directory_load_count());
731
732 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
733 }
734
TEST_F(FileSystemTest,CreateDirectoryByImplicitLoad)735 TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) {
736 // Intentionally *not* calling LoadFullResourceList(), for testing that
737 // CreateDirectory ensures the resource list is loaded before it runs.
738
739 base::FilePath existing_directory(
740 FILE_PATH_LITERAL("drive/root/Directory 1"));
741 FileError error = FILE_ERROR_FAILED;
742 file_system_->CreateDirectory(
743 existing_directory,
744 true, // is_exclusive
745 false, // is_recursive
746 google_apis::test_util::CreateCopyResultCallback(&error));
747 test_util::RunBlockingPoolTask();
748
749 // It should fail because is_exclusive is set to true.
750 EXPECT_EQ(FILE_ERROR_EXISTS, error);
751 }
752
TEST_F(FileSystemTest,CreateDirectoryRecursively)753 TEST_F(FileSystemTest, CreateDirectoryRecursively) {
754 // Intentionally *not* calling LoadFullResourceList(), for testing that
755 // CreateDirectory ensures the resource list is loaded before it runs.
756
757 base::FilePath new_directory(
758 FILE_PATH_LITERAL("drive/root/Directory 1/a/b/c/d"));
759 FileError error = FILE_ERROR_FAILED;
760 file_system_->CreateDirectory(
761 new_directory,
762 true, // is_exclusive
763 true, // is_recursive
764 google_apis::test_util::CreateCopyResultCallback(&error));
765 test_util::RunBlockingPoolTask();
766
767 EXPECT_EQ(FILE_ERROR_OK, error);
768
769 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(new_directory));
770 ASSERT_TRUE(entry);
771 EXPECT_TRUE(entry->file_info().is_directory());
772 }
773
TEST_F(FileSystemTest,PinAndUnpin)774 TEST_F(FileSystemTest, PinAndUnpin) {
775 ASSERT_TRUE(LoadFullResourceList());
776
777 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
778
779 // Get the file info.
780 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
781 ASSERT_TRUE(entry);
782
783 // Pin the file.
784 FileError error = FILE_ERROR_FAILED;
785 file_system_->Pin(file_path,
786 google_apis::test_util::CreateCopyResultCallback(&error));
787 test_util::RunBlockingPoolTask();
788 EXPECT_EQ(FILE_ERROR_OK, error);
789
790 entry = GetResourceEntrySync(file_path);
791 ASSERT_TRUE(entry);
792 EXPECT_TRUE(entry->file_specific_info().cache_state().is_pinned());
793 EXPECT_TRUE(entry->file_specific_info().cache_state().is_present());
794
795 // Unpin the file.
796 error = FILE_ERROR_FAILED;
797 file_system_->Unpin(file_path,
798 google_apis::test_util::CreateCopyResultCallback(&error));
799 test_util::RunBlockingPoolTask();
800 EXPECT_EQ(FILE_ERROR_OK, error);
801
802 entry = GetResourceEntrySync(file_path);
803 ASSERT_TRUE(entry);
804 EXPECT_FALSE(entry->file_specific_info().cache_state().is_pinned());
805
806 // Pinned file gets synced and it results in entry state changes.
807 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
808 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
809 mock_directory_observer_->changed_directories()[0]);
810 }
811
TEST_F(FileSystemTest,PinAndUnpin_NotSynced)812 TEST_F(FileSystemTest, PinAndUnpin_NotSynced) {
813 ASSERT_TRUE(LoadFullResourceList());
814
815 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
816
817 // Get the file info.
818 scoped_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
819 ASSERT_TRUE(entry);
820
821 // Unpin the file just after pinning. File fetch should be cancelled.
822 FileError error_pin = FILE_ERROR_FAILED;
823 file_system_->Pin(
824 file_path,
825 google_apis::test_util::CreateCopyResultCallback(&error_pin));
826
827 FileError error_unpin = FILE_ERROR_FAILED;
828 file_system_->Unpin(
829 file_path,
830 google_apis::test_util::CreateCopyResultCallback(&error_unpin));
831
832 test_util::RunBlockingPoolTask();
833 EXPECT_EQ(FILE_ERROR_OK, error_pin);
834 EXPECT_EQ(FILE_ERROR_OK, error_unpin);
835
836 // No cache file available because the sync was cancelled by Unpin().
837 entry = GetResourceEntrySync(file_path);
838 ASSERT_TRUE(entry);
839 EXPECT_FALSE(entry->file_specific_info().cache_state().is_present());
840 }
841
TEST_F(FileSystemTest,GetAvailableSpace)842 TEST_F(FileSystemTest, GetAvailableSpace) {
843 FileError error = FILE_ERROR_OK;
844 int64 bytes_total;
845 int64 bytes_used;
846 file_system_->GetAvailableSpace(
847 google_apis::test_util::CreateCopyResultCallback(
848 &error, &bytes_total, &bytes_used));
849 test_util::RunBlockingPoolTask();
850 EXPECT_EQ(6789012345LL, bytes_used);
851 EXPECT_EQ(9876543210LL, bytes_total);
852 }
853
TEST_F(FileSystemTest,MarkCacheFileAsMountedAndUnmounted)854 TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
855 ASSERT_TRUE(LoadFullResourceList());
856
857 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
858
859 // Make the file cached.
860 FileError error = FILE_ERROR_FAILED;
861 base::FilePath file_path;
862 scoped_ptr<ResourceEntry> entry;
863 file_system_->GetFile(
864 file_in_root,
865 google_apis::test_util::CreateCopyResultCallback(
866 &error, &file_path, &entry));
867 test_util::RunBlockingPoolTask();
868 EXPECT_EQ(FILE_ERROR_OK, error);
869
870 // Test for mounting.
871 error = FILE_ERROR_FAILED;
872 file_path.clear();
873 file_system_->MarkCacheFileAsMounted(
874 file_in_root,
875 google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
876 test_util::RunBlockingPoolTask();
877 EXPECT_EQ(FILE_ERROR_OK, error);
878
879 // Cannot remove a cache entry while it's being mounted.
880 EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->local_id()));
881
882 // Test for unmounting.
883 error = FILE_ERROR_FAILED;
884 file_system_->MarkCacheFileAsUnmounted(
885 file_path,
886 google_apis::test_util::CreateCopyResultCallback(&error));
887 test_util::RunBlockingPoolTask();
888 EXPECT_EQ(FILE_ERROR_OK, error);
889
890 // Now able to remove the cache entry.
891 EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->local_id()));
892 }
893
TEST_F(FileSystemTest,GetShareUrl)894 TEST_F(FileSystemTest, GetShareUrl) {
895 ASSERT_TRUE(LoadFullResourceList());
896
897 const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt"));
898 const GURL kEmbedOrigin("chrome-extension://test-id");
899
900 // Try to fetch the URL for the sharing dialog.
901 FileError error = FILE_ERROR_FAILED;
902 GURL share_url;
903 file_system_->GetShareUrl(
904 kFileInRoot,
905 kEmbedOrigin,
906 google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
907 test_util::RunBlockingPoolTask();
908
909 // Verify the share url to the sharing dialog.
910 EXPECT_EQ(FILE_ERROR_OK, error);
911 EXPECT_TRUE(share_url.is_valid());
912 }
913
914 } // namespace drive
915