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.
5 #include "base/file_util.h"
6 #include "base/files/file_enumerator.h"
7 #include "net/disk_cache/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"
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
);
21 for (base::FilePath file
= iter
.Next(); !file
.value().empty();
30 namespace disk_cache
{
32 TEST_F(DiskCacheTest
, BlockFiles_Grow
) {
33 ASSERT_TRUE(CleanupCacheDir());
34 ASSERT_TRUE(file_util::CreateDirectory(cache_path_
));
36 BlockFiles
files(cache_path_
);
37 ASSERT_TRUE(files
.Init(true));
39 const int kMaxSize
= 35000;
40 Addr address
[kMaxSize
];
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
]));
46 EXPECT_EQ(6, NumberOfFiles(cache_path_
));
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
]));
54 EXPECT_EQ(6, NumberOfFiles(cache_path_
));
57 // We should be able to delete empty block files.
58 TEST_F(DiskCacheTest
, BlockFiles_Shrink
) {
59 ASSERT_TRUE(CleanupCacheDir());
60 ASSERT_TRUE(file_util::CreateDirectory(cache_path_
));
62 BlockFiles
files(cache_path_
);
63 ASSERT_TRUE(files
.Init(true));
65 const int kMaxSize
= 35000;
66 Addr address
[kMaxSize
];
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
]));
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);
77 EXPECT_EQ(4, NumberOfFiles(cache_path_
));
80 // Handling of block files not properly closed.
81 TEST_F(DiskCacheTest
, BlockFiles_Recover
) {
82 ASSERT_TRUE(CleanupCacheDir());
83 ASSERT_TRUE(file_util::CreateDirectory(cache_path_
));
85 BlockFiles
files(cache_path_
);
86 ASSERT_TRUE(files
.Init(true));
88 const int kNumEntries
= 2000;
89 CacheAddr entries
[kNumEntries
];
91 int seed
= static_cast<int>(Time::Now().ToInternalValue());
93 for (int i
= 0; i
< kNumEntries
; i
++) {
95 int size
= (rand() % 4) + 1;
96 EXPECT_TRUE(files
.CreateBlock(RANKINGS
, size
, &address
));
97 entries
[i
] = address
.value();
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
;
108 for (int i
= 0; i
< kNumEntries
/ 2; i
++) {
109 Addr
address(entries
[i
]);
110 files
.DeleteBlock(address
, false);
113 // At this point, there are kNumEntries / 2 entries on the file, randomly
114 // distributed both on location and size.
116 Addr
address(entries
[kNumEntries
/ 2]);
117 MappedFile
* file
= files
.GetFile(address
);
118 ASSERT_TRUE(NULL
!= file
);
120 BlockFileHeader
* header
=
121 reinterpret_cast<BlockFileHeader
*>(file
->buffer());
122 ASSERT_TRUE(NULL
!= header
);
124 ASSERT_EQ(0, header
->updating
);
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];
133 header
->max_entries
= header
->empty
[0] = 0;
134 header
->empty
[1] = header
->empty
[2] = header
->empty
[3] = 0;
135 header
->updating
= -1;
139 ASSERT_TRUE(files
.Init(false));
141 // The file must have been fixed.
142 file
= files
.GetFile(address
);
143 ASSERT_TRUE(NULL
!= file
);
145 header
= reinterpret_cast<BlockFileHeader
*>(file
->buffer());
146 ASSERT_TRUE(NULL
!= header
);
148 ASSERT_EQ(0, header
->updating
);
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]);
157 // Handling of truncated files.
158 TEST_F(DiskCacheTest
, BlockFiles_ZeroSizeFile
) {
159 ASSERT_TRUE(CleanupCacheDir());
160 ASSERT_TRUE(file_util::CreateDirectory(cache_path_
));
162 BlockFiles
files(cache_path_
);
163 ASSERT_TRUE(files
.Init(true));
165 base::FilePath filename
= files
.Name(0);
167 // Truncate one of the files.
169 scoped_refptr
<File
> file(new File
);
170 ASSERT_TRUE(file
->Init(filename
));
171 EXPECT_TRUE(file
->SetLength(0));
174 // Initializing should fail, not crash.
175 ASSERT_FALSE(files
.Init(false));
178 // Handling of truncated files (non empty).
179 TEST_F(DiskCacheTest
, BlockFiles_TruncatedFile
) {
180 ASSERT_TRUE(CleanupCacheDir());
181 ASSERT_TRUE(file_util::CreateDirectory(cache_path_
));
183 BlockFiles
files(cache_path_
);
184 ASSERT_TRUE(files
.Init(true));
186 EXPECT_TRUE(files
.CreateBlock(RANKINGS
, 2, &address
));
188 base::FilePath filename
= files
.Name(0);
190 // Truncate one of the files.
192 scoped_refptr
<File
> file(new File
);
193 ASSERT_TRUE(file
->Init(filename
));
194 EXPECT_TRUE(file
->SetLength(15000));
197 // Initializing should fail, not crash.
198 ASSERT_FALSE(files
.Init(false));
201 // Tests detection of out of sync counters.
202 TEST_F(DiskCacheTest
, BlockFiles_Counters
) {
203 ASSERT_TRUE(CleanupCacheDir());
204 ASSERT_TRUE(file_util::CreateDirectory(cache_path_
));
206 BlockFiles
files(cache_path_
);
207 ASSERT_TRUE(files
.Init(true));
209 // Create a block of size 2.
211 EXPECT_TRUE(files
.CreateBlock(RANKINGS
, 2, &address
));
213 MappedFile
* file
= files
.GetFile(address
);
214 ASSERT_TRUE(NULL
!= file
);
216 BlockFileHeader
* header
= reinterpret_cast<BlockFileHeader
*>(file
->buffer());
217 ASSERT_TRUE(NULL
!= header
);
218 ASSERT_EQ(0, header
->updating
);
220 // Alter the counters so that the free space doesn't add up.
221 header
->empty
[2] = 50; // 50 free blocks of size 3.
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
);
230 // The file must have been fixed.
231 ASSERT_EQ(0, header
->empty
[2]);
233 // Change the number of entries.
234 header
->num_entries
= 3;
235 header
->updating
= 1;
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
);
244 // The file must have been "fixed".
245 ASSERT_EQ(2, header
->num_entries
);
247 // Change the number of entries.
248 header
->num_entries
= -1;
249 header
->updating
= 1;
253 ASSERT_FALSE(files
.Init(false));
256 // An invalid file can be detected after init.
257 TEST_F(DiskCacheTest
, BlockFiles_InvalidFile
) {
258 ASSERT_TRUE(CleanupCacheDir());
259 ASSERT_TRUE(file_util::CreateDirectory(cache_path_
));
261 BlockFiles
files(cache_path_
);
262 ASSERT_TRUE(files
.Init(true));
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
));
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 file_util::WriteFile(filename
, header
, kBlockHeaderSize
));
275 EXPECT_TRUE(NULL
== files
.GetFile(addr
));
277 // The file should not have been changed (it is still invalid).
278 EXPECT_TRUE(NULL
== files
.GetFile(addr
));
281 // Tests that we generate the correct file stats.
282 TEST_F(DiskCacheTest
, BlockFiles_Stats
) {
283 ASSERT_TRUE(CopyTestCache("remove_load1"));
285 BlockFiles
files(cache_path_
);
286 ASSERT_TRUE(files
.Init(false));
289 files
.GetFileStats(0, &used
, &load
);
290 EXPECT_EQ(101, used
);
293 files
.GetFileStats(1, &used
, &load
);
294 EXPECT_EQ(203, used
);
297 files
.GetFileStats(2, &used
, &load
);
302 // Tests that we add and remove blocks correctly.
303 TEST_F(DiskCacheTest
, AllocationMap
) {
304 ASSERT_TRUE(CleanupCacheDir());
305 ASSERT_TRUE(file_util::CreateDirectory(cache_path_
));
307 BlockFiles
files(cache_path_
);
308 ASSERT_TRUE(files
.Init(true));
310 // Create a bunch of entries.
311 const int kSize
= 100;
313 for (int i
= 0; i
< kSize
; 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);
323 for (int i
= 0; i
< kSize
; i
++) {
325 EXPECT_TRUE(files
.IsValid(address
[i
]));
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
++) {
335 EXPECT_EQ(0xff, buffer
[i
]);
338 for (int i
= 0; i
< kSize
; i
++) {
340 files
.DeleteBlock(address
[i
], false);
343 // The allocation map should be empty.
344 for (int i
=0; i
< 50; i
++) {
346 EXPECT_EQ(0, buffer
[i
]);
350 } // namespace disk_cache