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