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/callback_helpers.h"
8 #include "base/file_util.h"
9 #include "base/task_runner_util.h"
10 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
11 #include "chrome/browser/chromeos/drive/file_cache.h"
12 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
13 #include "chrome/browser/chromeos/drive/file_system_util.h"
14 #include "chrome/browser/drive/fake_drive_service.h"
15 #include "google_apis/drive/test_util.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/cros_system_api/constants/cryptohome.h"
20 namespace file_system
{
22 class DownloadOperationTest
: public OperationTestBase
{
24 virtual void SetUp() OVERRIDE
{
25 OperationTestBase::SetUp();
27 operation_
.reset(new DownloadOperation(
28 blocking_task_runner(), observer(), scheduler(), metadata(), cache(),
32 scoped_ptr
<DownloadOperation
> operation_
;
35 TEST_F(DownloadOperationTest
,
36 EnsureFileDownloadedByPath_FromServer_EnoughSpace
) {
37 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
38 ResourceEntry src_entry
;
39 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
40 const int64 file_size
= src_entry
.file_info().size();
42 // Pretend we have enough space.
43 fake_free_disk_space_getter()->set_default_value(
44 file_size
+ cryptohome::kMinFreeSpaceInBytes
);
46 FileError error
= FILE_ERROR_FAILED
;
47 base::FilePath file_path
;
48 scoped_ptr
<ResourceEntry
> entry
;
49 operation_
->EnsureFileDownloadedByPath(
51 ClientContext(USER_INITIATED
),
52 GetFileContentInitializedCallback(),
53 google_apis::GetContentCallback(),
54 google_apis::test_util::CreateCopyResultCallback(
55 &error
, &file_path
, &entry
));
56 test_util::RunBlockingPoolTask();
58 EXPECT_EQ(FILE_ERROR_OK
, error
);
60 EXPECT_FALSE(entry
->file_specific_info().is_hosted_document());
62 // The transfered file is cached and the change of "offline available"
63 // attribute is notified.
64 EXPECT_EQ(1U, observer()->get_changed_paths().size());
65 EXPECT_EQ(1U, observer()->get_changed_paths().count(file_in_root
.DirName()));
67 // Verify that readable permission is set.
69 EXPECT_TRUE(base::GetPosixFilePermissions(file_path
, &permission
));
70 EXPECT_EQ(base::FILE_PERMISSION_READ_BY_USER
|
71 base::FILE_PERMISSION_WRITE_BY_USER
|
72 base::FILE_PERMISSION_READ_BY_GROUP
|
73 base::FILE_PERMISSION_READ_BY_OTHERS
, permission
);
76 TEST_F(DownloadOperationTest
,
77 EnsureFileDownloadedByPath_FromServer_NoSpaceAtAll
) {
78 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
80 // Pretend we have no space at all.
81 fake_free_disk_space_getter()->set_default_value(0);
83 FileError error
= FILE_ERROR_OK
;
84 base::FilePath file_path
;
85 scoped_ptr
<ResourceEntry
> entry
;
86 operation_
->EnsureFileDownloadedByPath(
88 ClientContext(USER_INITIATED
),
89 GetFileContentInitializedCallback(),
90 google_apis::GetContentCallback(),
91 google_apis::test_util::CreateCopyResultCallback(
92 &error
, &file_path
, &entry
));
93 test_util::RunBlockingPoolTask();
95 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE
, error
);
98 TEST_F(DownloadOperationTest
,
99 EnsureFileDownloadedByPath_FromServer_NoEnoughSpaceButCanFreeUp
) {
100 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
101 ResourceEntry src_entry
;
102 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
103 const int64 file_size
= src_entry
.file_info().size();
105 // Pretend we have no space first (checked before downloading a file),
106 // but then start reporting we have space. This is to emulate that
107 // the disk space was freed up by removing temporary files.
108 fake_free_disk_space_getter()->PushFakeValue(
109 file_size
+ cryptohome::kMinFreeSpaceInBytes
);
110 fake_free_disk_space_getter()->PushFakeValue(0);
111 fake_free_disk_space_getter()->set_default_value(
112 file_size
+ cryptohome::kMinFreeSpaceInBytes
);
114 // Store something of the file size in the temporary cache directory.
115 const std::string
content(file_size
, 'x');
116 base::ScopedTempDir temp_dir
;
117 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
118 const base::FilePath tmp_file
=
119 temp_dir
.path().AppendASCII("something.txt");
120 ASSERT_TRUE(google_apis::test_util::WriteStringToFile(tmp_file
, content
));
122 FileError error
= FILE_ERROR_FAILED
;
123 base::PostTaskAndReplyWithResult(
124 blocking_task_runner(),
126 base::Bind(&internal::FileCache::Store
,
127 base::Unretained(cache()),
128 "<id>", "<md5>", tmp_file
,
129 internal::FileCache::FILE_OPERATION_COPY
),
130 google_apis::test_util::CreateCopyResultCallback(&error
));
131 test_util::RunBlockingPoolTask();
132 EXPECT_EQ(FILE_ERROR_OK
, error
);
134 base::FilePath file_path
;
135 scoped_ptr
<ResourceEntry
> entry
;
136 operation_
->EnsureFileDownloadedByPath(
138 ClientContext(USER_INITIATED
),
139 GetFileContentInitializedCallback(),
140 google_apis::GetContentCallback(),
141 google_apis::test_util::CreateCopyResultCallback(
142 &error
, &file_path
, &entry
));
143 test_util::RunBlockingPoolTask();
145 EXPECT_EQ(FILE_ERROR_OK
, error
);
147 EXPECT_FALSE(entry
->file_specific_info().is_hosted_document());
149 // The transfered file is cached and the change of "offline available"
150 // attribute is notified.
151 EXPECT_EQ(1U, observer()->get_changed_paths().size());
152 EXPECT_EQ(1U, observer()->get_changed_paths().count(file_in_root
.DirName()));
154 // The cache entry should be removed in order to free up space.
155 FileCacheEntry cache_entry
;
157 base::PostTaskAndReplyWithResult(
158 blocking_task_runner(),
160 base::Bind(&internal::FileCache::GetCacheEntry
,
161 base::Unretained(cache()),
164 google_apis::test_util::CreateCopyResultCallback(&result
));
165 test_util::RunBlockingPoolTask();
166 ASSERT_FALSE(result
);
169 TEST_F(DownloadOperationTest
,
170 EnsureFileDownloadedByPath_FromServer_EnoughSpaceButBecomeFull
) {
171 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
172 ResourceEntry src_entry
;
173 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
174 const int64 file_size
= src_entry
.file_info().size();
176 // Pretend we have enough space first (checked before downloading a file),
177 // but then start reporting we have not enough space. This is to emulate that
178 // the disk space becomes full after the file is downloaded for some reason
179 // (ex. the actual file was larger than the expected size).
180 fake_free_disk_space_getter()->PushFakeValue(
181 file_size
+ cryptohome::kMinFreeSpaceInBytes
);
182 fake_free_disk_space_getter()->set_default_value(
183 cryptohome::kMinFreeSpaceInBytes
- 1);
185 FileError error
= FILE_ERROR_OK
;
186 base::FilePath file_path
;
187 scoped_ptr
<ResourceEntry
> entry
;
188 operation_
->EnsureFileDownloadedByPath(
190 ClientContext(USER_INITIATED
),
191 GetFileContentInitializedCallback(),
192 google_apis::GetContentCallback(),
193 google_apis::test_util::CreateCopyResultCallback(
194 &error
, &file_path
, &entry
));
195 test_util::RunBlockingPoolTask();
197 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE
, error
);
200 TEST_F(DownloadOperationTest
, EnsureFileDownloadedByPath_FromCache
) {
201 base::FilePath temp_file
;
202 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file
));
204 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
205 ResourceEntry src_entry
;
206 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
208 // Store something as cached version of this file.
209 FileError error
= FILE_ERROR_OK
;
210 base::PostTaskAndReplyWithResult(
211 blocking_task_runner(),
213 base::Bind(&internal::FileCache::Store
,
214 base::Unretained(cache()),
215 GetLocalId(file_in_root
),
216 src_entry
.file_specific_info().md5(),
218 internal::FileCache::FILE_OPERATION_COPY
),
219 google_apis::test_util::CreateCopyResultCallback(&error
));
220 test_util::RunBlockingPoolTask();
221 EXPECT_EQ(FILE_ERROR_OK
, error
);
223 base::FilePath file_path
;
224 scoped_ptr
<ResourceEntry
> entry
;
225 operation_
->EnsureFileDownloadedByPath(
227 ClientContext(USER_INITIATED
),
228 GetFileContentInitializedCallback(),
229 google_apis::GetContentCallback(),
230 google_apis::test_util::CreateCopyResultCallback(
231 &error
, &file_path
, &entry
));
232 test_util::RunBlockingPoolTask();
234 EXPECT_EQ(FILE_ERROR_OK
, error
);
236 EXPECT_FALSE(entry
->file_specific_info().is_hosted_document());
239 TEST_F(DownloadOperationTest
, EnsureFileDownloadedByPath_HostedDocument
) {
240 base::FilePath
file_in_root(FILE_PATH_LITERAL(
241 "drive/root/Document 1 excludeDir-test.gdoc"));
243 FileError error
= FILE_ERROR_FAILED
;
244 base::FilePath file_path
;
245 scoped_ptr
<ResourceEntry
> entry
;
246 operation_
->EnsureFileDownloadedByPath(
248 ClientContext(USER_INITIATED
),
249 GetFileContentInitializedCallback(),
250 google_apis::GetContentCallback(),
251 google_apis::test_util::CreateCopyResultCallback(
252 &error
, &file_path
, &entry
));
253 test_util::RunBlockingPoolTask();
255 EXPECT_EQ(FILE_ERROR_OK
, error
);
257 EXPECT_TRUE(entry
->file_specific_info().is_hosted_document());
258 EXPECT_FALSE(file_path
.empty());
260 EXPECT_EQ(GURL(entry
->file_specific_info().alternate_url()),
261 util::ReadUrlFromGDocFile(file_path
));
262 EXPECT_EQ(entry
->resource_id(), util::ReadResourceIdFromGDocFile(file_path
));
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
),
430 src_entry
.file_specific_info().md5(),
432 internal::FileCache::FILE_OPERATION_COPY
),
433 google_apis::test_util::CreateCopyResultCallback(&error
));
434 test_util::RunBlockingPoolTask();
435 EXPECT_EQ(FILE_ERROR_OK
, error
);
436 scoped_ptr
<base::ScopedClosureRunner
> file_closer
;
437 base::PostTaskAndReplyWithResult(
438 blocking_task_runner(),
440 base::Bind(&internal::FileCache::OpenForWrite
,
441 base::Unretained(cache()),
442 GetLocalId(file_in_root
),
444 google_apis::test_util::CreateCopyResultCallback(&error
));
445 test_util::RunBlockingPoolTask();
446 EXPECT_EQ(FILE_ERROR_OK
, error
);
448 // Record values passed to GetFileContentInitializedCallback().
449 FileError init_error
;
450 base::FilePath init_path
;
451 scoped_ptr
<ResourceEntry
> init_entry
;
452 base::Closure cancel_callback
;
454 base::FilePath file_path
;
455 scoped_ptr
<ResourceEntry
> entry
;
456 operation_
->EnsureFileDownloadedByPath(
458 ClientContext(USER_INITIATED
),
459 google_apis::test_util::CreateCopyResultCallback(
460 &init_error
, &init_entry
, &init_path
, &cancel_callback
),
461 google_apis::GetContentCallback(),
462 google_apis::test_util::CreateCopyResultCallback(
463 &error
, &file_path
, &entry
));
464 test_util::RunBlockingPoolTask();
466 EXPECT_EQ(FILE_ERROR_OK
, error
);
467 // Check that the result of local modification is propagated.
468 EXPECT_EQ(static_cast<int64
>(dirty_size
), init_entry
->file_info().size());
469 EXPECT_EQ(static_cast<int64
>(dirty_size
), entry
->file_info().size());
472 } // namespace file_system