836d50a7d41f75174f922fc38f3ffc7e69f68258
[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/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"
17
18 namespace drive {
19 namespace file_system {
20
21 class DownloadOperationTest : public OperationTestBase {
22  protected:
23   virtual void SetUp() OVERRIDE {
24     OperationTestBase::SetUp();
25
26     operation_.reset(new DownloadOperation(
27         blocking_task_runner(), observer(), scheduler(), metadata(), cache(),
28         temp_dir()));
29   }
30
31   scoped_ptr<DownloadOperation> operation_;
32 };
33
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();
40
41   // Pretend we have enough space.
42   fake_free_disk_space_getter()->set_default_value(
43       file_size + cryptohome::kMinFreeSpaceInBytes);
44
45   FileError error = FILE_ERROR_FAILED;
46   base::FilePath file_path;
47   scoped_ptr<ResourceEntry> entry;
48   operation_->EnsureFileDownloadedByPath(
49       file_in_root,
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();
56
57   EXPECT_EQ(FILE_ERROR_OK, error);
58   ASSERT_TRUE(entry);
59   EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
60
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()));
65
66   // Verify that readable permission is set.
67   int permission = 0;
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);
73 }
74
75 TEST_F(DownloadOperationTest,
76        EnsureFileDownloadedByPath_FromServer_NoSpaceAtAll) {
77   base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
78
79   // Pretend we have no space at all.
80   fake_free_disk_space_getter()->set_default_value(0);
81
82   FileError error = FILE_ERROR_OK;
83   base::FilePath file_path;
84   scoped_ptr<ResourceEntry> entry;
85   operation_->EnsureFileDownloadedByPath(
86       file_in_root,
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();
93
94   EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
95 }
96
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();
103
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);
112
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));
120
121   FileError error = FILE_ERROR_FAILED;
122   base::PostTaskAndReplyWithResult(
123       blocking_task_runner(),
124       FROM_HERE,
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);
132
133   base::FilePath file_path;
134   scoped_ptr<ResourceEntry> entry;
135   operation_->EnsureFileDownloadedByPath(
136       file_in_root,
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();
143
144   EXPECT_EQ(FILE_ERROR_OK, error);
145   ASSERT_TRUE(entry);
146   EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
147
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()));
152
153   // The cache entry should be removed in order to free up space.
154   FileCacheEntry cache_entry;
155   bool result = true;
156   base::PostTaskAndReplyWithResult(
157       blocking_task_runner(),
158       FROM_HERE,
159       base::Bind(&internal::FileCache::GetCacheEntry,
160                  base::Unretained(cache()),
161                  "<id>",
162                  &cache_entry),
163       google_apis::test_util::CreateCopyResultCallback(&result));
164   test_util::RunBlockingPoolTask();
165   ASSERT_FALSE(result);
166 }
167
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();
174
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);
183
184   FileError error = FILE_ERROR_OK;
185   base::FilePath file_path;
186   scoped_ptr<ResourceEntry> entry;
187   operation_->EnsureFileDownloadedByPath(
188       file_in_root,
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();
195
196   EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
197 }
198
199 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_FromCache) {
200   base::FilePath temp_file;
201   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
202
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));
206
207   // Store something as cached version of this file.
208   FileError error = FILE_ERROR_OK;
209   base::PostTaskAndReplyWithResult(
210       blocking_task_runner(),
211       FROM_HERE,
212       base::Bind(&internal::FileCache::Store,
213                  base::Unretained(cache()),
214                  GetLocalId(file_in_root),
215                  src_entry.file_specific_info().md5(),
216                  temp_file,
217                  internal::FileCache::FILE_OPERATION_COPY),
218       google_apis::test_util::CreateCopyResultCallback(&error));
219   test_util::RunBlockingPoolTask();
220   EXPECT_EQ(FILE_ERROR_OK, error);
221
222   base::FilePath file_path;
223   scoped_ptr<ResourceEntry> entry;
224   operation_->EnsureFileDownloadedByPath(
225       file_in_root,
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();
232
233   EXPECT_EQ(FILE_ERROR_OK, error);
234   ASSERT_TRUE(entry);
235   EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
236 }
237
238 TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_HostedDocument) {
239   base::FilePath file_in_root(FILE_PATH_LITERAL(
240       "drive/root/Document 1 excludeDir-test.gdoc"));
241
242   FileError error = FILE_ERROR_FAILED;
243   base::FilePath file_path;
244   scoped_ptr<ResourceEntry> entry;
245   operation_->EnsureFileDownloadedByPath(
246       file_in_root,
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();
253
254   EXPECT_EQ(FILE_ERROR_OK, error);
255   ASSERT_TRUE(entry);
256   EXPECT_TRUE(entry->file_specific_info().is_hosted_document());
257   EXPECT_FALSE(file_path.empty());
258
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());
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                  std::string(),
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
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;
442
443   base::FilePath file_path;
444   scoped_ptr<ResourceEntry> entry;
445   operation_->EnsureFileDownloadedByPath(
446       file_in_root,
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();
454
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());
459 }
460
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));
466
467   ResourceEntry new_file;
468   new_file.set_title("New File.txt");
469   new_file.set_parent_local_id(parent.local_id());
470
471   FileError error = FILE_ERROR_FAILED;
472   std::string local_id;
473   base::PostTaskAndReplyWithResult(
474       blocking_task_runner(),
475       FROM_HERE,
476       base::Bind(&internal::ResourceMetadata::AddEntry,
477                  base::Unretained(metadata()),
478                  new_file,
479                  &local_id),
480       google_apis::test_util::CreateCopyResultCallback(&error));
481   test_util::RunBlockingPoolTask();
482   EXPECT_EQ(FILE_ERROR_OK, error);
483
484   // Empty cache file should be returned.
485   base::FilePath cache_file_path;
486   scoped_ptr<ResourceEntry> entry;
487   operation_->EnsureFileDownloadedByPath(
488       file_path,
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);
496
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);
500   ASSERT_TRUE(entry);
501   EXPECT_EQ(cache_file_size, entry->file_info().size());
502 }
503
504 }  // namespace file_system
505 }  // namespace drive