file_cache_unittest.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/drive/file_cache.h"
6
7#include <string>
8#include <vector>
9
10#include "base/file_util.h"
11#include "base/files/scoped_temp_dir.h"
12#include "base/message_loop.h"
13#include "base/threading/sequenced_worker_pool.h"
14#include "chrome/browser/chromeos/drive/drive.pb.h"
15#include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
16#include "chrome/browser/chromeos/drive/file_system_util.h"
17#include "chrome/browser/chromeos/drive/mock_file_cache_observer.h"
18#include "chrome/browser/chromeos/drive/test_util.h"
19#include "chrome/browser/google_apis/test_util.h"
20#include "content/public/test/test_browser_thread.h"
21#include "testing/gmock/include/gmock/gmock.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24using ::testing::StrictMock;
25
26namespace drive {
27namespace internal {
28namespace {
29
30struct PathToVerify {
31  PathToVerify(const base::FilePath& in_path_to_scan,
32               const base::FilePath& in_expected_existing_path) :
33      path_to_scan(in_path_to_scan),
34      expected_existing_path(in_expected_existing_path) {
35  }
36
37  base::FilePath path_to_scan;
38  base::FilePath expected_existing_path;
39};
40
41// Copies results from Iterate().
42void OnIterate(std::vector<std::string>* out_resource_ids,
43               std::vector<FileCacheEntry>* out_cache_entries,
44               const std::string& resource_id,
45               const FileCacheEntry& cache_entry) {
46  out_resource_ids->push_back(resource_id);
47  out_cache_entries->push_back(cache_entry);
48}
49
50// Called upon completion of Iterate().
51void OnIterateCompleted(bool* out_is_called) {
52  *out_is_called = true;
53}
54
55}  // namespace
56
57class FileCacheTest : public testing::Test {
58 protected:
59  FileCacheTest()
60      : ui_thread_(content::BrowserThread::UI, &message_loop_),
61        expected_error_(FILE_ERROR_OK),
62        expected_cache_state_(0),
63        expected_sub_dir_type_(FileCache::CACHE_TYPE_META),
64        expected_success_(true) {
65  }
66
67  virtual void SetUp() OVERRIDE {
68    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
69    fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
70
71    scoped_refptr<base::SequencedWorkerPool> pool =
72        content::BrowserThread::GetBlockingPool();
73    blocking_task_runner_ =
74        pool->GetSequencedTaskRunner(pool->GetSequenceToken());
75    cache_.reset(new FileCache(temp_dir_.path(),
76                                blocking_task_runner_,
77                                fake_free_disk_space_getter_.get()));
78
79    mock_cache_observer_.reset(new StrictMock<MockCacheObserver>);
80    cache_->AddObserver(mock_cache_observer_.get());
81
82    bool success = false;
83    cache_->RequestInitialize(
84        google_apis::test_util::CreateCopyResultCallback(&success));
85    google_apis::test_util::RunBlockingPoolTask();
86    ASSERT_TRUE(success);
87  }
88
89  virtual void TearDown() OVERRIDE {
90    cache_.reset();
91  }
92
93  void TestGetFileFromCacheByResourceIdAndMd5(
94      const std::string& resource_id,
95      const std::string& md5,
96      FileError expected_error,
97      const std::string& expected_file_extension) {
98    FileError error = FILE_ERROR_OK;
99    base::FilePath cache_file_path;
100    cache_->GetFileOnUIThread(resource_id, md5,
101                              google_apis::test_util::CreateCopyResultCallback(
102                                  &error, &cache_file_path));
103    google_apis::test_util::RunBlockingPoolTask();
104
105    EXPECT_EQ(expected_error, error);
106    if (error == FILE_ERROR_OK) {
107      // Verify filename of |cache_file_path|.
108      base::FilePath base_name = cache_file_path.BaseName();
109      EXPECT_EQ(util::EscapeCacheFileName(resource_id) +
110                base::FilePath::kExtensionSeparator +
111                util::EscapeCacheFileName(
112                    expected_file_extension.empty() ?
113                    md5 : expected_file_extension),
114                base_name.value());
115    } else {
116      EXPECT_TRUE(cache_file_path.empty());
117    }
118  }
119
120  void TestStoreToCache(
121      const std::string& resource_id,
122      const std::string& md5,
123      const base::FilePath& source_path,
124      FileError expected_error,
125      int expected_cache_state,
126      FileCache::CacheSubDirectoryType expected_sub_dir_type) {
127    expected_error_ = expected_error;
128    expected_cache_state_ = expected_cache_state;
129    expected_sub_dir_type_ = expected_sub_dir_type;
130
131    FileError error = FILE_ERROR_OK;
132    cache_->StoreOnUIThread(
133        resource_id, md5, source_path,
134        FileCache::FILE_OPERATION_COPY,
135        google_apis::test_util::CreateCopyResultCallback(&error));
136    google_apis::test_util::RunBlockingPoolTask();
137    VerifyCacheFileState(error, resource_id, md5);
138  }
139
140  void TestStoreLocallyModifiedToCache(
141      const std::string& resource_id,
142      const std::string& md5,
143      const base::FilePath& source_path,
144      FileError expected_error,
145      int expected_cache_state,
146      FileCache::CacheSubDirectoryType expected_sub_dir_type) {
147    expected_error_ = expected_error;
148    expected_cache_state_ = expected_cache_state;
149    expected_sub_dir_type_ = expected_sub_dir_type;
150
151    FileError error = FILE_ERROR_OK;
152    cache_->StoreLocallyModifiedOnUIThread(
153        resource_id, md5, source_path,
154        FileCache::FILE_OPERATION_COPY,
155        google_apis::test_util::CreateCopyResultCallback(&error));
156    google_apis::test_util::RunBlockingPoolTask();
157    VerifyCacheFileState(error, resource_id, md5);
158  }
159
160  void TestRemoveFromCache(const std::string& resource_id,
161                           FileError expected_error) {
162    expected_error_ = expected_error;
163
164    FileError error = FILE_ERROR_OK;
165    cache_->RemoveOnUIThread(
166        resource_id,
167        google_apis::test_util::CreateCopyResultCallback(&error));
168    google_apis::test_util::RunBlockingPoolTask();
169    VerifyRemoveFromCache(error, resource_id, "");
170  }
171
172  void VerifyRemoveFromCache(FileError error,
173                             const std::string& resource_id,
174                             const std::string& md5) {
175    EXPECT_EQ(expected_error_, error);
176
177    // Verify cache map.
178    FileCacheEntry cache_entry;
179    const bool cache_entry_found =
180        GetCacheEntryFromOriginThread(resource_id, md5, &cache_entry);
181    if (cache_entry_found)
182      EXPECT_TRUE(cache_entry.is_dirty());
183
184    // If entry doesn't exist, verify that no files with "<resource_id>.*"
185    // exist in persistent and tmp dirs.
186    std::vector<PathToVerify> paths_to_verify;
187    paths_to_verify.push_back(  // Index 0: CACHE_TYPE_TMP.
188        PathToVerify(cache_->GetCacheFilePath(resource_id, "*",
189                     FileCache::CACHE_TYPE_TMP,
190                     FileCache::CACHED_FILE_FROM_SERVER), base::FilePath()));
191    paths_to_verify.push_back(  // Index 1: CACHE_TYPE_PERSISTENT.
192        PathToVerify(cache_->GetCacheFilePath(resource_id, "*",
193                     FileCache::CACHE_TYPE_PERSISTENT,
194                     FileCache::CACHED_FILE_FROM_SERVER), base::FilePath()));
195    if (!cache_entry_found) {
196      for (size_t i = 0; i < paths_to_verify.size(); ++i) {
197        file_util::FileEnumerator enumerator(
198            paths_to_verify[i].path_to_scan.DirName(), false /* not recursive*/,
199            file_util::FileEnumerator::FILES,
200            paths_to_verify[i].path_to_scan.BaseName().value());
201        EXPECT_TRUE(enumerator.Next().empty());
202      }
203    } else {
204      // Entry is dirty, verify that:
205      // - no files with "<resource_id>.*" exist in tmp dir
206      // - only 1 "<resource_id>.local" exists in persistent dir
207      // - if entry is pinned, only 1 <resource_id> exists in pinned dir.
208
209      // Change expected_existing_path of CACHE_TYPE_PERSISTENT (index 1).
210      paths_to_verify[1].expected_existing_path =
211          GetCacheFilePath(resource_id,
212                           std::string(),
213                           FileCache::CACHE_TYPE_PERSISTENT,
214                           FileCache::CACHED_FILE_LOCALLY_MODIFIED);
215
216      for (size_t i = 0; i < paths_to_verify.size(); ++i) {
217        const struct PathToVerify& verify = paths_to_verify[i];
218        file_util::FileEnumerator enumerator(
219            verify.path_to_scan.DirName(), false /* not recursive */,
220            file_util::FileEnumerator::FILES,
221            verify.path_to_scan.BaseName().value());
222        size_t num_files_found = 0;
223        for (base::FilePath current = enumerator.Next(); !current.empty();
224             current = enumerator.Next()) {
225          ++num_files_found;
226          EXPECT_EQ(verify.expected_existing_path, current);
227        }
228        if (verify.expected_existing_path.empty())
229          EXPECT_EQ(0U, num_files_found);
230        else
231          EXPECT_EQ(1U, num_files_found);
232      }
233    }
234  }
235
236  void TestPin(
237      const std::string& resource_id,
238      const std::string& md5,
239      FileError expected_error,
240      int expected_cache_state,
241      FileCache::CacheSubDirectoryType expected_sub_dir_type) {
242    expected_error_ = expected_error;
243    expected_cache_state_ = expected_cache_state;
244    expected_sub_dir_type_ = expected_sub_dir_type;
245
246    FileError error = FILE_ERROR_OK;
247    cache_->PinOnUIThread(
248        resource_id, md5,
249        google_apis::test_util::CreateCopyResultCallback(&error));
250    google_apis::test_util::RunBlockingPoolTask();
251    VerifyCacheFileState(error, resource_id, md5);
252  }
253
254  void TestUnpin(
255      const std::string& resource_id,
256      const std::string& md5,
257      FileError expected_error,
258      int expected_cache_state,
259      FileCache::CacheSubDirectoryType expected_sub_dir_type) {
260    expected_error_ = expected_error;
261    expected_cache_state_ = expected_cache_state;
262    expected_sub_dir_type_ = expected_sub_dir_type;
263
264    FileError error = FILE_ERROR_OK;
265    cache_->UnpinOnUIThread(
266        resource_id, md5,
267        google_apis::test_util::CreateCopyResultCallback(&error));
268    google_apis::test_util::RunBlockingPoolTask();
269    VerifyCacheFileState(error, resource_id, md5);
270  }
271
272  void TestMarkDirty(const std::string& resource_id,
273                     const std::string& md5,
274                     FileError expected_error,
275                     int expected_cache_state,
276                     FileCache::CacheSubDirectoryType expected_sub_dir_type) {
277    expected_error_ = expected_error;
278    expected_cache_state_ = expected_cache_state;
279    expected_sub_dir_type_ = expected_sub_dir_type;
280
281    FileError error = FILE_ERROR_OK;
282    cache_->MarkDirtyOnUIThread(
283        resource_id, md5,
284        google_apis::test_util::CreateCopyResultCallback(&error));
285    google_apis::test_util::RunBlockingPoolTask();
286
287    VerifyCacheFileState(error, resource_id, md5);
288
289    // Verify filename.
290    if (error == FILE_ERROR_OK) {
291      base::FilePath cache_file_path;
292      cache_->GetFileOnUIThread(
293          resource_id, md5,
294          google_apis::test_util::CreateCopyResultCallback(
295              &error, &cache_file_path));
296      google_apis::test_util::RunBlockingPoolTask();
297
298      EXPECT_EQ(FILE_ERROR_OK, error);
299      base::FilePath base_name = cache_file_path.BaseName();
300      EXPECT_EQ(util::EscapeCacheFileName(resource_id) +
301                base::FilePath::kExtensionSeparator +
302                "local",
303                base_name.value());
304    }
305  }
306
307  void TestCommitDirty(
308      const std::string& resource_id,
309      const std::string& md5,
310      FileError expected_error,
311      int expected_cache_state,
312      FileCache::CacheSubDirectoryType expected_sub_dir_type) {
313    expected_error_ = expected_error;
314    expected_cache_state_ = expected_cache_state;
315    expected_sub_dir_type_ = expected_sub_dir_type;
316
317    FileError error = FILE_ERROR_OK;
318    cache_->CommitDirtyOnUIThread(
319        resource_id, md5,
320        google_apis::test_util::CreateCopyResultCallback(&error));
321    google_apis::test_util::RunBlockingPoolTask();
322    VerifyCacheFileState(error, resource_id, md5);
323  }
324
325  void TestClearDirty(
326      const std::string& resource_id,
327      const std::string& md5,
328      FileError expected_error,
329      int expected_cache_state,
330      FileCache::CacheSubDirectoryType expected_sub_dir_type) {
331    expected_error_ = expected_error;
332    expected_cache_state_ = expected_cache_state;
333    expected_sub_dir_type_ = expected_sub_dir_type;
334
335    FileError error = FILE_ERROR_OK;
336    PostTaskAndReplyWithResult(
337        blocking_task_runner_,
338        FROM_HERE,
339        base::Bind(&FileCache::ClearDirty,
340                   base::Unretained(cache_.get()),
341                   resource_id, md5),
342        google_apis::test_util::CreateCopyResultCallback(&error));
343    google_apis::test_util::RunBlockingPoolTask();
344    VerifyCacheFileState(error, resource_id, md5);
345  }
346
347  void TestMarkAsMounted(
348      const std::string& resource_id,
349      const std::string& md5,
350      FileError expected_error,
351      int expected_cache_state,
352      FileCache::CacheSubDirectoryType expected_sub_dir_type) {
353    expected_error_ = expected_error;
354    expected_cache_state_ = expected_cache_state;
355    expected_sub_dir_type_ = expected_sub_dir_type;
356
357    FileError error = FILE_ERROR_OK;
358    base::FilePath cache_file_path;
359    cache_->MarkAsMountedOnUIThread(
360        resource_id, md5,
361        google_apis::test_util::CreateCopyResultCallback(
362            &error, &cache_file_path));
363    google_apis::test_util::RunBlockingPoolTask();
364
365    EXPECT_TRUE(file_util::PathExists(cache_file_path));
366    EXPECT_EQ(cache_file_path,
367              cache_->GetCacheFilePath(resource_id,
368                                       md5,
369                                       expected_sub_dir_type_,
370                                       FileCache::CACHED_FILE_MOUNTED));
371  }
372
373  void TestMarkAsUnmounted(
374      const std::string& resource_id,
375      const std::string& md5,
376      const base::FilePath& file_path,
377      FileError expected_error,
378      int expected_cache_state,
379      FileCache::CacheSubDirectoryType expected_sub_dir_type) {
380    expected_error_ = expected_error;
381    expected_cache_state_ = expected_cache_state;
382    expected_sub_dir_type_ = expected_sub_dir_type;
383
384    FileError error = FILE_ERROR_OK;
385    cache_->MarkAsUnmountedOnUIThread(
386        file_path,
387        google_apis::test_util::CreateCopyResultCallback(&error));
388    google_apis::test_util::RunBlockingPoolTask();
389
390    base::FilePath cache_file_path;
391    cache_->GetFileOnUIThread(
392        resource_id, md5,
393        google_apis::test_util::CreateCopyResultCallback(
394            &error, &cache_file_path));
395    google_apis::test_util::RunBlockingPoolTask();
396    EXPECT_EQ(FILE_ERROR_OK, error);
397
398    EXPECT_TRUE(file_util::PathExists(cache_file_path));
399    EXPECT_EQ(cache_file_path,
400              cache_->GetCacheFilePath(resource_id,
401                                       md5,
402                                       expected_sub_dir_type_,
403                                       FileCache::CACHED_FILE_FROM_SERVER));
404  }
405
406  void VerifyCacheFileState(FileError error,
407                            const std::string& resource_id,
408                            const std::string& md5) {
409    EXPECT_EQ(expected_error_, error);
410
411    // Verify cache map.
412    FileCacheEntry cache_entry;
413    const bool cache_entry_found =
414        GetCacheEntryFromOriginThread(resource_id, md5, &cache_entry);
415    if (test_util::ToCacheEntry(expected_cache_state_).is_present() ||
416        test_util::ToCacheEntry(expected_cache_state_).is_pinned()) {
417      ASSERT_TRUE(cache_entry_found);
418      EXPECT_TRUE(test_util::CacheStatesEqual(
419          test_util::ToCacheEntry(expected_cache_state_),
420          cache_entry));
421      EXPECT_EQ(expected_sub_dir_type_,
422                FileCache::GetSubDirectoryType(cache_entry));
423    } else {
424      EXPECT_FALSE(cache_entry_found);
425    }
426
427    // Verify actual cache file.
428    base::FilePath dest_path = cache_->GetCacheFilePath(
429        resource_id,
430        md5,
431        test_util::ToCacheEntry(expected_cache_state_).is_pinned() ||
432        test_util::ToCacheEntry(expected_cache_state_).is_dirty() ?
433                FileCache::CACHE_TYPE_PERSISTENT :
434                FileCache::CACHE_TYPE_TMP,
435        test_util::ToCacheEntry(expected_cache_state_).is_dirty() ?
436            FileCache::CACHED_FILE_LOCALLY_MODIFIED :
437            FileCache::CACHED_FILE_FROM_SERVER);
438    bool exists = file_util::PathExists(dest_path);
439    if (test_util::ToCacheEntry(expected_cache_state_).is_present())
440      EXPECT_TRUE(exists);
441    else
442      EXPECT_FALSE(exists);
443  }
444
445  base::FilePath GetCacheFilePath(const std::string& resource_id,
446                            const std::string& md5,
447                            FileCache::CacheSubDirectoryType sub_dir_type,
448                            FileCache::CachedFileOrigin file_origin) {
449    return cache_->GetCacheFilePath(resource_id, md5, sub_dir_type,
450                                    file_origin);
451  }
452
453  // Helper function to call GetCacheEntry from origin thread.
454  bool GetCacheEntryFromOriginThread(const std::string& resource_id,
455                                     const std::string& md5,
456                                     FileCacheEntry* cache_entry) {
457    bool result = false;
458    cache_->GetCacheEntryOnUIThread(
459        resource_id, md5,
460        google_apis::test_util::CreateCopyResultCallback(&result, cache_entry));
461    google_apis::test_util::RunBlockingPoolTask();
462    return result;
463  }
464
465  // Returns true if the cache entry exists for the given resource ID and MD5.
466  bool CacheEntryExists(const std::string& resource_id,
467                        const std::string& md5) {
468    FileCacheEntry cache_entry;
469    return GetCacheEntryFromOriginThread(resource_id, md5, &cache_entry);
470  }
471
472  void TestGetCacheFilePath(const std::string& resource_id,
473                            const std::string& md5,
474                            const std::string& expected_filename) {
475    base::FilePath actual_path = cache_->GetCacheFilePath(
476        resource_id,
477        md5,
478        FileCache::CACHE_TYPE_TMP,
479        FileCache::CACHED_FILE_FROM_SERVER);
480    base::FilePath expected_path =
481        cache_->GetCacheDirectoryPath(FileCache::CACHE_TYPE_TMP);
482    expected_path = expected_path.Append(
483        base::FilePath::FromUTF8Unsafe(expected_filename));
484    EXPECT_EQ(expected_path, actual_path);
485
486    base::FilePath base_name = actual_path.BaseName();
487
488    // base::FilePath::Extension returns ".", so strip it.
489    std::string unescaped_md5 = util::UnescapeCacheFileName(
490        base_name.Extension().substr(1));
491    EXPECT_EQ(md5, unescaped_md5);
492    std::string unescaped_resource_id = util::UnescapeCacheFileName(
493        base_name.RemoveExtension().value());
494    EXPECT_EQ(resource_id, unescaped_resource_id);
495  }
496
497  // Returns the number of the cache files with name <resource_id>, and Confirm
498  // that they have the <md5>. This should return 1 or 0.
499  size_t CountCacheFiles(const std::string& resource_id,
500                         const std::string& md5) {
501    base::FilePath path = GetCacheFilePath(
502        resource_id, "*",
503        (test_util::ToCacheEntry(expected_cache_state_).is_pinned() ?
504         FileCache::CACHE_TYPE_PERSISTENT :
505         FileCache::CACHE_TYPE_TMP),
506        FileCache::CACHED_FILE_FROM_SERVER);
507    file_util::FileEnumerator enumerator(path.DirName(), false,
508                                         file_util::FileEnumerator::FILES,
509                                         path.BaseName().value());
510    size_t num_files_found = 0;
511    for (base::FilePath current = enumerator.Next(); !current.empty();
512         current = enumerator.Next()) {
513      ++num_files_found;
514      EXPECT_EQ(util::EscapeCacheFileName(resource_id) +
515                base::FilePath::kExtensionSeparator +
516                util::EscapeCacheFileName(md5),
517                current.BaseName().value());
518    }
519    return num_files_found;
520  }
521
522  base::MessageLoopForUI message_loop_;
523  content::TestBrowserThread ui_thread_;
524  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
525  base::ScopedTempDir temp_dir_;
526
527  scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
528  scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
529  scoped_ptr<StrictMock<MockCacheObserver> > mock_cache_observer_;
530
531  FileError expected_error_;
532  int expected_cache_state_;
533  FileCache::CacheSubDirectoryType expected_sub_dir_type_;
534  bool expected_success_;
535  std::string expected_file_extension_;
536};
537
538TEST_F(FileCacheTest, GetCacheFilePath) {
539  // Use alphanumeric characters for resource id.
540  std::string resource_id("pdf:1a2b");
541  std::string md5("abcdef0123456789");
542  TestGetCacheFilePath(resource_id, md5,
543                       resource_id + base::FilePath::kExtensionSeparator + md5);
544
545  // Use non-alphanumeric characters for resource id, including '.' which is an
546  // extension separator, to test that the characters are escaped and unescaped
547  // correctly, and '.' doesn't mess up the filename format and operations.
548  resource_id = "pdf:`~!@#$%^&*()-_=+[{|]}\\;',<.>/?";
549  std::string escaped_resource_id = util::EscapeCacheFileName(resource_id);
550  std::string escaped_md5 = util::EscapeCacheFileName(md5);
551  TestGetCacheFilePath(
552      resource_id, md5, escaped_resource_id +
553      base::FilePath::kExtensionSeparator + escaped_md5);
554}
555
556TEST_F(FileCacheTest, StoreToCacheSimple) {
557  fake_free_disk_space_getter_->set_fake_free_disk_space(
558      test_util::kLotsOfSpace);
559
560  std::string resource_id("pdf:1a2b");
561  std::string md5("abcdef0123456789");
562
563  // Store an existing file.
564  TestStoreToCache(
565      resource_id, md5,
566      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
567      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
568      FileCache::CACHE_TYPE_TMP);
569
570  // Store a non-existent file to the same |resource_id| and |md5|.
571  TestStoreToCache(resource_id, md5, base::FilePath("./non_existent.json"),
572                   FILE_ERROR_FAILED,
573                   test_util::TEST_CACHE_STATE_PRESENT,
574                   FileCache::CACHE_TYPE_TMP);
575
576  // Store a different existing file to the same |resource_id| but different
577  // |md5|.
578  md5 = "new_md5";
579  TestStoreToCache(
580      resource_id, md5,
581      google_apis::test_util::GetTestFilePath("chromeos/gdata/empty_feed.json"),
582      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
583      FileCache::CACHE_TYPE_TMP);
584
585  // Verify that there's only one file with name <resource_id>, i.e. previously
586  // cached file with the different md5 should be deleted.
587  EXPECT_EQ(1U, CountCacheFiles(resource_id, md5));
588}
589
590TEST_F(FileCacheTest, LocallyModifiedSimple) {
591  fake_free_disk_space_getter_->set_fake_free_disk_space(
592      test_util::kLotsOfSpace);
593
594  std::string resource_id("pdf:1a2b");
595  std::string md5("abcdef0123456789");
596
597  const int kDirtyCacheState =
598      test_util::TEST_CACHE_STATE_PRESENT |
599      test_util::TEST_CACHE_STATE_DIRTY |
600      test_util::TEST_CACHE_STATE_PERSISTENT;
601
602  EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(resource_id)).Times(1);
603  TestStoreLocallyModifiedToCache(
604      resource_id, md5,
605      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
606      FILE_ERROR_OK, kDirtyCacheState, FileCache::CACHE_TYPE_PERSISTENT);
607}
608
609TEST_F(FileCacheTest, GetFromCacheSimple) {
610  fake_free_disk_space_getter_->set_fake_free_disk_space(
611      test_util::kLotsOfSpace);
612
613  std::string resource_id("pdf:1a2b");
614  std::string md5("abcdef0123456789");
615  // First store a file to cache.
616  TestStoreToCache(
617      resource_id, md5,
618      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
619      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
620      FileCache::CACHE_TYPE_TMP);
621
622  // Then try to get the existing file from cache.
623  TestGetFileFromCacheByResourceIdAndMd5(
624      resource_id, md5, FILE_ERROR_OK, md5);
625
626  // Get file from cache with same resource id as existing file but different
627  // md5.
628  TestGetFileFromCacheByResourceIdAndMd5(
629      resource_id, "9999", FILE_ERROR_NOT_FOUND, md5);
630
631  // Get file from cache with different resource id from existing file but same
632  // md5.
633  resource_id = "document:1a2b";
634  TestGetFileFromCacheByResourceIdAndMd5(
635      resource_id, md5, FILE_ERROR_NOT_FOUND, md5);
636}
637
638TEST_F(FileCacheTest, RemoveFromCacheSimple) {
639  fake_free_disk_space_getter_->set_fake_free_disk_space(
640      test_util::kLotsOfSpace);
641
642  // Use alphanumeric characters for resource id.
643  std::string resource_id("pdf:1a2b");
644  std::string md5("abcdef0123456789");
645  // First store a file to cache.
646  TestStoreToCache(
647      resource_id, md5,
648      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
649      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
650      FileCache::CACHE_TYPE_TMP);
651
652  // Then try to remove existing file from cache.
653  TestRemoveFromCache(resource_id, FILE_ERROR_OK);
654
655  // Repeat using non-alphanumeric characters for resource id, including '.'
656  // which is an extension separator.
657  resource_id = "pdf:`~!@#$%^&*()-_=+[{|]}\\;',<.>/?";
658  TestStoreToCache(
659      resource_id, md5,
660      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
661      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
662      FileCache::CACHE_TYPE_TMP);
663
664  TestRemoveFromCache(resource_id, FILE_ERROR_OK);
665}
666
667TEST_F(FileCacheTest, PinAndUnpin) {
668  fake_free_disk_space_getter_->set_fake_free_disk_space(
669      test_util::kLotsOfSpace);
670
671  std::string resource_id("pdf:1a2b");
672  std::string md5("abcdef0123456789");
673  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(2);
674  EXPECT_CALL(*mock_cache_observer_, OnCacheUnpinned(resource_id, md5))
675      .Times(1);
676
677  // First store a file to cache.
678  TestStoreToCache(
679      resource_id, md5,
680      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
681      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
682      FileCache::CACHE_TYPE_TMP);
683
684  // Pin the existing file in cache.
685  TestPin(resource_id, md5, FILE_ERROR_OK,
686          test_util::TEST_CACHE_STATE_PRESENT |
687          test_util::TEST_CACHE_STATE_PINNED |
688          test_util::TEST_CACHE_STATE_PERSISTENT,
689          FileCache::CACHE_TYPE_PERSISTENT);
690
691  // Unpin the existing file in cache.
692  TestUnpin(resource_id, md5, FILE_ERROR_OK,
693            test_util::TEST_CACHE_STATE_PRESENT,
694            FileCache::CACHE_TYPE_TMP);
695
696  // Pin back the same existing file in cache.
697  TestPin(resource_id, md5, FILE_ERROR_OK,
698          test_util::TEST_CACHE_STATE_PRESENT |
699          test_util::TEST_CACHE_STATE_PINNED |
700          test_util::TEST_CACHE_STATE_PERSISTENT,
701          FileCache::CACHE_TYPE_PERSISTENT);
702
703  // Pin a non-existent file in cache.
704  resource_id = "document:1a2b";
705  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(1);
706  EXPECT_CALL(*mock_cache_observer_, OnCacheUnpinned(resource_id, md5))
707      .Times(1);
708
709  TestPin(resource_id, md5, FILE_ERROR_OK,
710          test_util::TEST_CACHE_STATE_PINNED,
711          FileCache::CACHE_TYPE_TMP);
712
713  // Unpin the previously pinned non-existent file in cache.
714  TestUnpin(resource_id, md5, FILE_ERROR_OK,
715            test_util::TEST_CACHE_STATE_NONE,
716            FileCache::CACHE_TYPE_TMP);
717
718  // Unpin a file that doesn't exist in cache and is not pinned, i.e. cache
719  // has zero knowledge of the file.
720  resource_id = "not-in-cache:1a2b";
721  // Because unpinning will fail, OnCacheUnpinned() won't be run.
722  EXPECT_CALL(*mock_cache_observer_, OnCacheUnpinned(resource_id, md5))
723      .Times(0);
724
725  TestUnpin(resource_id, md5, FILE_ERROR_NOT_FOUND,
726            test_util::TEST_CACHE_STATE_NONE,
727            FileCache::CACHE_TYPE_TMP /* non-applicable */);
728}
729
730TEST_F(FileCacheTest, StoreToCachePinned) {
731  fake_free_disk_space_getter_->set_fake_free_disk_space(
732      test_util::kLotsOfSpace);
733
734  std::string resource_id("pdf:1a2b");
735  std::string md5("abcdef0123456789");
736  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(1);
737
738  // Pin a non-existent file.
739  TestPin(resource_id, md5, FILE_ERROR_OK,
740          test_util::TEST_CACHE_STATE_PINNED,
741          FileCache::CACHE_TYPE_TMP);
742
743  // Store an existing file to a previously pinned file.
744  TestStoreToCache(
745      resource_id, md5,
746      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
747      FILE_ERROR_OK,
748      test_util::TEST_CACHE_STATE_PRESENT |
749      test_util::TEST_CACHE_STATE_PINNED |
750      test_util::TEST_CACHE_STATE_PERSISTENT,
751      FileCache::CACHE_TYPE_PERSISTENT);
752
753  // Store a non-existent file to a previously pinned and stored file.
754  TestStoreToCache(resource_id, md5, base::FilePath("./non_existent.json"),
755                   FILE_ERROR_FAILED,
756                   test_util::TEST_CACHE_STATE_PRESENT |
757                   test_util::TEST_CACHE_STATE_PINNED |
758                   test_util::TEST_CACHE_STATE_PERSISTENT,
759                   FileCache::CACHE_TYPE_PERSISTENT);
760}
761
762TEST_F(FileCacheTest, GetFromCachePinned) {
763  fake_free_disk_space_getter_->set_fake_free_disk_space(
764      test_util::kLotsOfSpace);
765
766  std::string resource_id("pdf:1a2b");
767  std::string md5("abcdef0123456789");
768  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(1);
769
770  // Pin a non-existent file.
771  TestPin(resource_id, md5, FILE_ERROR_OK,
772          test_util::TEST_CACHE_STATE_PINNED,
773          FileCache::CACHE_TYPE_TMP);
774
775  // Get the non-existent pinned file from cache.
776  TestGetFileFromCacheByResourceIdAndMd5(
777      resource_id, md5, FILE_ERROR_NOT_FOUND, md5);
778
779  // Store an existing file to the previously pinned non-existent file.
780  TestStoreToCache(
781      resource_id, md5,
782      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
783      FILE_ERROR_OK,
784      test_util::TEST_CACHE_STATE_PRESENT |
785      test_util::TEST_CACHE_STATE_PINNED |
786      test_util::TEST_CACHE_STATE_PERSISTENT,
787      FileCache::CACHE_TYPE_PERSISTENT);
788
789  // Get the previously pinned and stored file from cache.
790  TestGetFileFromCacheByResourceIdAndMd5(
791      resource_id, md5, FILE_ERROR_OK, md5);
792}
793
794TEST_F(FileCacheTest, RemoveFromCachePinned) {
795  fake_free_disk_space_getter_->set_fake_free_disk_space(
796      test_util::kLotsOfSpace);
797
798  // Use alphanumeric characters for resource_id.
799  std::string resource_id("pdf:1a2b");
800  std::string md5("abcdef0123456789");
801  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(1);
802
803  // Store a file to cache, and pin it.
804  TestStoreToCache(
805      resource_id, md5,
806      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
807      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
808      FileCache::CACHE_TYPE_TMP);
809  TestPin(resource_id, md5, FILE_ERROR_OK,
810          test_util::TEST_CACHE_STATE_PRESENT |
811          test_util::TEST_CACHE_STATE_PINNED |
812          test_util::TEST_CACHE_STATE_PERSISTENT,
813          FileCache::CACHE_TYPE_PERSISTENT);
814
815  // Remove |resource_id| from cache.
816  TestRemoveFromCache(resource_id, FILE_ERROR_OK);
817
818  // Repeat using non-alphanumeric characters for resource id, including '.'
819  // which is an extension separator.
820  resource_id = "pdf:`~!@#$%^&*()-_=+[{|]}\\;',<.>/?";
821  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(1);
822
823  TestStoreToCache(
824      resource_id, md5,
825      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
826      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
827      FileCache::CACHE_TYPE_TMP);
828  TestPin(resource_id, md5, FILE_ERROR_OK,
829          test_util::TEST_CACHE_STATE_PRESENT |
830          test_util::TEST_CACHE_STATE_PINNED |
831          test_util::TEST_CACHE_STATE_PERSISTENT,
832          FileCache::CACHE_TYPE_PERSISTENT);
833
834  TestRemoveFromCache(resource_id, FILE_ERROR_OK);
835}
836
837TEST_F(FileCacheTest, DirtyCacheSimple) {
838  fake_free_disk_space_getter_->set_fake_free_disk_space(
839      test_util::kLotsOfSpace);
840
841  std::string resource_id("pdf:1a2b");
842  std::string md5("abcdef0123456789");
843  EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(resource_id)).Times(1);
844
845  // First store a file to cache.
846  TestStoreToCache(
847      resource_id, md5,
848      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
849      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
850      FileCache::CACHE_TYPE_TMP);
851
852  // Mark the file dirty.
853  TestMarkDirty(resource_id, md5, FILE_ERROR_OK,
854                test_util::TEST_CACHE_STATE_PRESENT |
855                test_util::TEST_CACHE_STATE_DIRTY |
856                test_util::TEST_CACHE_STATE_PERSISTENT,
857                FileCache::CACHE_TYPE_PERSISTENT);
858
859  // Commit the file dirty.
860  TestCommitDirty(resource_id, md5, FILE_ERROR_OK,
861                  test_util::TEST_CACHE_STATE_PRESENT |
862                  test_util::TEST_CACHE_STATE_DIRTY |
863                  test_util::TEST_CACHE_STATE_PERSISTENT,
864                  FileCache::CACHE_TYPE_PERSISTENT);
865
866  // Clear dirty state of the file.
867  TestClearDirty(resource_id, md5, FILE_ERROR_OK,
868                 test_util::TEST_CACHE_STATE_PRESENT,
869                 FileCache::CACHE_TYPE_TMP);
870}
871
872TEST_F(FileCacheTest, DirtyCachePinned) {
873  fake_free_disk_space_getter_->set_fake_free_disk_space(
874      test_util::kLotsOfSpace);
875
876  std::string resource_id("pdf:1a2b");
877  std::string md5("abcdef0123456789");
878  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(1);
879  EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(resource_id)).Times(1);
880
881  // First store a file to cache and pin it.
882  TestStoreToCache(
883      resource_id, md5,
884      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
885      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
886      FileCache::CACHE_TYPE_TMP);
887  TestPin(resource_id, md5, FILE_ERROR_OK,
888          test_util::TEST_CACHE_STATE_PRESENT |
889          test_util::TEST_CACHE_STATE_PINNED |
890          test_util::TEST_CACHE_STATE_PERSISTENT,
891          FileCache::CACHE_TYPE_PERSISTENT);
892
893  // Mark the file dirty.
894  TestMarkDirty(resource_id, md5, FILE_ERROR_OK,
895                test_util::TEST_CACHE_STATE_PRESENT |
896                test_util::TEST_CACHE_STATE_DIRTY |
897                test_util::TEST_CACHE_STATE_PINNED |
898                test_util::TEST_CACHE_STATE_PERSISTENT,
899                FileCache::CACHE_TYPE_PERSISTENT);
900
901  // Commit the file dirty.
902  TestCommitDirty(resource_id, md5, FILE_ERROR_OK,
903                  test_util::TEST_CACHE_STATE_PRESENT |
904                  test_util::TEST_CACHE_STATE_DIRTY |
905                  test_util::TEST_CACHE_STATE_PINNED |
906                  test_util::TEST_CACHE_STATE_PERSISTENT,
907                  FileCache::CACHE_TYPE_PERSISTENT);
908
909  // Clear dirty state of the file.
910  TestClearDirty(resource_id, md5, FILE_ERROR_OK,
911                 test_util::TEST_CACHE_STATE_PRESENT |
912                 test_util::TEST_CACHE_STATE_PINNED |
913                 test_util::TEST_CACHE_STATE_PERSISTENT,
914                 FileCache::CACHE_TYPE_PERSISTENT);
915}
916
917// Test is disabled because it is flaky (http://crbug.com/134146)
918TEST_F(FileCacheTest, PinAndUnpinDirtyCache) {
919  fake_free_disk_space_getter_->set_fake_free_disk_space(
920      test_util::kLotsOfSpace);
921
922  std::string resource_id("pdf:1a2b");
923  std::string md5("abcdef0123456789");
924  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(1);
925  EXPECT_CALL(*mock_cache_observer_, OnCacheUnpinned(resource_id, md5))
926      .Times(1);
927
928  // First store a file to cache and mark it as dirty.
929  TestStoreToCache(
930      resource_id, md5,
931      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
932      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
933      FileCache::CACHE_TYPE_TMP);
934  TestMarkDirty(resource_id, md5, FILE_ERROR_OK,
935                test_util::TEST_CACHE_STATE_PRESENT |
936                test_util::TEST_CACHE_STATE_DIRTY |
937                test_util::TEST_CACHE_STATE_PERSISTENT,
938                FileCache::CACHE_TYPE_PERSISTENT);
939
940  // Verifies dirty file exists.
941  base::FilePath dirty_path;
942  FileError error = FILE_ERROR_FAILED;
943  cache_->GetFileOnUIThread(
944      resource_id, md5,
945      google_apis::test_util::CreateCopyResultCallback(&error, &dirty_path));
946  google_apis::test_util::RunBlockingPoolTask();
947  EXPECT_EQ(FILE_ERROR_OK, error);
948  EXPECT_TRUE(file_util::PathExists(dirty_path));
949
950  // Pin the dirty file.
951  TestPin(resource_id, md5, FILE_ERROR_OK,
952          test_util::TEST_CACHE_STATE_PRESENT |
953          test_util::TEST_CACHE_STATE_DIRTY |
954          test_util::TEST_CACHE_STATE_PINNED |
955          test_util::TEST_CACHE_STATE_PERSISTENT,
956          FileCache::CACHE_TYPE_PERSISTENT);
957
958  // Verify dirty file still exist at the same pathname.
959  EXPECT_TRUE(file_util::PathExists(dirty_path));
960
961  // Unpin the dirty file.
962  TestUnpin(resource_id, md5, FILE_ERROR_OK,
963            test_util::TEST_CACHE_STATE_PRESENT |
964            test_util::TEST_CACHE_STATE_DIRTY |
965            test_util::TEST_CACHE_STATE_PERSISTENT,
966            FileCache::CACHE_TYPE_PERSISTENT);
967
968  // Verify dirty file still exist at the same pathname.
969  EXPECT_TRUE(file_util::PathExists(dirty_path));
970}
971
972TEST_F(FileCacheTest, DirtyCacheRepetitive) {
973  fake_free_disk_space_getter_->set_fake_free_disk_space(
974      test_util::kLotsOfSpace);
975
976  std::string resource_id("pdf:1a2b");
977  std::string md5("abcdef0123456789");
978  EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(resource_id)).Times(3);
979
980  // First store a file to cache.
981  TestStoreToCache(
982      resource_id, md5,
983      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
984      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
985      FileCache::CACHE_TYPE_TMP);
986
987  // Mark the file dirty.
988  TestMarkDirty(resource_id, md5, FILE_ERROR_OK,
989                test_util::TEST_CACHE_STATE_PRESENT |
990                test_util::TEST_CACHE_STATE_DIRTY |
991                test_util::TEST_CACHE_STATE_PERSISTENT,
992                FileCache::CACHE_TYPE_PERSISTENT);
993
994  // Again, mark the file dirty.  Nothing should change.
995  TestMarkDirty(resource_id, md5, FILE_ERROR_OK,
996                test_util::TEST_CACHE_STATE_PRESENT |
997                test_util::TEST_CACHE_STATE_DIRTY |
998                test_util::TEST_CACHE_STATE_PERSISTENT,
999                FileCache::CACHE_TYPE_PERSISTENT);
1000
1001  // Commit the file dirty.
1002  TestCommitDirty(resource_id, md5, FILE_ERROR_OK,
1003                  test_util::TEST_CACHE_STATE_PRESENT |
1004                  test_util::TEST_CACHE_STATE_DIRTY |
1005                  test_util::TEST_CACHE_STATE_PERSISTENT,
1006                  FileCache::CACHE_TYPE_PERSISTENT);
1007
1008  // Again, commit the file dirty.  Nothing should change.
1009  TestCommitDirty(resource_id, md5, FILE_ERROR_OK,
1010                  test_util::TEST_CACHE_STATE_PRESENT |
1011                  test_util::TEST_CACHE_STATE_DIRTY |
1012                  test_util::TEST_CACHE_STATE_PERSISTENT,
1013                  FileCache::CACHE_TYPE_PERSISTENT);
1014
1015  // Mark the file dirty again after it's being committed.
1016  TestMarkDirty(resource_id, md5, FILE_ERROR_OK,
1017                test_util::TEST_CACHE_STATE_PRESENT |
1018                test_util::TEST_CACHE_STATE_DIRTY |
1019                test_util::TEST_CACHE_STATE_PERSISTENT,
1020                FileCache::CACHE_TYPE_PERSISTENT);
1021
1022  // Commit the file dirty.
1023  TestCommitDirty(resource_id, md5, FILE_ERROR_OK,
1024                  test_util::TEST_CACHE_STATE_PRESENT |
1025                  test_util::TEST_CACHE_STATE_DIRTY |
1026                  test_util::TEST_CACHE_STATE_PERSISTENT,
1027                  FileCache::CACHE_TYPE_PERSISTENT);
1028
1029  // Clear dirty state of the file.
1030  TestClearDirty(resource_id, md5, FILE_ERROR_OK,
1031                 test_util::TEST_CACHE_STATE_PRESENT,
1032                 FileCache::CACHE_TYPE_TMP);
1033
1034  // Again, clear dirty state of the file, which is no longer dirty.
1035  TestClearDirty(resource_id, md5, FILE_ERROR_INVALID_OPERATION,
1036                 test_util::TEST_CACHE_STATE_PRESENT,
1037                 FileCache::CACHE_TYPE_TMP);
1038}
1039
1040TEST_F(FileCacheTest, DirtyCacheInvalid) {
1041  fake_free_disk_space_getter_->set_fake_free_disk_space(
1042      test_util::kLotsOfSpace);
1043
1044  std::string resource_id("pdf:1a2b");
1045  std::string md5("abcdef0123456789");
1046
1047  // Mark a non-existent file dirty.
1048  TestMarkDirty(resource_id, md5, FILE_ERROR_NOT_FOUND,
1049                test_util::TEST_CACHE_STATE_NONE,
1050                FileCache::CACHE_TYPE_TMP);
1051
1052  // Clear dirty state of a non-existent file.
1053  TestClearDirty(resource_id, md5, FILE_ERROR_NOT_FOUND,
1054                 test_util::TEST_CACHE_STATE_NONE,
1055                 FileCache::CACHE_TYPE_TMP);
1056
1057  // Store a file to cache.
1058  TestStoreToCache(
1059      resource_id, md5,
1060      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
1061      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
1062      FileCache::CACHE_TYPE_TMP);
1063
1064  // Clear dirty state of a non-dirty existing file.
1065  TestClearDirty(resource_id, md5, FILE_ERROR_INVALID_OPERATION,
1066                 test_util::TEST_CACHE_STATE_PRESENT,
1067                 FileCache::CACHE_TYPE_TMP);
1068
1069  // Mark an existing file dirty, then store a new file to the same resource id
1070  // but different md5, which should fail.
1071  TestMarkDirty(resource_id, md5, FILE_ERROR_OK,
1072                test_util::TEST_CACHE_STATE_PRESENT |
1073                test_util::TEST_CACHE_STATE_DIRTY |
1074                test_util::TEST_CACHE_STATE_PERSISTENT,
1075                FileCache::CACHE_TYPE_PERSISTENT);
1076  md5 = "new_md5";
1077  TestStoreToCache(
1078      resource_id, md5,
1079      google_apis::test_util::GetTestFilePath(
1080          "chromeos/gdata/empty_feed.json"),
1081      FILE_ERROR_IN_USE,
1082      test_util::TEST_CACHE_STATE_PRESENT |
1083      test_util::TEST_CACHE_STATE_DIRTY |
1084      test_util::TEST_CACHE_STATE_PERSISTENT,
1085      FileCache::CACHE_TYPE_PERSISTENT);
1086}
1087
1088TEST_F(FileCacheTest, RemoveFromDirtyCache) {
1089  fake_free_disk_space_getter_->set_fake_free_disk_space(
1090      test_util::kLotsOfSpace);
1091
1092  std::string resource_id("pdf:1a2b");
1093  std::string md5("abcdef0123456789");
1094  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(1);
1095  EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(resource_id)).Times(1);
1096
1097  // Store a file to cache, pin it, mark it dirty and commit it.
1098  TestStoreToCache(
1099      resource_id, md5,
1100      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
1101      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
1102      FileCache::CACHE_TYPE_TMP);
1103  TestPin(resource_id, md5, FILE_ERROR_OK,
1104          test_util::TEST_CACHE_STATE_PRESENT |
1105          test_util::TEST_CACHE_STATE_PINNED |
1106          test_util::TEST_CACHE_STATE_PERSISTENT,
1107          FileCache::CACHE_TYPE_PERSISTENT);
1108  TestMarkDirty(resource_id, md5, FILE_ERROR_OK,
1109                test_util::TEST_CACHE_STATE_PRESENT |
1110                test_util::TEST_CACHE_STATE_PINNED |
1111                test_util::TEST_CACHE_STATE_DIRTY |
1112                test_util::TEST_CACHE_STATE_PERSISTENT,
1113                FileCache::CACHE_TYPE_PERSISTENT);
1114  TestCommitDirty(resource_id, md5, FILE_ERROR_OK,
1115                  test_util::TEST_CACHE_STATE_PRESENT |
1116                  test_util::TEST_CACHE_STATE_PINNED |
1117                  test_util::TEST_CACHE_STATE_DIRTY |
1118                  test_util::TEST_CACHE_STATE_PERSISTENT,
1119                  FileCache::CACHE_TYPE_PERSISTENT);
1120
1121  // Try to remove the file.  Since file is dirty, it should not be removed.
1122  TestRemoveFromCache(resource_id, FILE_ERROR_OK);
1123}
1124
1125TEST_F(FileCacheTest, MountUnmount) {
1126  fake_free_disk_space_getter_->set_fake_free_disk_space(
1127      test_util::kLotsOfSpace);
1128
1129  std::string resource_id("pdf:1a2b");
1130  std::string md5("abcdef0123456789");
1131
1132  // First store a file to cache in the tmp subdir.
1133  TestStoreToCache(
1134      resource_id, md5,
1135      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
1136      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
1137      FileCache::CACHE_TYPE_TMP);
1138
1139  // Mark the file mounted.
1140  TestMarkAsMounted(resource_id,
1141                    md5,
1142                    FILE_ERROR_OK,
1143                    test_util::TEST_CACHE_STATE_PRESENT |
1144                    test_util::TEST_CACHE_STATE_MOUNTED |
1145                    test_util::TEST_CACHE_STATE_PERSISTENT,
1146                    FileCache::CACHE_TYPE_PERSISTENT);
1147  EXPECT_TRUE(CacheEntryExists(resource_id, md5));
1148
1149  // Clear mounted state of the file.
1150  base::FilePath file_path;
1151  FileError error = FILE_ERROR_FAILED;
1152  cache_->GetFileOnUIThread(
1153      resource_id, md5,
1154      google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
1155  google_apis::test_util::RunBlockingPoolTask();
1156  EXPECT_EQ(FILE_ERROR_OK, error);
1157
1158  TestMarkAsUnmounted(resource_id, md5, file_path,
1159                      FILE_ERROR_OK,
1160                      test_util::TEST_CACHE_STATE_PRESENT,
1161                      FileCache::CACHE_TYPE_TMP);
1162  EXPECT_TRUE(CacheEntryExists(resource_id, md5));
1163
1164  // Try to remove the file.
1165  TestRemoveFromCache(resource_id, FILE_ERROR_OK);
1166}
1167
1168TEST_F(FileCacheTest, Iterate) {
1169  fake_free_disk_space_getter_->set_fake_free_disk_space(
1170      test_util::kLotsOfSpace);
1171  const std::vector<test_util::TestCacheResource> cache_resources(
1172      test_util::GetDefaultTestCacheResources());
1173  // Set mock expectations.
1174  for (size_t i = 0; i < cache_resources.size(); ++i) {
1175    if (cache_resources[i].is_pinned) {
1176      EXPECT_CALL(*mock_cache_observer_,
1177                  OnCachePinned(cache_resources[i].resource_id,
1178                                cache_resources[i].md5)).Times(1);
1179    }
1180    if (cache_resources[i].is_dirty) {
1181      EXPECT_CALL(*mock_cache_observer_,
1182                  OnCacheCommitted(cache_resources[i].resource_id)).Times(1);
1183    }
1184  }
1185  ASSERT_TRUE(test_util::PrepareTestCacheResources(
1186      cache_.get(),
1187      cache_resources));
1188
1189  std::vector<std::string> resource_ids;
1190  std::vector<FileCacheEntry> cache_entries;
1191  bool completed = false;
1192  cache_->IterateOnUIThread(
1193      base::Bind(&OnIterate, &resource_ids, &cache_entries),
1194      base::Bind(&OnIterateCompleted, &completed));
1195  google_apis::test_util::RunBlockingPoolTask();
1196
1197  ASSERT_TRUE(completed);
1198
1199  sort(resource_ids.begin(), resource_ids.end());
1200  ASSERT_EQ(6U, resource_ids.size());
1201  EXPECT_EQ("dirty:existing", resource_ids[0]);
1202  EXPECT_EQ("dirty_and_pinned:existing", resource_ids[1]);
1203  EXPECT_EQ("pinned:existing", resource_ids[2]);
1204  EXPECT_EQ("pinned:non-existent", resource_ids[3]);
1205  EXPECT_EQ("tmp:`~!@#$%^&*()-_=+[{|]}\\;',<.>/?", resource_ids[4]);
1206  EXPECT_EQ("tmp:resource_id", resource_ids[5]);
1207
1208  ASSERT_EQ(6U, cache_entries.size());
1209}
1210
1211
1212TEST_F(FileCacheTest, ClearAll) {
1213  fake_free_disk_space_getter_->set_fake_free_disk_space(
1214      test_util::kLotsOfSpace);
1215
1216  std::string resource_id("pdf:1a2b");
1217  std::string md5("abcdef0123456789");
1218
1219  // Store an existing file.
1220  TestStoreToCache(
1221      resource_id, md5,
1222      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
1223      FILE_ERROR_OK, test_util::TEST_CACHE_STATE_PRESENT,
1224      FileCache::CACHE_TYPE_TMP);
1225
1226  // Verify that there's only one cached file.
1227  EXPECT_EQ(1U, CountCacheFiles(resource_id, md5));
1228
1229  // Clear cache.
1230  bool success = false;
1231  cache_->ClearAllOnUIThread(
1232      google_apis::test_util::CreateCopyResultCallback(&success));
1233  google_apis::test_util::RunBlockingPoolTask();
1234  EXPECT_TRUE(success);
1235
1236  // Verify that all the cache is removed.
1237  expected_error_ = FILE_ERROR_OK;
1238  VerifyRemoveFromCache(FILE_ERROR_OK, resource_id, md5);
1239  EXPECT_EQ(0U, CountCacheFiles(resource_id, md5));
1240}
1241
1242TEST_F(FileCacheTest, StoreToCacheNoSpace) {
1243  fake_free_disk_space_getter_->set_fake_free_disk_space(0);
1244
1245  std::string resource_id("pdf:1a2b");
1246  std::string md5("abcdef0123456789");
1247
1248  // Try to store an existing file.
1249  TestStoreToCache(
1250      resource_id, md5,
1251      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
1252      FILE_ERROR_NO_SPACE,
1253      test_util::TEST_CACHE_STATE_NONE,
1254      FileCache::CACHE_TYPE_TMP);
1255
1256  // Verify that there's no files added.
1257  EXPECT_EQ(0U, CountCacheFiles(resource_id, md5));
1258}
1259
1260// Don't use TEST_F, as we don't want SetUp() and TearDown() for this test.
1261TEST(FileCacheExtraTest, InitializationFailure) {
1262  base::MessageLoopForUI message_loop;
1263  content::TestBrowserThread ui_thread(content::BrowserThread::UI,
1264                                       &message_loop);
1265
1266  scoped_refptr<base::SequencedWorkerPool> pool =
1267      content::BrowserThread::GetBlockingPool();
1268
1269  // Set the cache root to a non existent path, so the initialization fails.
1270  scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache(new FileCache(
1271      base::FilePath::FromUTF8Unsafe("/somewhere/nonexistent/blah/blah"),
1272      pool->GetSequencedTaskRunner(pool->GetSequenceToken()),
1273      NULL /* free_disk_space_getter */));
1274
1275  bool success = true;
1276  cache->RequestInitialize(
1277      google_apis::test_util::CreateCopyResultCallback(&success));
1278  google_apis::test_util::RunBlockingPoolTask();
1279  EXPECT_FALSE(success);
1280}
1281
1282TEST_F(FileCacheTest, UpdatePinnedCache) {
1283  fake_free_disk_space_getter_->set_fake_free_disk_space(
1284      test_util::kLotsOfSpace);
1285
1286  std::string resource_id("pdf:1a2b");
1287  std::string md5("abcdef0123456789");
1288  std::string md5_modified("aaaaaa0000000000");
1289
1290  // Store an existing file.
1291  TestStoreToCache(
1292      resource_id, md5,
1293      google_apis::test_util::GetTestFilePath("chromeos/gdata/root_feed.json"),
1294      FILE_ERROR_OK,
1295      test_util::TEST_CACHE_STATE_PRESENT,
1296      FileCache::CACHE_TYPE_TMP);
1297
1298  // Pin the file.
1299  EXPECT_CALL(*mock_cache_observer_, OnCachePinned(resource_id, md5)).Times(1);
1300  TestPin(
1301      resource_id, md5,
1302      FILE_ERROR_OK,
1303      test_util::TEST_CACHE_STATE_PRESENT |
1304      test_util::TEST_CACHE_STATE_PINNED |
1305      test_util::TEST_CACHE_STATE_PERSISTENT,
1306      FileCache::CACHE_TYPE_PERSISTENT);
1307
1308  // Store the file with a modified content and md5. It should stay pinned.
1309  TestStoreToCache(
1310      resource_id, md5_modified,
1311      google_apis::test_util::GetTestFilePath("chromeos/gdata/empty_feed.json"),
1312      FILE_ERROR_OK,
1313      test_util::TEST_CACHE_STATE_PRESENT |
1314      test_util::TEST_CACHE_STATE_PINNED |
1315      test_util::TEST_CACHE_STATE_PERSISTENT,
1316      FileCache::CACHE_TYPE_PERSISTENT);
1317}
1318
1319}  // namespace internal
1320}  // namespace drive
1321