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 "components/drive/file_system/download_operation.h"
7 #include "base/files/file_util.h"
8 #include "base/task_runner_util.h"
9 #include "components/drive/fake_free_disk_space_getter.h"
10 #include "components/drive/file_cache.h"
11 #include "components/drive/file_change.h"
12 #include "components/drive/file_system/operation_test_base.h"
13 #include "components/drive/file_system_core_util.h"
14 #include "components/drive/job_scheduler.h"
15 #include "components/drive/service/fake_drive_service.h"
16 #include "content/public/test/test_utils.h"
17 #include "google_apis/drive/test_util.h"
18 #include "testing/gtest/include/gtest/gtest.h"
21 namespace file_system
{
23 class DownloadOperationTest
: public OperationTestBase
{
25 void SetUp() override
{
26 OperationTestBase::SetUp();
28 operation_
.reset(new DownloadOperation(
29 blocking_task_runner(), delegate(), scheduler(), metadata(), cache(),
33 scoped_ptr
<DownloadOperation
> operation_
;
36 TEST_F(DownloadOperationTest
,
37 EnsureFileDownloadedByPath_FromServer_EnoughSpace
) {
38 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
39 ResourceEntry src_entry
;
40 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
41 const int64 file_size
= src_entry
.file_info().size();
43 // Pretend we have enough space.
44 fake_free_disk_space_getter()->set_default_value(
45 file_size
+ drive::internal::kMinFreeSpaceInBytes
);
47 FileError error
= FILE_ERROR_FAILED
;
48 base::FilePath file_path
;
49 scoped_ptr
<ResourceEntry
> entry
;
50 operation_
->EnsureFileDownloadedByPath(
52 ClientContext(USER_INITIATED
),
53 GetFileContentInitializedCallback(),
54 google_apis::GetContentCallback(),
55 google_apis::test_util::CreateCopyResultCallback(
56 &error
, &file_path
, &entry
));
57 content::RunAllBlockingPoolTasksUntilIdle();
59 EXPECT_EQ(FILE_ERROR_OK
, error
);
61 EXPECT_FALSE(entry
->file_specific_info().is_hosted_document());
63 // The transfered file is cached and the change of "offline available"
64 // attribute is notified.
65 EXPECT_EQ(1U, delegate()->get_changed_files().size());
66 EXPECT_EQ(1U, delegate()->get_changed_files().count(file_in_root
));
69 TEST_F(DownloadOperationTest
,
70 EnsureFileDownloadedByPath_FromServer_NoSpaceAtAll
) {
71 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
73 // Pretend we have no space at all.
74 fake_free_disk_space_getter()->set_default_value(0);
76 FileError error
= FILE_ERROR_OK
;
77 base::FilePath file_path
;
78 scoped_ptr
<ResourceEntry
> entry
;
79 operation_
->EnsureFileDownloadedByPath(
81 ClientContext(USER_INITIATED
),
82 GetFileContentInitializedCallback(),
83 google_apis::GetContentCallback(),
84 google_apis::test_util::CreateCopyResultCallback(
85 &error
, &file_path
, &entry
));
86 content::RunAllBlockingPoolTasksUntilIdle();
88 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE
, error
);
91 TEST_F(DownloadOperationTest
,
92 EnsureFileDownloadedByPath_FromServer_NoEnoughSpaceButCanFreeUp
) {
93 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
94 ResourceEntry src_entry
;
95 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
96 const int64 file_size
= src_entry
.file_info().size();
98 // Make another file cached.
99 // This file's cache file will be removed to free up the disk space.
100 base::FilePath
cached_file(
101 FILE_PATH_LITERAL("drive/root/Duplicate Name.txt"));
102 FileError error
= FILE_ERROR_FAILED
;
103 base::FilePath file_path
;
104 scoped_ptr
<ResourceEntry
> entry
;
105 operation_
->EnsureFileDownloadedByPath(
107 ClientContext(USER_INITIATED
),
108 GetFileContentInitializedCallback(),
109 google_apis::GetContentCallback(),
110 google_apis::test_util::CreateCopyResultCallback(
111 &error
, &file_path
, &entry
));
112 content::RunAllBlockingPoolTasksUntilIdle();
113 EXPECT_EQ(FILE_ERROR_OK
, error
);
115 EXPECT_TRUE(entry
->file_specific_info().cache_state().is_present());
117 // Pretend we have no space first (checked before downloading a file),
118 // but then start reporting we have space. This is to emulate that
119 // the disk space was freed up by removing temporary files.
120 fake_free_disk_space_getter()->set_default_value(
121 file_size
+ drive::internal::kMinFreeSpaceInBytes
);
122 fake_free_disk_space_getter()->PushFakeValue(0);
124 operation_
->EnsureFileDownloadedByPath(
126 ClientContext(USER_INITIATED
),
127 GetFileContentInitializedCallback(),
128 google_apis::GetContentCallback(),
129 google_apis::test_util::CreateCopyResultCallback(
130 &error
, &file_path
, &entry
));
131 content::RunAllBlockingPoolTasksUntilIdle();
133 EXPECT_EQ(FILE_ERROR_OK
, error
);
135 EXPECT_FALSE(entry
->file_specific_info().is_hosted_document());
137 // The transfered file is cached and the change of "offline available"
138 // attribute is notified.
139 EXPECT_EQ(2U, delegate()->get_changed_files().size());
140 EXPECT_TRUE(delegate()->get_changed_files().count(file_in_root
));
141 EXPECT_TRUE(delegate()->get_changed_files().count(cached_file
));
143 // The cache for the other file should be removed in order to free up space.
144 ResourceEntry cached_file_entry
;
145 EXPECT_EQ(FILE_ERROR_OK
,
146 GetLocalResourceEntry(cached_file
, &cached_file_entry
));
148 cached_file_entry
.file_specific_info().cache_state().is_present());
151 TEST_F(DownloadOperationTest
,
152 EnsureFileDownloadedByPath_FromServer_EnoughSpaceButBecomeFull
) {
153 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
154 ResourceEntry src_entry
;
155 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
156 const int64 file_size
= src_entry
.file_info().size();
158 // Pretend we have enough space first (checked before downloading a file),
159 // but then start reporting we have not enough space. This is to emulate that
160 // the disk space becomes full after the file is downloaded for some reason
161 // (ex. the actual file was larger than the expected size).
162 fake_free_disk_space_getter()->PushFakeValue(
163 file_size
+ drive::internal::kMinFreeSpaceInBytes
);
164 fake_free_disk_space_getter()->set_default_value(
165 drive::internal::kMinFreeSpaceInBytes
- 1);
167 FileError error
= FILE_ERROR_OK
;
168 base::FilePath file_path
;
169 scoped_ptr
<ResourceEntry
> entry
;
170 operation_
->EnsureFileDownloadedByPath(
172 ClientContext(USER_INITIATED
),
173 GetFileContentInitializedCallback(),
174 google_apis::GetContentCallback(),
175 google_apis::test_util::CreateCopyResultCallback(
176 &error
, &file_path
, &entry
));
177 content::RunAllBlockingPoolTasksUntilIdle();
179 EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE
, error
);
182 TEST_F(DownloadOperationTest
, EnsureFileDownloadedByPath_FromCache
) {
183 base::FilePath temp_file
;
184 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file
));
186 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
187 ResourceEntry src_entry
;
188 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
190 // Store something as cached version of this file.
191 FileError error
= FILE_ERROR_OK
;
192 base::PostTaskAndReplyWithResult(
193 blocking_task_runner(),
195 base::Bind(&internal::FileCache::Store
,
196 base::Unretained(cache()),
197 GetLocalId(file_in_root
),
198 src_entry
.file_specific_info().md5(),
200 internal::FileCache::FILE_OPERATION_COPY
),
201 google_apis::test_util::CreateCopyResultCallback(&error
));
202 content::RunAllBlockingPoolTasksUntilIdle();
203 EXPECT_EQ(FILE_ERROR_OK
, error
);
205 base::FilePath file_path
;
206 scoped_ptr
<ResourceEntry
> entry
;
207 operation_
->EnsureFileDownloadedByPath(
209 ClientContext(USER_INITIATED
),
210 GetFileContentInitializedCallback(),
211 google_apis::GetContentCallback(),
212 google_apis::test_util::CreateCopyResultCallback(
213 &error
, &file_path
, &entry
));
214 content::RunAllBlockingPoolTasksUntilIdle();
216 EXPECT_EQ(FILE_ERROR_OK
, error
);
218 EXPECT_FALSE(entry
->file_specific_info().is_hosted_document());
221 TEST_F(DownloadOperationTest
, EnsureFileDownloadedByPath_HostedDocument
) {
222 base::FilePath
file_in_root(FILE_PATH_LITERAL(
223 "drive/root/Document 1 excludeDir-test.gdoc"));
225 FileError error
= FILE_ERROR_FAILED
;
226 base::FilePath file_path
;
227 scoped_ptr
<ResourceEntry
> entry
;
228 operation_
->EnsureFileDownloadedByPath(
230 ClientContext(USER_INITIATED
),
231 GetFileContentInitializedCallback(),
232 google_apis::GetContentCallback(),
233 google_apis::test_util::CreateCopyResultCallback(
234 &error
, &file_path
, &entry
));
235 content::RunAllBlockingPoolTasksUntilIdle();
237 EXPECT_EQ(FILE_ERROR_OK
, error
);
239 EXPECT_TRUE(entry
->file_specific_info().is_hosted_document());
240 EXPECT_FALSE(file_path
.empty());
242 EXPECT_EQ(GURL(entry
->file_specific_info().alternate_url()),
243 util::ReadUrlFromGDocFile(file_path
));
244 EXPECT_EQ(entry
->resource_id(), util::ReadResourceIdFromGDocFile(file_path
));
245 EXPECT_EQ(FILE_PATH_LITERAL(".gdoc"), file_path
.Extension());
248 TEST_F(DownloadOperationTest
, EnsureFileDownloadedByLocalId
) {
249 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
250 ResourceEntry src_entry
;
251 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
253 FileError error
= FILE_ERROR_OK
;
254 base::FilePath file_path
;
255 scoped_ptr
<ResourceEntry
> entry
;
256 operation_
->EnsureFileDownloadedByLocalId(
257 GetLocalId(file_in_root
),
258 ClientContext(USER_INITIATED
),
259 GetFileContentInitializedCallback(),
260 google_apis::GetContentCallback(),
261 google_apis::test_util::CreateCopyResultCallback(
262 &error
, &file_path
, &entry
));
263 content::RunAllBlockingPoolTasksUntilIdle();
265 EXPECT_EQ(FILE_ERROR_OK
, error
);
267 EXPECT_FALSE(entry
->file_specific_info().is_hosted_document());
269 // The transfered file is cached and the change of "offline available"
270 // attribute is notified.
271 EXPECT_EQ(1U, delegate()->get_changed_files().size());
272 EXPECT_EQ(1U, delegate()->get_changed_files().count(file_in_root
));
275 TEST_F(DownloadOperationTest
,
276 EnsureFileDownloadedByPath_WithGetContentCallback
) {
277 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
280 FileError initialized_error
= FILE_ERROR_FAILED
;
281 scoped_ptr
<ResourceEntry
> entry
, entry_dontcare
;
282 base::FilePath local_path
, local_path_dontcare
;
283 google_apis::test_util::TestGetContentCallback get_content_callback
;
284 FileError completion_error
= FILE_ERROR_FAILED
;
285 base::Closure cancel_download
= operation_
->EnsureFileDownloadedByPath(
287 ClientContext(USER_INITIATED
),
288 google_apis::test_util::CreateCopyResultCallback(
289 &initialized_error
, &local_path
, &entry
),
290 get_content_callback
.callback(),
291 google_apis::test_util::CreateCopyResultCallback(
292 &completion_error
, &local_path_dontcare
, &entry_dontcare
));
293 content::RunAllBlockingPoolTasksUntilIdle();
295 // For the first time, file is downloaded from the remote server.
296 // In this case, |local_path| is empty.
297 EXPECT_EQ(FILE_ERROR_OK
, initialized_error
);
299 ASSERT_TRUE(local_path
.empty());
300 EXPECT_FALSE(cancel_download
.is_null());
301 // Content is available through the second callback argument.
302 EXPECT_EQ(static_cast<size_t>(entry
->file_info().size()),
303 get_content_callback
.GetConcatenatedData().size());
304 EXPECT_EQ(FILE_ERROR_OK
, completion_error
);
306 // The transfered file is cached and the change of "offline available"
307 // attribute is notified.
308 EXPECT_EQ(1U, delegate()->get_changed_files().size());
309 EXPECT_EQ(1U, delegate()->get_changed_files().count(file_in_root
));
313 FileError initialized_error
= FILE_ERROR_FAILED
;
314 scoped_ptr
<ResourceEntry
> entry
, entry_dontcare
;
315 base::FilePath local_path
, local_path_dontcare
;
316 google_apis::test_util::TestGetContentCallback get_content_callback
;
317 FileError completion_error
= FILE_ERROR_FAILED
;
318 base::Closure cancel_download
= operation_
->EnsureFileDownloadedByPath(
320 ClientContext(USER_INITIATED
),
321 google_apis::test_util::CreateCopyResultCallback(
322 &initialized_error
, &local_path
, &entry
),
323 get_content_callback
.callback(),
324 google_apis::test_util::CreateCopyResultCallback(
325 &completion_error
, &local_path_dontcare
, &entry_dontcare
));
326 content::RunAllBlockingPoolTasksUntilIdle();
328 // Try second download. In this case, the file should be cached, so
329 // |local_path| should not be empty.
330 EXPECT_EQ(FILE_ERROR_OK
, initialized_error
);
332 ASSERT_TRUE(!local_path
.empty());
333 EXPECT_FALSE(cancel_download
.is_null());
334 // The content is available from the cache file.
335 EXPECT_TRUE(get_content_callback
.data().empty());
336 int64 local_file_size
= 0;
337 base::GetFileSize(local_path
, &local_file_size
);
338 EXPECT_EQ(entry
->file_info().size(), local_file_size
);
339 EXPECT_EQ(FILE_ERROR_OK
, completion_error
);
343 TEST_F(DownloadOperationTest
, EnsureFileDownloadedByLocalId_FromCache
) {
344 base::FilePath temp_file
;
345 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file
));
347 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
348 ResourceEntry src_entry
;
349 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
351 // Store something as cached version of this file.
352 FileError error
= FILE_ERROR_FAILED
;
353 base::PostTaskAndReplyWithResult(
354 blocking_task_runner(),
356 base::Bind(&internal::FileCache::Store
,
357 base::Unretained(cache()),
358 GetLocalId(file_in_root
),
359 src_entry
.file_specific_info().md5(),
361 internal::FileCache::FILE_OPERATION_COPY
),
362 google_apis::test_util::CreateCopyResultCallback(&error
));
363 content::RunAllBlockingPoolTasksUntilIdle();
364 EXPECT_EQ(FILE_ERROR_OK
, error
);
366 // The file is obtained from the cache.
367 // Hence the downloading should work even if the drive service is offline.
368 fake_service()->set_offline(true);
370 base::FilePath file_path
;
371 scoped_ptr
<ResourceEntry
> entry
;
372 operation_
->EnsureFileDownloadedByLocalId(
373 GetLocalId(file_in_root
),
374 ClientContext(USER_INITIATED
),
375 GetFileContentInitializedCallback(),
376 google_apis::GetContentCallback(),
377 google_apis::test_util::CreateCopyResultCallback(
378 &error
, &file_path
, &entry
));
379 content::RunAllBlockingPoolTasksUntilIdle();
381 EXPECT_EQ(FILE_ERROR_OK
, error
);
383 EXPECT_FALSE(entry
->file_specific_info().is_hosted_document());
386 TEST_F(DownloadOperationTest
, EnsureFileDownloadedByPath_DirtyCache
) {
387 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
388 ResourceEntry src_entry
;
389 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
391 // Prepare a dirty file to store to cache that has a different size than
392 // stored in resource metadata.
393 base::FilePath dirty_file
= temp_dir().AppendASCII("dirty.txt");
394 size_t dirty_size
= src_entry
.file_info().size() + 10;
395 google_apis::test_util::WriteStringToFile(dirty_file
,
396 std::string(dirty_size
, 'x'));
398 // Store the file as a cache, marking it to be dirty.
399 FileError error
= FILE_ERROR_FAILED
;
400 base::PostTaskAndReplyWithResult(
401 blocking_task_runner(),
403 base::Bind(&internal::FileCache::Store
,
404 base::Unretained(cache()),
405 GetLocalId(file_in_root
),
408 internal::FileCache::FILE_OPERATION_COPY
),
409 google_apis::test_util::CreateCopyResultCallback(&error
));
410 content::RunAllBlockingPoolTasksUntilIdle();
411 EXPECT_EQ(FILE_ERROR_OK
, error
);
413 // Record values passed to GetFileContentInitializedCallback().
414 FileError init_error
;
415 base::FilePath init_path
;
416 scoped_ptr
<ResourceEntry
> init_entry
;
417 base::FilePath file_path
;
418 scoped_ptr
<ResourceEntry
> entry
;
419 base::Closure cancel_callback
= operation_
->EnsureFileDownloadedByPath(
421 ClientContext(USER_INITIATED
),
422 google_apis::test_util::CreateCopyResultCallback(
423 &init_error
, &init_path
, &init_entry
),
424 google_apis::GetContentCallback(),
425 google_apis::test_util::CreateCopyResultCallback(
426 &error
, &file_path
, &entry
));
427 content::RunAllBlockingPoolTasksUntilIdle();
429 EXPECT_EQ(FILE_ERROR_OK
, error
);
430 // Check that the result of local modification is propagated.
431 EXPECT_EQ(static_cast<int64
>(dirty_size
), init_entry
->file_info().size());
432 EXPECT_EQ(static_cast<int64
>(dirty_size
), entry
->file_info().size());
435 TEST_F(DownloadOperationTest
, EnsureFileDownloadedByPath_LocallyCreatedFile
) {
436 // Add a new file with an empty resource ID.
437 base::FilePath
file_path(FILE_PATH_LITERAL("drive/root/New File.txt"));
438 ResourceEntry parent
;
439 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_path
.DirName(), &parent
));
441 ResourceEntry new_file
;
442 new_file
.set_title("New File.txt");
443 new_file
.set_parent_local_id(parent
.local_id());
445 FileError error
= FILE_ERROR_FAILED
;
446 std::string local_id
;
447 base::PostTaskAndReplyWithResult(
448 blocking_task_runner(),
450 base::Bind(&internal::ResourceMetadata::AddEntry
,
451 base::Unretained(metadata()),
454 google_apis::test_util::CreateCopyResultCallback(&error
));
455 content::RunAllBlockingPoolTasksUntilIdle();
456 EXPECT_EQ(FILE_ERROR_OK
, error
);
458 // Empty cache file should be returned.
459 base::FilePath cache_file_path
;
460 scoped_ptr
<ResourceEntry
> entry
;
461 operation_
->EnsureFileDownloadedByPath(
463 ClientContext(USER_INITIATED
),
464 GetFileContentInitializedCallback(),
465 google_apis::GetContentCallback(),
466 google_apis::test_util::CreateCopyResultCallback(
467 &error
, &cache_file_path
, &entry
));
468 content::RunAllBlockingPoolTasksUntilIdle();
469 EXPECT_EQ(FILE_ERROR_OK
, error
);
471 int64 cache_file_size
= 0;
472 EXPECT_TRUE(base::GetFileSize(cache_file_path
, &cache_file_size
));
473 EXPECT_EQ(static_cast<int64
>(0), cache_file_size
);
475 EXPECT_EQ(cache_file_size
, entry
->file_info().size());
478 TEST_F(DownloadOperationTest
, CancelBeforeDownloadStarts
) {
479 base::FilePath
file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
480 ResourceEntry src_entry
;
481 ASSERT_EQ(FILE_ERROR_OK
, GetLocalResourceEntry(file_in_root
, &src_entry
));
484 FileError error
= FILE_ERROR_OK
;
485 base::FilePath file_path
;
486 scoped_ptr
<ResourceEntry
> entry
;
487 base::Closure cancel_closure
= operation_
->EnsureFileDownloadedByLocalId(
488 GetLocalId(file_in_root
),
489 ClientContext(USER_INITIATED
),
490 GetFileContentInitializedCallback(),
491 google_apis::GetContentCallback(),
492 google_apis::test_util::CreateCopyResultCallback(
493 &error
, &file_path
, &entry
));
495 // Cancel immediately.
496 ASSERT_FALSE(cancel_closure
.is_null());
497 cancel_closure
.Run();
498 content::RunAllBlockingPoolTasksUntilIdle();
500 EXPECT_EQ(FILE_ERROR_ABORT
, error
);
503 } // namespace file_system