1 // Copyright 2013 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.
5 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
7 #include "base/file_util.h"
8 #include "base/task_runner_util.h"
9 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
10 #include "chrome/browser/chromeos/drive/file_cache.h"
11 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
12 #include "chrome/browser/chromeos/drive/file_system_util.h"
13 #include "chrome/browser/drive/fake_drive_service.h"
14 #include "chrome/browser/google_apis/test_util.h"
15 #include "testing/gtest/include/gtest/gtest.h"
18 namespace file_system {
20 class DownloadOperationTest : public OperationTestBase {
22 virtual void SetUp() OVERRIDE {
23 OperationTestBase::SetUp();
25 operation_.reset(new DownloadOperation(
26 blocking_task_runner(), observer(), scheduler(), metadata(), cache(),
30 scoped_ptr<DownloadOperation> operation_;
33 TEST_F(DownloadOperationTest,
34 EnsureFileDownloadedByPath_FromServer_EnoughSpace) {
35 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
36 ResourceEntry src_entry;
37 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
38 const int64 file_size = src_entry.file_info().size();
40 // Pretend we have enough space.
41 fake_free_disk_space_getter()->set_default_value(
42 file_size + internal::kMinFreeSpace);
44 FileError error = FILE_ERROR_FAILED;
45 base::FilePath file_path;
46 scoped_ptr<ResourceEntry> entry;
47 operation_->EnsureFileDownloadedByPath(
49 ClientContext(USER_INITIATED),
50 GetFileContentInitializedCallback(),
51 google_apis::GetContentCallback(),
52 google_apis::test_util::CreateCopyResultCallback(
53 &error, &file_path, &entry));
54 test_util::RunBlockingPoolTask();
56 EXPECT_EQ(FILE_ERROR_OK, error);
58 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
60 // The transfered file is cached and the change of "offline available"
61 // attribute is notified.
62 EXPECT_EQ(1U, observer()->get_changed_paths().size());
63 EXPECT_EQ(1U, observer()->get_changed_paths().count(file_in_root.DirName()));
65 // Verify that readable permission is set.
67 EXPECT_TRUE(file_util::GetPosixFilePermissions(file_path, &permission));
68 EXPECT_EQ(file_util::FILE_PERMISSION_READ_BY_USER |
69 file_util::FILE_PERMISSION_WRITE_BY_USER |
70 file_util::FILE_PERMISSION_READ_BY_GROUP |
71 file_util::FILE_PERMISSION_READ_BY_OTHERS, permission);
74 TEST_F(DownloadOperationTest,
75 EnsureFileDownloadedByPath_FromServer_NoSpaceAtAll) {
76 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
78 // Pretend we have no space at all.
79 fake_free_disk_space_getter()->set_default_value(0);
81 FileError error = FILE_ERROR_OK;
82 base::FilePath file_path;
83 scoped_ptr<ResourceEntry> entry;
84 operation_->EnsureFileDownloadedByPath(
86 ClientContext(USER_INITIATED),
87 GetFileContentInitializedCallback(),
88 google_apis::GetContentCallback(),
89 google_apis::test_util::CreateCopyResultCallback(
90 &error, &file_path, &entry));
91 test_util::RunBlockingPoolTask();
93 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
96 TEST_F(DownloadOperationTest,
97 EnsureFileDownloadedByPath_FromServer_NoEnoughSpaceButCanFreeUp) {
98 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
99 ResourceEntry src_entry;
100 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
101 const int64 file_size = src_entry.file_info().size();
103 // Pretend we have no space first (checked before downloading a file),
104 // but then start reporting we have space. This is to emulate that
105 // the disk space was freed up by removing temporary files.
106 fake_free_disk_space_getter()->PushFakeValue(
107 file_size + internal::kMinFreeSpace);
108 fake_free_disk_space_getter()->PushFakeValue(0);
109 fake_free_disk_space_getter()->set_default_value(
110 file_size + internal::kMinFreeSpace);
112 // Store something of the file size in the temporary cache directory.
113 const std::string content(file_size, 'x');
114 base::ScopedTempDir temp_dir;
115 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
116 const base::FilePath tmp_file =
117 temp_dir.path().AppendASCII("something.txt");
118 ASSERT_TRUE(google_apis::test_util::WriteStringToFile(tmp_file, content));
120 FileError error = FILE_ERROR_FAILED;
121 base::PostTaskAndReplyWithResult(
122 blocking_task_runner(),
124 base::Bind(&internal::FileCache::Store,
125 base::Unretained(cache()),
126 "<id>", "<md5>", tmp_file,
127 internal::FileCache::FILE_OPERATION_COPY),
128 google_apis::test_util::CreateCopyResultCallback(&error));
129 test_util::RunBlockingPoolTask();
130 EXPECT_EQ(FILE_ERROR_OK, error);
132 base::FilePath file_path;
133 scoped_ptr<ResourceEntry> entry;
134 operation_->EnsureFileDownloadedByPath(
136 ClientContext(USER_INITIATED),
137 GetFileContentInitializedCallback(),
138 google_apis::GetContentCallback(),
139 google_apis::test_util::CreateCopyResultCallback(
140 &error, &file_path, &entry));
141 test_util::RunBlockingPoolTask();
143 EXPECT_EQ(FILE_ERROR_OK, error);
145 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
147 // The transfered file is cached and the change of "offline available"
148 // attribute is notified.
149 EXPECT_EQ(1U, observer()->get_changed_paths().size());
150 EXPECT_EQ(1U, observer()->get_changed_paths().count(file_in_root.DirName()));
152 // The cache entry should be removed in order to free up space.
153 FileCacheEntry cache_entry;
155 base::PostTaskAndReplyWithResult(
156 blocking_task_runner(),
158 base::Bind(&internal::FileCache::GetCacheEntry,
159 base::Unretained(cache()),
162 google_apis::test_util::CreateCopyResultCallback(&result));
163 test_util::RunBlockingPoolTask();
164 ASSERT_FALSE(result);
167 TEST_F(DownloadOperationTest,
168 EnsureFileDownloadedByPath_FromServer_EnoughSpaceButBecomeFull) {
169 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
170 ResourceEntry src_entry;
171 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
172 const int64 file_size = src_entry.file_info().size();
174 // Pretend we have enough space first (checked before downloading a file),
175 // but then start reporting we have not enough space. This is to emulate that
176 // the disk space becomes full after the file is downloaded for some reason
177 // (ex. the actual file was larger than the expected size).
178 fake_free_disk_space_getter()->PushFakeValue(
179 file_size + internal::kMinFreeSpace);
180 fake_free_disk_space_getter()->set_default_value(
181 internal::kMinFreeSpace - 1);
183 FileError error = FILE_ERROR_OK;
184 base::FilePath file_path;
185 scoped_ptr<ResourceEntry> entry;
186 operation_->EnsureFileDownloadedByPath(
188 ClientContext(USER_INITIATED),
189 GetFileContentInitializedCallback(),
190 google_apis::GetContentCallback(),
191 google_apis::test_util::CreateCopyResultCallback(
192 &error, &file_path, &entry));
193 test_util::RunBlockingPoolTask();
195 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
198 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_FromCache) {
199 base::FilePath temp_file;
200 ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir(), &temp_file));
202 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
203 ResourceEntry src_entry;
204 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
206 // Store something as cached version of this file.
207 FileError error = FILE_ERROR_OK;
208 base::PostTaskAndReplyWithResult(
209 blocking_task_runner(),
211 base::Bind(&internal::FileCache::Store,
212 base::Unretained(cache()),
213 GetLocalId(file_in_root),
214 src_entry.file_specific_info().md5(),
216 internal::FileCache::FILE_OPERATION_COPY),
217 google_apis::test_util::CreateCopyResultCallback(&error));
218 test_util::RunBlockingPoolTask();
219 EXPECT_EQ(FILE_ERROR_OK, error);
221 base::FilePath file_path;
222 scoped_ptr<ResourceEntry> entry;
223 operation_->EnsureFileDownloadedByPath(
225 ClientContext(USER_INITIATED),
226 GetFileContentInitializedCallback(),
227 google_apis::GetContentCallback(),
228 google_apis::test_util::CreateCopyResultCallback(
229 &error, &file_path, &entry));
230 test_util::RunBlockingPoolTask();
232 EXPECT_EQ(FILE_ERROR_OK, error);
234 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
237 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_HostedDocument) {
238 base::FilePath file_in_root(FILE_PATH_LITERAL(
239 "drive/root/Document 1 excludeDir-test.gdoc"));
241 FileError error = FILE_ERROR_FAILED;
242 base::FilePath file_path;
243 scoped_ptr<ResourceEntry> entry;
244 operation_->EnsureFileDownloadedByPath(
246 ClientContext(USER_INITIATED),
247 GetFileContentInitializedCallback(),
248 google_apis::GetContentCallback(),
249 google_apis::test_util::CreateCopyResultCallback(
250 &error, &file_path, &entry));
251 test_util::RunBlockingPoolTask();
253 EXPECT_EQ(FILE_ERROR_OK, error);
255 EXPECT_TRUE(entry->file_specific_info().is_hosted_document());
256 EXPECT_FALSE(file_path.empty());
258 EXPECT_EQ(GURL(entry->file_specific_info().alternate_url()),
259 util::ReadUrlFromGDocFile(file_path));
260 EXPECT_EQ(entry->resource_id(), util::ReadResourceIdFromGDocFile(file_path));
263 TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId) {
264 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
265 ResourceEntry src_entry;
266 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
268 FileError error = FILE_ERROR_OK;
269 base::FilePath file_path;
270 scoped_ptr<ResourceEntry> entry;
271 operation_->EnsureFileDownloadedByLocalId(
272 GetLocalId(file_in_root),
273 ClientContext(USER_INITIATED),
274 GetFileContentInitializedCallback(),
275 google_apis::GetContentCallback(),
276 google_apis::test_util::CreateCopyResultCallback(
277 &error, &file_path, &entry));
278 test_util::RunBlockingPoolTask();
280 EXPECT_EQ(FILE_ERROR_OK, error);
282 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
284 // The transfered file is cached and the change of "offline available"
285 // attribute is notified.
286 EXPECT_EQ(1U, observer()->get_changed_paths().size());
287 EXPECT_EQ(1U, observer()->get_changed_paths().count(file_in_root.DirName()));
290 TEST_F(DownloadOperationTest,
291 EnsureFileDownloadedByPath_WithGetContentCallback) {
292 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
295 FileError initialized_error = FILE_ERROR_FAILED;
296 scoped_ptr<ResourceEntry> entry, entry_dontcare;
297 base::FilePath local_path, local_path_dontcare;
298 base::Closure cancel_download;
299 google_apis::test_util::TestGetContentCallback get_content_callback;
301 FileError completion_error = FILE_ERROR_FAILED;
303 operation_->EnsureFileDownloadedByPath(
305 ClientContext(USER_INITIATED),
306 google_apis::test_util::CreateCopyResultCallback(
307 &initialized_error, &entry, &local_path, &cancel_download),
308 get_content_callback.callback(),
309 google_apis::test_util::CreateCopyResultCallback(
310 &completion_error, &local_path_dontcare, &entry_dontcare));
311 test_util::RunBlockingPoolTask();
313 // For the first time, file is downloaded from the remote server.
314 // In this case, |local_path| is empty while |cancel_download| is not.
315 EXPECT_EQ(FILE_ERROR_OK, initialized_error);
317 ASSERT_TRUE(local_path.empty());
318 EXPECT_TRUE(!cancel_download.is_null());
319 // Content is available through the second callback argument.
320 EXPECT_EQ(static_cast<size_t>(entry->file_info().size()),
321 get_content_callback.GetConcatenatedData().size());
322 EXPECT_EQ(FILE_ERROR_OK, completion_error);
324 // The transfered file is cached and the change of "offline available"
325 // attribute is notified.
326 EXPECT_EQ(1U, observer()->get_changed_paths().size());
328 observer()->get_changed_paths().count(file_in_root.DirName()));
332 FileError initialized_error = FILE_ERROR_FAILED;
333 scoped_ptr<ResourceEntry> entry, entry_dontcare;
334 base::FilePath local_path, local_path_dontcare;
335 base::Closure cancel_download;
336 google_apis::test_util::TestGetContentCallback get_content_callback;
338 FileError completion_error = FILE_ERROR_FAILED;
340 operation_->EnsureFileDownloadedByPath(
342 ClientContext(USER_INITIATED),
343 google_apis::test_util::CreateCopyResultCallback(
344 &initialized_error, &entry, &local_path, &cancel_download),
345 get_content_callback.callback(),
346 google_apis::test_util::CreateCopyResultCallback(
347 &completion_error, &local_path_dontcare, &entry_dontcare));
348 test_util::RunBlockingPoolTask();
350 // Try second download. In this case, the file should be cached, so
351 // |local_path| should not be empty while |cancel_download| is empty.
352 EXPECT_EQ(FILE_ERROR_OK, initialized_error);
354 ASSERT_TRUE(!local_path.empty());
355 EXPECT_TRUE(cancel_download.is_null());
356 // The content is available from the cache file.
357 EXPECT_TRUE(get_content_callback.data().empty());
358 int64 local_file_size = 0;
359 file_util::GetFileSize(local_path, &local_file_size);
360 EXPECT_EQ(entry->file_info().size(), local_file_size);
361 EXPECT_EQ(FILE_ERROR_OK, completion_error);
365 TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId_FromCache) {
366 base::FilePath temp_file;
367 ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir(), &temp_file));
369 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
370 ResourceEntry src_entry;
371 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
373 // Store something as cached version of this file.
374 FileError error = FILE_ERROR_FAILED;
375 base::PostTaskAndReplyWithResult(
376 blocking_task_runner(),
378 base::Bind(&internal::FileCache::Store,
379 base::Unretained(cache()),
380 GetLocalId(file_in_root),
381 src_entry.file_specific_info().md5(),
383 internal::FileCache::FILE_OPERATION_COPY),
384 google_apis::test_util::CreateCopyResultCallback(&error));
385 test_util::RunBlockingPoolTask();
386 EXPECT_EQ(FILE_ERROR_OK, error);
388 // The file is obtained from the cache.
389 // Hence the downloading should work even if the drive service is offline.
390 fake_service()->set_offline(true);
392 base::FilePath file_path;
393 scoped_ptr<ResourceEntry> entry;
394 operation_->EnsureFileDownloadedByLocalId(
395 GetLocalId(file_in_root),
396 ClientContext(USER_INITIATED),
397 GetFileContentInitializedCallback(),
398 google_apis::GetContentCallback(),
399 google_apis::test_util::CreateCopyResultCallback(
400 &error, &file_path, &entry));
401 test_util::RunBlockingPoolTask();
403 EXPECT_EQ(FILE_ERROR_OK, error);
405 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
408 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_DirtyCache) {
409 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
410 ResourceEntry src_entry;
411 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
413 // Prepare a dirty file to store to cache that has a different size than
414 // stored in resource metadata.
415 base::FilePath dirty_file = temp_dir().AppendASCII("dirty.txt");
416 size_t dirty_size = src_entry.file_info().size() + 10;
417 google_apis::test_util::WriteStringToFile(dirty_file,
418 std::string(dirty_size, 'x'));
420 // Store the file as a cache, marking it to be dirty.
421 FileError error = FILE_ERROR_FAILED;
422 base::PostTaskAndReplyWithResult(
423 blocking_task_runner(),
425 base::Bind(&internal::FileCache::Store,
426 base::Unretained(cache()),
427 GetLocalId(file_in_root),
428 src_entry.file_specific_info().md5(),
430 internal::FileCache::FILE_OPERATION_COPY),
431 google_apis::test_util::CreateCopyResultCallback(&error));
432 test_util::RunBlockingPoolTask();
433 EXPECT_EQ(FILE_ERROR_OK, error);
434 base::PostTaskAndReplyWithResult(
435 blocking_task_runner(),
437 base::Bind(&internal::FileCache::MarkDirty,
438 base::Unretained(cache()),
439 GetLocalId(file_in_root)),
440 google_apis::test_util::CreateCopyResultCallback(&error));
441 test_util::RunBlockingPoolTask();
442 EXPECT_EQ(FILE_ERROR_OK, error);
444 // Record values passed to GetFileContentInitializedCallback().
445 FileError init_error;
446 base::FilePath init_path;
447 scoped_ptr<ResourceEntry> init_entry;
448 base::Closure cancel_callback;
450 base::FilePath file_path;
451 scoped_ptr<ResourceEntry> entry;
452 operation_->EnsureFileDownloadedByPath(
454 ClientContext(USER_INITIATED),
455 google_apis::test_util::CreateCopyResultCallback(
456 &init_error, &init_entry, &init_path, &cancel_callback),
457 google_apis::GetContentCallback(),
458 google_apis::test_util::CreateCopyResultCallback(
459 &error, &file_path, &entry));
460 test_util::RunBlockingPoolTask();
462 EXPECT_EQ(FILE_ERROR_OK, error);
463 // Check that the result of local modification is propagated.
464 EXPECT_EQ(static_cast<int64>(dirty_size), init_entry->file_info().size());
465 EXPECT_EQ(static_cast<int64>(dirty_size), entry->file_info().size());
468 } // namespace file_system