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