5aaedfcb9249f3499747a35319b07dc801733917
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / file_system / download_operation_unittest.cc
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/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"
18
19 namespace drive {
20 namespace file_system {
21
22 class DownloadOperationTest : public OperationTestBase {
23  protected:
24   virtual void SetUp() OVERRIDE {
25     OperationTestBase::SetUp();
26
27     operation_.reset(new DownloadOperation(
28         blocking_task_runner(), observer(), scheduler(), metadata(), cache(),
29         temp_dir()));
30   }
31
32   scoped_ptr<DownloadOperation> operation_;
33 };
34
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();
41
42   // Pretend we have enough space.
43   fake_free_disk_space_getter()->set_default_value(
44       file_size + cryptohome::kMinFreeSpaceInBytes);
45
46   FileError error = FILE_ERROR_FAILED;
47   base::FilePath file_path;
48   scoped_ptr<ResourceEntry> entry;
49   operation_->EnsureFileDownloadedByPath(
50       file_in_root,
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();
57
58   EXPECT_EQ(FILE_ERROR_OK, error);
59   ASSERT_TRUE(entry);
60   EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
61
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()));
66
67   // Verify that readable permission is set.
68   int permission = 0;
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);
74 }
75
76 TEST_F(DownloadOperationTest,
77        EnsureFileDownloadedByPath_FromServer_NoSpaceAtAll) {
78   base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
79
80   // Pretend we have no space at all.
81   fake_free_disk_space_getter()->set_default_value(0);
82
83   FileError error = FILE_ERROR_OK;
84   base::FilePath file_path;
85   scoped_ptr<ResourceEntry> entry;
86   operation_->EnsureFileDownloadedByPath(
87       file_in_root,
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();
94
95   EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
96 }
97
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();
104
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);
113
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));
121
122   FileError error = FILE_ERROR_FAILED;
123   base::PostTaskAndReplyWithResult(
124       blocking_task_runner(),
125       FROM_HERE,
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);
133
134   base::FilePath file_path;
135   scoped_ptr<ResourceEntry> entry;
136   operation_->EnsureFileDownloadedByPath(
137       file_in_root,
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();
144
145   EXPECT_EQ(FILE_ERROR_OK, error);
146   ASSERT_TRUE(entry);
147   EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
148
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()));
153
154   // The cache entry should be removed in order to free up space.
155   FileCacheEntry cache_entry;
156   bool result = true;
157   base::PostTaskAndReplyWithResult(
158       blocking_task_runner(),
159       FROM_HERE,
160       base::Bind(&internal::FileCache::GetCacheEntry,
161                  base::Unretained(cache()),
162                  "<id>",
163                  &cache_entry),
164       google_apis::test_util::CreateCopyResultCallback(&result));
165   test_util::RunBlockingPoolTask();
166   ASSERT_FALSE(result);
167 }
168
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();
175
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);
184
185   FileError error = FILE_ERROR_OK;
186   base::FilePath file_path;
187   scoped_ptr<ResourceEntry> entry;
188   operation_->EnsureFileDownloadedByPath(
189       file_in_root,
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();
196
197   EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
198 }
199
200 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_FromCache) {
201   base::FilePath temp_file;
202   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
203
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));
207
208   // Store something as cached version of this file.
209   FileError error = FILE_ERROR_OK;
210   base::PostTaskAndReplyWithResult(
211       blocking_task_runner(),
212       FROM_HERE,
213       base::Bind(&internal::FileCache::Store,
214                  base::Unretained(cache()),
215                  GetLocalId(file_in_root),
216                  src_entry.file_specific_info().md5(),
217                  temp_file,
218                  internal::FileCache::FILE_OPERATION_COPY),
219       google_apis::test_util::CreateCopyResultCallback(&error));
220   test_util::RunBlockingPoolTask();
221   EXPECT_EQ(FILE_ERROR_OK, error);
222
223   base::FilePath file_path;
224   scoped_ptr<ResourceEntry> entry;
225   operation_->EnsureFileDownloadedByPath(
226       file_in_root,
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();
233
234   EXPECT_EQ(FILE_ERROR_OK, error);
235   ASSERT_TRUE(entry);
236   EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
237 }
238
239 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_HostedDocument) {
240   base::FilePath file_in_root(FILE_PATH_LITERAL(
241       "drive/root/Document 1 excludeDir-test.gdoc"));
242
243   FileError error = FILE_ERROR_FAILED;
244   base::FilePath file_path;
245   scoped_ptr<ResourceEntry> entry;
246   operation_->EnsureFileDownloadedByPath(
247       file_in_root,
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();
254
255   EXPECT_EQ(FILE_ERROR_OK, error);
256   ASSERT_TRUE(entry);
257   EXPECT_TRUE(entry->file_specific_info().is_hosted_document());
258   EXPECT_FALSE(file_path.empty());
259
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));
263 }
264
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));
269
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();
281
282   EXPECT_EQ(FILE_ERROR_OK, error);
283   ASSERT_TRUE(entry);
284   EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
285
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()));
290 }
291
292 TEST_F(DownloadOperationTest,
293        EnsureFileDownloadedByPath_WithGetContentCallback) {
294   base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
295
296   {
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;
302
303     FileError completion_error = FILE_ERROR_FAILED;
304
305     operation_->EnsureFileDownloadedByPath(
306         file_in_root,
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();
314
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);
318     ASSERT_TRUE(entry);
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);
325
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());
329     EXPECT_EQ(1U,
330               observer()->get_changed_paths().count(file_in_root.DirName()));
331   }
332
333   {
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;
339
340     FileError completion_error = FILE_ERROR_FAILED;
341
342     operation_->EnsureFileDownloadedByPath(
343         file_in_root,
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();
351
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);
355     ASSERT_TRUE(entry);
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);
364   }
365 }
366
367 TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId_FromCache) {
368   base::FilePath temp_file;
369   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
370
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));
374
375   // Store something as cached version of this file.
376   FileError error = FILE_ERROR_FAILED;
377   base::PostTaskAndReplyWithResult(
378       blocking_task_runner(),
379       FROM_HERE,
380       base::Bind(&internal::FileCache::Store,
381                  base::Unretained(cache()),
382                  GetLocalId(file_in_root),
383                  src_entry.file_specific_info().md5(),
384                  temp_file,
385                  internal::FileCache::FILE_OPERATION_COPY),
386       google_apis::test_util::CreateCopyResultCallback(&error));
387   test_util::RunBlockingPoolTask();
388   EXPECT_EQ(FILE_ERROR_OK, error);
389
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);
393
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();
404
405   EXPECT_EQ(FILE_ERROR_OK, error);
406   ASSERT_TRUE(entry);
407   EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
408 }
409
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));
414
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'));
421
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(),
426       FROM_HERE,
427       base::Bind(&internal::FileCache::Store,
428                  base::Unretained(cache()),
429                  GetLocalId(file_in_root),
430                  src_entry.file_specific_info().md5(),
431                  dirty_file,
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(),
439       FROM_HERE,
440       base::Bind(&internal::FileCache::OpenForWrite,
441                  base::Unretained(cache()),
442                  GetLocalId(file_in_root),
443                  &file_closer),
444       google_apis::test_util::CreateCopyResultCallback(&error));
445   test_util::RunBlockingPoolTask();
446   EXPECT_EQ(FILE_ERROR_OK, error);
447
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;
453
454   base::FilePath file_path;
455   scoped_ptr<ResourceEntry> entry;
456   operation_->EnsureFileDownloadedByPath(
457       file_in_root,
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();
465
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());
470 }
471
472 }  // namespace file_system
473 }  // namespace drive