Home | History | Annotate | Download | only in apps
      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 <algorithm>
      6 
      7 #include "apps/saved_files_service.h"
      8 #include "base/files/file_path.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "base/test/values_test_util.h"
     11 #include "base/values.h"
     12 #include "chrome/browser/extensions/test_extension_environment.h"
     13 #include "chrome/test/base/testing_profile.h"
     14 #include "extensions/browser/extension_prefs.h"
     15 #include "extensions/browser/extension_system.h"
     16 #include "extensions/common/extension.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 #if !defined(OS_ANDROID)
     20 
     21 #define TRACE_CALL(expression) \
     22   do {                         \
     23     SCOPED_TRACE(#expression); \
     24     expression;                \
     25   } while (0)
     26 
     27 using apps::SavedFileEntry;
     28 using apps::SavedFilesService;
     29 
     30 namespace {
     31 
     32 std::string GenerateId(int i) {
     33   return base::IntToString(i) + ":filename.ext";
     34 }
     35 
     36 }  // namespace
     37 
     38 class SavedFilesServiceUnitTest : public testing::Test {
     39  protected:
     40   virtual void SetUp() OVERRIDE {
     41     testing::Test::SetUp();
     42     extension_ = env_.MakeExtension(*base::test::ParseJson(
     43         "{"
     44         "  \"app\": {"
     45         "    \"background\": {"
     46         "      \"scripts\": [\"background.js\"]"
     47         "    }"
     48         "  },"
     49         "  \"permissions\": ["
     50         "    {\"fileSystem\": [\"retainEntries\"]}"
     51         "  ]"
     52         "}"));
     53     service_ = SavedFilesService::Get(env_.profile());
     54     path_ = base::FilePath(FILE_PATH_LITERAL("filename.ext"));
     55   }
     56 
     57   virtual void TearDown() OVERRIDE {
     58     SavedFilesService::ClearMaxSequenceNumberForTest();
     59     SavedFilesService::ClearLruSizeForTest();
     60     testing::Test::TearDown();
     61   }
     62 
     63   // Check that a registered file entry has the correct value.
     64   void CheckEntrySequenceNumber(int id, int sequence_number) {
     65     std::string id_string = GenerateId(id);
     66     SCOPED_TRACE(id_string);
     67     EXPECT_TRUE(service_->IsRegistered(extension_->id(), id_string));
     68     const SavedFileEntry* entry =
     69         service_->GetFileEntry(extension_->id(), id_string);
     70     ASSERT_TRUE(entry);
     71     EXPECT_EQ(id_string, entry->id);
     72     EXPECT_EQ(path_, entry->path);
     73     EXPECT_TRUE(entry->is_directory);
     74     EXPECT_EQ(sequence_number, entry->sequence_number);
     75   }
     76 
     77   // Check that a range of registered file entries have the correct values.
     78   void CheckRangeEnqueuedInOrder(int start, int end) {
     79     SavedFileEntry entry;
     80     for (int i = start; i < end; i++) {
     81       CheckEntrySequenceNumber(i, i + 1);
     82     }
     83   }
     84 
     85   extensions::TestExtensionEnvironment env_;
     86   const extensions::Extension* extension_;
     87   SavedFilesService* service_;
     88   base::FilePath path_;
     89 };
     90 
     91 TEST_F(SavedFilesServiceUnitTest, RetainTwoFilesTest) {
     92   service_->RegisterFileEntry(extension_->id(), GenerateId(1), path_, true);
     93   service_->RegisterFileEntry(extension_->id(), GenerateId(2), path_, true);
     94   service_->RegisterFileEntry(extension_->id(), GenerateId(3), path_, true);
     95 
     96   // Test that no entry has a sequence number.
     97   TRACE_CALL(CheckEntrySequenceNumber(1, 0));
     98   TRACE_CALL(CheckEntrySequenceNumber(2, 0));
     99   TRACE_CALL(CheckEntrySequenceNumber(3, 0));
    100 
    101   // Test that only entry #1 has a sequence number.
    102   service_->EnqueueFileEntry(extension_->id(), GenerateId(1));
    103   TRACE_CALL(CheckEntrySequenceNumber(1, 1));
    104   TRACE_CALL(CheckEntrySequenceNumber(2, 0));
    105 
    106   // Test that entry #1 has not changed sequence number because it is the most
    107   // recently enqueued entry.
    108   service_->EnqueueFileEntry(extension_->id(), GenerateId(1));
    109   TRACE_CALL(CheckEntrySequenceNumber(1, 1));
    110   TRACE_CALL(CheckEntrySequenceNumber(2, 0));
    111 
    112   // Test that entry #1 is unchanged and entry #2 has been assigned the next
    113   // sequence number.
    114   service_->EnqueueFileEntry(extension_->id(), GenerateId(2));
    115   TRACE_CALL(CheckEntrySequenceNumber(1, 1));
    116   TRACE_CALL(CheckEntrySequenceNumber(2, 2));
    117 
    118   // Test that both entries #1 and #2 are unchanged because #2 is the most
    119   // recently enqueued entry.
    120   service_->EnqueueFileEntry(extension_->id(), GenerateId(2));
    121   TRACE_CALL(CheckEntrySequenceNumber(1, 1));
    122   TRACE_CALL(CheckEntrySequenceNumber(2, 2));
    123 
    124   // Test that entry #1 has been assigned the next sequence number.
    125   service_->EnqueueFileEntry(extension_->id(), GenerateId(1));
    126   TRACE_CALL(CheckEntrySequenceNumber(1, 3));
    127   TRACE_CALL(CheckEntrySequenceNumber(2, 2));
    128   TRACE_CALL(CheckEntrySequenceNumber(3, 0));
    129 
    130   EXPECT_FALSE(service_->IsRegistered(extension_->id(), "another id"));
    131   SavedFileEntry entry;
    132   EXPECT_FALSE(service_->GetFileEntry(extension_->id(), "another id"));
    133 
    134   // ClearQueueIfNoRetainPermission should be a no-op because the app has the
    135   // fileSystem.retainEntries permission.
    136   service_->ClearQueueIfNoRetainPermission(extension_);
    137   TRACE_CALL(CheckEntrySequenceNumber(1, 3));
    138   TRACE_CALL(CheckEntrySequenceNumber(2, 2));
    139   TRACE_CALL(CheckEntrySequenceNumber(3, 0));
    140 
    141   // Test that after a clear, retained file entries are unchanged, but file
    142   // entries that have been registered but not retained are no longer
    143   // registered.
    144   service_->Clear(extension_->id());
    145   TRACE_CALL(CheckEntrySequenceNumber(1, 3));
    146   TRACE_CALL(CheckEntrySequenceNumber(2, 2));
    147   EXPECT_FALSE(service_->IsRegistered(extension_->id(), GenerateId(3)));
    148 }
    149 
    150 TEST_F(SavedFilesServiceUnitTest, NoRetainEntriesPermissionTest) {
    151   extension_ = env_.MakeExtension(*base::test::ParseJson(
    152       "{\"app\": {\"background\": {\"scripts\": [\"background.js\"]}},"
    153       "\"permissions\": [\"fileSystem\"]}"));
    154   service_->RegisterFileEntry(extension_->id(), GenerateId(1), path_, true);
    155   TRACE_CALL(CheckEntrySequenceNumber(1, 0));
    156   SavedFileEntry entry;
    157   service_->EnqueueFileEntry(extension_->id(), GenerateId(1));
    158   TRACE_CALL(CheckEntrySequenceNumber(1, 1));
    159   EXPECT_FALSE(service_->IsRegistered(extension_->id(), "another id"));
    160   EXPECT_FALSE(service_->GetFileEntry(extension_->id(), "another id"));
    161 
    162   // ClearQueueIfNoRetainPermission should clear the queue, since the app does
    163   // not have the "retainEntries" permission.
    164   service_->ClearQueueIfNoRetainPermission(extension_);
    165   std::vector<SavedFileEntry> entries =
    166       service_->GetAllFileEntries(extension_->id());
    167   EXPECT_TRUE(entries.empty());
    168 }
    169 
    170 TEST_F(SavedFilesServiceUnitTest, EvictionTest) {
    171   SavedFilesService::SetLruSizeForTest(10);
    172   for (int i = 0; i < 10; i++) {
    173     service_->RegisterFileEntry(extension_->id(), GenerateId(i), path_, true);
    174     service_->EnqueueFileEntry(extension_->id(), GenerateId(i));
    175   }
    176   service_->RegisterFileEntry(extension_->id(), GenerateId(10), path_, true);
    177 
    178   // Expect that entries 0 to 9 are in the queue, but 10 is not.
    179   TRACE_CALL(CheckRangeEnqueuedInOrder(0, 10));
    180   TRACE_CALL(CheckEntrySequenceNumber(10, 0));
    181   service_->EnqueueFileEntry(extension_->id(), GenerateId(10));
    182 
    183   // Expect that entries 1 to 10 are in the queue, but entry 0 is not.
    184   TRACE_CALL(CheckEntrySequenceNumber(0, 0));
    185   TRACE_CALL(CheckRangeEnqueuedInOrder(1, 11));
    186 
    187   // Check that retained entries are unchanged after a clear.
    188   service_->Clear(extension_->id());
    189   SavedFileEntry entry;
    190   EXPECT_FALSE(service_->GetFileEntry(extension_->id(), GenerateId(0)));
    191   TRACE_CALL(CheckRangeEnqueuedInOrder(1, 11));
    192 
    193   // Expect that entry 2 is now at the back of the queue, and no further entries
    194   // have been evicted.
    195   service_->EnqueueFileEntry(extension_->id(), GenerateId(2));
    196   TRACE_CALL(CheckEntrySequenceNumber(2, 12));
    197   TRACE_CALL(CheckRangeEnqueuedInOrder(1, 1));
    198   TRACE_CALL(CheckRangeEnqueuedInOrder(3, 11));
    199 
    200   // Check that retained entries are unchanged after a clear.
    201   service_->Clear(extension_->id());
    202   TRACE_CALL(CheckEntrySequenceNumber(2, 12));
    203   TRACE_CALL(CheckRangeEnqueuedInOrder(1, 1));
    204   TRACE_CALL(CheckRangeEnqueuedInOrder(3, 11));
    205 }
    206 
    207 TEST_F(SavedFilesServiceUnitTest, SequenceNumberCompactionTest) {
    208   SavedFilesService::SetMaxSequenceNumberForTest(8);
    209   SavedFilesService::SetLruSizeForTest(8);
    210   for (int i = 0; i < 4; i++) {
    211     service_->RegisterFileEntry(extension_->id(), GenerateId(i), path_, true);
    212     service_->EnqueueFileEntry(extension_->id(), GenerateId(i));
    213   }
    214   service_->EnqueueFileEntry(extension_->id(), GenerateId(2));
    215   service_->EnqueueFileEntry(extension_->id(), GenerateId(3));
    216   service_->EnqueueFileEntry(extension_->id(), GenerateId(2));
    217 
    218   // The sequence numbers should be sparse, as they have not gone over the
    219   // limit.
    220   TRACE_CALL(CheckEntrySequenceNumber(0, 1));
    221   TRACE_CALL(CheckEntrySequenceNumber(1, 2));
    222   TRACE_CALL(CheckEntrySequenceNumber(2, 7));
    223   TRACE_CALL(CheckEntrySequenceNumber(3, 6));
    224   service_->Clear(extension_->id());
    225   TRACE_CALL(CheckEntrySequenceNumber(0, 1));
    226   TRACE_CALL(CheckEntrySequenceNumber(1, 2));
    227   TRACE_CALL(CheckEntrySequenceNumber(2, 7));
    228   TRACE_CALL(CheckEntrySequenceNumber(3, 6));
    229 
    230   // This should push the sequence number to the limit of 8, and trigger a
    231   // sequence number compaction. Expect that the sequence numbers are
    232   // contiguous from 1 to 4.
    233   service_->EnqueueFileEntry(extension_->id(), GenerateId(3));
    234   TRACE_CALL(CheckRangeEnqueuedInOrder(0, 4));
    235   service_->Clear(extension_->id());
    236   TRACE_CALL(CheckRangeEnqueuedInOrder(0, 4));
    237 }
    238 #endif
    239