| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/browser/chromeos/drive/file_cache.h" | 5 #include "chrome/browser/chromeos/drive/file_cache.h" | 
| 6 | 6 | 
| 7 #include <string> | 7 #include <string> | 
| 8 #include <vector> | 8 #include <vector> | 
| 9 | 9 | 
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" | 
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" | 
| 12 #include "base/files/file_enumerator.h" | 12 #include "base/files/file_enumerator.h" | 
| 13 #include "base/files/scoped_temp_dir.h" | 13 #include "base/files/scoped_temp_dir.h" | 
| 14 #include "base/md5.h" | 14 #include "base/md5.h" | 
| 15 #include "base/path_service.h" | 15 #include "base/path_service.h" | 
| 16 #include "base/run_loop.h" |  | 
| 17 #include "base/threading/sequenced_worker_pool.h" |  | 
| 18 #include "chrome/browser/chromeos/drive/drive.pb.h" | 16 #include "chrome/browser/chromeos/drive/drive.pb.h" | 
| 19 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h" | 17 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h" | 
| 20 #include "chrome/browser/chromeos/drive/file_system_util.h" | 18 #include "chrome/browser/chromeos/drive/file_system_util.h" | 
| 21 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h" | 19 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h" | 
| 22 #include "chrome/browser/chromeos/drive/test_util.h" | 20 #include "chrome/browser/chromeos/drive/test_util.h" | 
| 23 #include "content/public/browser/browser_thread.h" |  | 
| 24 #include "content/public/test/test_browser_thread_bundle.h" | 21 #include "content/public/test/test_browser_thread_bundle.h" | 
| 25 #include "google_apis/drive/test_util.h" | 22 #include "google_apis/drive/test_util.h" | 
| 26 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" | 
| 27 | 24 | 
| 28 namespace drive { | 25 namespace drive { | 
| 29 namespace internal { | 26 namespace internal { | 
| 30 namespace { | 27 namespace { | 
| 31 | 28 | 
| 32 const char kCacheFileDirectory[] = "files"; | 29 const char kCacheFileDirectory[] = "files"; | 
| 33 | 30 | 
| 34 // Bitmask of cache states in FileCacheEntry. |  | 
| 35 enum TestFileCacheState { |  | 
| 36   TEST_CACHE_STATE_NONE       = 0, |  | 
| 37   TEST_CACHE_STATE_PINNED     = 1 << 0, |  | 
| 38   TEST_CACHE_STATE_PRESENT    = 1 << 1, |  | 
| 39   TEST_CACHE_STATE_DIRTY      = 1 << 2, |  | 
| 40 }; |  | 
| 41 |  | 
| 42 }  // namespace | 31 }  // namespace | 
| 43 | 32 | 
| 44 // Tests FileCache methods from UI thread. It internally uses a real blocking |  | 
| 45 // pool and tests the interaction among threads. |  | 
| 46 // TODO(hashimoto): remove this class. crbug.com/231221. |  | 
| 47 class FileCacheTestOnUIThread : public testing::Test { |  | 
| 48  protected: |  | 
| 49   FileCacheTestOnUIThread() : expected_error_(FILE_ERROR_OK), |  | 
| 50                               expected_cache_state_(0) { |  | 
| 51   } |  | 
| 52 |  | 
| 53   virtual void SetUp() OVERRIDE { |  | 
| 54     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |  | 
| 55     const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta"); |  | 
| 56     const base::FilePath cache_dir = |  | 
| 57         temp_dir_.path().AppendASCII(kCacheFileDirectory); |  | 
| 58 |  | 
| 59     ASSERT_TRUE(base::CreateDirectory(metadata_dir)); |  | 
| 60     ASSERT_TRUE(base::CreateDirectory(cache_dir)); |  | 
| 61 |  | 
| 62     ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), |  | 
| 63                                                &dummy_file_path_)); |  | 
| 64     fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter); |  | 
| 65 |  | 
| 66     scoped_refptr<base::SequencedWorkerPool> pool = |  | 
| 67         content::BrowserThread::GetBlockingPool(); |  | 
| 68     blocking_task_runner_ = |  | 
| 69         pool->GetSequencedTaskRunner(pool->GetSequenceToken()); |  | 
| 70 |  | 
| 71     metadata_storage_.reset(new ResourceMetadataStorage( |  | 
| 72         metadata_dir, |  | 
| 73         blocking_task_runner_.get())); |  | 
| 74 |  | 
| 75     bool success = false; |  | 
| 76     base::PostTaskAndReplyWithResult( |  | 
| 77         blocking_task_runner_.get(), |  | 
| 78         FROM_HERE, |  | 
| 79         base::Bind(&ResourceMetadataStorage::Initialize, |  | 
| 80                    base::Unretained(metadata_storage_.get())), |  | 
| 81         google_apis::test_util::CreateCopyResultCallback(&success)); |  | 
| 82     test_util::RunBlockingPoolTask(); |  | 
| 83     ASSERT_TRUE(success); |  | 
| 84 |  | 
| 85     cache_.reset(new FileCache( |  | 
| 86         metadata_storage_.get(), |  | 
| 87         cache_dir, |  | 
| 88         blocking_task_runner_.get(), |  | 
| 89         fake_free_disk_space_getter_.get())); |  | 
| 90 |  | 
| 91     success = false; |  | 
| 92     base::PostTaskAndReplyWithResult( |  | 
| 93         blocking_task_runner_.get(), |  | 
| 94         FROM_HERE, |  | 
| 95         base::Bind(&FileCache::Initialize, base::Unretained(cache_.get())), |  | 
| 96         google_apis::test_util::CreateCopyResultCallback(&success)); |  | 
| 97     test_util::RunBlockingPoolTask(); |  | 
| 98     ASSERT_TRUE(success); |  | 
| 99   } |  | 
| 100 |  | 
| 101   void TestStoreToCache(const std::string& id, |  | 
| 102                         const std::string& md5, |  | 
| 103                         const base::FilePath& source_path, |  | 
| 104                         FileError expected_error, |  | 
| 105                         int expected_cache_state) { |  | 
| 106     expected_error_ = expected_error; |  | 
| 107     expected_cache_state_ = expected_cache_state; |  | 
| 108 |  | 
| 109     FileError error = FILE_ERROR_OK; |  | 
| 110     base::PostTaskAndReplyWithResult( |  | 
| 111         blocking_task_runner_, |  | 
| 112         FROM_HERE, |  | 
| 113         base::Bind(&internal::FileCache::Store, |  | 
| 114                    base::Unretained(cache_.get()), |  | 
| 115                    id, md5, source_path, |  | 
| 116                    FileCache::FILE_OPERATION_COPY), |  | 
| 117         google_apis::test_util::CreateCopyResultCallback(&error)); |  | 
| 118     test_util::RunBlockingPoolTask(); |  | 
| 119 |  | 
| 120     if (error == FILE_ERROR_OK) { |  | 
| 121       FileCacheEntry cache_entry; |  | 
| 122       EXPECT_TRUE(GetCacheEntryFromOriginThread(id, &cache_entry)); |  | 
| 123       EXPECT_EQ(md5, cache_entry.md5()); |  | 
| 124     } |  | 
| 125 |  | 
| 126     VerifyCacheFileState(error, id); |  | 
| 127   } |  | 
| 128 |  | 
| 129   void TestRemoveFromCache(const std::string& id, FileError expected_error) { |  | 
| 130     expected_error_ = expected_error; |  | 
| 131 |  | 
| 132     FileError error = FILE_ERROR_OK; |  | 
| 133     base::PostTaskAndReplyWithResult( |  | 
| 134         blocking_task_runner_, |  | 
| 135         FROM_HERE, |  | 
| 136         base::Bind(&internal::FileCache::Remove, |  | 
| 137                    base::Unretained(cache_.get()), |  | 
| 138                    id), |  | 
| 139         google_apis::test_util::CreateCopyResultCallback(&error)); |  | 
| 140     test_util::RunBlockingPoolTask(); |  | 
| 141     VerifyRemoveFromCache(error, id); |  | 
| 142   } |  | 
| 143 |  | 
| 144   void VerifyRemoveFromCache(FileError error, const std::string& id) { |  | 
| 145     EXPECT_EQ(expected_error_, error); |  | 
| 146 |  | 
| 147     FileCacheEntry cache_entry; |  | 
| 148     if (!GetCacheEntryFromOriginThread(id, &cache_entry)) { |  | 
| 149       EXPECT_EQ(FILE_ERROR_OK, error); |  | 
| 150 |  | 
| 151       const base::FilePath path = cache_->GetCacheFilePath(id); |  | 
| 152       EXPECT_FALSE(base::PathExists(path)); |  | 
| 153     } |  | 
| 154   } |  | 
| 155 |  | 
| 156   void TestPin(const std::string& id, |  | 
| 157                FileError expected_error, |  | 
| 158                int expected_cache_state) { |  | 
| 159     expected_error_ = expected_error; |  | 
| 160     expected_cache_state_ = expected_cache_state; |  | 
| 161 |  | 
| 162     FileError error = FILE_ERROR_OK; |  | 
| 163     base::PostTaskAndReplyWithResult( |  | 
| 164         blocking_task_runner_, |  | 
| 165         FROM_HERE, |  | 
| 166         base::Bind(&internal::FileCache::Pin, |  | 
| 167                    base::Unretained(cache_.get()), |  | 
| 168                    id), |  | 
| 169         google_apis::test_util::CreateCopyResultCallback(&error)); |  | 
| 170     test_util::RunBlockingPoolTask(); |  | 
| 171     VerifyCacheFileState(error, id); |  | 
| 172   } |  | 
| 173 |  | 
| 174   void TestUnpin(const std::string& id, |  | 
| 175                  FileError expected_error, |  | 
| 176                  int expected_cache_state) { |  | 
| 177     expected_error_ = expected_error; |  | 
| 178     expected_cache_state_ = expected_cache_state; |  | 
| 179 |  | 
| 180     FileError error = FILE_ERROR_OK; |  | 
| 181     base::PostTaskAndReplyWithResult( |  | 
| 182         blocking_task_runner_, |  | 
| 183         FROM_HERE, |  | 
| 184         base::Bind(&internal::FileCache::Unpin, |  | 
| 185                    base::Unretained(cache_.get()), |  | 
| 186                    id), |  | 
| 187         google_apis::test_util::CreateCopyResultCallback(&error)); |  | 
| 188     test_util::RunBlockingPoolTask(); |  | 
| 189     VerifyCacheFileState(error, id); |  | 
| 190   } |  | 
| 191 |  | 
| 192   void TestMarkAsMounted(const std::string& id, |  | 
| 193                          FileError expected_error, |  | 
| 194                          int expected_cache_state) { |  | 
| 195     expected_error_ = expected_error; |  | 
| 196     expected_cache_state_ = expected_cache_state; |  | 
| 197 |  | 
| 198     FileCacheEntry entry; |  | 
| 199     EXPECT_TRUE(GetCacheEntryFromOriginThread(id, &entry)); |  | 
| 200 |  | 
| 201     FileError error = FILE_ERROR_OK; |  | 
| 202     base::FilePath cache_file_path; |  | 
| 203 |  | 
| 204     base::PostTaskAndReplyWithResult( |  | 
| 205         blocking_task_runner_.get(), |  | 
| 206         FROM_HERE, |  | 
| 207         base::Bind(&FileCache::MarkAsMounted, |  | 
| 208                    base::Unretained(cache_.get()), |  | 
| 209                    id, |  | 
| 210                    &cache_file_path), |  | 
| 211         google_apis::test_util::CreateCopyResultCallback(&error)); |  | 
| 212     test_util::RunBlockingPoolTask(); |  | 
| 213 |  | 
| 214     EXPECT_TRUE(base::PathExists(cache_file_path)); |  | 
| 215     EXPECT_EQ(cache_file_path, cache_->GetCacheFilePath(id)); |  | 
| 216   } |  | 
| 217 |  | 
| 218   void TestMarkAsUnmounted(const std::string& id, |  | 
| 219                            const base::FilePath& file_path, |  | 
| 220                            FileError expected_error, |  | 
| 221                            int expected_cache_state) { |  | 
| 222     expected_error_ = expected_error; |  | 
| 223     expected_cache_state_ = expected_cache_state; |  | 
| 224 |  | 
| 225     FileError error = FILE_ERROR_OK; |  | 
| 226     base::PostTaskAndReplyWithResult( |  | 
| 227         blocking_task_runner_.get(), |  | 
| 228         FROM_HERE, |  | 
| 229         base::Bind(&FileCache::MarkAsUnmounted, |  | 
| 230                    base::Unretained(cache_.get()), |  | 
| 231                    file_path), |  | 
| 232         google_apis::test_util::CreateCopyResultCallback(&error)); |  | 
| 233     test_util::RunBlockingPoolTask(); |  | 
| 234 |  | 
| 235     base::FilePath cache_file_path; |  | 
| 236     base::PostTaskAndReplyWithResult( |  | 
| 237         blocking_task_runner_, |  | 
| 238         FROM_HERE, |  | 
| 239         base::Bind(&FileCache::GetFile, |  | 
| 240                    base::Unretained(cache_.get()), |  | 
| 241                    id, &cache_file_path), |  | 
| 242         google_apis::test_util::CreateCopyResultCallback(&error)); |  | 
| 243     test_util::RunBlockingPoolTask(); |  | 
| 244     EXPECT_EQ(FILE_ERROR_OK, error); |  | 
| 245 |  | 
| 246     EXPECT_TRUE(base::PathExists(cache_file_path)); |  | 
| 247     EXPECT_EQ(cache_file_path, cache_->GetCacheFilePath(id)); |  | 
| 248   } |  | 
| 249 |  | 
| 250   void VerifyCacheFileState(FileError error, const std::string& id) { |  | 
| 251     EXPECT_EQ(expected_error_, error); |  | 
| 252 |  | 
| 253     // Verify cache map. |  | 
| 254     FileCacheEntry cache_entry; |  | 
| 255     const bool cache_entry_found = |  | 
| 256         GetCacheEntryFromOriginThread(id, &cache_entry); |  | 
| 257     if ((expected_cache_state_ & TEST_CACHE_STATE_PRESENT) || |  | 
| 258         (expected_cache_state_ & TEST_CACHE_STATE_PINNED)) { |  | 
| 259       ASSERT_TRUE(cache_entry_found); |  | 
| 260       EXPECT_EQ((expected_cache_state_ & TEST_CACHE_STATE_PINNED) != 0, |  | 
| 261                 cache_entry.is_pinned()); |  | 
| 262       EXPECT_EQ((expected_cache_state_ & TEST_CACHE_STATE_PRESENT) != 0, |  | 
| 263                 cache_entry.is_present()); |  | 
| 264       EXPECT_EQ((expected_cache_state_ & TEST_CACHE_STATE_DIRTY) != 0, |  | 
| 265                 cache_entry.is_dirty()); |  | 
| 266     } else { |  | 
| 267       EXPECT_FALSE(cache_entry_found); |  | 
| 268     } |  | 
| 269 |  | 
| 270     // Verify actual cache file. |  | 
| 271     base::FilePath dest_path = cache_->GetCacheFilePath(id); |  | 
| 272     EXPECT_EQ((expected_cache_state_ & TEST_CACHE_STATE_PRESENT) != 0, |  | 
| 273               base::PathExists(dest_path)); |  | 
| 274   } |  | 
| 275 |  | 
| 276   // Helper function to call GetCacheEntry from origin thread. |  | 
| 277   bool GetCacheEntryFromOriginThread(const std::string& id, |  | 
| 278                                      FileCacheEntry* cache_entry) { |  | 
| 279     bool result = false; |  | 
| 280     base::PostTaskAndReplyWithResult( |  | 
| 281         blocking_task_runner_, |  | 
| 282         FROM_HERE, |  | 
| 283         base::Bind(&internal::FileCache::GetCacheEntry, |  | 
| 284                    base::Unretained(cache_.get()), |  | 
| 285                    id, |  | 
| 286                    cache_entry), |  | 
| 287         google_apis::test_util::CreateCopyResultCallback(&result)); |  | 
| 288     test_util::RunBlockingPoolTask(); |  | 
| 289     return result; |  | 
| 290   } |  | 
| 291 |  | 
| 292   // Returns true if the cache entry exists for the given ID. |  | 
| 293   bool CacheEntryExists(const std::string& id) { |  | 
| 294     FileCacheEntry cache_entry; |  | 
| 295     return GetCacheEntryFromOriginThread(id, &cache_entry); |  | 
| 296   } |  | 
| 297 |  | 
| 298   // Returns the number of the cache files with name <id>, and Confirm |  | 
| 299   // that they have the <md5>. This should return 1 or 0. |  | 
| 300   size_t CountCacheFiles(const std::string& id, const std::string& md5) { |  | 
| 301     base::FilePath path = cache_->GetCacheFilePath(id); |  | 
| 302     base::FileEnumerator enumerator(path.DirName(), |  | 
| 303                                     false,  // recursive |  | 
| 304                                     base::FileEnumerator::FILES, |  | 
| 305                                     path.BaseName().value()); |  | 
| 306     size_t num_files_found = 0; |  | 
| 307     for (base::FilePath current = enumerator.Next(); !current.empty(); |  | 
| 308          current = enumerator.Next()) { |  | 
| 309       ++num_files_found; |  | 
| 310       EXPECT_EQ(util::EscapeCacheFileName(id), |  | 
| 311                 current.BaseName().AsUTF8Unsafe()); |  | 
| 312     } |  | 
| 313     return num_files_found; |  | 
| 314   } |  | 
| 315 |  | 
| 316   content::TestBrowserThreadBundle thread_bundle_; |  | 
| 317   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; |  | 
| 318   base::ScopedTempDir temp_dir_; |  | 
| 319   base::FilePath dummy_file_path_; |  | 
| 320 |  | 
| 321   scoped_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests> |  | 
| 322       metadata_storage_; |  | 
| 323   scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_; |  | 
| 324   scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_; |  | 
| 325 |  | 
| 326   FileError expected_error_; |  | 
| 327   int expected_cache_state_; |  | 
| 328   std::string expected_file_extension_; |  | 
| 329 }; |  | 
| 330 |  | 
| 331 TEST_F(FileCacheTestOnUIThread, StoreToCacheSimple) { |  | 
| 332   std::string id("pdf:1a2b"); |  | 
| 333   std::string md5("abcdef0123456789"); |  | 
| 334 |  | 
| 335   // Store an existing file. |  | 
| 336   TestStoreToCache(id, md5, dummy_file_path_, |  | 
| 337                    FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 338 |  | 
| 339   // Store a non-existent file to the same |id| and |md5|. |  | 
| 340   TestStoreToCache(id, md5, |  | 
| 341                    base::FilePath::FromUTF8Unsafe("non_existent_file"), |  | 
| 342                    FILE_ERROR_FAILED, |  | 
| 343                    TEST_CACHE_STATE_PRESENT); |  | 
| 344 |  | 
| 345   // Store a different existing file to the same |id| but different |  | 
| 346   // |md5|. |  | 
| 347   md5 = "new_md5"; |  | 
| 348   TestStoreToCache(id, md5, dummy_file_path_, |  | 
| 349                    FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 350 |  | 
| 351   // Verify that there's only one file with name <id>, i.e. previously |  | 
| 352   // cached file with the different md5 should be deleted. |  | 
| 353   EXPECT_EQ(1U, CountCacheFiles(id, md5)); |  | 
| 354 |  | 
| 355   // Passing empty MD5 marks the entry as dirty. |  | 
| 356   TestStoreToCache(id, std::string(), dummy_file_path_, FILE_ERROR_OK, |  | 
| 357                    TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_DIRTY); |  | 
| 358 } |  | 
| 359 |  | 
| 360 TEST_F(FileCacheTestOnUIThread, RemoveFromCacheSimple) { |  | 
| 361   std::string id("pdf:1a2b"); |  | 
| 362   std::string md5("abcdef0123456789"); |  | 
| 363   // First store a file to cache. |  | 
| 364   TestStoreToCache(id, md5, dummy_file_path_, |  | 
| 365                    FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 366 |  | 
| 367   // Then try to remove existing file from cache. |  | 
| 368   TestRemoveFromCache(id, FILE_ERROR_OK); |  | 
| 369 |  | 
| 370   // Repeat using non-alphanumeric characters for ID, including '.' |  | 
| 371   // which is an extension separator. |  | 
| 372   id = "pdf:`~!@#$%^&*()-_=+[{|]}\\;',<.>/?"; |  | 
| 373   TestStoreToCache(id, md5, dummy_file_path_, |  | 
| 374                    FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 375 |  | 
| 376   TestRemoveFromCache(id, FILE_ERROR_OK); |  | 
| 377 } |  | 
| 378 |  | 
| 379 TEST_F(FileCacheTestOnUIThread, PinAndUnpin) { |  | 
| 380   std::string id("pdf:1a2b"); |  | 
| 381   std::string md5("abcdef0123456789"); |  | 
| 382 |  | 
| 383   // First store a file to cache. |  | 
| 384   TestStoreToCache(id, md5, dummy_file_path_, |  | 
| 385                    FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 386 |  | 
| 387   // Pin the existing file in cache. |  | 
| 388   TestPin(id, FILE_ERROR_OK, |  | 
| 389           TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_PINNED); |  | 
| 390 |  | 
| 391   // Unpin the existing file in cache. |  | 
| 392   TestUnpin(id, FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 393 |  | 
| 394   // Pin back the same existing file in cache. |  | 
| 395   TestPin(id, FILE_ERROR_OK, |  | 
| 396           TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_PINNED); |  | 
| 397 |  | 
| 398   // Pin a non-existent file in cache. |  | 
| 399   id = "document:1a2b"; |  | 
| 400 |  | 
| 401   TestPin(id, FILE_ERROR_OK, TEST_CACHE_STATE_PINNED); |  | 
| 402 |  | 
| 403   // Unpin the previously pinned non-existent file in cache. |  | 
| 404   TestUnpin(id, FILE_ERROR_OK, TEST_CACHE_STATE_NONE); |  | 
| 405 |  | 
| 406   // Unpin a file that doesn't exist in cache and is not pinned, i.e. cache |  | 
| 407   // has zero knowledge of the file. |  | 
| 408   id = "not-in-cache:1a2b"; |  | 
| 409 |  | 
| 410   TestUnpin(id, FILE_ERROR_NOT_FOUND, TEST_CACHE_STATE_NONE); |  | 
| 411 } |  | 
| 412 |  | 
| 413 TEST_F(FileCacheTestOnUIThread, StoreToCachePinned) { |  | 
| 414   std::string id("pdf:1a2b"); |  | 
| 415   std::string md5("abcdef0123456789"); |  | 
| 416 |  | 
| 417   // Pin a non-existent file. |  | 
| 418   TestPin(id, FILE_ERROR_OK, TEST_CACHE_STATE_PINNED); |  | 
| 419 |  | 
| 420   // Store an existing file to a previously pinned file. |  | 
| 421   TestStoreToCache(id, md5, dummy_file_path_, FILE_ERROR_OK, |  | 
| 422                    TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_PINNED); |  | 
| 423 |  | 
| 424   // Store a non-existent file to a previously pinned and stored file. |  | 
| 425   TestStoreToCache(id, md5, |  | 
| 426                    base::FilePath::FromUTF8Unsafe("non_existent_file"), |  | 
| 427                    FILE_ERROR_FAILED, |  | 
| 428                    TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_PINNED); |  | 
| 429 } |  | 
| 430 |  | 
| 431 TEST_F(FileCacheTestOnUIThread, RemoveFromCachePinned) { |  | 
| 432   std::string id("pdf:1a2b"); |  | 
| 433   std::string md5("abcdef0123456789"); |  | 
| 434 |  | 
| 435   // Store a file to cache, and pin it. |  | 
| 436   TestStoreToCache(id, md5, dummy_file_path_, |  | 
| 437                    FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 438   TestPin(id, FILE_ERROR_OK, |  | 
| 439           TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_PINNED); |  | 
| 440 |  | 
| 441   // Remove |id| from cache. |  | 
| 442   TestRemoveFromCache(id, FILE_ERROR_OK); |  | 
| 443 |  | 
| 444   // Use non-alphanumeric characters for ID, including '.' |  | 
| 445   // which is an extension separator. |  | 
| 446   id = "pdf:`~!@#$%^&*()-_=+[{|]}\\;',<.>/?"; |  | 
| 447 |  | 
| 448   TestStoreToCache(id, md5, dummy_file_path_, |  | 
| 449                    FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 450   TestPin(id, FILE_ERROR_OK, |  | 
| 451           TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_PINNED); |  | 
| 452 |  | 
| 453   TestRemoveFromCache(id, FILE_ERROR_OK); |  | 
| 454 } |  | 
| 455 |  | 
| 456 TEST_F(FileCacheTestOnUIThread, MountUnmount) { |  | 
| 457   std::string id("pdf:1a2b"); |  | 
| 458   std::string md5("abcdef0123456789"); |  | 
| 459 |  | 
| 460   // First store a file to cache. |  | 
| 461   TestStoreToCache(id, md5, dummy_file_path_, |  | 
| 462                    FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 463 |  | 
| 464   // Mark the file mounted. |  | 
| 465   TestMarkAsMounted(id, FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 466   EXPECT_TRUE(CacheEntryExists(id)); |  | 
| 467 |  | 
| 468   // Try to remove the file. |  | 
| 469   TestRemoveFromCache(id, FILE_ERROR_IN_USE); |  | 
| 470 |  | 
| 471   // Clear mounted state of the file. |  | 
| 472   base::FilePath file_path; |  | 
| 473   FileError error = FILE_ERROR_FAILED; |  | 
| 474   base::PostTaskAndReplyWithResult( |  | 
| 475       blocking_task_runner_, |  | 
| 476       FROM_HERE, |  | 
| 477       base::Bind(&FileCache::GetFile, |  | 
| 478                  base::Unretained(cache_.get()), |  | 
| 479                  id, &file_path), |  | 
| 480       google_apis::test_util::CreateCopyResultCallback(&error)); |  | 
| 481   test_util::RunBlockingPoolTask(); |  | 
| 482   EXPECT_EQ(FILE_ERROR_OK, error); |  | 
| 483 |  | 
| 484   TestMarkAsUnmounted(id, file_path, FILE_ERROR_OK, TEST_CACHE_STATE_PRESENT); |  | 
| 485   EXPECT_TRUE(CacheEntryExists(id)); |  | 
| 486 |  | 
| 487   // Try to remove the file. |  | 
| 488   TestRemoveFromCache(id, FILE_ERROR_OK); |  | 
| 489 } |  | 
| 490 |  | 
| 491 TEST_F(FileCacheTestOnUIThread, StoreToCacheNoSpace) { |  | 
| 492   fake_free_disk_space_getter_->set_default_value(0); |  | 
| 493 |  | 
| 494   std::string id("pdf:1a2b"); |  | 
| 495   std::string md5("abcdef0123456789"); |  | 
| 496 |  | 
| 497   // Try to store an existing file. |  | 
| 498   TestStoreToCache(id, md5, dummy_file_path_, |  | 
| 499                    FILE_ERROR_NO_LOCAL_SPACE, |  | 
| 500                    TEST_CACHE_STATE_NONE); |  | 
| 501 |  | 
| 502   // Verify that there's no files added. |  | 
| 503   EXPECT_EQ(0U, CountCacheFiles(id, md5)); |  | 
| 504 } |  | 
| 505 |  | 
| 506 TEST_F(FileCacheTestOnUIThread, UpdatePinnedCache) { |  | 
| 507   std::string id("pdf:1a2b"); |  | 
| 508   std::string md5("abcdef0123456789"); |  | 
| 509   std::string md5_modified("aaaaaa0000000000"); |  | 
| 510 |  | 
| 511   // Store an existing file. |  | 
| 512   TestStoreToCache(id, md5, dummy_file_path_, FILE_ERROR_OK, |  | 
| 513                    TEST_CACHE_STATE_PRESENT); |  | 
| 514 |  | 
| 515   // Pin the file. |  | 
| 516   TestPin(id, FILE_ERROR_OK, |  | 
| 517           TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_PINNED); |  | 
| 518 |  | 
| 519   // Store the file with a modified content and md5. It should stay pinned. |  | 
| 520   TestStoreToCache(id, md5_modified, dummy_file_path_, FILE_ERROR_OK, |  | 
| 521                    TEST_CACHE_STATE_PRESENT | TEST_CACHE_STATE_PINNED); |  | 
| 522 } |  | 
| 523 |  | 
| 524 // Tests FileCache methods working with the blocking task runner. | 33 // Tests FileCache methods working with the blocking task runner. | 
| 525 class FileCacheTest : public testing::Test { | 34 class FileCacheTest : public testing::Test { | 
| 526  protected: | 35  protected: | 
| 527   virtual void SetUp() OVERRIDE { | 36   virtual void SetUp() OVERRIDE { | 
| 528     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 37     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 
| 529     const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta"); | 38     const base::FilePath metadata_dir = temp_dir_.path().AppendASCII("meta"); | 
| 530     cache_files_dir_ = temp_dir_.path().AppendASCII(kCacheFileDirectory); | 39     cache_files_dir_ = temp_dir_.path().AppendASCII(kCacheFileDirectory); | 
| 531 | 40 | 
| 532     ASSERT_TRUE(base::CreateDirectory(metadata_dir)); | 41     ASSERT_TRUE(base::CreateDirectory(metadata_dir)); | 
| 533     ASSERT_TRUE(base::CreateDirectory(cache_files_dir_)); | 42     ASSERT_TRUE(base::CreateDirectory(cache_files_dir_)); | 
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 716   EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(id, &cache_file_path)); | 225   EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(id, &cache_file_path)); | 
| 717   EXPECT_EQ( | 226   EXPECT_EQ( | 
| 718       cache_file_directory.AppendASCII(util::EscapeCacheFileName(id)).value(), | 227       cache_file_directory.AppendASCII(util::EscapeCacheFileName(id)).value(), | 
| 719       cache_file_path.value()); | 228       cache_file_path.value()); | 
| 720 | 229 | 
| 721   contents.clear(); | 230   contents.clear(); | 
| 722   EXPECT_TRUE(base::ReadFileToString(cache_file_path, &contents)); | 231   EXPECT_TRUE(base::ReadFileToString(cache_file_path, &contents)); | 
| 723   EXPECT_EQ(src_contents, contents); | 232   EXPECT_EQ(src_contents, contents); | 
| 724 } | 233 } | 
| 725 | 234 | 
|  | 235 TEST_F(FileCacheTest, Store) { | 
|  | 236   const base::FilePath src_file_path = temp_dir_.path().Append("test.dat"); | 
|  | 237   const std::string src_contents = "test"; | 
|  | 238   EXPECT_TRUE(google_apis::test_util::WriteStringToFile(src_file_path, | 
|  | 239                                                         src_contents)); | 
|  | 240   std::string id("id"); | 
|  | 241   std::string md5(base::MD5String(src_contents)); | 
|  | 242 | 
|  | 243   // Store a file. | 
|  | 244   EXPECT_EQ(FILE_ERROR_OK, cache_->Store( | 
|  | 245       id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); | 
|  | 246 | 
|  | 247   FileCacheEntry cache_entry; | 
|  | 248   EXPECT_TRUE(cache_->GetCacheEntry(id, &cache_entry)); | 
|  | 249   EXPECT_TRUE(cache_entry.is_present()); | 
|  | 250   EXPECT_EQ(md5, cache_entry.md5()); | 
|  | 251 | 
|  | 252   base::FilePath cache_file_path; | 
|  | 253   EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(id, &cache_file_path)); | 
|  | 254   EXPECT_TRUE(base::ContentsEqual(src_file_path, cache_file_path)); | 
|  | 255 | 
|  | 256   // Store a non-existent file. | 
|  | 257   EXPECT_EQ(FILE_ERROR_FAILED, cache_->Store( | 
|  | 258       id, md5, base::FilePath::FromUTF8Unsafe("non_existent_file"), | 
|  | 259       FileCache::FILE_OPERATION_COPY)); | 
|  | 260 | 
|  | 261   // Passing empty MD5 marks the entry as dirty. | 
|  | 262   EXPECT_EQ(FILE_ERROR_OK, cache_->Store( | 
|  | 263       id, std::string(), src_file_path, FileCache::FILE_OPERATION_COPY)); | 
|  | 264 | 
|  | 265   EXPECT_TRUE(cache_->GetCacheEntry(id, &cache_entry)); | 
|  | 266   EXPECT_TRUE(cache_entry.is_present()); | 
|  | 267   EXPECT_TRUE(cache_entry.md5().empty()); | 
|  | 268   EXPECT_TRUE(cache_entry.is_dirty()); | 
|  | 269 | 
|  | 270   // No free space available. | 
|  | 271   fake_free_disk_space_getter_->set_default_value(0); | 
|  | 272 | 
|  | 273   EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, cache_->Store( | 
|  | 274       id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); | 
|  | 275 } | 
|  | 276 | 
|  | 277 TEST_F(FileCacheTest, PinAndUnpin) { | 
|  | 278   const base::FilePath src_file_path = temp_dir_.path().Append("test.dat"); | 
|  | 279   const std::string src_contents = "test"; | 
|  | 280   EXPECT_TRUE(google_apis::test_util::WriteStringToFile(src_file_path, | 
|  | 281                                                         src_contents)); | 
|  | 282   std::string id("id_present"); | 
|  | 283   std::string md5(base::MD5String(src_contents)); | 
|  | 284 | 
|  | 285   // Store a file. | 
|  | 286   EXPECT_EQ(FILE_ERROR_OK, cache_->Store( | 
|  | 287       id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); | 
|  | 288 | 
|  | 289   FileCacheEntry cache_entry; | 
|  | 290   EXPECT_TRUE(cache_->GetCacheEntry(id, &cache_entry)); | 
|  | 291   EXPECT_FALSE(cache_entry.is_pinned()); | 
|  | 292 | 
|  | 293   // Pin the existing file. | 
|  | 294   EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(id)); | 
|  | 295 | 
|  | 296   EXPECT_TRUE(cache_->GetCacheEntry(id, &cache_entry)); | 
|  | 297   EXPECT_TRUE(cache_entry.is_pinned()); | 
|  | 298 | 
|  | 299   // Unpin the file. | 
|  | 300   EXPECT_EQ(FILE_ERROR_OK, cache_->Unpin(id)); | 
|  | 301 | 
|  | 302   EXPECT_TRUE(cache_->GetCacheEntry(id, &cache_entry)); | 
|  | 303   EXPECT_FALSE(cache_entry.is_pinned()); | 
|  | 304 | 
|  | 305   // Pin a non-present file. | 
|  | 306   std::string id_non_present = "id_non_present"; | 
|  | 307   EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(id_non_present)); | 
|  | 308 | 
|  | 309   EXPECT_TRUE(cache_->GetCacheEntry(id_non_present, &cache_entry)); | 
|  | 310   EXPECT_TRUE(cache_entry.is_pinned()); | 
|  | 311 | 
|  | 312   // Unpin the previously pinned non-existent file. | 
|  | 313   EXPECT_EQ(FILE_ERROR_OK, cache_->Unpin(id_non_present)); | 
|  | 314 | 
|  | 315   EXPECT_FALSE(cache_->GetCacheEntry(id_non_present, &cache_entry)); | 
|  | 316 | 
|  | 317   // Unpin a file that doesn't exist in cache and is not pinned. | 
|  | 318   EXPECT_EQ(FILE_ERROR_NOT_FOUND, cache_->Unpin("id_non_existent")); | 
|  | 319 } | 
|  | 320 | 
|  | 321 TEST_F(FileCacheTest, MountUnmount) { | 
|  | 322   const base::FilePath src_file_path = temp_dir_.path().Append("test.dat"); | 
|  | 323   const std::string src_contents = "test"; | 
|  | 324   EXPECT_TRUE(google_apis::test_util::WriteStringToFile(src_file_path, | 
|  | 325                                                         src_contents)); | 
|  | 326   std::string id("id_present"); | 
|  | 327   std::string md5(base::MD5String(src_contents)); | 
|  | 328 | 
|  | 329   // Store a file. | 
|  | 330   EXPECT_EQ(FILE_ERROR_OK, cache_->Store( | 
|  | 331       id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); | 
|  | 332 | 
|  | 333   // Mark the file mounted. | 
|  | 334   base::FilePath cache_file_path; | 
|  | 335   EXPECT_EQ(FILE_ERROR_OK, cache_->MarkAsMounted(id, &cache_file_path)); | 
|  | 336 | 
|  | 337   // Try to remove it. | 
|  | 338   EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(id)); | 
|  | 339 | 
|  | 340   // Clear mounted state of the file. | 
|  | 341   EXPECT_EQ(FILE_ERROR_OK, cache_->MarkAsUnmounted(cache_file_path)); | 
|  | 342 | 
|  | 343   // Try to remove again. | 
|  | 344   EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(id)); | 
|  | 345 } | 
|  | 346 | 
| 726 TEST_F(FileCacheTest, OpenForWrite) { | 347 TEST_F(FileCacheTest, OpenForWrite) { | 
| 727   // Prepare a file. | 348   // Prepare a file. | 
| 728   base::FilePath src_file; | 349   base::FilePath src_file; | 
| 729   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &src_file)); | 350   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &src_file)); | 
| 730 | 351 | 
| 731   const std::string id = "id"; | 352   const std::string id = "id"; | 
| 732   ASSERT_EQ(FILE_ERROR_OK, cache_->Store(id, "md5", src_file, | 353   ASSERT_EQ(FILE_ERROR_OK, cache_->Store(id, "md5", src_file, | 
| 733                                          FileCache::FILE_OPERATION_COPY)); | 354                                          FileCache::FILE_OPERATION_COPY)); | 
| 734 | 355 | 
| 735   // Entry is not dirty nor opened. | 356   // Entry is not dirty nor opened. | 
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 825 | 446 | 
| 826   // Close the file and clear the dirty bit. | 447   // Close the file and clear the dirty bit. | 
| 827   file_closer.reset(); | 448   file_closer.reset(); | 
| 828   EXPECT_EQ(FILE_ERROR_OK, cache_->ClearDirty(id)); | 449   EXPECT_EQ(FILE_ERROR_OK, cache_->ClearDirty(id)); | 
| 829 | 450 | 
| 830   // Entry is not dirty. | 451   // Entry is not dirty. | 
| 831   EXPECT_TRUE(cache_->GetCacheEntry(id, &entry)); | 452   EXPECT_TRUE(cache_->GetCacheEntry(id, &entry)); | 
| 832   EXPECT_FALSE(entry.is_dirty()); | 453   EXPECT_FALSE(entry.is_dirty()); | 
| 833 } | 454 } | 
| 834 | 455 | 
|  | 456 TEST_F(FileCacheTest, Remove) { | 
|  | 457   const base::FilePath src_file_path = temp_dir_.path().Append("test.dat"); | 
|  | 458   const std::string src_contents = "test"; | 
|  | 459   EXPECT_TRUE(google_apis::test_util::WriteStringToFile(src_file_path, | 
|  | 460                                                         src_contents)); | 
|  | 461   std::string id("id"); | 
|  | 462   std::string md5(base::MD5String(src_contents)); | 
|  | 463 | 
|  | 464   // First store a file to cache. | 
|  | 465   base::FilePath src_file; | 
|  | 466   ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &src_file)); | 
|  | 467   EXPECT_EQ(FILE_ERROR_OK, cache_->Store( | 
|  | 468       id, md5, src_file_path, FileCache::FILE_OPERATION_COPY)); | 
|  | 469 | 
|  | 470   base::FilePath cache_file_path; | 
|  | 471   EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(id, &cache_file_path)); | 
|  | 472 | 
|  | 473   // Then try to remove existing file from cache. | 
|  | 474   EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(id)); | 
|  | 475   EXPECT_FALSE(base::PathExists(cache_file_path)); | 
|  | 476 } | 
|  | 477 | 
| 835 TEST_F(FileCacheTest, RenameCacheFilesToNewFormat) { | 478 TEST_F(FileCacheTest, RenameCacheFilesToNewFormat) { | 
| 836   const base::FilePath file_directory = | 479   const base::FilePath file_directory = | 
| 837       temp_dir_.path().AppendASCII(kCacheFileDirectory); | 480       temp_dir_.path().AppendASCII(kCacheFileDirectory); | 
| 838 | 481 | 
| 839   // File with an old style "<prefix>:<ID>.<MD5>" name. | 482   // File with an old style "<prefix>:<ID>.<MD5>" name. | 
| 840   ASSERT_TRUE(google_apis::test_util::WriteStringToFile( | 483   ASSERT_TRUE(google_apis::test_util::WriteStringToFile( | 
| 841       file_directory.AppendASCII("file:id_koo.md5"), "koo")); | 484       file_directory.AppendASCII("file:id_koo.md5"), "koo")); | 
| 842 | 485 | 
| 843   // File with multiple extensions should be removed. | 486   // File with multiple extensions should be removed. | 
| 844   ASSERT_TRUE(google_apis::test_util::WriteStringToFile( | 487   ASSERT_TRUE(google_apis::test_util::WriteStringToFile( | 
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 888   // Clear cache. | 531   // Clear cache. | 
| 889   EXPECT_TRUE(cache_->ClearAll()); | 532   EXPECT_TRUE(cache_->ClearAll()); | 
| 890 | 533 | 
| 891   // Verify that the cache is removed. | 534   // Verify that the cache is removed. | 
| 892   EXPECT_FALSE(cache_->GetCacheEntry(id, &cache_entry)); | 535   EXPECT_FALSE(cache_->GetCacheEntry(id, &cache_entry)); | 
| 893   EXPECT_TRUE(base::IsDirectoryEmpty(cache_files_dir_)); | 536   EXPECT_TRUE(base::IsDirectoryEmpty(cache_files_dir_)); | 
| 894 } | 537 } | 
| 895 | 538 | 
| 896 }  // namespace internal | 539 }  // namespace internal | 
| 897 }  // namespace drive | 540 }  // namespace drive | 
| OLD | NEW | 
|---|