• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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