download_operation_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 18namespace drive { 19namespace file_system { 20 21class 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 34TEST_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 75TEST_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 97TEST_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 168TEST_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 199TEST_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 238TEST_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 265TEST_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 292TEST_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 367TEST_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 410TEST_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 461TEST_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 506