blob: 0f0ca56f8b95ed2c660d187867cddd74a24c7970 [file] [log] [blame]
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001// 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"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010014#include "base/memory/scoped_ptr.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010015#include "base/message_loop/message_loop_proxy.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010016#include "base/prefs/testing_pref_service.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010017#include "base/run_loop.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010018#include "chrome/browser/chromeos/drive/change_list_loader.h"
19#include "chrome/browser/chromeos/drive/drive.pb.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010020#include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010021#include "chrome/browser/chromeos/drive/file_system_observer.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010022#include "chrome/browser/chromeos/drive/file_system_util.h"
23#include "chrome/browser/chromeos/drive/job_scheduler.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010024#include "chrome/browser/chromeos/drive/sync_client.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010025#include "chrome/browser/chromeos/drive/test_util.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010026#include "chrome/browser/drive/fake_drive_service.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010027#include "chrome/browser/google_apis/drive_api_parser.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010028#include "chrome/browser/google_apis/test_util.h"
29#include "chrome/test/base/testing_profile.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010030#include "content/public/test/test_browser_thread_bundle.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010031#include "testing/gtest/include/gtest/gtest.h"
32
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010033namespace drive {
34namespace {
35
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010036const int64 kLotsOfSpace = internal::kMinFreeSpace * 10;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010037
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010038// Counts the number of invocation, and if it increased up to |expected_counter|
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010039// quits the current message loop by calling |quit|.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010040void AsyncInitializationCallback(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010041 int* counter, int expected_counter, const base::Closure& quit,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010042 FileError error, scoped_ptr<ResourceEntry> entry) {
43 if (error != FILE_ERROR_OK || !entry) {
44 // If we hit an error case, quit the message loop immediately.
45 // Then the expectation in the test case can find it because the actual
46 // value of |counter| is different from the expected one.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010047 quit.Run();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010048 return;
49 }
50
51 (*counter)++;
52 if (*counter >= expected_counter)
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010053 quit.Run();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010054}
55
Ben Murdocheb525c52013-07-10 11:40:50 +010056// This class is used to record directory changes and examine them later.
57class MockDirectoryChangeObserver : public FileSystemObserver {
58 public:
59 MockDirectoryChangeObserver() {}
60 virtual ~MockDirectoryChangeObserver() {}
61
62 // FileSystemObserver overrides.
63 virtual void OnDirectoryChanged(
64 const base::FilePath& directory_path) OVERRIDE {
65 changed_directories_.push_back(directory_path);
66 }
67
68 const std::vector<base::FilePath>& changed_directories() const {
69 return changed_directories_;
70 }
71
72 private:
73 std::vector<base::FilePath> changed_directories_;
74 DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver);
75};
76
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010077} // namespace
78
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010079class FileSystemTest : public testing::Test {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010080 protected:
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010081 virtual void SetUp() OVERRIDE {
82 profile_.reset(new TestingProfile);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010083 pref_service_.reset(new TestingPrefServiceSimple);
84 test_util::RegisterDrivePrefs(pref_service_->registry());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010085
Ben Murdocheb525c52013-07-10 11:40:50 +010086 fake_network_change_notifier_.reset(
87 new test_util::FakeNetworkChangeNotifier);
88
89 fake_drive_service_.reset(new FakeDriveService);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010090 fake_drive_service_->LoadResourceListForWapi(
Ben Murdocheb525c52013-07-10 11:40:50 +010091 "gdata/root_feed.json");
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010092 fake_drive_service_->LoadAccountMetadataForWapi(
Ben Murdocheb525c52013-07-10 11:40:50 +010093 "gdata/account_metadata.json");
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010094
95 fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
96
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010097 scheduler_.reset(new JobScheduler(pref_service_.get(),
Ben Murdocheb525c52013-07-10 11:40:50 +010098 fake_drive_service_.get(),
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010099 base::MessageLoopProxy::current().get()));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100100
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100101 ASSERT_TRUE(file_util::CreateDirectory(util::GetCacheRootPath(
102 profile_.get()).Append(util::kMetadataDirectory)));
103 ASSERT_TRUE(file_util::CreateDirectory(util::GetCacheRootPath(
104 profile_.get()).Append(util::kCacheFileDirectory)));
105 ASSERT_TRUE(file_util::CreateDirectory(util::GetCacheRootPath(
106 profile_.get()).Append(util::kTemporaryFileDirectory)));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100107
Ben Murdocheb525c52013-07-10 11:40:50 +0100108 mock_directory_observer_.reset(new MockDirectoryChangeObserver);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100109
110 SetUpResourceMetadataAndFileSystem();
111 }
112
113 void SetUpResourceMetadataAndFileSystem() {
Ben Murdocheb525c52013-07-10 11:40:50 +0100114 metadata_storage_.reset(new internal::ResourceMetadataStorage(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100115 util::GetCacheRootPath(profile_.get()).Append(util::kMetadataDirectory),
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100116 base::MessageLoopProxy::current().get()));
Ben Murdocheb525c52013-07-10 11:40:50 +0100117 ASSERT_TRUE(metadata_storage_->Initialize());
118
119 cache_.reset(new internal::FileCache(
120 metadata_storage_.get(),
121 util::GetCacheRootPath(profile_.get()).Append(
122 util::kCacheFileDirectory),
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100123 base::MessageLoopProxy::current().get(),
Ben Murdocheb525c52013-07-10 11:40:50 +0100124 fake_free_disk_space_getter_.get()));
125 ASSERT_TRUE(cache_->Initialize());
126
127 resource_metadata_.reset(new internal::ResourceMetadata(
128 metadata_storage_.get(), base::MessageLoopProxy::current()));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100129
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100130 file_system_.reset(new FileSystem(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100131 pref_service_.get(),
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100132 cache_.get(),
133 fake_drive_service_.get(),
134 scheduler_.get(),
135 resource_metadata_.get(),
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100136 base::MessageLoopProxy::current().get(),
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100137 util::GetCacheRootPath(profile_.get()).Append(
138 util::kTemporaryFileDirectory)));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100139 file_system_->AddObserver(mock_directory_observer_.get());
140 file_system_->Initialize();
141
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100142 // Disable delaying so that the sync starts immediately.
143 file_system_->sync_client_for_testing()->set_delay_for_testing(
144 base::TimeDelta::FromSeconds(0));
145
146 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100147 }
148
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100149 // Loads the full resource list via FakeDriveService.
150 bool LoadFullResourceList() {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100151 FileError error = FILE_ERROR_FAILED;
Ben Murdochbb1529c2013-08-08 10:24:53 +0100152 file_system_->change_list_loader_for_testing()->LoadIfNeeded(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100153 DirectoryFetchInfo(),
154 google_apis::test_util::CreateCopyResultCallback(&error));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100155 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100156 return error == FILE_ERROR_OK;
157 }
158
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100159 // Gets resource entry by path synchronously.
160 scoped_ptr<ResourceEntry> GetResourceEntryByPathSync(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100161 const base::FilePath& file_path) {
162 FileError error = FILE_ERROR_FAILED;
163 scoped_ptr<ResourceEntry> entry;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100164 file_system_->GetResourceEntryByPath(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100165 file_path,
166 google_apis::test_util::CreateCopyResultCallback(&error, &entry));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100167 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100168
169 return entry.Pass();
170 }
171
172 // Gets directory info by path synchronously.
173 scoped_ptr<ResourceEntryVector> ReadDirectoryByPathSync(
174 const base::FilePath& file_path) {
175 FileError error = FILE_ERROR_FAILED;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100176 scoped_ptr<ResourceEntryVector> entries;
177 file_system_->ReadDirectoryByPath(
178 file_path,
179 google_apis::test_util::CreateCopyResultCallback(
Ben Murdocheb525c52013-07-10 11:40:50 +0100180 &error, &entries));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100181 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100182
183 return entries.Pass();
184 }
185
186 // Returns true if an entry exists at |file_path|.
187 bool EntryExists(const base::FilePath& file_path) {
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100188 return GetResourceEntryByPathSync(file_path);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100189 }
190
191 // Gets the resource ID of |file_path|. Returns an empty string if not found.
192 std::string GetResourceIdByPath(const base::FilePath& file_path) {
193 scoped_ptr<ResourceEntry> entry =
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100194 GetResourceEntryByPathSync(file_path);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100195 if (entry)
196 return entry->resource_id();
197 else
198 return "";
199 }
200
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100201 // Flag for specifying the timestamp of the test filesystem cache.
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100202 enum SetUpTestFileSystemParam {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100203 USE_OLD_TIMESTAMP,
204 USE_SERVER_TIMESTAMP,
205 };
206
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100207 // Sets up a filesystem with directories: drive/root, drive/root/Dir1,
208 // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2,
209 // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets
210 // the changestamp to 654321, equal to that of "account_metadata.json" test
211 // data, indicating the cache is holding the latest file system info.
212 bool SetUpTestFileSystem(SetUpTestFileSystemParam param) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100213 // Destroy the existing resource metadata to close DB.
214 resource_metadata_.reset();
215
Ben Murdocheb525c52013-07-10 11:40:50 +0100216 base::FilePath metadata_directory =
217 util::GetCacheRootPath(profile_.get()).Append(util::kMetadataDirectory);
218 scoped_ptr<internal::ResourceMetadataStorage,
219 test_util::DestroyHelperForTests> metadata_storage(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100220 new internal::ResourceMetadataStorage(
221 metadata_directory, base::MessageLoopProxy::current().get()));
Ben Murdocheb525c52013-07-10 11:40:50 +0100222
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100223 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
224 resource_metadata(new internal::ResourceMetadata(
Ben Murdocheb525c52013-07-10 11:40:50 +0100225 metadata_storage_.get(), base::MessageLoopProxy::current()));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100226
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100227 if (resource_metadata->Initialize() != FILE_ERROR_OK)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100228 return false;
229
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100230 const int64 changestamp = param == USE_SERVER_TIMESTAMP ? 654321 : 1;
231 if (resource_metadata->SetLargestChangestamp(changestamp) != FILE_ERROR_OK)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100232 return false;
233
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100234 // drive/root
Ben Murdocheb525c52013-07-10 11:40:50 +0100235 const std::string root_resource_id =
236 fake_drive_service_->GetRootResourceId();
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100237 if (resource_metadata->AddEntry(util::CreateMyDriveRootEntry(
238 root_resource_id)) != FILE_ERROR_OK)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100239 return false;
240
241 // drive/root/File1
242 ResourceEntry file1;
243 file1.set_title("File1");
244 file1.set_resource_id("resource_id:File1");
245 file1.set_parent_resource_id(root_resource_id);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100246 file1.mutable_file_specific_info()->set_md5("md5");
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100247 file1.mutable_file_info()->set_is_directory(false);
248 file1.mutable_file_info()->set_size(1048576);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100249 if (resource_metadata->AddEntry(file1) != FILE_ERROR_OK)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100250 return false;
251
252 // drive/root/Dir1
253 ResourceEntry dir1;
254 dir1.set_title("Dir1");
255 dir1.set_resource_id("resource_id:Dir1");
256 dir1.set_parent_resource_id(root_resource_id);
257 dir1.mutable_file_info()->set_is_directory(true);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100258 if (resource_metadata->AddEntry(dir1) != FILE_ERROR_OK)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100259 return false;
260
261 // drive/root/Dir1/File2
262 ResourceEntry file2;
263 file2.set_title("File2");
264 file2.set_resource_id("resource_id:File2");
265 file2.set_parent_resource_id(dir1.resource_id());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100266 file2.mutable_file_specific_info()->set_md5("md5");
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100267 file2.mutable_file_info()->set_is_directory(false);
268 file2.mutable_file_info()->set_size(555);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100269 if (resource_metadata->AddEntry(file2) != FILE_ERROR_OK)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100270 return false;
271
272 // drive/root/Dir1/SubDir2
273 ResourceEntry dir2;
274 dir2.set_title("SubDir2");
275 dir2.set_resource_id("resource_id:SubDir2");
276 dir2.set_parent_resource_id(dir1.resource_id());
277 dir2.mutable_file_info()->set_is_directory(true);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100278 if (resource_metadata->AddEntry(dir2) != FILE_ERROR_OK)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100279 return false;
280
281 // drive/root/Dir1/SubDir2/File3
282 ResourceEntry file3;
283 file3.set_title("File3");
284 file3.set_resource_id("resource_id:File3");
285 file3.set_parent_resource_id(dir2.resource_id());
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100286 file3.mutable_file_specific_info()->set_md5("md5");
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100287 file3.mutable_file_info()->set_is_directory(false);
288 file3.mutable_file_info()->set_size(12345);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100289 if (resource_metadata->AddEntry(file3) != FILE_ERROR_OK)
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100290 return false;
291
292 // Recreate resource metadata.
293 SetUpResourceMetadataAndFileSystem();
294
295 return true;
296 }
297
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100298 content::TestBrowserThreadBundle thread_bundle_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100299 scoped_ptr<TestingProfile> profile_;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100300 // We don't use TestingProfile::GetPrefs() in favor of having less
301 // dependencies to Profile in general.
302 scoped_ptr<TestingPrefServiceSimple> pref_service_;
Ben Murdocheb525c52013-07-10 11:40:50 +0100303 scoped_ptr<test_util::FakeNetworkChangeNotifier>
304 fake_network_change_notifier_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100305
Ben Murdocheb525c52013-07-10 11:40:50 +0100306 scoped_ptr<FakeDriveService> fake_drive_service_;
307 scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100308 scoped_ptr<JobScheduler> scheduler_;
Ben Murdocheb525c52013-07-10 11:40:50 +0100309 scoped_ptr<MockDirectoryChangeObserver> mock_directory_observer_;
310
311 scoped_ptr<internal::ResourceMetadataStorage,
312 test_util::DestroyHelperForTests> metadata_storage_;
313 scoped_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100314 scoped_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
315 resource_metadata_;
Ben Murdocheb525c52013-07-10 11:40:50 +0100316 scoped_ptr<FileSystem> file_system_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100317};
318
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100319TEST_F(FileSystemTest, DuplicatedAsyncInitialization) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100320 base::RunLoop loop;
321
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100322 int counter = 0;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100323 const GetResourceEntryCallback& callback = base::Bind(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100324 &AsyncInitializationCallback, &counter, 2, loop.QuitClosure());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100325
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100326 file_system_->GetResourceEntryByPath(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100327 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100328 file_system_->GetResourceEntryByPath(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100329 base::FilePath(FILE_PATH_LITERAL("drive/root")), callback);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100330 loop.Run(); // Wait to get our result
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100331 EXPECT_EQ(2, counter);
332
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100333 // Although GetResourceEntryByPath() was called twice, the resource list
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100334 // should only be loaded once. In the past, there was a bug that caused
335 // it to be loaded twice.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100336 EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100337 // See the comment in GetMyDriveRoot test case why this is 2.
338 EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
Ben Murdocheb525c52013-07-10 11:40:50 +0100339
340 // "Fast fetch" will fire an OnirectoryChanged event.
341 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
342 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
343 mock_directory_observer_->changed_directories()[0]);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100344}
345
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100346TEST_F(FileSystemTest, GetGrandRootEntry) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100347 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100348 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100349 ASSERT_TRUE(entry);
350 EXPECT_EQ(util::kDriveGrandRootSpecialResourceId, entry->resource_id());
351
352 // Getting the grand root entry should not cause the resource load to happen.
353 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
354 EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
355}
356
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100357TEST_F(FileSystemTest, GetOtherDirEntry) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100358 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100359 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100360 ASSERT_TRUE(entry);
361 EXPECT_EQ(util::kDriveOtherDirSpecialResourceId, entry->resource_id());
362
363 // Getting the "other" directory entry should not cause the resource load to
364 // happen.
365 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
366 EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
367}
368
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100369TEST_F(FileSystemTest, GetMyDriveRoot) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100370 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100371 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100372 ASSERT_TRUE(entry);
373 EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
374
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100375 // Absence of "drive/root" in the local metadata triggers the "fast fetch"
376 // of "drive" directory. Fetch of "drive" grand root directory has a special
377 // implementation. Instead of normal GetResourceListInDirectory(), it is
378 // emulated by calling GetAboutResource() so that the resource_id of
379 // "drive/root" is listed.
380 // Together with the normal GetAboutResource() call to retrieve the largest
381 // changestamp, the method is called twice.
382 EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100383
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100384 // After "fast fetch" is done, full resource list is fetched.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100385 EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
Ben Murdocheb525c52013-07-10 11:40:50 +0100386
387 // "Fast fetch" will fire an OnirectoryChanged event.
388 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
389 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
390 mock_directory_observer_->changed_directories()[0]);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100391}
392
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100393TEST_F(FileSystemTest, GetExistingFile) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100394 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100395 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100396 ASSERT_TRUE(entry);
397 EXPECT_EQ("file:2_file_resource_id", entry->resource_id());
398
399 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
400 EXPECT_EQ(1, fake_drive_service_->resource_list_load_count());
401}
402
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100403TEST_F(FileSystemTest, GetExistingDocument) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100404 const base::FilePath kFilePath(
405 FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100406 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100407 ASSERT_TRUE(entry);
408 EXPECT_EQ("document:5_document_resource_id", entry->resource_id());
409}
410
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100411TEST_F(FileSystemTest, GetNonExistingFile) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100412 const base::FilePath kFilePath(
413 FILE_PATH_LITERAL("drive/root/nonexisting.file"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100414 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100415 EXPECT_FALSE(entry);
416}
417
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100418TEST_F(FileSystemTest, GetEncodedFileNames) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100419 const base::FilePath kFilePath1(
420 FILE_PATH_LITERAL("drive/root/Slash / in file 1.txt"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100421 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath1);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100422 ASSERT_FALSE(entry);
423
424 const base::FilePath kFilePath2 = base::FilePath::FromUTF8Unsafe(
425 "drive/root/Slash \xE2\x88\x95 in file 1.txt");
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100426 entry = GetResourceEntryByPathSync(kFilePath2);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100427 ASSERT_TRUE(entry);
428 EXPECT_EQ("file:slash_file_resource_id", entry->resource_id());
429
430 const base::FilePath kFilePath3 = base::FilePath::FromUTF8Unsafe(
431 "drive/root/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt");
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100432 entry = GetResourceEntryByPathSync(kFilePath3);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100433 ASSERT_TRUE(entry);
434 EXPECT_EQ("file:slash_subdir_file", entry->resource_id());
435}
436
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100437TEST_F(FileSystemTest, GetDuplicateNames) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100438 const base::FilePath kFilePath1(
439 FILE_PATH_LITERAL("drive/root/Duplicate Name.txt"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100440 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath1);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100441 ASSERT_TRUE(entry);
442 const std::string resource_id1 = entry->resource_id();
443
444 const base::FilePath kFilePath2(
Ben Murdocheb525c52013-07-10 11:40:50 +0100445 FILE_PATH_LITERAL("drive/root/Duplicate Name (1).txt"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100446 entry = GetResourceEntryByPathSync(kFilePath2);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100447 ASSERT_TRUE(entry);
448 const std::string resource_id2 = entry->resource_id();
449
450 // The entries are de-duped non-deterministically, so we shouldn't rely on the
451 // names matching specific resource ids.
452 const std::string file3_resource_id = "file:3_file_resource_id";
453 const std::string file4_resource_id = "file:4_file_resource_id";
454 EXPECT_TRUE(file3_resource_id == resource_id1 ||
455 file3_resource_id == resource_id2);
456 EXPECT_TRUE(file4_resource_id == resource_id1 ||
457 file4_resource_id == resource_id2);
458}
459
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100460TEST_F(FileSystemTest, GetExistingDirectory) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100461 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/Directory 1"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100462 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100463 ASSERT_TRUE(entry);
464 ASSERT_EQ("folder:1_folder_resource_id", entry->resource_id());
465
466 // The changestamp should be propagated to the directory.
467 EXPECT_EQ(fake_drive_service_->largest_changestamp(),
468 entry->directory_specific_info().changestamp());
469}
470
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100471TEST_F(FileSystemTest, GetInSubSubdir) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100472 const base::FilePath kFilePath(
473 FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/"
474 "Sub Sub Directory Folder"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100475 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100476 ASSERT_TRUE(entry);
477 ASSERT_EQ("folder:sub_sub_directory_folder_id", entry->resource_id());
478}
479
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100480TEST_F(FileSystemTest, GetOrphanFile) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100481 const base::FilePath kFilePath(
482 FILE_PATH_LITERAL("drive/other/Orphan File 1.txt"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100483 scoped_ptr<ResourceEntry> entry = GetResourceEntryByPathSync(kFilePath);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100484 ASSERT_TRUE(entry);
485 EXPECT_EQ("file:1_orphanfile_resource_id", entry->resource_id());
486}
487
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100488TEST_F(FileSystemTest, ReadDirectoryByPath_Root) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100489 // ReadDirectoryByPath() should kick off the resource list loading.
490 scoped_ptr<ResourceEntryVector> entries(
491 ReadDirectoryByPathSync(base::FilePath::FromUTF8Unsafe("drive")));
492 // The root directory should be read correctly.
493 ASSERT_TRUE(entries);
494 ASSERT_EQ(2U, entries->size());
495
496 // The found two directories should be /drive/root and /drive/other.
497 bool found_other = false;
498 bool found_my_drive = false;
499 for (size_t i = 0; i < entries->size(); ++i) {
500 const base::FilePath title =
501 base::FilePath::FromUTF8Unsafe((*entries)[i].title());
502 if (title == base::FilePath(util::kDriveOtherDirName)) {
503 found_other = true;
504 } else if (title == base::FilePath(util::kDriveMyDriveRootDirName)) {
505 found_my_drive = true;
506 }
507 }
508
509 EXPECT_TRUE(found_other);
510 EXPECT_TRUE(found_my_drive);
Ben Murdocheb525c52013-07-10 11:40:50 +0100511
512 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
513 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive")),
514 mock_directory_observer_->changed_directories()[0]);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100515}
516
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100517TEST_F(FileSystemTest, ReadDirectoryByPath_NonRootDirectory) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100518 // ReadDirectoryByPath() should kick off the resource list loading.
519 scoped_ptr<ResourceEntryVector> entries(
520 ReadDirectoryByPathSync(
521 base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
522 // The non root directory should also be read correctly.
523 // There was a bug (crbug.com/181487), which broke this behavior.
524 // Make sure this is fixed.
525 ASSERT_TRUE(entries);
526 EXPECT_EQ(3U, entries->size());
527}
528
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100529TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100530 ASSERT_TRUE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100531
532 // Kicks loading of cached file system and query for server update.
533 EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveMyDriveRootPath()));
534
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100535 // SetUpTestFileSystem and "account_metadata.json" have the same
536 // changestamp (i.e. the local metadata is up-to-date), so no request for
537 // new resource list (i.e., call to GetResourceList) should happen.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100538 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
539 EXPECT_EQ(0, fake_drive_service_->resource_list_load_count());
540
541 // Since the file system has verified that it holds the latest snapshot,
542 // it should change its state to "loaded", which admits periodic refresh.
543 // To test it, call CheckForUpdates and verify it does try to check updates.
544 file_system_->CheckForUpdates();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100545 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100546 EXPECT_EQ(2, fake_drive_service_->about_resource_load_count());
547}
548
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100549TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100550 ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100551
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100552 // Make GetResourceList fail for simulating offline situation. This will
553 // leave the file system "loaded from cache, but not synced with server"
554 // state.
Ben Murdocheb525c52013-07-10 11:40:50 +0100555 fake_network_change_notifier_->SetConnectionType(
556 net::NetworkChangeNotifier::CONNECTION_NONE);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100557 fake_drive_service_->set_offline(true);
558
Ben Murdocheb525c52013-07-10 11:40:50 +0100559 // Load the root.
560 EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveGrandRootPath()));
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100561 // Loading of about resource should not happen as it's offline.
562 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100563
Ben Murdocheb525c52013-07-10 11:40:50 +0100564 // Load "My Drive".
565 EXPECT_TRUE(ReadDirectoryByPathSync(util::GetDriveMyDriveRootPath()));
566 EXPECT_EQ(0, fake_drive_service_->about_resource_load_count());
567
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100568 // Tests that cached data can be loaded even if the server is not reachable.
569 EXPECT_TRUE(EntryExists(base::FilePath(
570 FILE_PATH_LITERAL("drive/root/File1"))));
571 EXPECT_TRUE(EntryExists(base::FilePath(
572 FILE_PATH_LITERAL("drive/root/Dir1"))));
573 EXPECT_TRUE(
574 EntryExists(base::FilePath(FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
575 EXPECT_TRUE(EntryExists(base::FilePath(
576 FILE_PATH_LITERAL("drive/root/Dir1/SubDir2"))));
577 EXPECT_TRUE(EntryExists(
578 base::FilePath(FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"))));
579
580 // Since the file system has at least succeeded to load cached snapshot,
581 // the file system should be able to start periodic refresh.
582 // To test it, call CheckForUpdates and verify it does try to check
583 // updates, which will cause directory changes.
Ben Murdocheb525c52013-07-10 11:40:50 +0100584 fake_network_change_notifier_->SetConnectionType(
585 net::NetworkChangeNotifier::CONNECTION_WIFI);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100586 fake_drive_service_->set_offline(false);
587
588 file_system_->CheckForUpdates();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100589
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100590 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100591 EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
592 EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
Ben Murdocheb525c52013-07-10 11:40:50 +0100593
594 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100595}
596
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100597TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100598 // Enter the "refreshing" state so the fast fetch will be performed.
599 ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
600 file_system_->CheckForUpdates();
601
602 // The list of resources in "drive/root/Dir1" should be fetched.
603 EXPECT_TRUE(ReadDirectoryByPathSync(base::FilePath(
604 FILE_PATH_LITERAL("drive/root/Dir1"))));
605 EXPECT_EQ(1, fake_drive_service_->directory_load_count());
Ben Murdocheb525c52013-07-10 11:40:50 +0100606
607 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100608}
609
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100610TEST_F(FileSystemTest, GetResourceEntryExistingWhileRefreshing) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100611 // Enter the "refreshing" state.
612 ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
613 file_system_->CheckForUpdates();
614
615 // If an entry is already found in local metadata, no directory fetch happens.
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100616 EXPECT_TRUE(GetResourceEntryByPathSync(base::FilePath(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100617 FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
618 EXPECT_EQ(0, fake_drive_service_->directory_load_count());
619}
620
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100621TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100622 // Enter the "refreshing" state so the fast fetch will be performed.
623 ASSERT_TRUE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
624 file_system_->CheckForUpdates();
625
626 // If an entry is not found, parent directory's resource list is fetched.
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100627 EXPECT_FALSE(GetResourceEntryByPathSync(base::FilePath(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100628 FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
629 EXPECT_EQ(1, fake_drive_service_->directory_load_count());
Ben Murdocheb525c52013-07-10 11:40:50 +0100630
631 ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100632}
633
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100634TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100635 // Intentionally *not* calling LoadFullResourceList(), for testing that
636 // CreateDirectory ensures the resource list is loaded before it runs.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100637
638 base::FilePath existing_directory(
639 FILE_PATH_LITERAL("drive/root/Directory 1"));
640 FileError error = FILE_ERROR_FAILED;
641 file_system_->CreateDirectory(
642 existing_directory,
643 true, // is_exclusive
644 false, // is_recursive
645 google_apis::test_util::CreateCopyResultCallback(&error));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100646 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100647
648 // It should fail because is_exclusive is set to true.
649 EXPECT_EQ(FILE_ERROR_EXISTS, error);
650}
651
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100652TEST_F(FileSystemTest, PinAndUnpin) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100653 ASSERT_TRUE(LoadFullResourceList());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100654
655 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
656
657 // Get the file info.
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100658 scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_path));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100659 ASSERT_TRUE(entry);
660
661 // Pin the file.
662 FileError error = FILE_ERROR_FAILED;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100663 file_system_->Pin(file_path,
664 google_apis::test_util::CreateCopyResultCallback(&error));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100665 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100666 EXPECT_EQ(FILE_ERROR_OK, error);
667
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100668 FileCacheEntry cache_entry;
Ben Murdoch558790d2013-07-30 15:19:42 +0100669 EXPECT_TRUE(cache_->GetCacheEntry(entry->resource_id(), &cache_entry));
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100670 EXPECT_TRUE(cache_entry.is_pinned());
671 EXPECT_TRUE(cache_entry.is_present());
672
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100673 // Unpin the file.
674 error = FILE_ERROR_FAILED;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100675 file_system_->Unpin(file_path,
676 google_apis::test_util::CreateCopyResultCallback(&error));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100677 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100678 EXPECT_EQ(FILE_ERROR_OK, error);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100679
Ben Murdoch558790d2013-07-30 15:19:42 +0100680 EXPECT_TRUE(cache_->GetCacheEntry(entry->resource_id(), &cache_entry));
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100681 EXPECT_FALSE(cache_entry.is_pinned());
Ben Murdocheb525c52013-07-10 11:40:50 +0100682
683 // Pinned file gets synced and it results in entry state changes.
684 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
685 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
686 mock_directory_observer_->changed_directories()[0]);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100687}
688
689TEST_F(FileSystemTest, PinAndUnpin_NotSynced) {
690 ASSERT_TRUE(LoadFullResourceList());
691
692 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
693
694 // Get the file info.
695 scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_path));
696 ASSERT_TRUE(entry);
697
698 // Unpin the file just after pinning. File fetch should be cancelled.
699 FileError error_pin = FILE_ERROR_FAILED;
700 file_system_->Pin(
701 file_path,
702 google_apis::test_util::CreateCopyResultCallback(&error_pin));
703
704 FileError error_unpin = FILE_ERROR_FAILED;
705 file_system_->Unpin(
706 file_path,
707 google_apis::test_util::CreateCopyResultCallback(&error_unpin));
708
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100709 test_util::RunBlockingPoolTask();
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100710 EXPECT_EQ(FILE_ERROR_OK, error_pin);
711 EXPECT_EQ(FILE_ERROR_OK, error_unpin);
712
713 // No cache file available because the sync was cancelled by Unpin().
714 FileCacheEntry cache_entry;
Ben Murdoch558790d2013-07-30 15:19:42 +0100715 EXPECT_FALSE(cache_->GetCacheEntry(entry->resource_id(), &cache_entry));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100716}
717
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100718TEST_F(FileSystemTest, GetAvailableSpace) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100719 FileError error = FILE_ERROR_OK;
720 int64 bytes_total;
721 int64 bytes_used;
722 file_system_->GetAvailableSpace(
723 google_apis::test_util::CreateCopyResultCallback(
724 &error, &bytes_total, &bytes_used));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100725 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100726 EXPECT_EQ(GG_LONGLONG(6789012345), bytes_used);
727 EXPECT_EQ(GG_LONGLONG(9876543210), bytes_total);
728}
729
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100730TEST_F(FileSystemTest, OpenAndCloseFile) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100731 ASSERT_TRUE(LoadFullResourceList());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100732
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100733 const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100734 scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(kFileInRoot));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100735 const std::string& file_resource_id = entry->resource_id();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100736
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100737 // Open kFileInRoot ("drive/root/File 1.txt").
738 FileError error = FILE_ERROR_FAILED;
739 base::FilePath file_path;
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100740 base::Closure close_callback;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100741 file_system_->OpenFile(
742 kFileInRoot,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100743 OPEN_FILE,
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100744 google_apis::test_util::CreateCopyResultCallback(
745 &error, &file_path, &close_callback));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100746 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100747 const base::FilePath opened_file_path = file_path;
748
749 // Verify that the file was properly opened.
750 EXPECT_EQ(FILE_ERROR_OK, error);
751
Ben Murdocheb525c52013-07-10 11:40:50 +0100752 // The opened file is downloaded, which means the file is available
753 // offline. The directory change should be notified so Files.app can change
754 // the offline availability status of the file.
755 ASSERT_EQ(1u, mock_directory_observer_->changed_directories().size());
756 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
757 mock_directory_observer_->changed_directories()[0]);
758
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100759 // Verify that the file contents match the expected contents.
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100760 const std::string kExpectedContent = "This is some test content.";
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100761 std::string cache_file_data;
762 EXPECT_TRUE(file_util::ReadFileToString(opened_file_path, &cache_file_data));
763 EXPECT_EQ(kExpectedContent, cache_file_data);
764
765 FileCacheEntry cache_entry;
Ben Murdoch558790d2013-07-30 15:19:42 +0100766 EXPECT_TRUE(cache_->GetCacheEntry(file_resource_id, &cache_entry));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100767 EXPECT_TRUE(cache_entry.is_present());
768 EXPECT_TRUE(cache_entry.is_dirty());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100769
770 base::FilePath cache_file_path;
Ben Murdoch58e6fbe2013-07-26 10:20:38 +0100771 EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(file_resource_id, &cache_file_path));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100772 EXPECT_EQ(cache_file_path, opened_file_path);
773
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100774 // Write a new content.
775 const std::string kNewContent = kExpectedContent + kExpectedContent;
776 EXPECT_TRUE(google_apis::test_util::WriteStringToFile(cache_file_path,
777 kNewContent));
778
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100779 // Close kFileInRoot ("drive/root/File 1.txt").
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100780 ASSERT_FALSE(close_callback.is_null());
781 close_callback.Run();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100782 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100783
784 // Verify that the file was properly closed.
785 EXPECT_EQ(FILE_ERROR_OK, error);
786
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100787 // Verify that the file was synced as expected.
788 google_apis::GDataErrorCode gdata_error = google_apis::GDATA_FILE_ERROR;
789 scoped_ptr<google_apis::ResourceEntry> gdata_entry;
790 fake_drive_service_->GetResourceEntry(
791 file_resource_id,
792 google_apis::test_util::CreateCopyResultCallback(
793 &gdata_error, &gdata_entry));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100794 test_util::RunBlockingPoolTask();
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100795 EXPECT_EQ(gdata_error, google_apis::HTTP_SUCCESS);
796 ASSERT_TRUE(gdata_entry);
797 EXPECT_EQ(static_cast<int>(kNewContent.size()), gdata_entry->file_size());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100798
Ben Murdocheb525c52013-07-10 11:40:50 +0100799 // The modified file is uploaded. The directory change should be notified
800 // so Files.app can show new metadata of the modified file.
801 ASSERT_EQ(2u, mock_directory_observer_->changed_directories().size());
802 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("drive/root")),
803 mock_directory_observer_->changed_directories()[1]);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100804}
805
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100806TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100807 ASSERT_TRUE(LoadFullResourceList());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100808
809 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100810 scoped_ptr<ResourceEntry> entry(GetResourceEntryByPathSync(file_in_root));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100811 ASSERT_TRUE(entry);
812
813 // Write to cache.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100814 ASSERT_EQ(FILE_ERROR_OK, cache_->Store(
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100815 entry->resource_id(),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100816 entry->file_specific_info().md5(),
Ben Murdocheb525c52013-07-10 11:40:50 +0100817 google_apis::test_util::GetTestFilePath("gdata/root_feed.json"),
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100818 internal::FileCache::FILE_OPERATION_COPY));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100819
820 // Test for mounting.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100821 FileError error = FILE_ERROR_FAILED;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100822 base::FilePath file_path;
823 file_system_->MarkCacheFileAsMounted(
824 file_in_root,
825 google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100826 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100827 EXPECT_EQ(FILE_ERROR_OK, error);
828
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100829 // Cannot remove a cache entry while it's being mounted.
830 EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->resource_id()));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100831
832 // Test for unmounting.
833 error = FILE_ERROR_FAILED;
834 file_system_->MarkCacheFileAsUnmounted(
835 file_path,
836 google_apis::test_util::CreateCopyResultCallback(&error));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100837 test_util::RunBlockingPoolTask();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100838 EXPECT_EQ(FILE_ERROR_OK, error);
839
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100840 // Now able to remove the cache entry.
841 EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->resource_id()));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100842}
843
Ben Murdochbbcdd452013-07-25 10:06:34 +0100844TEST_F(FileSystemTest, GetShareUrl) {
845 ASSERT_TRUE(LoadFullResourceList());
846
847 const base::FilePath kFileInRoot(FILE_PATH_LITERAL("drive/root/File 1.txt"));
848 const GURL kEmbedOrigin("chrome-extension://test-id");
849
850 // Try to fetch the URL for the sharing dialog.
851 FileError error = FILE_ERROR_FAILED;
852 GURL share_url;
853 file_system_->GetShareUrl(
854 kFileInRoot,
855 kEmbedOrigin,
856 google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
857 test_util::RunBlockingPoolTask();
858
859 // Verify the share url to the sharing dialog.
860 EXPECT_EQ(FILE_ERROR_OK, error);
861 EXPECT_EQ(GURL("https://file_link_share/"), share_url);
862}
863
864TEST_F(FileSystemTest, GetShareUrlNotAvailable) {
865 ASSERT_TRUE(LoadFullResourceList());
866
867 const base::FilePath kFileInRoot(
868 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
869 const GURL kEmbedOrigin("chrome-extension://test-id");
870
871 // Try to fetch the URL for the sharing dialog.
872 FileError error = FILE_ERROR_FAILED;
873 GURL share_url;
874
875 file_system_->GetShareUrl(
876 kFileInRoot,
877 kEmbedOrigin,
878 google_apis::test_util::CreateCopyResultCallback(&error, &share_url));
879 test_util::RunBlockingPoolTask();
880
881 // Verify the error and the share url, which should be empty.
882 EXPECT_EQ(FILE_ERROR_FAILED, error);
883 EXPECT_TRUE(share_url.is_empty());
884}
885
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100886} // namespace drive