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 "google_apis/drive/test_util.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/cros_system_api/constants/cryptohome.h"
19 namespace file_system {
21 class DownloadOperationTest : public OperationTestBase {
23 virtual void SetUp() OVERRIDE {
24 OperationTestBase::SetUp();
26 operation_.reset(new DownloadOperation(
27 blocking_task_runner(), observer(), scheduler(), metadata(), cache(),
31 scoped_ptr<DownloadOperation> operation_;
34 TEST_F(DownloadOperationTest,
35 EnsureFileDownloadedByPath_FromServer_EnoughSpace) {
36 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
37 ResourceEntry src_entry;
38 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
39 const int64 file_size = src_entry.file_info().size();
41 // Pretend we have enough space.
42 fake_free_disk_space_getter()->set_default_value(
43 file_size + cryptohome::kMinFreeSpaceInBytes);
45 FileError error = FILE_ERROR_FAILED;
46 base::FilePath file_path;
47 scoped_ptr<ResourceEntry> entry;
48 operation_->EnsureFileDownloadedByPath(
50 ClientContext(USER_INITIATED),
51 GetFileContentInitializedCallback(),
52 google_apis::GetContentCallback(),
53 google_apis::test_util::CreateCopyResultCallback(
54 &error, &file_path, &entry));
55 test_util::RunBlockingPoolTask();
57 EXPECT_EQ(FILE_ERROR_OK, error);
59 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
61 // The transfered file is cached and the change of "offline available"
62 // attribute is notified.
63 EXPECT_EQ(1U, observer()->get_changed_paths().size());
64 EXPECT_EQ(1U, observer()->get_changed_paths().count(file_in_root.DirName()));
66 // Verify that readable permission is set.
68 EXPECT_TRUE(base::GetPosixFilePermissions(file_path, &permission));
69 EXPECT_EQ(base::FILE_PERMISSION_READ_BY_USER |
70 base::FILE_PERMISSION_WRITE_BY_USER |
71 base::FILE_PERMISSION_READ_BY_GROUP |
72 base::FILE_PERMISSION_READ_BY_OTHERS, permission);
75 TEST_F(DownloadOperationTest,
76 EnsureFileDownloadedByPath_FromServer_NoSpaceAtAll) {
77 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
79 // Pretend we have no space at all.
80 fake_free_disk_space_getter()->set_default_value(0);
82 FileError error = FILE_ERROR_OK;
83 base::FilePath file_path;
84 scoped_ptr<ResourceEntry> entry;
85 operation_->EnsureFileDownloadedByPath(
87 ClientContext(USER_INITIATED),
88 GetFileContentInitializedCallback(),
89 google_apis::GetContentCallback(),
90 google_apis::test_util::CreateCopyResultCallback(
91 &error, &file_path, &entry));
92 test_util::RunBlockingPoolTask();
94 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
97 TEST_F(DownloadOperationTest,
98 EnsureFileDownloadedByPath_FromServer_NoEnoughSpaceButCanFreeUp) {
99 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
100 ResourceEntry src_entry;
101 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
102 const int64 file_size = src_entry.file_info().size();
104 // Pretend we have no space first (checked before downloading a file),
105 // but then start reporting we have space. This is to emulate that
106 // the disk space was freed up by removing temporary files.
107 fake_free_disk_space_getter()->PushFakeValue(
108 file_size + cryptohome::kMinFreeSpaceInBytes);
109 fake_free_disk_space_getter()->PushFakeValue(0);
110 fake_free_disk_space_getter()->set_default_value(
111 file_size + cryptohome::kMinFreeSpaceInBytes);
113 // Store something of the file size in the temporary cache directory.
114 const std::string content(file_size, 'x');
115 base::ScopedTempDir temp_dir;
116 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
117 const base::FilePath tmp_file =
118 temp_dir.path().AppendASCII("something.txt");
119 ASSERT_TRUE(google_apis::test_util::WriteStringToFile(tmp_file, content));
121 FileError error = FILE_ERROR_FAILED;
122 base::PostTaskAndReplyWithResult(
123 blocking_task_runner(),
125 base::Bind(&internal::FileCache::Store,
126 base::Unretained(cache()),
127 "<id>", "<md5>", tmp_file,
128 internal::FileCache::FILE_OPERATION_COPY),
129 google_apis::test_util::CreateCopyResultCallback(&error));
130 test_util::RunBlockingPoolTask();
131 EXPECT_EQ(FILE_ERROR_OK, error);
133 base::FilePath file_path;
134 scoped_ptr<ResourceEntry> entry;
135 operation_->EnsureFileDownloadedByPath(
137 ClientContext(USER_INITIATED),
138 GetFileContentInitializedCallback(),
139 google_apis::GetContentCallback(),
140 google_apis::test_util::CreateCopyResultCallback(
141 &error, &file_path, &entry));
142 test_util::RunBlockingPoolTask();
144 EXPECT_EQ(FILE_ERROR_OK, error);
146 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
148 // The transfered file is cached and the change of "offline available"
149 // attribute is notified.
150 EXPECT_EQ(1U, observer()->get_changed_paths().size());
151 EXPECT_EQ(1U, observer()->get_changed_paths().count(file_in_root.DirName()));
153 // The cache entry should be removed in order to free up space.
154 FileCacheEntry cache_entry;
156 base::PostTaskAndReplyWithResult(
157 blocking_task_runner(),
159 base::Bind(&internal::FileCache::GetCacheEntry,
160 base::Unretained(cache()),
163 google_apis::test_util::CreateCopyResultCallback(&result));
164 test_util::RunBlockingPoolTask();
165 ASSERT_FALSE(result);
168 TEST_F(DownloadOperationTest,
169 EnsureFileDownloadedByPath_FromServer_EnoughSpaceButBecomeFull) {
170 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
171 ResourceEntry src_entry;
172 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
173 const int64 file_size = src_entry.file_info().size();
175 // Pretend we have enough space first (checked before downloading a file),
176 // but then start reporting we have not enough space. This is to emulate that
177 // the disk space becomes full after the file is downloaded for some reason
178 // (ex. the actual file was larger than the expected size).
179 fake_free_disk_space_getter()->PushFakeValue(
180 file_size + cryptohome::kMinFreeSpaceInBytes);
181 fake_free_disk_space_getter()->set_default_value(
182 cryptohome::kMinFreeSpaceInBytes - 1);
184 FileError error = FILE_ERROR_OK;
185 base::FilePath file_path;
186 scoped_ptr<ResourceEntry> entry;
187 operation_->EnsureFileDownloadedByPath(
189 ClientContext(USER_INITIATED),
190 GetFileContentInitializedCallback(),
191 google_apis::GetContentCallback(),
192 google_apis::test_util::CreateCopyResultCallback(
193 &error, &file_path, &entry));
194 test_util::RunBlockingPoolTask();
196 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
199 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_FromCache) {
200 base::FilePath temp_file;
201 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
203 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
204 ResourceEntry src_entry;
205 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
207 // Store something as cached version of this file.
208 FileError error = FILE_ERROR_OK;
209 base::PostTaskAndReplyWithResult(
210 blocking_task_runner(),
212 base::Bind(&internal::FileCache::Store,
213 base::Unretained(cache()),
214 GetLocalId(file_in_root),
215 src_entry.file_specific_info().md5(),
217 internal::FileCache::FILE_OPERATION_COPY),
218 google_apis::test_util::CreateCopyResultCallback(&error));
219 test_util::RunBlockingPoolTask();
220 EXPECT_EQ(FILE_ERROR_OK, error);
222 base::FilePath file_path;
223 scoped_ptr<ResourceEntry> entry;
224 operation_->EnsureFileDownloadedByPath(
226 ClientContext(USER_INITIATED),
227 GetFileContentInitializedCallback(),
228 google_apis::GetContentCallback(),
229 google_apis::test_util::CreateCopyResultCallback(
230 &error, &file_path, &entry));
231 test_util::RunBlockingPoolTask();
233 EXPECT_EQ(FILE_ERROR_OK, error);
235 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
238 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_HostedDocument) {
239 base::FilePath file_in_root(FILE_PATH_LITERAL(
240 "drive/root/Document 1 excludeDir-test.gdoc"));
242 FileError error = FILE_ERROR_FAILED;
243 base::FilePath file_path;
244 scoped_ptr<ResourceEntry> entry;
245 operation_->EnsureFileDownloadedByPath(
247 ClientContext(USER_INITIATED),
248 GetFileContentInitializedCallback(),
249 google_apis::GetContentCallback(),
250 google_apis::test_util::CreateCopyResultCallback(
251 &error, &file_path, &entry));
252 test_util::RunBlockingPoolTask();
254 EXPECT_EQ(FILE_ERROR_OK, error);
256 EXPECT_TRUE(entry->file_specific_info().is_hosted_document());
257 EXPECT_FALSE(file_path.empty());
259 EXPECT_EQ(GURL(entry->file_specific_info().alternate_url()),
260 util::ReadUrlFromGDocFile(file_path));
261 EXPECT_EQ(entry->resource_id(), util::ReadResourceIdFromGDocFile(file_path));
262 EXPECT_EQ(FILE_PATH_LITERAL(".gdoc"), file_path.Extension());
265 TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId) {
266 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
267 ResourceEntry src_entry;
268 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
270 FileError error = FILE_ERROR_OK;
271 base::FilePath file_path;
272 scoped_ptr<ResourceEntry> entry;
273 operation_->EnsureFileDownloadedByLocalId(
274 GetLocalId(file_in_root),
275 ClientContext(USER_INITIATED),
276 GetFileContentInitializedCallback(),
277 google_apis::GetContentCallback(),
278 google_apis::test_util::CreateCopyResultCallback(
279 &error, &file_path, &entry));
280 test_util::RunBlockingPoolTask();
282 EXPECT_EQ(FILE_ERROR_OK, error);
284 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
286 // The transfered file is cached and the change of "offline available"
287 // attribute is notified.
288 EXPECT_EQ(1U, observer()->get_changed_paths().size());
289 EXPECT_EQ(1U, observer()->get_changed_paths().count(file_in_root.DirName()));
292 TEST_F(DownloadOperationTest,
293 EnsureFileDownloadedByPath_WithGetContentCallback) {
294 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
297 FileError initialized_error = FILE_ERROR_FAILED;
298 scoped_ptr<ResourceEntry> entry, entry_dontcare;
299 base::FilePath local_path, local_path_dontcare;
300 base::Closure cancel_download;
301 google_apis::test_util::TestGetContentCallback get_content_callback;
303 FileError completion_error = FILE_ERROR_FAILED;
305 operation_->EnsureFileDownloadedByPath(
307 ClientContext(USER_INITIATED),
308 google_apis::test_util::CreateCopyResultCallback(
309 &initialized_error, &entry, &local_path, &cancel_download),
310 get_content_callback.callback(),
311 google_apis::test_util::CreateCopyResultCallback(
312 &completion_error, &local_path_dontcare, &entry_dontcare));
313 test_util::RunBlockingPoolTask();
315 // For the first time, file is downloaded from the remote server.
316 // In this case, |local_path| is empty while |cancel_download| is not.
317 EXPECT_EQ(FILE_ERROR_OK, initialized_error);
319 ASSERT_TRUE(local_path.empty());
320 EXPECT_TRUE(!cancel_download.is_null());
321 // Content is available through the second callback argument.
322 EXPECT_EQ(static_cast<size_t>(entry->file_info().size()),
323 get_content_callback.GetConcatenatedData().size());
324 EXPECT_EQ(FILE_ERROR_OK, completion_error);
326 // The transfered file is cached and the change of "offline available"
327 // attribute is notified.
328 EXPECT_EQ(1U, observer()->get_changed_paths().size());
330 observer()->get_changed_paths().count(file_in_root.DirName()));
334 FileError initialized_error = FILE_ERROR_FAILED;
335 scoped_ptr<ResourceEntry> entry, entry_dontcare;
336 base::FilePath local_path, local_path_dontcare;
337 base::Closure cancel_download;
338 google_apis::test_util::TestGetContentCallback get_content_callback;
340 FileError completion_error = FILE_ERROR_FAILED;
342 operation_->EnsureFileDownloadedByPath(
344 ClientContext(USER_INITIATED),
345 google_apis::test_util::CreateCopyResultCallback(
346 &initialized_error, &entry, &local_path, &cancel_download),
347 get_content_callback.callback(),
348 google_apis::test_util::CreateCopyResultCallback(
349 &completion_error, &local_path_dontcare, &entry_dontcare));
350 test_util::RunBlockingPoolTask();
352 // Try second download. In this case, the file should be cached, so
353 // |local_path| should not be empty while |cancel_download| is empty.
354 EXPECT_EQ(FILE_ERROR_OK, initialized_error);
356 ASSERT_TRUE(!local_path.empty());
357 EXPECT_TRUE(cancel_download.is_null());
358 // The content is available from the cache file.
359 EXPECT_TRUE(get_content_callback.data().empty());
360 int64 local_file_size = 0;
361 base::GetFileSize(local_path, &local_file_size);
362 EXPECT_EQ(entry->file_info().size(), local_file_size);
363 EXPECT_EQ(FILE_ERROR_OK, completion_error);
367 TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId_FromCache) {
368 base::FilePath temp_file;
369 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
371 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
372 ResourceEntry src_entry;
373 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
375 // Store something as cached version of this file.
376 FileError error = FILE_ERROR_FAILED;
377 base::PostTaskAndReplyWithResult(
378 blocking_task_runner(),
380 base::Bind(&internal::FileCache::Store,
381 base::Unretained(cache()),
382 GetLocalId(file_in_root),
383 src_entry.file_specific_info().md5(),
385 internal::FileCache::FILE_OPERATION_COPY),
386 google_apis::test_util::CreateCopyResultCallback(&error));
387 test_util::RunBlockingPoolTask();
388 EXPECT_EQ(FILE_ERROR_OK, error);
390 // The file is obtained from the cache.
391 // Hence the downloading should work even if the drive service is offline.
392 fake_service()->set_offline(true);
394 base::FilePath file_path;
395 scoped_ptr<ResourceEntry> entry;
396 operation_->EnsureFileDownloadedByLocalId(
397 GetLocalId(file_in_root),
398 ClientContext(USER_INITIATED),
399 GetFileContentInitializedCallback(),
400 google_apis::GetContentCallback(),
401 google_apis::test_util::CreateCopyResultCallback(
402 &error, &file_path, &entry));
403 test_util::RunBlockingPoolTask();
405 EXPECT_EQ(FILE_ERROR_OK, error);
407 EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
410 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_DirtyCache) {
411 base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
412 ResourceEntry src_entry;
413 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
415 // Prepare a dirty file to store to cache that has a different size than
416 // stored in resource metadata.
417 base::FilePath dirty_file = temp_dir().AppendASCII("dirty.txt");
418 size_t dirty_size = src_entry.file_info().size() + 10;
419 google_apis::test_util::WriteStringToFile(dirty_file,
420 std::string(dirty_size, 'x'));
422 // Store the file as a cache, marking it to be dirty.
423 FileError error = FILE_ERROR_FAILED;
424 base::PostTaskAndReplyWithResult(
425 blocking_task_runner(),
427 base::Bind(&internal::FileCache::Store,
428 base::Unretained(cache()),
429 GetLocalId(file_in_root),
432 internal::FileCache::FILE_OPERATION_COPY),
433 google_apis::test_util::CreateCopyResultCallback(&error));
434 test_util::RunBlockingPoolTask();
435 EXPECT_EQ(FILE_ERROR_OK, error);
437 // Record values passed to GetFileContentInitializedCallback().
438 FileError init_error;
439 base::FilePath init_path;
440 scoped_ptr<ResourceEntry> init_entry;
441 base::Closure cancel_callback;
443 base::FilePath file_path;
444 scoped_ptr<ResourceEntry> entry;
445 operation_->EnsureFileDownloadedByPath(
447 ClientContext(USER_INITIATED),
448 google_apis::test_util::CreateCopyResultCallback(
449 &init_error, &init_entry, &init_path, &cancel_callback),
450 google_apis::GetContentCallback(),
451 google_apis::test_util::CreateCopyResultCallback(
452 &error, &file_path, &entry));
453 test_util::RunBlockingPoolTask();
455 EXPECT_EQ(FILE_ERROR_OK, error);
456 // Check that the result of local modification is propagated.
457 EXPECT_EQ(static_cast<int64>(dirty_size), init_entry->file_info().size());
458 EXPECT_EQ(static_cast<int64>(dirty_size), entry->file_info().size());
461 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_LocallyCreatedFile) {
462 // Add a new file with an empty resource ID.
463 base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt"));
464 ResourceEntry parent;
465 ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_path.DirName(), &parent));
467 ResourceEntry new_file;
468 new_file.set_title("New File.txt");
469 new_file.set_parent_local_id(parent.local_id());
471 FileError error = FILE_ERROR_FAILED;
472 std::string local_id;
473 base::PostTaskAndReplyWithResult(
474 blocking_task_runner(),
476 base::Bind(&internal::ResourceMetadata::AddEntry,
477 base::Unretained(metadata()),
480 google_apis::test_util::CreateCopyResultCallback(&error));
481 test_util::RunBlockingPoolTask();
482 EXPECT_EQ(FILE_ERROR_OK, error);
484 // Empty cache file should be returned.
485 base::FilePath cache_file_path;
486 scoped_ptr<ResourceEntry> entry;
487 operation_->EnsureFileDownloadedByPath(
489 ClientContext(USER_INITIATED),
490 GetFileContentInitializedCallback(),
491 google_apis::GetContentCallback(),
492 google_apis::test_util::CreateCopyResultCallback(
493 &error, &cache_file_path, &entry));
494 test_util::RunBlockingPoolTask();
495 EXPECT_EQ(FILE_ERROR_OK, error);
497 int64 cache_file_size = 0;
498 EXPECT_TRUE(base::GetFileSize(cache_file_path, &cache_file_size));
499 EXPECT_EQ(static_cast<int64>(0), cache_file_size);
501 EXPECT_EQ(cache_file_size, entry->file_info().size());
504 } // namespace file_system