• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GenerateId(int i)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:
SetUp()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 
TearDown()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.
CheckEntrySequenceNumber(int id,int sequence_number)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.
CheckRangeEnqueuedInOrder(int start,int end)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 
TEST_F(SavedFilesServiceUnitTest,RetainTwoFilesTest)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 
TEST_F(SavedFilesServiceUnitTest,NoRetainEntriesPermissionTest)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 
TEST_F(SavedFilesServiceUnitTest,EvictionTest)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 
TEST_F(SavedFilesServiceUnitTest,SequenceNumberCompactionTest)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