OLD | NEW |
| (Empty) |
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 "base/files/file_enumerator.h" | |
6 #include "base/files/file_util.h" | |
7 #include "net/disk_cache/blockfile/block_files.h" | |
8 #include "net/disk_cache/disk_cache.h" | |
9 #include "net/disk_cache/disk_cache_test_base.h" | |
10 #include "net/disk_cache/disk_cache_test_util.h" | |
11 #include "testing/gtest/include/gtest/gtest.h" | |
12 | |
13 using base::Time; | |
14 | |
15 namespace { | |
16 | |
17 // Returns the number of files in this folder. | |
18 int NumberOfFiles(const base::FilePath& path) { | |
19 base::FileEnumerator iter(path, false, base::FileEnumerator::FILES); | |
20 int count = 0; | |
21 for (base::FilePath file = iter.Next(); !file.value().empty(); | |
22 file = iter.Next()) { | |
23 count++; | |
24 } | |
25 return count; | |
26 } | |
27 | |
28 } // namespace | |
29 | |
30 namespace disk_cache { | |
31 | |
32 TEST_F(DiskCacheTest, BlockFiles_Grow) { | |
33 ASSERT_TRUE(CleanupCacheDir()); | |
34 ASSERT_TRUE(base::CreateDirectory(cache_path_)); | |
35 | |
36 BlockFiles files(cache_path_); | |
37 ASSERT_TRUE(files.Init(true)); | |
38 | |
39 const int kMaxSize = 35000; | |
40 Addr address[kMaxSize]; | |
41 | |
42 // Fill up the 32-byte block file (use three files). | |
43 for (int i = 0; i < kMaxSize; i++) { | |
44 EXPECT_TRUE(files.CreateBlock(RANKINGS, 4, &address[i])); | |
45 } | |
46 EXPECT_EQ(6, NumberOfFiles(cache_path_)); | |
47 | |
48 // Make sure we don't keep adding files. | |
49 for (int i = 0; i < kMaxSize * 4; i += 2) { | |
50 int target = i % kMaxSize; | |
51 files.DeleteBlock(address[target], false); | |
52 EXPECT_TRUE(files.CreateBlock(RANKINGS, 4, &address[target])); | |
53 } | |
54 EXPECT_EQ(6, NumberOfFiles(cache_path_)); | |
55 } | |
56 | |
57 // We should be able to delete empty block files. | |
58 TEST_F(DiskCacheTest, BlockFiles_Shrink) { | |
59 ASSERT_TRUE(CleanupCacheDir()); | |
60 ASSERT_TRUE(base::CreateDirectory(cache_path_)); | |
61 | |
62 BlockFiles files(cache_path_); | |
63 ASSERT_TRUE(files.Init(true)); | |
64 | |
65 const int kMaxSize = 35000; | |
66 Addr address[kMaxSize]; | |
67 | |
68 // Fill up the 32-byte block file (use three files). | |
69 for (int i = 0; i < kMaxSize; i++) { | |
70 EXPECT_TRUE(files.CreateBlock(RANKINGS, 4, &address[i])); | |
71 } | |
72 | |
73 // Now delete all the blocks, so that we can delete the two extra files. | |
74 for (int i = 0; i < kMaxSize; i++) { | |
75 files.DeleteBlock(address[i], false); | |
76 } | |
77 EXPECT_EQ(4, NumberOfFiles(cache_path_)); | |
78 } | |
79 | |
80 // Handling of block files not properly closed. | |
81 TEST_F(DiskCacheTest, BlockFiles_Recover) { | |
82 ASSERT_TRUE(CleanupCacheDir()); | |
83 ASSERT_TRUE(base::CreateDirectory(cache_path_)); | |
84 | |
85 BlockFiles files(cache_path_); | |
86 ASSERT_TRUE(files.Init(true)); | |
87 | |
88 const int kNumEntries = 2000; | |
89 CacheAddr entries[kNumEntries]; | |
90 | |
91 int seed = static_cast<int>(Time::Now().ToInternalValue()); | |
92 srand(seed); | |
93 for (int i = 0; i < kNumEntries; i++) { | |
94 Addr address(0); | |
95 int size = (rand() % 4) + 1; | |
96 EXPECT_TRUE(files.CreateBlock(RANKINGS, size, &address)); | |
97 entries[i] = address.value(); | |
98 } | |
99 | |
100 for (int i = 0; i < kNumEntries; i++) { | |
101 int source1 = rand() % kNumEntries; | |
102 int source2 = rand() % kNumEntries; | |
103 CacheAddr temp = entries[source1]; | |
104 entries[source1] = entries[source2]; | |
105 entries[source2] = temp; | |
106 } | |
107 | |
108 for (int i = 0; i < kNumEntries / 2; i++) { | |
109 Addr address(entries[i]); | |
110 files.DeleteBlock(address, false); | |
111 } | |
112 | |
113 // At this point, there are kNumEntries / 2 entries on the file, randomly | |
114 // distributed both on location and size. | |
115 | |
116 Addr address(entries[kNumEntries / 2]); | |
117 MappedFile* file = files.GetFile(address); | |
118 ASSERT_TRUE(NULL != file); | |
119 | |
120 BlockFileHeader* header = | |
121 reinterpret_cast<BlockFileHeader*>(file->buffer()); | |
122 ASSERT_TRUE(NULL != header); | |
123 | |
124 ASSERT_EQ(0, header->updating); | |
125 | |
126 int max_entries = header->max_entries; | |
127 int empty_1 = header->empty[0]; | |
128 int empty_2 = header->empty[1]; | |
129 int empty_3 = header->empty[2]; | |
130 int empty_4 = header->empty[3]; | |
131 | |
132 // Corrupt the file. | |
133 header->max_entries = header->empty[0] = 0; | |
134 header->empty[1] = header->empty[2] = header->empty[3] = 0; | |
135 header->updating = -1; | |
136 | |
137 files.CloseFiles(); | |
138 | |
139 ASSERT_TRUE(files.Init(false)); | |
140 | |
141 // The file must have been fixed. | |
142 file = files.GetFile(address); | |
143 ASSERT_TRUE(NULL != file); | |
144 | |
145 header = reinterpret_cast<BlockFileHeader*>(file->buffer()); | |
146 ASSERT_TRUE(NULL != header); | |
147 | |
148 ASSERT_EQ(0, header->updating); | |
149 | |
150 EXPECT_EQ(max_entries, header->max_entries); | |
151 EXPECT_EQ(empty_1, header->empty[0]); | |
152 EXPECT_EQ(empty_2, header->empty[1]); | |
153 EXPECT_EQ(empty_3, header->empty[2]); | |
154 EXPECT_EQ(empty_4, header->empty[3]); | |
155 } | |
156 | |
157 // Handling of truncated files. | |
158 TEST_F(DiskCacheTest, BlockFiles_ZeroSizeFile) { | |
159 ASSERT_TRUE(CleanupCacheDir()); | |
160 ASSERT_TRUE(base::CreateDirectory(cache_path_)); | |
161 | |
162 BlockFiles files(cache_path_); | |
163 ASSERT_TRUE(files.Init(true)); | |
164 | |
165 base::FilePath filename = files.Name(0); | |
166 files.CloseFiles(); | |
167 // Truncate one of the files. | |
168 { | |
169 scoped_refptr<File> file(new File); | |
170 ASSERT_TRUE(file->Init(filename)); | |
171 EXPECT_TRUE(file->SetLength(0)); | |
172 } | |
173 | |
174 // Initializing should fail, not crash. | |
175 ASSERT_FALSE(files.Init(false)); | |
176 } | |
177 | |
178 // Handling of truncated files (non empty). | |
179 TEST_F(DiskCacheTest, BlockFiles_TruncatedFile) { | |
180 ASSERT_TRUE(CleanupCacheDir()); | |
181 ASSERT_TRUE(base::CreateDirectory(cache_path_)); | |
182 | |
183 BlockFiles files(cache_path_); | |
184 ASSERT_TRUE(files.Init(true)); | |
185 Addr address; | |
186 EXPECT_TRUE(files.CreateBlock(RANKINGS, 2, &address)); | |
187 | |
188 base::FilePath filename = files.Name(0); | |
189 files.CloseFiles(); | |
190 // Truncate one of the files. | |
191 { | |
192 scoped_refptr<File> file(new File); | |
193 ASSERT_TRUE(file->Init(filename)); | |
194 EXPECT_TRUE(file->SetLength(15000)); | |
195 } | |
196 | |
197 // Initializing should fail, not crash. | |
198 ASSERT_FALSE(files.Init(false)); | |
199 } | |
200 | |
201 // Tests detection of out of sync counters. | |
202 TEST_F(DiskCacheTest, BlockFiles_Counters) { | |
203 ASSERT_TRUE(CleanupCacheDir()); | |
204 ASSERT_TRUE(base::CreateDirectory(cache_path_)); | |
205 | |
206 BlockFiles files(cache_path_); | |
207 ASSERT_TRUE(files.Init(true)); | |
208 | |
209 // Create a block of size 2. | |
210 Addr address(0); | |
211 EXPECT_TRUE(files.CreateBlock(RANKINGS, 2, &address)); | |
212 | |
213 MappedFile* file = files.GetFile(address); | |
214 ASSERT_TRUE(NULL != file); | |
215 | |
216 BlockFileHeader* header = reinterpret_cast<BlockFileHeader*>(file->buffer()); | |
217 ASSERT_TRUE(NULL != header); | |
218 ASSERT_EQ(0, header->updating); | |
219 | |
220 // Alter the counters so that the free space doesn't add up. | |
221 header->empty[2] = 50; // 50 free blocks of size 3. | |
222 files.CloseFiles(); | |
223 | |
224 ASSERT_TRUE(files.Init(false)); | |
225 file = files.GetFile(address); | |
226 ASSERT_TRUE(NULL != file); | |
227 header = reinterpret_cast<BlockFileHeader*>(file->buffer()); | |
228 ASSERT_TRUE(NULL != header); | |
229 | |
230 // The file must have been fixed. | |
231 ASSERT_EQ(0, header->empty[2]); | |
232 | |
233 // Change the number of entries. | |
234 header->num_entries = 3; | |
235 header->updating = 1; | |
236 files.CloseFiles(); | |
237 | |
238 ASSERT_TRUE(files.Init(false)); | |
239 file = files.GetFile(address); | |
240 ASSERT_TRUE(NULL != file); | |
241 header = reinterpret_cast<BlockFileHeader*>(file->buffer()); | |
242 ASSERT_TRUE(NULL != header); | |
243 | |
244 // The file must have been "fixed". | |
245 ASSERT_EQ(2, header->num_entries); | |
246 | |
247 // Change the number of entries. | |
248 header->num_entries = -1; | |
249 header->updating = 1; | |
250 files.CloseFiles(); | |
251 | |
252 // Detect the error. | |
253 ASSERT_FALSE(files.Init(false)); | |
254 } | |
255 | |
256 // An invalid file can be detected after init. | |
257 TEST_F(DiskCacheTest, BlockFiles_InvalidFile) { | |
258 ASSERT_TRUE(CleanupCacheDir()); | |
259 ASSERT_TRUE(base::CreateDirectory(cache_path_)); | |
260 | |
261 BlockFiles files(cache_path_); | |
262 ASSERT_TRUE(files.Init(true)); | |
263 | |
264 // Let's access block 10 of file 5. (There is no file). | |
265 Addr addr(BLOCK_256, 1, 5, 10); | |
266 EXPECT_TRUE(NULL == files.GetFile(addr)); | |
267 | |
268 // Let's create an invalid file. | |
269 base::FilePath filename(files.Name(5)); | |
270 char header[kBlockHeaderSize]; | |
271 memset(header, 'a', kBlockHeaderSize); | |
272 EXPECT_EQ(kBlockHeaderSize, | |
273 base::WriteFile(filename, header, kBlockHeaderSize)); | |
274 | |
275 EXPECT_TRUE(NULL == files.GetFile(addr)); | |
276 | |
277 // The file should not have been changed (it is still invalid). | |
278 EXPECT_TRUE(NULL == files.GetFile(addr)); | |
279 } | |
280 | |
281 // Tests that we generate the correct file stats. | |
282 TEST_F(DiskCacheTest, BlockFiles_Stats) { | |
283 ASSERT_TRUE(CopyTestCache("remove_load1")); | |
284 | |
285 BlockFiles files(cache_path_); | |
286 ASSERT_TRUE(files.Init(false)); | |
287 int used, load; | |
288 | |
289 files.GetFileStats(0, &used, &load); | |
290 EXPECT_EQ(101, used); | |
291 EXPECT_EQ(9, load); | |
292 | |
293 files.GetFileStats(1, &used, &load); | |
294 EXPECT_EQ(203, used); | |
295 EXPECT_EQ(19, load); | |
296 | |
297 files.GetFileStats(2, &used, &load); | |
298 EXPECT_EQ(0, used); | |
299 EXPECT_EQ(0, load); | |
300 } | |
301 | |
302 // Tests that we add and remove blocks correctly. | |
303 TEST_F(DiskCacheTest, AllocationMap) { | |
304 ASSERT_TRUE(CleanupCacheDir()); | |
305 ASSERT_TRUE(base::CreateDirectory(cache_path_)); | |
306 | |
307 BlockFiles files(cache_path_); | |
308 ASSERT_TRUE(files.Init(true)); | |
309 | |
310 // Create a bunch of entries. | |
311 const int kSize = 100; | |
312 Addr address[kSize]; | |
313 for (int i = 0; i < kSize; i++) { | |
314 SCOPED_TRACE(i); | |
315 int block_size = i % 4 + 1; | |
316 EXPECT_TRUE(files.CreateBlock(BLOCK_1K, block_size, &address[i])); | |
317 EXPECT_EQ(BLOCK_1K, address[i].file_type()); | |
318 EXPECT_EQ(block_size, address[i].num_blocks()); | |
319 int start = address[i].start_block(); | |
320 EXPECT_EQ(start / 4, (start + block_size - 1) / 4); | |
321 } | |
322 | |
323 for (int i = 0; i < kSize; i++) { | |
324 SCOPED_TRACE(i); | |
325 EXPECT_TRUE(files.IsValid(address[i])); | |
326 } | |
327 | |
328 // The first part of the allocation map should be completely filled. We used | |
329 // 10 bits per each four entries, so 250 bits total. | |
330 BlockFileHeader* header = | |
331 reinterpret_cast<BlockFileHeader*>(files.GetFile(address[0])->buffer()); | |
332 uint8* buffer = reinterpret_cast<uint8*>(&header->allocation_map); | |
333 for (int i =0; i < 29; i++) { | |
334 SCOPED_TRACE(i); | |
335 EXPECT_EQ(0xff, buffer[i]); | |
336 } | |
337 | |
338 for (int i = 0; i < kSize; i++) { | |
339 SCOPED_TRACE(i); | |
340 files.DeleteBlock(address[i], false); | |
341 } | |
342 | |
343 // The allocation map should be empty. | |
344 for (int i =0; i < 50; i++) { | |
345 SCOPED_TRACE(i); | |
346 EXPECT_EQ(0, buffer[i]); | |
347 } | |
348 } | |
349 | |
350 } // namespace disk_cache | |
OLD | NEW |