file_system_unittest.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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/json/json_file_value_serializer.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/message_loop.h"
17#include "base/stringprintf.h"
18#include "base/threading/sequenced_worker_pool.h"
19#include "base/values.h"
20#include "chrome/browser/chromeos/drive/change_list_loader.h"
21#include "chrome/browser/chromeos/drive/drive.pb.h"
22#include "chrome/browser/chromeos/drive/drive_webapps_registry.h"
23#include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
24#include "chrome/browser/chromeos/drive/file_system_util.h"
25#include "chrome/browser/chromeos/drive/job_scheduler.h"
26#include "chrome/browser/chromeos/drive/mock_directory_change_observer.h"
27#include "chrome/browser/chromeos/drive/mock_file_cache_observer.h"
28#include "chrome/browser/chromeos/drive/test_util.h"
29#include "chrome/browser/google_apis/drive_api_parser.h"
30#include "chrome/browser/google_apis/fake_drive_service.h"
31#include "chrome/browser/google_apis/test_util.h"
32#include "chrome/test/base/testing_profile.h"
33#include "content/public/browser/browser_thread.h"
34#include "content/public/test/test_browser_thread.h"
35#include "testing/gmock/include/gmock/gmock.h"
36#include "testing/gtest/include/gtest/gtest.h"
37
38using ::testing::AtLeast;
39using ::testing::Eq;
40using ::testing::StrictMock;
41using ::testing::_;
42
43namespace drive {
44namespace {
45
46const int64 kLotsOfSpace = internal::kMinFreeSpace * 10;
47
48struct SearchResultPair {
49  const char* path;
50  const bool is_directory;
51};
52
53// Callback to FileSystem::Search used in ContentSearch tests.
54// Verifies returned vector of results and next feed url.
55void DriveSearchCallback(
56    MessageLoop* message_loop,
57    const SearchResultPair* expected_results,
58    size_t expected_results_size,
59    const GURL& expected_next_feed,
60    FileError error,
61    const GURL& next_feed,
62    scoped_ptr<std::vector<SearchResultInfo> > results) {
63  ASSERT_TRUE(results);
64  ASSERT_EQ(expected_results_size, results->size());
65
66  for (size_t i = 0; i < results->size(); i++) {
67    EXPECT_EQ(base::FilePath(expected_results[i].path),
68              results->at(i).path);
69    EXPECT_EQ(expected_results[i].is_directory,
70              results->at(i).entry.file_info().is_directory());
71  }
72
73  EXPECT_EQ(expected_next_feed, next_feed);
74
75  message_loop->Quit();
76}
77
78// Counts the number of files (not directories) in |entries|.
79int CountFiles(const ResourceEntryVector& entries) {
80  int num_files = 0;
81  for (size_t i = 0; i < entries.size(); ++i) {
82    if (!entries[i].file_info().is_directory())
83      ++num_files;
84  }
85  return num_files;
86}
87
88// Counts the number of invocation, and if it increased up to |expected_counter|
89// quits the current message loop.
90void AsyncInitializationCallback(
91    int* counter, int expected_counter, MessageLoop* message_loop,
92    FileError error, scoped_ptr<ResourceEntry> entry) {
93  if (error != FILE_ERROR_OK || !entry) {
94    // If we hit an error case, quit the message loop immediately.
95    // Then the expectation in the test case can find it because the actual
96    // value of |counter| is different from the expected one.
97    message_loop->Quit();
98    return;
99  }
100
101  (*counter)++;
102  if (*counter >= expected_counter)
103    message_loop->Quit();
104}
105
106void AppendContent(std::vector<std::string>* buffer,
107                   google_apis::GDataErrorCode error,
108                   scoped_ptr<std::string> content) {
109  DCHECK_EQ(error, google_apis::HTTP_SUCCESS);
110  buffer->push_back(*content);
111}
112
113}  // namespace
114
115class DriveFileSystemTest : public testing::Test {
116 protected:
117  DriveFileSystemTest()
118      : ui_thread_(content::BrowserThread::UI, &message_loop_),
119        // |root_feed_changestamp_| should be set to the largest changestamp in
120        // about resource feed. But we fake it by some non-zero positive
121        // increasing value.  See |LoadFeed()|.
122        root_feed_changestamp_(1) {
123  }
124
125  virtual void SetUp() OVERRIDE {
126    profile_.reset(new TestingProfile);
127
128    // The fake object will be manually deleted in TearDown().
129    fake_drive_service_.reset(new google_apis::FakeDriveService);
130    fake_drive_service_->LoadResourceListForWapi(
131        "chromeos/gdata/root_feed.json");
132    fake_drive_service_->LoadAccountMetadataForWapi(
133        "chromeos/gdata/account_metadata.json");
134    fake_drive_service_->LoadAppListForDriveApi("chromeos/drive/applist.json");
135
136    fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
137
138    scheduler_.reset(new JobScheduler(profile_.get(),
139                                      fake_drive_service_.get()));
140
141    scoped_refptr<base::SequencedWorkerPool> pool =
142        content::BrowserThread::GetBlockingPool();
143    blocking_task_runner_ =
144        pool->GetSequencedTaskRunner(pool->GetSequenceToken());
145
146    cache_.reset(new internal::FileCache(util::GetCacheRootPath(profile_.get()),
147                                         blocking_task_runner_,
148                                         fake_free_disk_space_getter_.get()));
149
150    drive_webapps_registry_.reset(new DriveWebAppsRegistry);
151
152    mock_cache_observer_.reset(new StrictMock<MockCacheObserver>);
153    cache_->AddObserver(mock_cache_observer_.get());
154
155    mock_directory_observer_.reset(new StrictMock<MockDirectoryChangeObserver>);
156
157    cache_->RequestInitializeForTesting();
158    google_apis::test_util::RunBlockingPoolTask();
159
160    SetUpResourceMetadataAndFileSystem();
161  }
162
163  void SetUpResourceMetadataAndFileSystem() {
164    resource_metadata_.reset(new internal::ResourceMetadata(
165        cache_->GetCacheDirectoryPath(internal::FileCache::CACHE_TYPE_META),
166        blocking_task_runner_));
167
168    file_system_.reset(new FileSystem(profile_.get(),
169                                      cache_.get(),
170                                      fake_drive_service_.get(),
171                                      scheduler_.get(),
172                                      drive_webapps_registry_.get(),
173                                      resource_metadata_.get(),
174                                      blocking_task_runner_));
175    file_system_->AddObserver(mock_directory_observer_.get());
176    file_system_->Initialize();
177
178    FileError error = FILE_ERROR_FAILED;
179    resource_metadata_->Initialize(
180        google_apis::test_util::CreateCopyResultCallback(&error));
181    google_apis::test_util::RunBlockingPoolTask();
182    ASSERT_EQ(FILE_ERROR_OK, error);
183  }
184
185  virtual void TearDown() OVERRIDE {
186    ASSERT_TRUE(file_system_);
187    file_system_.reset();
188    scheduler_.reset();
189    fake_drive_service_.reset();
190    cache_.reset();
191    profile_.reset(NULL);
192  }
193
194  // Loads test json file as root ("/drive") element.
195  bool LoadRootFeedDocument() {
196    FileError error = FILE_ERROR_FAILED;
197    file_system_->change_list_loader()->LoadIfNeeded(
198        DirectoryFetchInfo(),
199        google_apis::test_util::CreateCopyResultCallback(&error));
200    google_apis::test_util::RunBlockingPoolTask();
201    return error == FILE_ERROR_OK;
202  }
203
204  bool LoadChangeFeed(const std::string& filename) {
205    if (!test_util::LoadChangeFeed(filename,
206                                   file_system_->change_list_loader(),
207                                   true,  // is_delta_feed
208                                   fake_drive_service_->GetRootResourceId(),
209                                   root_feed_changestamp_)) {
210      return false;
211    }
212    root_feed_changestamp_++;
213    return true;
214  }
215
216  FileError AddDirectory(const base::FilePath& directory_path) {
217    FileError error = FILE_ERROR_FAILED;
218    file_system_->CreateDirectory(
219        directory_path,
220        false,  // is_exclusive
221        false,  // is_recursive
222        google_apis::test_util::CreateCopyResultCallback(&error));
223    google_apis::test_util::RunBlockingPoolTask();
224    return error;
225  }
226
227  bool RemoveEntry(const base::FilePath& file_path) {
228    FileError error = FILE_ERROR_FAILED;
229    file_system_->Remove(
230        file_path, false,
231        google_apis::test_util::CreateCopyResultCallback(&error));
232    google_apis::test_util::RunBlockingPoolTask();
233    return error == FILE_ERROR_OK;
234  }
235
236  // Gets resource entry by path synchronously.
237  scoped_ptr<ResourceEntry> GetResourceEntryByPathSync(
238      const base::FilePath& file_path) {
239    FileError error = FILE_ERROR_FAILED;
240    scoped_ptr<ResourceEntry> entry;
241    file_system_->GetResourceEntryByPath(
242        file_path,
243        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
244    google_apis::test_util::RunBlockingPoolTask();
245
246    return entry.Pass();
247  }
248
249  // Gets directory info by path synchronously.
250  scoped_ptr<ResourceEntryVector> ReadDirectoryByPathSync(
251      const base::FilePath& file_path) {
252    FileError error = FILE_ERROR_FAILED;
253    bool unused_hide_hosted_documents;
254    scoped_ptr<ResourceEntryVector> entries;
255    file_system_->ReadDirectoryByPath(
256        file_path,
257        google_apis::test_util::CreateCopyResultCallback(
258            &error, &unused_hide_hosted_documents, &entries));
259    google_apis::test_util::RunBlockingPoolTask();
260
261    return entries.Pass();
262  }
263
264  // Returns true if an entry exists at |file_path|.
265  bool EntryExists(const base::FilePath& file_path) {
266    return GetResourceEntryByPathSync(file_path);
267  }
268
269  // Gets the resource ID of |file_path|. Returns an empty string if not found.
270  std::string GetResourceIdByPath(const base::FilePath& file_path) {
271    scoped_ptr<ResourceEntry> entry =
272        GetResourceEntryByPathSync(file_path);
273    if (entry)
274      return entry->resource_id();
275    else
276      return "";
277  }
278
279  // Helper function to call GetCacheEntry from origin thread.
280  bool GetCacheEntryFromOriginThread(const std::string& resource_id,
281                                     const std::string& md5,
282                                     FileCacheEntry* cache_entry) {
283    bool result = false;
284    cache_->GetCacheEntryOnUIThread(
285        resource_id, md5,
286        google_apis::test_util::CreateCopyResultCallback(&result, cache_entry));
287    google_apis::test_util::RunBlockingPoolTask();
288    return result;
289  }
290
291  // Returns true if the cache entry exists for the given resource ID and MD5.
292  bool CacheEntryExists(const std::string& resource_id,
293                        const std::string& md5) {
294    FileCacheEntry cache_entry;
295    return GetCacheEntryFromOriginThread(resource_id, md5, &cache_entry);
296  }
297
298  // Flag for specifying the timestamp of the test filesystem cache.
299  enum SetUpTestFileSystemParam {
300    USE_OLD_TIMESTAMP,
301    USE_SERVER_TIMESTAMP,
302  };
303
304  // Sets up a filesystem with directories: drive/root, drive/root/Dir1,
305  // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2,
306  // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets
307  // the changestamp to 654321, equal to that of "account_metadata.json" test
308  // data, indicating the cache is holding the latest file system info.
309  bool SetUpTestFileSystem(SetUpTestFileSystemParam param) {
310    // Destroy the existing resource metadata to close DB.
311    resource_metadata_.reset();
312
313    const std::string root_resource_id =
314        fake_drive_service_->GetRootResourceId();
315    scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
316        resource_metadata(new internal::ResourceMetadata(
317            cache_->GetCacheDirectoryPath(internal::FileCache::CACHE_TYPE_META),
318            blocking_task_runner_));
319
320    FileError error = FILE_ERROR_FAILED;
321    resource_metadata->Initialize(
322        google_apis::test_util::CreateCopyResultCallback(&error));
323    google_apis::test_util::RunBlockingPoolTask();
324    if (error != FILE_ERROR_OK)
325      return false;
326
327    resource_metadata->SetLargestChangestampOnUIThread(
328        param == USE_SERVER_TIMESTAMP ? 654321 : 1,
329        google_apis::test_util::CreateCopyResultCallback(&error));
330    google_apis::test_util::RunBlockingPoolTask();
331    if (error != FILE_ERROR_OK)
332      return false;
333
334    // drive/root is already prepared by ResourceMetadata.
335    base::FilePath file_path;
336
337    // drive/root
338    resource_metadata->AddEntryOnUIThread(
339        util::CreateMyDriveRootEntry(root_resource_id),
340        google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
341    google_apis::test_util::RunBlockingPoolTask();
342    if (error != FILE_ERROR_OK)
343      return false;
344
345    // drive/root/File1
346    ResourceEntry file1;
347    file1.set_title("File1");
348    file1.set_resource_id("resource_id:File1");
349    file1.set_parent_resource_id(root_resource_id);
350    file1.mutable_file_specific_info()->set_file_md5("md5");
351    file1.mutable_file_info()->set_is_directory(false);
352    file1.mutable_file_info()->set_size(1048576);
353    resource_metadata->AddEntryOnUIThread(
354        file1,
355        google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
356    google_apis::test_util::RunBlockingPoolTask();
357    if (error != FILE_ERROR_OK)
358      return false;
359
360    // drive/root/Dir1
361    ResourceEntry dir1;
362    dir1.set_title("Dir1");
363    dir1.set_resource_id("resource_id:Dir1");
364    dir1.set_parent_resource_id(root_resource_id);
365    dir1.mutable_file_info()->set_is_directory(true);
366    resource_metadata->AddEntryOnUIThread(
367        dir1,
368        google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
369    google_apis::test_util::RunBlockingPoolTask();
370    if (error != FILE_ERROR_OK)
371      return false;
372
373    // drive/root/Dir1/File2
374    ResourceEntry file2;
375    file2.set_title("File2");
376    file2.set_resource_id("resource_id:File2");
377    file2.set_parent_resource_id(dir1.resource_id());
378    file2.mutable_file_specific_info()->set_file_md5("md5");
379    file2.mutable_file_info()->set_is_directory(false);
380    file2.mutable_file_info()->set_size(555);
381    resource_metadata->AddEntryOnUIThread(
382        file2,
383        google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
384    google_apis::test_util::RunBlockingPoolTask();
385    if (error != FILE_ERROR_OK)
386      return false;
387
388    // drive/root/Dir1/SubDir2
389    ResourceEntry dir2;
390    dir2.set_title("SubDir2");
391    dir2.set_resource_id("resource_id:SubDir2");
392    dir2.set_parent_resource_id(dir1.resource_id());
393    dir2.mutable_file_info()->set_is_directory(true);
394    resource_metadata->AddEntryOnUIThread(
395        dir2,
396        google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
397    google_apis::test_util::RunBlockingPoolTask();
398    if (error != FILE_ERROR_OK)
399      return false;
400
401    // drive/root/Dir1/SubDir2/File3
402    ResourceEntry file3;
403    file3.set_title("File3");
404    file3.set_resource_id("resource_id:File3");
405    file3.set_parent_resource_id(dir2.resource_id());
406    file3.mutable_file_specific_info()->set_file_md5("md5");
407    file3.mutable_file_info()->set_is_directory(false);
408    file3.mutable_file_info()->set_size(12345);
409    resource_metadata->AddEntryOnUIThread(
410        file3,
411        google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
412    google_apis::test_util::RunBlockingPoolTask();
413    if (error != FILE_ERROR_OK)
414      return false;
415
416    // Recreate resource metadata.
417    SetUpResourceMetadataAndFileSystem();
418
419    return true;
420  }
421
422  // Verifies that |file_path| is a valid JSON file for the hosted document
423  // associated with |entry| (i.e. |url| and |resource_id| match).
424  void VerifyHostedDocumentJSONFile(const ResourceEntry& entry,
425                                    const base::FilePath& file_path) {
426    std::string error;
427    JSONFileValueSerializer serializer(file_path);
428    scoped_ptr<Value> value(serializer.Deserialize(NULL, &error));
429    ASSERT_TRUE(value) << "Parse error " << file_path.value() << ": " << error;
430    DictionaryValue* dict_value = NULL;
431    ASSERT_TRUE(value->GetAsDictionary(&dict_value));
432
433    std::string alternate_url, resource_id;
434    EXPECT_TRUE(dict_value->GetString("url", &alternate_url));
435    EXPECT_TRUE(dict_value->GetString("resource_id", &resource_id));
436
437    EXPECT_EQ(entry.file_specific_info().alternate_url(), alternate_url);
438    EXPECT_EQ(entry.resource_id(), resource_id);
439  }
440
441  MessageLoopForUI message_loop_;
442  content::TestBrowserThread ui_thread_;
443  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
444  scoped_ptr<TestingProfile> profile_;
445
446  scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
447  scoped_ptr<FileSystem> file_system_;
448  scoped_ptr<google_apis::FakeDriveService> fake_drive_service_;
449  scoped_ptr<JobScheduler> scheduler_;
450  scoped_ptr<DriveWebAppsRegistry> drive_webapps_registry_;
451  scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
452      resource_metadata_;
453  scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
454  scoped_ptr<StrictMock<MockCacheObserver> > mock_cache_observer_;
455  scoped_ptr<StrictMock<MockDirectoryChangeObserver> > mock_directory_observer_;
456
457  int root_feed_changestamp_;
458};
459
460TEST_F(DriveFileSystemTest, DuplicatedAsyncInitialization) {
461  // "Fast fetch" will fire an OnirectoryChanged event.
462  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
463      Eq(base::FilePath(FILE_PATH_LITERAL("drive"))))).Times(1);
464
465  int counter = 0;
466  const GetResourceEntryCallback& callback = base::Bind(
467      &AsyncInitializationCallback, &counter, 2, &message_loop_);
468
469  file_system_->GetResourceEntryByPath(
470      base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
471  file_system_->GetResourceEntryByPath(
472      base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
473  message_loop_.Run();  // Wait to get our result
474  EXPECT_EQ(2, counter);
475
476  // Although GetResourceEntryByPath() was called twice, the resource list
477  // should only be loaded once. In the past, there was a bug that caused
478  // it to be loaded twice.
479  EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
480  // See the comment in GetMyDriveRoot test case why this is 2.
481  EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
482}
483
484TEST_F(DriveFileSystemTest, GetGrandRootEntry) {
485  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive"));
486  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
487  ASSERT_TRUE(entry);
488  EXPECT_EQ(util::kDriveGrandRootSpecialResourceId, entry->resource_id());
489
490  // Getting the grand root entry should not cause the resource load to happen.
491  EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
492  EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
493}
494
495TEST_F(DriveFileSystemTest, GetOtherDirEntry) {
496  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other"));
497  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
498  ASSERT_TRUE(entry);
499  EXPECT_EQ(util::kDriveOtherDirSpecialResourceId, entry->resource_id());
500
501  // Getting the "other" directory entry should not cause the resource load to
502  // happen.
503  EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
504  EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
505}
506
507TEST_F(DriveFileSystemTest, GetMyDriveRoot) {
508  // "Fast fetch" will fire an OnirectoryChanged event.
509  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
510      Eq(base::FilePath(FILE_PATH_LITERAL("drive"))))).Times(1);
511
512  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
513  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
514  ASSERT_TRUE(entry);
515  EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
516
517  // Absence of "drive/root" in the local metadata triggers the "fast fetch"
518  // of "drive" directory. Fetch of "drive" grand root directory has a special
519  // implementation. Instead of normal GetResourceListInDirectory(), it is
520  // emulated by calling GetAboutResource() so that the resource_id of
521  // "drive/root" is listed.
522  // Together with the normal GetAboutResource() call to retrieve the largest
523  // changestamp, the method is called twice.
524  EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
525
526  // After "fast fetch" is done, full resource list is fetched.
527  EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
528}
529
530TEST_F(DriveFileSystemTest, GetExistingFile) {
531  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
532  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
533  ASSERT_TRUE(entry);
534  EXPECT_EQ("file:2_file_resource_id", entry->resource_id());
535
536  EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
537  EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
538}
539
540TEST_F(DriveFileSystemTest, GetExistingDocument) {
541  const base::FilePath kFilePath(
542      FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
543  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
544  ASSERT_TRUE(entry);
545  EXPECT_EQ("document:5_document_resource_id", entry->resource_id());
546}
547
548TEST_F(DriveFileSystemTest, GetNonExistingFile) {
549  const base::FilePath kFilePath(
550      FILE_PATH_LITERAL("drive/root/nonexisting.file"));
551  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
552  EXPECT_FALSE(entry);
553}
554
555TEST_F(DriveFileSystemTest, GetEncodedFileNames) {
556  const base::FilePath kFilePath1(
557      FILE_PATH_LITERAL("drive/root/Slash / in file 1.txt"));
558  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath1);
559  ASSERT_FALSE(entry);
560
561  const base::FilePath kFilePath2 = base::FilePath::FromUTF8Unsafe(
562      "drive/root/Slash \xE2\x88\x95 in file 1.txt");
563  entry = GetResourceEntryByPathSync(kFilePath2);
564  ASSERT_TRUE(entry);
565  EXPECT_EQ("file:slash_file_resource_id", entry->resource_id());
566
567  const base::FilePath kFilePath3 = base::FilePath::FromUTF8Unsafe(
568      "drive/root/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt");
569  entry = GetResourceEntryByPathSync(kFilePath3);
570  ASSERT_TRUE(entry);
571  EXPECT_EQ("file:slash_subdir_file", entry->resource_id());
572}
573
574TEST_F(DriveFileSystemTest, GetDuplicateNames) {
575  const base::FilePath kFilePath1(
576      FILE_PATH_LITERAL("drive/root/Duplicate Name.txt"));
577  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath1);
578  ASSERT_TRUE(entry);
579  const std::string resource_id1 = entry->resource_id();
580
581  const base::FilePath kFilePath2(
582      FILE_PATH_LITERAL("drive/root/Duplicate Name (2).txt"));
583  entry = GetResourceEntryByPathSync(kFilePath2);
584  ASSERT_TRUE(entry);
585  const std::string resource_id2 = entry->resource_id();
586
587  // The entries are de-duped non-deterministically, so we shouldn't rely on the
588  // names matching specific resource ids.
589  const std::string file3_resource_id = "file:3_file_resource_id";
590  const std::string file4_resource_id = "file:4_file_resource_id";
591  EXPECT_TRUE(file3_resource_id == resource_id1 ||
592              file3_resource_id == resource_id2);
593  EXPECT_TRUE(file4_resource_id == resource_id1 ||
594              file4_resource_id == resource_id2);
595}
596
597TEST_F(DriveFileSystemTest, GetExistingDirectory) {
598  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/Directory 1"));
599  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
600  ASSERT_TRUE(entry);
601  ASSERT_EQ("folder:1_folder_resource_id", entry->resource_id());
602
603  // The changestamp should be propagated to the directory.
604  EXPECT_EQ(fake_drive_service_->largest_changestamp(),
605            entry->directory_specific_info().changestamp());
606}
607
608TEST_F(DriveFileSystemTest, GetInSubSubdir) {
609  const base::FilePath kFilePath(
610      FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/"
611                        "Sub Sub Directory Folder"));
612  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
613  ASSERT_TRUE(entry);
614  ASSERT_EQ("folder:sub_sub_directory_folder_id", entry->resource_id());
615}
616
617TEST_F(DriveFileSystemTest, GetOrphanFile) {
618  const base::FilePath kFilePath(
619      FILE_PATH_LITERAL("drive/other/Orphan File 1.txt"));
620  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
621  ASSERT_TRUE(entry);
622  EXPECT_EQ("file:1_orphanfile_resource_id", entry->resource_id());
623}
624
625TEST_F(DriveFileSystemTest, ReadDirectoryByPath_Root) {
626  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
627      Eq(base::FilePath(FILE_PATH_LITERAL("drive"))))).Times(1);
628
629  // ReadDirectoryByPath() should kick off the resource list loading.
630  scoped_ptr<ResourceEntryVector> entries(
631      ReadDirectoryByPathSync(base::FilePath::FromUTF8Unsafe("drive")));
632  // The root directory should be read correctly.
633  ASSERT_TRUE(entries);
634  ASSERT_EQ(2U, entries->size());
635
636  // The found two directories should be /drive/root and /drive/other.
637  bool found_other = false;
638  bool found_my_drive = false;
639  for (size_t i = 0; i < entries->size(); ++i) {
640    const base::FilePath title =
641        base::FilePath::FromUTF8Unsafe((*entries)[i].title());
642    if (title == base::FilePath(util::kDriveOtherDirName)) {
643      found_other = true;
644    } else if (title == base::FilePath(util::kDriveMyDriveRootDirName)) {
645      found_my_drive = true;
646    }
647  }
648
649  EXPECT_TRUE(found_other);
650  EXPECT_TRUE(found_my_drive);
651}
652
653TEST_F(DriveFileSystemTest, ReadDirectoryByPath_NonRootDirectory) {
654  // ReadDirectoryByPath() should kick off the resource list loading.
655  scoped_ptr<ResourceEntryVector> entries(
656      ReadDirectoryByPathSync(
657          base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
658  // The non root directory should also be read correctly.
659  // There was a bug (crbug.com/181487), which broke this behavior.
660  // Make sure this is fixed.
661  ASSERT_TRUE(entries);
662  EXPECT_EQ(3U, entries->size());
663}
664
665TEST_F(DriveFileSystemTest, ChangeFeed_AddAndDeleteFileInRoot) {
666  ASSERT_TRUE(LoadRootFeedDocument());
667
668  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
669      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(2);
670
671  ASSERT_TRUE(LoadChangeFeed("chromeos/gdata/delta_file_added_in_root.json"));
672  EXPECT_TRUE(EntryExists(
673      base::FilePath(FILE_PATH_LITERAL("drive/root/Added file.gdoc"))));
674
675  ASSERT_TRUE(LoadChangeFeed("chromeos/gdata/delta_file_deleted_in_root.json"));
676  EXPECT_FALSE(EntryExists(
677      base::FilePath(FILE_PATH_LITERAL("drive/root/Added file.gdoc"))));
678}
679
680TEST_F(DriveFileSystemTest, ChangeFeed_AddAndDeleteFileFromExistingDirectory) {
681  ASSERT_TRUE(LoadRootFeedDocument());
682
683  EXPECT_TRUE(
684      EntryExists(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1"))));
685
686  // Add file to an existing directory.
687  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
688      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
689  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
690      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
691      .Times(1);
692  ASSERT_TRUE(
693      LoadChangeFeed("chromeos/gdata/delta_file_added_in_directory.json"));
694  EXPECT_TRUE(EntryExists(base::FilePath(
695      FILE_PATH_LITERAL("drive/root/Directory 1/Added file.gdoc"))));
696
697  // Remove that file from the directory.
698  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
699      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
700      .Times(1);
701  ASSERT_TRUE(
702      LoadChangeFeed("chromeos/gdata/delta_file_deleted_in_directory.json"));
703  EXPECT_TRUE(
704      EntryExists(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1"))));
705  EXPECT_FALSE(EntryExists(base::FilePath(
706      FILE_PATH_LITERAL("drive/root/Directory 1/Added file.gdoc"))));
707}
708
709TEST_F(DriveFileSystemTest, ChangeFeed_AddFileToNewDirectory) {
710  ASSERT_TRUE(LoadRootFeedDocument());
711  // Add file to a new directory.
712  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
713      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
714  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
715      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/New Directory")))))
716      .Times(1);
717
718  ASSERT_TRUE(
719      LoadChangeFeed("chromeos/gdata/delta_file_added_in_new_directory.json"));
720
721  EXPECT_TRUE(
722      EntryExists(base::FilePath(
723          FILE_PATH_LITERAL("drive/root/New Directory"))));
724  EXPECT_TRUE(EntryExists(base::FilePath(
725      FILE_PATH_LITERAL("drive/root/New Directory/File in new dir.gdoc"))));
726}
727
728TEST_F(DriveFileSystemTest, ChangeFeed_AddFileToNewButDeletedDirectory) {
729  ASSERT_TRUE(LoadRootFeedDocument());
730
731  // This feed contains the following updates:
732  // 1) A new PDF file is added to a new directory
733  // 2) but the new directory is marked "deleted" (i.e. moved to Trash)
734  // Hence, the PDF file should be just ignored.
735  ASSERT_TRUE(LoadChangeFeed(
736      "chromeos/gdata/delta_file_added_in_new_but_deleted_directory.json"));
737}
738
739TEST_F(DriveFileSystemTest, ChangeFeed_DirectoryMovedFromRootToDirectory) {
740  ASSERT_TRUE(LoadRootFeedDocument());
741
742  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
743      "drive/root/Directory 2 excludeDir-test"))));
744  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
745      "drive/root/Directory 1"))));
746  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
747      "drive/root/Directory 1/SubDirectory File 1.txt"))));
748  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
749      "drive/root/Directory 1/Sub Directory Folder"))));
750  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
751      "drive/root/Directory 1/Sub Directory Folder/"
752      "Sub Sub Directory Folder"))));
753
754  // This will move "Directory 1" from "drive/root/" to
755  // "drive/root/Directory 2/".
756  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
757      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
758  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
759      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
760      .Times(1);
761  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
762      Eq(base::FilePath(FILE_PATH_LITERAL(
763          "drive/root/Directory 2 excludeDir-test"))))).Times(1);
764  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
765      Eq(base::FilePath(FILE_PATH_LITERAL(
766          "drive/root/Directory 2 excludeDir-test/Directory 1"))))).Times(1);
767  ASSERT_TRUE(LoadChangeFeed(
768      "chromeos/gdata/delta_dir_moved_from_root_to_directory.json"));
769
770  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
771      "drive/root/Directory 2 excludeDir-test"))));
772  EXPECT_FALSE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
773      "drive/root/Directory 1"))));
774  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
775      "drive/root/Directory 2 excludeDir-test/Directory 1"))));
776  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
777      "drive/root/Directory 2 excludeDir-test/Directory 1/"
778      "SubDirectory File 1.txt"))));
779  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
780      "drive/root/Directory 2 excludeDir-test/Directory 1/"
781      "Sub Directory Folder"))));
782  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
783      "drive/root/Directory 2 excludeDir-test/Directory 1/Sub Directory Folder/"
784      "Sub Sub Directory Folder"))));
785}
786
787TEST_F(DriveFileSystemTest, ChangeFeed_FileMovedFromDirectoryToRoot) {
788  ASSERT_TRUE(LoadRootFeedDocument());
789
790  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
791      "drive/root/Directory 1"))));
792  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
793      "drive/root/Directory 1/Sub Directory Folder"))));
794  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
795      "drive/root/Directory 1/Sub Directory Folder/"
796      "Sub Sub Directory Folder"))));
797  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
798      "drive/root/Directory 1/SubDirectory File 1.txt"))));
799
800  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
801      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
802  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
803      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
804      .Times(1);
805  ASSERT_TRUE(LoadChangeFeed(
806      "chromeos/gdata/delta_file_moved_from_directory_to_root.json"));
807
808  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
809      "drive/root/Directory 1"))));
810  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
811      "drive/root/Directory 1/Sub Directory Folder"))));
812  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
813      "drive/root/Directory 1/Sub Directory Folder/"
814      "Sub Sub Directory Folder"))));
815  EXPECT_FALSE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
816      "drive/root/Directory 1/SubDirectory File 1.txt"))));
817  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
818      "drive/root/SubDirectory File 1.txt"))));
819}
820
821TEST_F(DriveFileSystemTest, ChangeFeed_FileRenamedInDirectory) {
822  ASSERT_TRUE(LoadRootFeedDocument());
823
824  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
825      "drive/root/Directory 1"))));
826  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
827      "drive/root/Directory 1/SubDirectory File 1.txt"))));
828
829  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
830      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
831  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
832      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
833      .Times(1);
834  ASSERT_TRUE(LoadChangeFeed(
835      "chromeos/gdata/delta_file_renamed_in_directory.json"));
836
837  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
838      "drive/root/Directory 1"))));
839  EXPECT_FALSE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
840      "drive/root/Directory 1/SubDirectory File 1.txt"))));
841  EXPECT_TRUE(EntryExists(base::FilePath(FILE_PATH_LITERAL(
842      "drive/root/Directory 1/New SubDirectory File 1.txt"))));
843}
844
845TEST_F(DriveFileSystemTest, CachedFeedLoadingThenServerFeedLoading) {
846  ASSERT_TRUE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
847
848  // Kicks loading of cached file system and query for server update.
849  EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveMyDriveRootPath()));
850
851  // SetUpTestFileSystem and "account_metadata.json" have the same changestamp,
852  // so no request for new feeds (i.e., call to GetResourceList) should happen.
853  EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
854  EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
855
856  // Since the file system has verified that it holds the latest snapshot,
857  // it should change its state to "loaded", which admits periodic refresh.
858  // To test it, call CheckForUpdates and verify it does try to check updates.
859  file_system_->CheckForUpdates();
860  google_apis::test_util::RunBlockingPoolTask();
861  EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
862}
863
864TEST_F(DriveFileSystemTest, OfflineCachedFeedLoading) {
865  ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
866
867  // Make GetResourceList fail for simulating offline situation. This will leave
868  // the file system "loaded from cache, but not synced with server" state.
869  fake_drive_service_->set_offline(true);
870
871  // Kicks loading of cached file system and query for server update.
872  EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveMyDriveRootPath()));
873  // Loading of about resource should not happen as it's offline.
874  EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
875
876  // Tests that cached data can be loaded even if the server is not reachable.
877  EXPECT_TRUE(EntryExists(base::FilePath(
878      FILE_PATH_LITERAL("drive/root/File1"))));
879  EXPECT_TRUE(EntryExists(base::FilePath(
880      FILE_PATH_LITERAL("drive/root/Dir1"))));
881  EXPECT_TRUE(
882      EntryExists(base::FilePath(FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
883  EXPECT_TRUE(EntryExists(base::FilePath(
884      FILE_PATH_LITERAL("drive/root/Dir1/SubDir2"))));
885  EXPECT_TRUE(EntryExists(
886      base::FilePath(FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"))));
887
888  // Since the file system has at least succeeded to load cached snapshot,
889  // the file system should be able to start periodic refresh.
890  // To test it, call CheckForUpdates and verify it does try to check
891  // updates, which will cause directory changes.
892  fake_drive_service_->set_offline(false);
893
894  file_system_->CheckForUpdates();
895  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(_))
896      .Times(AtLeast(1));
897
898  google_apis::test_util::RunBlockingPoolTask();
899  EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
900  EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
901}
902
903TEST_F(DriveFileSystemTest, ReadDirectoryWhileRefreshing) {
904  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(_))
905      .Times(AtLeast(1));
906
907  // Enter the "refreshing" state so the fast fetch will be performed.
908  ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
909  file_system_->CheckForUpdates();
910
911  // The list of resources in "drive/root/Dir1" should be fetched.
912  EXPECT_TRUE(ReadDirectoryByPathSync(base::FilePath(
913      FILE_PATH_LITERAL("drive/root/Dir1"))));
914  EXPECT_EQ(1, fake_drive_service_->directory_load_count());
915}
916
917TEST_F(DriveFileSystemTest, GetResourceEntryExistingWhileRefreshing) {
918  // Enter the "refreshing" state.
919  ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
920  file_system_->CheckForUpdates();
921
922  // If an entry is already found in local metadata, no directory fetch happens.
923  EXPECT_TRUE(GetResourceEntryByPathSync(base::FilePath(
924      FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
925  EXPECT_EQ(0, fake_drive_service_->directory_load_count());
926}
927
928TEST_F(DriveFileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
929  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(_))
930      .Times(AtLeast(1));
931
932  // Enter the "refreshing" state so the fast fetch will be performed.
933  ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
934  file_system_->CheckForUpdates();
935
936  // If an entry is not found, parent directory's resource list is fetched.
937  EXPECT_FALSE(GetResourceEntryByPathSync(base::FilePath(
938      FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
939  EXPECT_EQ(1, fake_drive_service_->directory_load_count());
940}
941
942TEST_F(DriveFileSystemTest, TransferFileFromLocalToRemote_RegularFile) {
943  fake_free_disk_space_getter_->set_fake_free_disk_space(kLotsOfSpace);
944
945  ASSERT_TRUE(LoadRootFeedDocument());
946
947  // We'll add a file to the Drive root directory.
948  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
949      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
950
951  // Prepare a local file.
952  base::ScopedTempDir temp_dir;
953  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
954  const base::FilePath local_src_file_path =
955      temp_dir.path().AppendASCII("local.txt");
956  ASSERT_TRUE(
957      google_apis::test_util::WriteStringToFile(local_src_file_path, "hello"));
958
959  // Confirm that the remote file does not exist.
960  const base::FilePath remote_dest_file_path(
961      FILE_PATH_LITERAL("drive/root/remote.txt"));
962  EXPECT_FALSE(EntryExists(remote_dest_file_path));
963
964  // What TransferFileFromLocalToRemote does is to store the local file in
965  // the Drive file cache, and mark it as dirty+committed. Here we test that
966  // the "cache committed" event is indeed fired as a result of this test case.
967  //
968  // In the production environment, SyncClient listens this event and uploads
969  // the file to the remote server in background. This part should be tested in
970  // sync_client_unittest.cc
971  EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(_)).Times(1);
972
973  // Transfer the local file to Drive.
974  FileError error = FILE_ERROR_FAILED;
975  file_system_->TransferFileFromLocalToRemote(
976      local_src_file_path,
977      remote_dest_file_path,
978      google_apis::test_util::CreateCopyResultCallback(&error));
979  google_apis::test_util::RunBlockingPoolTask();
980
981  EXPECT_EQ(FILE_ERROR_OK, error);
982
983  // Now the remote file should exist.
984  EXPECT_TRUE(EntryExists(remote_dest_file_path));
985}
986
987TEST_F(DriveFileSystemTest, TransferFileFromLocalToRemote_HostedDocument) {
988  ASSERT_TRUE(LoadRootFeedDocument());
989
990  // Prepare a local file, which is a json file of a hosted document, which
991  // matches "Document 1" in root_feed.json.
992  base::ScopedTempDir temp_dir;
993  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
994  const base::FilePath local_src_file_path =
995      temp_dir.path().AppendASCII("local.gdoc");
996  const std::string kEditUrl =
997      "https://3_document_self_link/document:5_document_resource_id";
998  const std::string kResourceId = "document:5_document_resource_id";
999  ASSERT_TRUE(google_apis::test_util::WriteStringToFile(
1000      local_src_file_path,
1001      base::StringPrintf("{\"url\": \"%s\", \"resource_id\": \"%s\"}",
1002                         kEditUrl.c_str(), kResourceId.c_str())));
1003
1004  // Confirm that the remote file does not exist.
1005  const base::FilePath remote_dest_file_path(FILE_PATH_LITERAL(
1006      "drive/root/Directory 1/Document 1 excludeDir-test.gdoc"));
1007  EXPECT_FALSE(EntryExists(remote_dest_file_path));
1008
1009  // We'll add a file to the Drive root and then move to "Directory 1".
1010  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1011      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1012  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1013      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
1014      .Times(1);
1015
1016  // Transfer the local file to Drive.
1017  FileError error = FILE_ERROR_FAILED;
1018  file_system_->TransferFileFromLocalToRemote(
1019      local_src_file_path,
1020      remote_dest_file_path,
1021      google_apis::test_util::CreateCopyResultCallback(&error));
1022  google_apis::test_util::RunBlockingPoolTask();
1023
1024  EXPECT_EQ(FILE_ERROR_OK, error);
1025
1026  // Now the remote file should exist.
1027  EXPECT_TRUE(EntryExists(remote_dest_file_path));
1028}
1029
1030TEST_F(DriveFileSystemTest, TransferFileFromRemoteToLocal_RegularFile) {
1031  ASSERT_TRUE(LoadRootFeedDocument());
1032
1033  // The transfered file is cached and the change of "offline available"
1034  // attribute is notified.
1035  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1036      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1037
1038  base::ScopedTempDir temp_dir;
1039  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1040  base::FilePath local_dest_file_path =
1041      temp_dir.path().AppendASCII("local_copy.txt");
1042
1043  base::FilePath remote_src_file_path(
1044      FILE_PATH_LITERAL("drive/root/File 1.txt"));
1045  scoped_ptr<ResourceEntry> file = GetResourceEntryByPathSync(
1046      remote_src_file_path);
1047  const int64 file_size = file->file_info().size();
1048
1049  // Pretend we have enough space.
1050  fake_free_disk_space_getter_->set_fake_free_disk_space(
1051      file_size + internal::kMinFreeSpace);
1052
1053  FileError error = FILE_ERROR_FAILED;
1054  file_system_->TransferFileFromRemoteToLocal(
1055      remote_src_file_path,
1056      local_dest_file_path,
1057      google_apis::test_util::CreateCopyResultCallback(&error));
1058  google_apis::test_util::RunBlockingPoolTask();
1059
1060  EXPECT_EQ(FILE_ERROR_OK, error);
1061
1062  // The content is "x"s of the file size.
1063  base::FilePath cache_file_path;
1064  cache_->GetFileOnUIThread(file->resource_id(),
1065                            file->file_specific_info().file_md5(),
1066                            google_apis::test_util::CreateCopyResultCallback(
1067                                &error, &cache_file_path));
1068  google_apis::test_util::RunBlockingPoolTask();
1069  EXPECT_EQ(FILE_ERROR_OK, error);
1070
1071  const std::string kExpectedContent = "xxxxxxxxxx";
1072  std::string cache_file_data;
1073  EXPECT_TRUE(file_util::ReadFileToString(cache_file_path, &cache_file_data));
1074  EXPECT_EQ(kExpectedContent, cache_file_data);
1075
1076  std::string local_dest_file_data;
1077  EXPECT_TRUE(file_util::ReadFileToString(local_dest_file_path,
1078                                          &local_dest_file_data));
1079  EXPECT_EQ(kExpectedContent, local_dest_file_data);
1080}
1081
1082TEST_F(DriveFileSystemTest, TransferFileFromRemoteToLocal_HostedDocument) {
1083  ASSERT_TRUE(LoadRootFeedDocument());
1084
1085  base::ScopedTempDir temp_dir;
1086  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1087  base::FilePath local_dest_file_path =
1088      temp_dir.path().AppendASCII("local_copy.txt");
1089  base::FilePath remote_src_file_path(
1090      FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
1091  FileError error = FILE_ERROR_FAILED;
1092  file_system_->TransferFileFromRemoteToLocal(
1093      remote_src_file_path,
1094      local_dest_file_path,
1095      google_apis::test_util::CreateCopyResultCallback(&error));
1096  google_apis::test_util::RunBlockingPoolTask();
1097
1098  EXPECT_EQ(FILE_ERROR_OK, error);
1099
1100  scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(
1101      remote_src_file_path);
1102  ASSERT_TRUE(entry);
1103  VerifyHostedDocumentJSONFile(*entry, local_dest_file_path);
1104}
1105
1106TEST_F(DriveFileSystemTest, CopyNotExistingFile) {
1107  base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
1108  base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Test.log"));
1109
1110  ASSERT_TRUE(LoadRootFeedDocument());
1111
1112  EXPECT_FALSE(EntryExists(src_file_path));
1113
1114  FileError error = FILE_ERROR_OK;
1115  file_system_->Copy(
1116      src_file_path,
1117      dest_file_path,
1118      google_apis::test_util::CreateCopyResultCallback(&error));
1119  google_apis::test_util::RunBlockingPoolTask();
1120  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
1121
1122  EXPECT_FALSE(EntryExists(src_file_path));
1123  EXPECT_FALSE(EntryExists(dest_file_path));
1124}
1125
1126TEST_F(DriveFileSystemTest, CopyFileToNonExistingDirectory) {
1127  base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1128  base::FilePath dest_parent_path(FILE_PATH_LITERAL("drive/root/Dummy"));
1129  base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Dummy/Test.log"));
1130
1131  ASSERT_TRUE(LoadRootFeedDocument());
1132
1133  ASSERT_TRUE(EntryExists(src_file_path));
1134  scoped_ptr<ResourceEntry> src_entry = GetResourceEntryByPathSync(
1135      src_file_path);
1136  ASSERT_TRUE(src_entry);
1137  std::string src_file_path_resource_id = src_entry->resource_id();
1138
1139  EXPECT_FALSE(EntryExists(dest_parent_path));
1140
1141  FileError error = FILE_ERROR_OK;
1142  file_system_->Move(
1143      src_file_path,
1144      dest_file_path,
1145      google_apis::test_util::CreateCopyResultCallback(&error));
1146  google_apis::test_util::RunBlockingPoolTask();
1147  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
1148
1149  EXPECT_TRUE(EntryExists(src_file_path));
1150  EXPECT_FALSE(EntryExists(dest_parent_path));
1151  EXPECT_FALSE(EntryExists(dest_file_path));
1152}
1153
1154// Test the case where the parent of |dest_file_path| is an existing file,
1155// not a directory.
1156TEST_F(DriveFileSystemTest, CopyFileToInvalidPath) {
1157  base::FilePath src_file_path(FILE_PATH_LITERAL(
1158      "drive/root/Document 1 excludeDir-test.gdoc"));
1159  base::FilePath dest_parent_path(
1160      FILE_PATH_LITERAL("drive/root/Duplicate Name.txt"));
1161  base::FilePath dest_file_path(FILE_PATH_LITERAL(
1162      "drive/root/Duplicate Name.txt/Document 1 excludeDir-test.gdoc"));
1163
1164  ASSERT_TRUE(LoadRootFeedDocument());
1165
1166  ASSERT_TRUE(EntryExists(src_file_path));
1167  scoped_ptr<ResourceEntry> src_entry = GetResourceEntryByPathSync(
1168      src_file_path);
1169  ASSERT_TRUE(src_entry);
1170  std::string src_file_resource_id = src_entry->resource_id();
1171
1172  ASSERT_TRUE(EntryExists(dest_parent_path));
1173  scoped_ptr<ResourceEntry> dest_entry = GetResourceEntryByPathSync(
1174      dest_parent_path);
1175  ASSERT_TRUE(dest_entry);
1176
1177  FileError error = FILE_ERROR_OK;
1178  file_system_->Copy(
1179      src_file_path,
1180      dest_file_path,
1181      google_apis::test_util::CreateCopyResultCallback(&error));
1182  google_apis::test_util::RunBlockingPoolTask();
1183  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
1184
1185  EXPECT_TRUE(EntryExists(src_file_path));
1186  EXPECT_TRUE(EntryExists(src_file_path));
1187  EXPECT_TRUE(EntryExists(dest_parent_path));
1188
1189  EXPECT_FALSE(EntryExists(dest_file_path));
1190}
1191
1192TEST_F(DriveFileSystemTest, RenameFile) {
1193  const base::FilePath src_file_path(
1194      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
1195  const base::FilePath src_parent_path(
1196      FILE_PATH_LITERAL("drive/root/Directory 1"));
1197  const base::FilePath dest_file_path(
1198      FILE_PATH_LITERAL("drive/root/Directory 1/Test.log"));
1199
1200  ASSERT_TRUE(LoadRootFeedDocument());
1201
1202  ASSERT_TRUE(EntryExists(src_file_path));
1203  scoped_ptr<ResourceEntry> src_entry = GetResourceEntryByPathSync(
1204      src_file_path);
1205  ASSERT_TRUE(src_entry);
1206  std::string src_file_resource_id =
1207      src_entry->resource_id();
1208
1209  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1210      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
1211      .Times(1);
1212
1213  FileError error = FILE_ERROR_FAILED;
1214  file_system_->Move(
1215      src_file_path,
1216      dest_file_path,
1217      google_apis::test_util::CreateCopyResultCallback(&error));
1218  google_apis::test_util::RunBlockingPoolTask();
1219  EXPECT_EQ(FILE_ERROR_OK, error);
1220
1221  EXPECT_FALSE(EntryExists(src_file_path));
1222  EXPECT_TRUE(EntryExists(dest_file_path));
1223  EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path));
1224}
1225
1226TEST_F(DriveFileSystemTest, MoveFileFromRootToSubDirectory) {
1227  base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1228  base::FilePath dest_parent_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
1229  base::FilePath dest_file_path(
1230      FILE_PATH_LITERAL("drive/root/Directory 1/Test.log"));
1231
1232  ASSERT_TRUE(LoadRootFeedDocument());
1233
1234  ASSERT_TRUE(EntryExists(src_file_path));
1235  scoped_ptr<ResourceEntry> src_entry = GetResourceEntryByPathSync(
1236      src_file_path);
1237  ASSERT_TRUE(src_entry);
1238  std::string src_file_resource_id = src_entry->resource_id();
1239
1240  ASSERT_TRUE(EntryExists(dest_parent_path));
1241  scoped_ptr<ResourceEntry> dest_parent_proto = GetResourceEntryByPathSync(
1242      dest_parent_path);
1243  ASSERT_TRUE(dest_parent_proto);
1244  ASSERT_TRUE(dest_parent_proto->file_info().is_directory());
1245
1246  // Expect notification for both source and destination directories.
1247  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1248      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1249  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1250      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
1251      .Times(1);
1252
1253  FileError error = FILE_ERROR_FAILED;
1254  file_system_->Move(
1255      src_file_path,
1256      dest_file_path,
1257      google_apis::test_util::CreateCopyResultCallback(&error));
1258  google_apis::test_util::RunBlockingPoolTask();
1259  EXPECT_EQ(FILE_ERROR_OK, error);
1260
1261  EXPECT_FALSE(EntryExists(src_file_path));
1262  EXPECT_TRUE(EntryExists(dest_file_path));
1263  EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path));
1264}
1265
1266TEST_F(DriveFileSystemTest, MoveFileFromSubDirectoryToRoot) {
1267  base::FilePath src_parent_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
1268  base::FilePath src_file_path(
1269      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
1270  base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Test.log"));
1271
1272  ASSERT_TRUE(LoadRootFeedDocument());
1273
1274  ASSERT_TRUE(EntryExists(src_file_path));
1275  scoped_ptr<ResourceEntry> src_entry = GetResourceEntryByPathSync(
1276      src_file_path);
1277  ASSERT_TRUE(src_entry);
1278  std::string src_file_resource_id = src_entry->resource_id();
1279
1280  ASSERT_TRUE(EntryExists(src_parent_path));
1281  scoped_ptr<ResourceEntry> src_parent_proto = GetResourceEntryByPathSync(
1282      src_parent_path);
1283  ASSERT_TRUE(src_parent_proto);
1284  ASSERT_TRUE(src_parent_proto->file_info().is_directory());
1285
1286  // Expect notification for both source and destination directories.
1287  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1288      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1289  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1290      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
1291      .Times(1);
1292
1293  FileError error = FILE_ERROR_FAILED;
1294  file_system_->Move(
1295      src_file_path,
1296      dest_file_path,
1297      google_apis::test_util::CreateCopyResultCallback(&error));
1298  google_apis::test_util::RunBlockingPoolTask();
1299  EXPECT_EQ(FILE_ERROR_OK, error);
1300
1301  EXPECT_FALSE(EntryExists(src_file_path));
1302  ASSERT_TRUE(EntryExists(dest_file_path));
1303  EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path));
1304}
1305
1306TEST_F(DriveFileSystemTest, MoveFileBetweenSubDirectories) {
1307  base::FilePath src_parent_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
1308  base::FilePath src_file_path(
1309      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
1310  base::FilePath dest_parent_path(FILE_PATH_LITERAL("drive/root/New Folder 1"));
1311  base::FilePath dest_file_path(
1312      FILE_PATH_LITERAL("drive/root/New Folder 1/Test.log"));
1313  base::FilePath interim_file_path(FILE_PATH_LITERAL("drive/root/Test.log"));
1314
1315  ASSERT_TRUE(LoadRootFeedDocument());
1316
1317  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1318      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1319
1320  EXPECT_EQ(FILE_ERROR_OK, AddDirectory(dest_parent_path));
1321
1322  ASSERT_TRUE(EntryExists(src_file_path));
1323  scoped_ptr<ResourceEntry> src_entry = GetResourceEntryByPathSync(
1324      src_file_path);
1325  ASSERT_TRUE(src_entry);
1326  std::string src_file_resource_id = src_entry->resource_id();
1327
1328  ASSERT_TRUE(EntryExists(src_parent_path));
1329  scoped_ptr<ResourceEntry> src_parent_proto = GetResourceEntryByPathSync(
1330      src_parent_path);
1331  ASSERT_TRUE(src_parent_proto);
1332  ASSERT_TRUE(src_parent_proto->file_info().is_directory());
1333
1334  ASSERT_TRUE(EntryExists(dest_parent_path));
1335  scoped_ptr<ResourceEntry> dest_parent_proto = GetResourceEntryByPathSync(
1336      dest_parent_path);
1337  ASSERT_TRUE(dest_parent_proto);
1338  ASSERT_TRUE(dest_parent_proto->file_info().is_directory());
1339
1340  EXPECT_FALSE(EntryExists(interim_file_path));
1341
1342  // Expect notification for both source and destination directories.
1343  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1344      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/Directory 1")))))
1345      .Times(1);
1346  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1347      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/New Folder 1")))))
1348      .Times(1);
1349
1350  FileError error = FILE_ERROR_FAILED;
1351  file_system_->Move(
1352      src_file_path,
1353      dest_file_path,
1354      google_apis::test_util::CreateCopyResultCallback(&error));
1355  google_apis::test_util::RunBlockingPoolTask();
1356  EXPECT_EQ(FILE_ERROR_OK, error);
1357
1358  EXPECT_FALSE(EntryExists(src_file_path));
1359  EXPECT_FALSE(EntryExists(interim_file_path));
1360
1361  EXPECT_FALSE(EntryExists(src_file_path));
1362  EXPECT_TRUE(EntryExists(dest_file_path));
1363  EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path));
1364}
1365
1366TEST_F(DriveFileSystemTest, MoveNotExistingFile) {
1367  base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
1368  base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Test.log"));
1369
1370  ASSERT_TRUE(LoadRootFeedDocument());
1371
1372  EXPECT_FALSE(EntryExists(src_file_path));
1373
1374  FileError error = FILE_ERROR_OK;
1375  file_system_->Move(
1376      src_file_path,
1377      dest_file_path,
1378      google_apis::test_util::CreateCopyResultCallback(&error));
1379  google_apis::test_util::RunBlockingPoolTask();
1380  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
1381
1382  EXPECT_FALSE(EntryExists(src_file_path));
1383  EXPECT_FALSE(EntryExists(dest_file_path));
1384}
1385
1386TEST_F(DriveFileSystemTest, MoveFileToNonExistingDirectory) {
1387  base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1388  base::FilePath dest_parent_path(FILE_PATH_LITERAL("drive/root/Dummy"));
1389  base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Dummy/Test.log"));
1390
1391  ASSERT_TRUE(LoadRootFeedDocument());
1392
1393  ASSERT_TRUE(EntryExists(src_file_path));
1394  scoped_ptr<ResourceEntry> src_entry = GetResourceEntryByPathSync(
1395      src_file_path);
1396  ASSERT_TRUE(src_entry);
1397  std::string src_file_resource_id = src_entry->resource_id();
1398
1399  EXPECT_FALSE(EntryExists(dest_parent_path));
1400
1401  FileError error = FILE_ERROR_OK;
1402  file_system_->Move(
1403      src_file_path,
1404      dest_file_path,
1405      google_apis::test_util::CreateCopyResultCallback(&error));
1406  google_apis::test_util::RunBlockingPoolTask();
1407  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
1408
1409  EXPECT_FALSE(EntryExists(dest_parent_path));
1410  EXPECT_FALSE(EntryExists(dest_file_path));
1411}
1412
1413// Test the case where the parent of |dest_file_path| is a existing file,
1414// not a directory.
1415TEST_F(DriveFileSystemTest, MoveFileToInvalidPath) {
1416  base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1417  base::FilePath dest_parent_path(
1418      FILE_PATH_LITERAL("drive/root/Duplicate Name.txt"));
1419  base::FilePath dest_file_path(FILE_PATH_LITERAL(
1420      "drive/root/Duplicate Name.txt/Test.log"));
1421
1422  ASSERT_TRUE(LoadRootFeedDocument());
1423
1424  ASSERT_TRUE(EntryExists(src_file_path));
1425  scoped_ptr<ResourceEntry> src_entry = GetResourceEntryByPathSync(
1426      src_file_path);
1427  ASSERT_TRUE(src_entry);
1428  std::string src_file_resource_id = src_entry->resource_id();
1429
1430  ASSERT_TRUE(EntryExists(dest_parent_path));
1431  scoped_ptr<ResourceEntry> dest_parent_proto = GetResourceEntryByPathSync(
1432      dest_parent_path);
1433  ASSERT_TRUE(dest_parent_proto);
1434
1435  FileError error = FILE_ERROR_OK;
1436  file_system_->Move(
1437      src_file_path,
1438      dest_file_path,
1439      google_apis::test_util::CreateCopyResultCallback(&error));
1440  google_apis::test_util::RunBlockingPoolTask();
1441  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
1442
1443  EXPECT_TRUE(EntryExists(src_file_path));
1444  EXPECT_TRUE(EntryExists(dest_parent_path));
1445  EXPECT_FALSE(EntryExists(dest_file_path));
1446}
1447
1448TEST_F(DriveFileSystemTest, RemoveEntries) {
1449  ASSERT_TRUE(LoadRootFeedDocument());
1450
1451  base::FilePath nonexisting_file(
1452      FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
1453  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1454  base::FilePath dir_in_root(FILE_PATH_LITERAL("drive/root/Directory 1"));
1455  base::FilePath file_in_subdir(
1456      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
1457
1458  ASSERT_TRUE(EntryExists(file_in_root));
1459  scoped_ptr<ResourceEntry> file_in_root_proto = GetResourceEntryByPathSync(
1460      file_in_root);
1461  ASSERT_TRUE(file_in_root_proto);
1462
1463  ASSERT_TRUE(EntryExists(dir_in_root));
1464  scoped_ptr<ResourceEntry> dir_in_root_proto = GetResourceEntryByPathSync(
1465      dir_in_root);
1466  ASSERT_TRUE(dir_in_root_proto);
1467  ASSERT_TRUE(dir_in_root_proto->file_info().is_directory());
1468
1469  ASSERT_TRUE(EntryExists(file_in_subdir));
1470  scoped_ptr<ResourceEntry> file_in_subdir_proto = GetResourceEntryByPathSync(
1471      file_in_subdir);
1472  ASSERT_TRUE(file_in_subdir_proto);
1473
1474  // Once for file in root and once for file...
1475  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1476      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(2);
1477
1478  // Remove first file in root.
1479  EXPECT_TRUE(RemoveEntry(file_in_root));
1480  EXPECT_FALSE(EntryExists(file_in_root));
1481  EXPECT_TRUE(EntryExists(dir_in_root));
1482  EXPECT_TRUE(EntryExists(file_in_subdir));
1483
1484  // Remove directory.
1485  EXPECT_TRUE(RemoveEntry(dir_in_root));
1486  EXPECT_FALSE(EntryExists(file_in_root));
1487  EXPECT_FALSE(EntryExists(dir_in_root));
1488  EXPECT_FALSE(EntryExists(file_in_subdir));
1489
1490  // Try removing file in already removed subdirectory.
1491  EXPECT_FALSE(RemoveEntry(file_in_subdir));
1492
1493  // Try removing non-existing file.
1494  EXPECT_FALSE(RemoveEntry(nonexisting_file));
1495
1496  // Try removing root file element.
1497  EXPECT_FALSE(RemoveEntry(base::FilePath(FILE_PATH_LITERAL("drive/root"))));
1498
1499  // Need this to ensure OnDirectoryChanged() is run.
1500  google_apis::test_util::RunBlockingPoolTask();
1501}
1502
1503TEST_F(DriveFileSystemTest, CreateDirectory) {
1504  ASSERT_TRUE(LoadRootFeedDocument());
1505
1506  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1507      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1508
1509  // Create directory in root.
1510  base::FilePath dir_path(FILE_PATH_LITERAL("drive/root/New Folder 1"));
1511  EXPECT_FALSE(EntryExists(dir_path));
1512  EXPECT_EQ(FILE_ERROR_OK, AddDirectory(dir_path));
1513  EXPECT_TRUE(EntryExists(dir_path));
1514
1515  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1516      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root/New Folder 1")))))
1517      .Times(1);
1518
1519  // Create directory in a sub directory.
1520  base::FilePath subdir_path(
1521      FILE_PATH_LITERAL("drive/root/New Folder 1/New Folder 2"));
1522  EXPECT_FALSE(EntryExists(subdir_path));
1523  EXPECT_EQ(FILE_ERROR_OK, AddDirectory(subdir_path));
1524  EXPECT_TRUE(EntryExists(subdir_path));
1525}
1526
1527TEST_F(DriveFileSystemTest, CreateDirectoryByImplicitLoad) {
1528  // Intentionally *not* calling LoadRootFeedDocument(), for testing that
1529  // CreateDirectory ensures feed loading before it runs.
1530
1531  base::FilePath existing_directory(
1532      FILE_PATH_LITERAL("drive/root/Directory 1"));
1533  FileError error = FILE_ERROR_FAILED;
1534  file_system_->CreateDirectory(
1535      existing_directory,
1536      true,  // is_exclusive
1537      false,  // is_recursive
1538      google_apis::test_util::CreateCopyResultCallback(&error));
1539  google_apis::test_util::RunBlockingPoolTask();
1540
1541  // It should fail because is_exclusive is set to true.
1542  EXPECT_EQ(FILE_ERROR_EXISTS, error);
1543}
1544
1545TEST_F(DriveFileSystemTest, PinAndUnpin) {
1546  ASSERT_TRUE(LoadRootFeedDocument());
1547
1548  base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1549
1550  // Get the file info.
1551  scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_path));
1552  ASSERT_TRUE(entry);
1553
1554  // Pin the file.
1555  FileError error = FILE_ERROR_FAILED;
1556  EXPECT_CALL(*mock_cache_observer_,
1557              OnCachePinned(entry->resource_id(),
1558                            entry->file_specific_info().file_md5())).Times(1);
1559  file_system_->Pin(file_path,
1560                    google_apis::test_util::CreateCopyResultCallback(&error));
1561  google_apis::test_util::RunBlockingPoolTask();
1562  EXPECT_EQ(FILE_ERROR_OK, error);
1563
1564  // Unpin the file.
1565  error = FILE_ERROR_FAILED;
1566  EXPECT_CALL(*mock_cache_observer_,
1567              OnCacheUnpinned(entry->resource_id(),
1568                              entry->file_specific_info().file_md5())).Times(1);
1569  file_system_->Unpin(file_path,
1570                      google_apis::test_util::CreateCopyResultCallback(&error));
1571  google_apis::test_util::RunBlockingPoolTask();
1572  EXPECT_EQ(FILE_ERROR_OK, error);
1573}
1574
1575TEST_F(DriveFileSystemTest, GetFileByPath_FromGData_EnoughSpace) {
1576  ASSERT_TRUE(LoadRootFeedDocument());
1577
1578  // The transfered file is cached and the change of "offline available"
1579  // attribute is notified.
1580  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1581      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1582
1583  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1584  scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_in_root));
1585  const int64 file_size = entry->file_info().size();
1586
1587  // Pretend we have enough space.
1588  fake_free_disk_space_getter_->set_fake_free_disk_space(
1589      file_size + internal::kMinFreeSpace);
1590
1591  FileError error = FILE_ERROR_FAILED;
1592  base::FilePath file_path;
1593  entry.reset();
1594  file_system_->GetFileByPath(file_in_root,
1595                              google_apis::test_util::CreateCopyResultCallback(
1596                                  &error, &file_path, &entry));
1597  google_apis::test_util::RunBlockingPoolTask();
1598
1599  EXPECT_EQ(FILE_ERROR_OK, error);
1600  ASSERT_TRUE(entry);
1601  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
1602
1603  // Verify that readable permission is set.
1604  int permission = 0;
1605  EXPECT_TRUE(file_util::GetPosixFilePermissions(file_path, &permission));
1606  EXPECT_EQ(file_util::FILE_PERMISSION_READ_BY_USER |
1607            file_util::FILE_PERMISSION_WRITE_BY_USER |
1608            file_util::FILE_PERMISSION_READ_BY_GROUP |
1609            file_util::FILE_PERMISSION_READ_BY_OTHERS, permission);
1610}
1611
1612TEST_F(DriveFileSystemTest, GetFileByPath_FromGData_NoSpaceAtAll) {
1613  ASSERT_TRUE(LoadRootFeedDocument());
1614
1615  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1616
1617  // Pretend we have no space at all.
1618  fake_free_disk_space_getter_->set_fake_free_disk_space(0);
1619
1620  FileError error = FILE_ERROR_OK;
1621  base::FilePath file_path;
1622  scoped_ptr<ResourceEntry> entry;
1623  file_system_->GetFileByPath(file_in_root,
1624                              google_apis::test_util::CreateCopyResultCallback(
1625                                  &error, &file_path, &entry));
1626  google_apis::test_util::RunBlockingPoolTask();
1627
1628  EXPECT_EQ(FILE_ERROR_NO_SPACE, error);
1629}
1630
1631TEST_F(DriveFileSystemTest, GetFileByPath_FromGData_NoEnoughSpaceButCanFreeUp) {
1632  ASSERT_TRUE(LoadRootFeedDocument());
1633
1634  // The transfered file is cached and the change of "offline available"
1635  // attribute is notified.
1636  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1637      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1638
1639  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1640  scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_in_root));
1641  const int64 file_size = entry->file_info().size();
1642
1643  // Pretend we have no space first (checked before downloading a file),
1644  // but then start reporting we have space. This is to emulate that
1645  // the disk space was freed up by removing temporary files.
1646  fake_free_disk_space_getter_->set_fake_free_disk_space(
1647      file_size + internal::kMinFreeSpace);
1648  fake_free_disk_space_getter_->set_fake_free_disk_space(0);
1649  fake_free_disk_space_getter_->set_fake_free_disk_space(
1650      file_size + internal::kMinFreeSpace);
1651  fake_free_disk_space_getter_->set_fake_free_disk_space(
1652      file_size + internal::kMinFreeSpace);
1653
1654  // Store something of the file size in the temporary cache directory.
1655  const std::string content(file_size, 'x');
1656  base::ScopedTempDir temp_dir;
1657  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1658  const base::FilePath tmp_file =
1659      temp_dir.path().AppendASCII("something.txt");
1660  ASSERT_TRUE(google_apis::test_util::WriteStringToFile(tmp_file, content));
1661
1662  FileError error = FILE_ERROR_FAILED;
1663  cache_->StoreOnUIThread(
1664      "<resource_id>", "<md5>", tmp_file,
1665      internal::FileCache::FILE_OPERATION_COPY,
1666      google_apis::test_util::CreateCopyResultCallback(&error));
1667  google_apis::test_util::RunBlockingPoolTask();
1668  EXPECT_EQ(FILE_ERROR_OK, error);
1669  ASSERT_TRUE(CacheEntryExists("<resource_id>", "<md5>"));
1670
1671  base::FilePath file_path;
1672  entry.reset();
1673  file_system_->GetFileByPath(file_in_root,
1674                              google_apis::test_util::CreateCopyResultCallback(
1675                                  &error, &file_path, &entry));
1676  google_apis::test_util::RunBlockingPoolTask();
1677
1678  EXPECT_EQ(FILE_ERROR_OK, error);
1679  ASSERT_TRUE(entry);
1680  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
1681
1682  // The cache entry should be removed in order to free up space.
1683  ASSERT_FALSE(CacheEntryExists("<resource_id>", "<md5>"));
1684}
1685
1686TEST_F(DriveFileSystemTest, GetFileByPath_FromGData_EnoughSpaceButBecomeFull) {
1687  ASSERT_TRUE(LoadRootFeedDocument());
1688
1689  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1690  scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_in_root));
1691  const int64 file_size = entry->file_info().size();
1692
1693  // Pretend we have enough space first (checked before downloading a file),
1694  // but then start reporting we have not enough space. This is to emulate that
1695  // the disk space becomes full after the file is downloaded for some reason
1696  // (ex. the actual file was larger than the expected size).
1697  fake_free_disk_space_getter_->set_fake_free_disk_space(
1698      file_size + internal::kMinFreeSpace);
1699  fake_free_disk_space_getter_->set_fake_free_disk_space(
1700      internal::kMinFreeSpace - 1);
1701  fake_free_disk_space_getter_->set_fake_free_disk_space(
1702      internal::kMinFreeSpace - 1);
1703
1704  FileError error = FILE_ERROR_OK;
1705  base::FilePath file_path;
1706  entry.reset();
1707  file_system_->GetFileByPath(file_in_root,
1708                              google_apis::test_util::CreateCopyResultCallback(
1709                                  &error, &file_path, &entry));
1710  google_apis::test_util::RunBlockingPoolTask();
1711
1712  EXPECT_EQ(FILE_ERROR_NO_SPACE, error);
1713}
1714
1715TEST_F(DriveFileSystemTest, GetFileByPath_FromCache) {
1716  fake_free_disk_space_getter_->set_fake_free_disk_space(kLotsOfSpace);
1717
1718  ASSERT_TRUE(LoadRootFeedDocument());
1719
1720  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1721  scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_in_root));
1722
1723  // Store something as cached version of this file.
1724  FileError error = FILE_ERROR_OK;
1725  cache_->StoreOnUIThread(
1726      entry->resource_id(),
1727      entry->file_specific_info().file_md5(),
1728      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
1729      internal::FileCache::FILE_OPERATION_COPY,
1730      google_apis::test_util::CreateCopyResultCallback(&error));
1731  google_apis::test_util::RunBlockingPoolTask();
1732  EXPECT_EQ(FILE_ERROR_OK, error);
1733
1734  base::FilePath file_path;
1735  entry.reset();
1736  file_system_->GetFileByPath(file_in_root,
1737                              google_apis::test_util::CreateCopyResultCallback(
1738                                  &error, &file_path, &entry));
1739  google_apis::test_util::RunBlockingPoolTask();
1740
1741  EXPECT_EQ(FILE_ERROR_OK, error);
1742  ASSERT_TRUE(entry);
1743  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
1744}
1745
1746TEST_F(DriveFileSystemTest, GetFileByPath_HostedDocument) {
1747  ASSERT_TRUE(LoadRootFeedDocument());
1748
1749  base::FilePath file_in_root(FILE_PATH_LITERAL(
1750      "drive/root/Document 1 excludeDir-test.gdoc"));
1751  scoped_ptr<ResourceEntry> src_entry =
1752      GetResourceEntryByPathSync(file_in_root);
1753  ASSERT_TRUE(src_entry);
1754
1755  FileError error = FILE_ERROR_FAILED;
1756  base::FilePath file_path;
1757  scoped_ptr<ResourceEntry> entry;
1758  file_system_->GetFileByPath(file_in_root,
1759                              google_apis::test_util::CreateCopyResultCallback(
1760                                  &error, &file_path, &entry));
1761  google_apis::test_util::RunBlockingPoolTask();
1762
1763  EXPECT_EQ(FILE_ERROR_OK, error);
1764  ASSERT_TRUE(entry);
1765  EXPECT_TRUE(entry->file_specific_info().is_hosted_document());
1766  EXPECT_FALSE(file_path.empty());
1767
1768  ASSERT_TRUE(src_entry);
1769  VerifyHostedDocumentJSONFile(*src_entry, file_path);
1770}
1771
1772TEST_F(DriveFileSystemTest, GetFileByResourceId) {
1773  fake_free_disk_space_getter_->set_fake_free_disk_space(kLotsOfSpace);
1774
1775  // The transfered file is cached and the change of "offline available"
1776  // attribute is notified.
1777  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1778      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1779
1780  ASSERT_TRUE(LoadRootFeedDocument());
1781
1782  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1783  scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_in_root));
1784  std::string resource_id = entry->resource_id();
1785
1786  FileError error = FILE_ERROR_OK;
1787  base::FilePath file_path;
1788  entry.reset();
1789  file_system_->GetFileByResourceId(
1790      resource_id,
1791      DriveClientContext(USER_INITIATED),
1792      google_apis::test_util::CreateCopyResultCallback(
1793          &error, &file_path, &entry),
1794      google_apis::GetContentCallback());
1795  google_apis::test_util::RunBlockingPoolTask();
1796
1797  EXPECT_EQ(FILE_ERROR_OK, error);
1798  ASSERT_TRUE(entry);
1799  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
1800}
1801
1802TEST_F(DriveFileSystemTest, GetFileContentByPath) {
1803  fake_free_disk_space_getter_->set_fake_free_disk_space(kLotsOfSpace);
1804
1805  // The transfered file is cached and the change of "offline available"
1806  // attribute is notified.
1807  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
1808      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
1809
1810  ASSERT_TRUE(LoadRootFeedDocument());
1811
1812  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1813
1814  {
1815    FileError initialized_error = FILE_ERROR_FAILED;
1816    scoped_ptr<ResourceEntry> entry;
1817    base::FilePath local_path;
1818    base::Closure cancel_download;
1819
1820    std::vector<std::string> content_buffer;
1821
1822    FileError completion_error = FILE_ERROR_FAILED;
1823
1824    file_system_->GetFileContentByPath(
1825        file_in_root,
1826        google_apis::test_util::CreateCopyResultCallback(
1827            &initialized_error, &entry, &local_path, &cancel_download),
1828        base::Bind(&AppendContent, &content_buffer),
1829        google_apis::test_util::CreateCopyResultCallback(&completion_error));
1830    google_apis::test_util::RunBlockingPoolTask();
1831
1832    // For the first time, file is downloaded from the remote server.
1833    // In this case, |local_path| is empty while |cancel_download| is not.
1834    EXPECT_EQ(FILE_ERROR_OK, initialized_error);
1835    ASSERT_TRUE(entry);
1836    ASSERT_TRUE(local_path.empty());
1837    EXPECT_TRUE(!cancel_download.is_null());
1838    // Content is available through the second callback arguemnt.
1839    size_t content_size = 0;
1840    for (size_t i = 0; i < content_buffer.size(); ++i) {
1841      content_size += content_buffer[i].size();
1842    }
1843    EXPECT_EQ(static_cast<size_t>(entry->file_info().size()),
1844              content_size);
1845    EXPECT_EQ(FILE_ERROR_OK, completion_error);
1846  }
1847
1848  {
1849    FileError initialized_error = FILE_ERROR_FAILED;
1850    scoped_ptr<ResourceEntry> entry;
1851    base::FilePath local_path;
1852    base::Closure cancel_download;
1853
1854    std::vector<std::string> content_buffer;
1855
1856    FileError completion_error = FILE_ERROR_FAILED;
1857
1858    file_system_->GetFileContentByPath(
1859        file_in_root,
1860        google_apis::test_util::CreateCopyResultCallback(
1861            &initialized_error, &entry, &local_path, &cancel_download),
1862        base::Bind(&AppendContent, &content_buffer),
1863        google_apis::test_util::CreateCopyResultCallback(&completion_error));
1864    google_apis::test_util::RunBlockingPoolTask();
1865
1866    // Try second download. In this case, the file should be cached, so
1867    // |local_path| should not be empty while |cancel_download| is empty.
1868    EXPECT_EQ(FILE_ERROR_OK, initialized_error);
1869    ASSERT_TRUE(entry);
1870    ASSERT_TRUE(!local_path.empty());
1871    EXPECT_TRUE(cancel_download.is_null());
1872    // The content is available from the cache file.
1873    EXPECT_TRUE(content_buffer.empty());
1874    int64 local_file_size = 0;
1875    file_util::GetFileSize(local_path, &local_file_size);
1876    EXPECT_EQ(entry->file_info().size(), local_file_size);
1877    EXPECT_EQ(FILE_ERROR_OK, completion_error);
1878  }
1879}
1880
1881TEST_F(DriveFileSystemTest, GetFileByResourceId_FromCache) {
1882  fake_free_disk_space_getter_->set_fake_free_disk_space(kLotsOfSpace);
1883
1884  ASSERT_TRUE(LoadRootFeedDocument());
1885
1886  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1887  scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_in_root));
1888
1889  // Store something as cached version of this file.
1890  FileError error = FILE_ERROR_FAILED;
1891  cache_->StoreOnUIThread(
1892      entry->resource_id(),
1893      entry->file_specific_info().file_md5(),
1894      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
1895      internal::FileCache::FILE_OPERATION_COPY,
1896      google_apis::test_util::CreateCopyResultCallback(&error));
1897  google_apis::test_util::RunBlockingPoolTask();
1898  EXPECT_EQ(FILE_ERROR_OK, error);
1899
1900  // The file is obtained from the cache.
1901  // Hence the downloading should work even if the drive service is offline.
1902  fake_drive_service_->set_offline(true);
1903
1904  std::string resource_id = entry->resource_id();
1905  base::FilePath file_path;
1906  entry.reset();
1907  file_system_->GetFileByResourceId(
1908      resource_id,
1909      DriveClientContext(USER_INITIATED),
1910      google_apis::test_util::CreateCopyResultCallback(
1911          &error, &file_path, &entry),
1912      google_apis::GetContentCallback());
1913  google_apis::test_util::RunBlockingPoolTask();
1914
1915  EXPECT_EQ(FILE_ERROR_OK, error);
1916  ASSERT_TRUE(entry);
1917  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
1918}
1919
1920TEST_F(DriveFileSystemTest, UpdateFileByResourceId_PersistentFile) {
1921  fake_free_disk_space_getter_->set_fake_free_disk_space(kLotsOfSpace);
1922
1923  ASSERT_TRUE(LoadRootFeedDocument());
1924
1925  // This is a file defined in root_feed.json.
1926  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
1927  const std::string kResourceId("file:2_file_resource_id");
1928  const std::string kMd5("3b4382ebefec6e743578c76bbd0575ce");
1929
1930  // Pin the file so it'll be store in "persistent" directory.
1931  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(kResourceId, kMd5)).Times(1);
1932  FileError error = FILE_ERROR_OK;
1933  cache_->PinOnUIThread(
1934      kResourceId, kMd5,
1935      google_apis::test_util::CreateCopyResultCallback(&error));
1936  google_apis::test_util::RunBlockingPoolTask();
1937  EXPECT_EQ(FILE_ERROR_OK, error);
1938
1939  // First store a file to cache.
1940  cache_->StoreOnUIThread(
1941      kResourceId,
1942      kMd5,
1943      // Anything works.
1944      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
1945      internal::FileCache::FILE_OPERATION_COPY,
1946      google_apis::test_util::CreateCopyResultCallback(&error));
1947  google_apis::test_util::RunBlockingPoolTask();
1948  EXPECT_EQ(FILE_ERROR_OK, error);
1949
1950  // Add the dirty bit.
1951  cache_->MarkDirtyOnUIThread(
1952      kResourceId, kMd5,
1953      google_apis::test_util::CreateCopyResultCallback(&error));
1954  google_apis::test_util::RunBlockingPoolTask();
1955  EXPECT_EQ(FILE_ERROR_OK, error);
1956
1957  // Commit the dirty bit.
1958  EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(kResourceId)).Times(1);
1959  cache_->CommitDirtyOnUIThread(
1960      kResourceId, kMd5,
1961      google_apis::test_util::CreateCopyResultCallback(&error));
1962  google_apis::test_util::RunBlockingPoolTask();
1963  EXPECT_EQ(FILE_ERROR_OK, error);
1964
1965  // We'll notify the directory change to the observer upon completion.
1966  EXPECT_CALL(*mock_directory_observer_,
1967              OnDirectoryChanged(Eq(util::GetDriveMyDriveRootPath())))
1968      .Times(1);
1969
1970  // Check the number of files in the root directory. We'll compare the
1971  // number after updating a file.
1972  scoped_ptr<ResourceEntryVector> root_directory_entries(
1973      ReadDirectoryByPathSync(base::FilePath::FromUTF8Unsafe("drive/root")));
1974  ASSERT_TRUE(root_directory_entries);
1975  const int num_files_in_root = CountFiles(*root_directory_entries);
1976
1977  // The callback will be called upon completion of
1978  // UpdateFileByResourceId().
1979  file_system_->UpdateFileByResourceId(
1980      kResourceId,
1981      DriveClientContext(USER_INITIATED),
1982      google_apis::test_util::CreateCopyResultCallback(&error));
1983  google_apis::test_util::RunBlockingPoolTask();
1984  EXPECT_EQ(FILE_ERROR_OK, error);
1985
1986  // Make sure that the number of files did not change (i.e. we updated an
1987  // existing file, rather than adding a new file. The number of files
1988  // increases if we don't handle the file update right).
1989  EXPECT_EQ(num_files_in_root, CountFiles(*root_directory_entries));
1990}
1991
1992TEST_F(DriveFileSystemTest, UpdateFileByResourceId_NonexistentFile) {
1993  ASSERT_TRUE(LoadRootFeedDocument());
1994
1995  // This is nonexistent in root_feed.json.
1996  const base::FilePath kFilePath(
1997      FILE_PATH_LITERAL("drive/root/Nonexistent.txt"));
1998  const std::string kResourceId("file:nonexistent_resource_id");
1999  const std::string kMd5("nonexistent_md5");
2000
2001  // The callback will be called upon completion of
2002  // UpdateFileByResourceId().
2003  FileError error = FILE_ERROR_OK;
2004  file_system_->UpdateFileByResourceId(
2005      kResourceId,
2006      DriveClientContext(USER_INITIATED),
2007      google_apis::test_util::CreateCopyResultCallback(&error));
2008  google_apis::test_util::RunBlockingPoolTask();
2009  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
2010}
2011
2012TEST_F(DriveFileSystemTest, ContentSearch) {
2013  ASSERT_TRUE(LoadRootFeedDocument());
2014
2015  const SearchResultPair kExpectedResults[] = {
2016    { "drive/root/Directory 1/Sub Directory Folder/Sub Sub Directory Folder",
2017      true },
2018    { "drive/root/Directory 1/Sub Directory Folder", true },
2019    { "drive/root/Directory 1/SubDirectory File 1.txt", false },
2020    { "drive/root/Directory 1", true },
2021    { "drive/root/Directory 2 excludeDir-test", true },
2022  };
2023
2024  SearchCallback callback = base::Bind(
2025      &DriveSearchCallback,
2026      &message_loop_,
2027      kExpectedResults, ARRAYSIZE_UNSAFE(kExpectedResults),
2028      GURL());
2029
2030  file_system_->Search("Directory", GURL(), callback);
2031  message_loop_.Run();  // Wait to get our result.
2032}
2033
2034TEST_F(DriveFileSystemTest, ContentSearchWithNewEntry) {
2035  ASSERT_TRUE(LoadRootFeedDocument());
2036
2037  // Create a new directory in the drive service.
2038  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
2039  scoped_ptr<google_apis::ResourceEntry> resource_entry;
2040  fake_drive_service_->AddNewDirectory(
2041      fake_drive_service_->GetRootResourceId(),  // Add to the root directory.
2042      "New Directory 1!",
2043      google_apis::test_util::CreateCopyResultCallback(
2044          &error, &resource_entry));
2045  message_loop_.RunUntilIdle();
2046
2047  // As the result of the first Search(), only entries in the current file
2048  // system snapshot are expected to be returned (i.e. "New Directory 1!"
2049  // shouldn't be included in the search result even though it matches
2050  // "Directory 1".
2051  const SearchResultPair kExpectedResults[] = {
2052    { "drive/root/Directory 1", true }
2053  };
2054
2055  // At the same time, unknown entry should trigger delta feed request.
2056  // This will cause notification to directory observers (e.g., File Browser)
2057  // so that they can request search again.
2058  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(_))
2059      .Times(AtLeast(1));
2060
2061  SearchCallback callback = base::Bind(
2062      &DriveSearchCallback,
2063      &message_loop_,
2064      kExpectedResults, ARRAYSIZE_UNSAFE(kExpectedResults),
2065      GURL());
2066
2067  file_system_->Search("\"Directory 1\"", GURL(), callback);
2068  // Make sure all the delayed tasks to complete.
2069  // message_loop_.Run() can return before the delta feed processing finishes.
2070  google_apis::test_util::RunBlockingPoolTask();
2071}
2072
2073TEST_F(DriveFileSystemTest, ContentSearchEmptyResult) {
2074  ASSERT_TRUE(LoadRootFeedDocument());
2075
2076  const SearchResultPair* expected_results = NULL;
2077
2078  SearchCallback callback = base::Bind(
2079      &DriveSearchCallback,
2080      &message_loop_,
2081      expected_results,
2082      0u,
2083      GURL());
2084
2085  file_system_->Search("\"no-match query\"", GURL(), callback);
2086  message_loop_.Run();  // Wait to get our result.
2087}
2088
2089TEST_F(DriveFileSystemTest, GetAvailableSpace) {
2090  FileError error = FILE_ERROR_OK;
2091  int64 bytes_total;
2092  int64 bytes_used;
2093  file_system_->GetAvailableSpace(
2094      google_apis::test_util::CreateCopyResultCallback(
2095          &error, &bytes_total, &bytes_used));
2096  google_apis::test_util::RunBlockingPoolTask();
2097  EXPECT_EQ(GG_LONGLONG(6789012345), bytes_used);
2098  EXPECT_EQ(GG_LONGLONG(9876543210), bytes_total);
2099}
2100
2101TEST_F(DriveFileSystemTest, RefreshDirectory) {
2102  ASSERT_TRUE(LoadRootFeedDocument());
2103
2104  // We'll notify the directory change to the observer.
2105  EXPECT_CALL(*mock_directory_observer_,
2106              OnDirectoryChanged(Eq(util::GetDriveMyDriveRootPath()))).Times(1);
2107
2108  FileError error = FILE_ERROR_FAILED;
2109  file_system_->RefreshDirectory(
2110      util::GetDriveMyDriveRootPath(),
2111      google_apis::test_util::CreateCopyResultCallback(&error));
2112  google_apis::test_util::RunBlockingPoolTask();
2113  EXPECT_EQ(FILE_ERROR_OK, error);
2114}
2115
2116TEST_F(DriveFileSystemTest, OpenAndCloseFile) {
2117  ASSERT_TRUE(LoadRootFeedDocument());
2118
2119  // The transfered file is cached and the change of "offline available"
2120  // attribute is notified.
2121  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
2122      Eq(base::FilePath(FILE_PATH_LITERAL("drive/root"))))).Times(1);
2123
2124  const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt"));
2125  scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(kFileInRoot));
2126  const int64 file_size = entry->file_info().size();
2127  const std::string& file_resource_id =
2128      entry->resource_id();
2129  const std::string& file_md5 = entry->file_specific_info().file_md5();
2130
2131  // A dirty file is created on close.
2132  EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(file_resource_id))
2133      .Times(1);
2134
2135  // Pretend we have enough space.
2136  fake_free_disk_space_getter_->set_fake_free_disk_space(
2137      file_size + internal::kMinFreeSpace);
2138
2139  // Open kFileInRoot ("drive/root/File 1.txt").
2140  FileError error = FILE_ERROR_FAILED;
2141  base::FilePath file_path;
2142  file_system_->OpenFile(
2143      kFileInRoot,
2144      google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
2145  google_apis::test_util::RunBlockingPoolTask();
2146  const base::FilePath opened_file_path = file_path;
2147
2148  // Verify that the file was properly opened.
2149  EXPECT_EQ(FILE_ERROR_OK, error);
2150
2151  // Try to open the already opened file.
2152  file_system_->OpenFile(
2153      kFileInRoot,
2154      google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
2155  google_apis::test_util::RunBlockingPoolTask();
2156
2157  // It must fail.
2158  EXPECT_EQ(FILE_ERROR_IN_USE, error);
2159
2160  // Verify that the file contents match the expected contents.
2161  // The content is "x"s of the file size.
2162  const std::string kExpectedContent = "xxxxxxxxxx";
2163  std::string cache_file_data;
2164  EXPECT_TRUE(file_util::ReadFileToString(opened_file_path, &cache_file_data));
2165  EXPECT_EQ(kExpectedContent, cache_file_data);
2166
2167  FileCacheEntry cache_entry;
2168  EXPECT_TRUE(GetCacheEntryFromOriginThread(file_resource_id, file_md5,
2169                                            &cache_entry));
2170  EXPECT_TRUE(cache_entry.is_present());
2171  EXPECT_TRUE(cache_entry.is_dirty());
2172  EXPECT_TRUE(cache_entry.is_persistent());
2173
2174  base::FilePath cache_file_path;
2175  cache_->GetFileOnUIThread(file_resource_id, file_md5,
2176                            google_apis::test_util::CreateCopyResultCallback(
2177                                &error, &cache_file_path));
2178  google_apis::test_util::RunBlockingPoolTask();
2179  EXPECT_EQ(FILE_ERROR_OK, error);
2180  EXPECT_EQ(cache_file_path, opened_file_path);
2181
2182  // Close kFileInRoot ("drive/root/File 1.txt").
2183  file_system_->CloseFile(
2184      kFileInRoot,
2185      google_apis::test_util::CreateCopyResultCallback(&error));
2186  google_apis::test_util::RunBlockingPoolTask();
2187
2188  // Verify that the file was properly closed.
2189  EXPECT_EQ(FILE_ERROR_OK, error);
2190
2191  // Verify that the cache state was changed as expected.
2192  EXPECT_TRUE(GetCacheEntryFromOriginThread(file_resource_id, file_md5,
2193                                            &cache_entry));
2194  EXPECT_TRUE(cache_entry.is_present());
2195  EXPECT_TRUE(cache_entry.is_dirty());
2196  EXPECT_TRUE(cache_entry.is_persistent());
2197
2198  // Try to close the same file twice.
2199  file_system_->CloseFile(
2200      kFileInRoot,
2201      google_apis::test_util::CreateCopyResultCallback(&error));
2202  google_apis::test_util::RunBlockingPoolTask();
2203
2204  // It must fail.
2205  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
2206}
2207
2208// TODO(satorux): Testing if WebAppsRegistry is loaded here is awkward. We
2209// should move this to change_list_loader_unittest.cc. crbug.com/161703
2210TEST_F(DriveFileSystemTest, WebAppsRegistryIsLoaded) {
2211  ASSERT_TRUE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
2212
2213  // No apps should be found as the webapps registry is empty.
2214  ScopedVector<DriveWebAppInfo> apps;
2215  drive_webapps_registry_->GetWebAppsForFile(
2216      base::FilePath::FromUTF8Unsafe("foo.exe"),
2217      "" /* mime_type */,
2218      &apps);
2219  EXPECT_TRUE(apps.empty());
2220
2221  // Kicks loading of cached file system and query for server update. This
2222  // will cause GetAboutResource() to be called, to check the server-side
2223  // changestamp, and the webapps registry will be loaded at the same time.
2224  EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveMyDriveRootPath()));
2225
2226  // An app for foo.exe should now be found, as the registry was loaded.
2227  drive_webapps_registry_->GetWebAppsForFile(
2228      base::FilePath(FILE_PATH_LITERAL("foo.exe")),
2229      "" /* mime_type */,
2230      &apps);
2231  EXPECT_EQ(1U, apps.size());
2232}
2233
2234TEST_F(DriveFileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
2235  fake_free_disk_space_getter_->set_fake_free_disk_space(kLotsOfSpace);
2236  ASSERT_TRUE(LoadRootFeedDocument());
2237
2238  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
2239  scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_in_root));
2240  ASSERT_TRUE(entry);
2241
2242  // Write to cache.
2243  FileError error = FILE_ERROR_FAILED;
2244  cache_->StoreOnUIThread(
2245      entry->resource_id(),
2246      entry->file_specific_info().file_md5(),
2247      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
2248      internal::FileCache::FILE_OPERATION_COPY,
2249      google_apis::test_util::CreateCopyResultCallback(&error));
2250  google_apis::test_util::RunBlockingPoolTask();
2251  ASSERT_EQ(FILE_ERROR_OK, error);
2252
2253  // Test for mounting.
2254  base::FilePath file_path;
2255  file_system_->MarkCacheFileAsMounted(
2256      file_in_root,
2257      google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
2258  google_apis::test_util::RunBlockingPoolTask();
2259  EXPECT_EQ(FILE_ERROR_OK, error);
2260
2261  bool success = false;
2262  FileCacheEntry cache_entry;
2263  cache_->GetCacheEntryOnUIThread(
2264      entry->resource_id(),
2265      entry->file_specific_info().file_md5(),
2266      google_apis::test_util::CreateCopyResultCallback(&success, &cache_entry));
2267  google_apis::test_util::RunBlockingPoolTask();
2268
2269  EXPECT_TRUE(success);
2270  EXPECT_TRUE(cache_entry.is_mounted());
2271
2272  // Test for unmounting.
2273  error = FILE_ERROR_FAILED;
2274  file_system_->MarkCacheFileAsUnmounted(
2275      file_path,
2276      google_apis::test_util::CreateCopyResultCallback(&error));
2277  google_apis::test_util::RunBlockingPoolTask();
2278
2279  EXPECT_EQ(FILE_ERROR_OK, error);
2280
2281  success = false;
2282  cache_->GetCacheEntryOnUIThread(
2283      entry->resource_id(),
2284      entry->file_specific_info().file_md5(),
2285      google_apis::test_util::CreateCopyResultCallback(&success, &cache_entry));
2286  google_apis::test_util::RunBlockingPoolTask();
2287
2288  EXPECT_TRUE(success);
2289  EXPECT_FALSE(cache_entry.is_mounted());
2290}
2291
2292// TODO(kinaba): crbug.com/237066
2293// Create and move to file_system/create create_file_operation_unittest.cc.
2294TEST_F(DriveFileSystemTest, CreateFile) {
2295  fake_free_disk_space_getter_->set_fake_free_disk_space(kLotsOfSpace);
2296  ASSERT_TRUE(LoadRootFeedDocument());
2297
2298  const base::FilePath kExistingFile(
2299      FILE_PATH_LITERAL("drive/root/File 1.txt"));
2300  const base::FilePath kExistingDirectory(
2301      FILE_PATH_LITERAL("drive/root/Directory 1"));
2302  const base::FilePath kNonExistingFile(
2303      FILE_PATH_LITERAL("drive/root/Directory 1/not exist.png"));
2304  const base::FilePath kFileInNonExistingDirectory(
2305      FILE_PATH_LITERAL("drive/root/not exist/not exist.png"));
2306
2307  EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged(
2308      Eq(kNonExistingFile.DirName()))).Times(1);
2309
2310  // Create fails if is_exclusive = true and a file exists.
2311  FileError error = FILE_ERROR_FAILED;
2312  file_system_->CreateFile(
2313      kExistingFile,
2314      true /* is_exclusive */,
2315      google_apis::test_util::CreateCopyResultCallback(&error));
2316  google_apis::test_util::RunBlockingPoolTask();
2317  EXPECT_EQ(FILE_ERROR_EXISTS, error);
2318
2319  // Create succeeds if is_exclusive = false and a file exists.
2320  file_system_->CreateFile(
2321      kExistingFile,
2322      false /* is_exclusive */,
2323      google_apis::test_util::CreateCopyResultCallback(&error));
2324  google_apis::test_util::RunBlockingPoolTask();
2325  EXPECT_EQ(FILE_ERROR_OK, error);
2326
2327  // Create fails if a directory existed even when is_exclusive = false.
2328  file_system_->CreateFile(
2329      kExistingDirectory,
2330      false /* is_exclusive */,
2331      google_apis::test_util::CreateCopyResultCallback(&error));
2332  google_apis::test_util::RunBlockingPoolTask();
2333  EXPECT_EQ(FILE_ERROR_EXISTS, error);
2334
2335  // Create succeeds if no entry exists.
2336  file_system_->CreateFile(
2337      kNonExistingFile,
2338      true /* is_exclusive */,
2339      google_apis::test_util::CreateCopyResultCallback(&error));
2340  google_apis::test_util::RunBlockingPoolTask();
2341  EXPECT_EQ(FILE_ERROR_OK, error);
2342
2343  // Create fails if the parent directory does not exist.
2344  file_system_->CreateFile(
2345      kFileInNonExistingDirectory, false,
2346      google_apis::test_util::CreateCopyResultCallback(&error));
2347  google_apis::test_util::RunBlockingPoolTask();
2348  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
2349}
2350
2351}   // namespace drive
2352