]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testRock.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / tests / testRock.cc
1 /*
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #include "squid.h"
10 #include "ConfigParser.h"
11 #include "DiskIO/DiskIOModule.h"
12 #include "fs/rock/RockSwapDir.h"
13 #include "globals.h"
14 #include "HttpHeader.h"
15 #include "HttpReply.h"
16 #include "MemObject.h"
17 #include "RequestFlags.h"
18 #include "SquidConfig.h"
19 #include "Store.h"
20 #include "StoreFileSystem.h"
21 #include "StoreSearch.h"
22 #include "SwapDir.h"
23 #include "testRock.h"
24 #include "testStoreSupport.h"
25
26 #include <stdexcept>
27 #if HAVE_SYS_STAT_H
28 #include <sys/stat.h>
29 #endif
30 #if HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #define TESTDIR "testRock_Store"
35
36 CPPUNIT_TEST_SUITE_REGISTRATION( testRock );
37
38 extern REMOVALPOLICYCREATE createRemovalPolicy_lru;
39
40 static char cwd[MAXPATHLEN];
41
42 static void
43 addSwapDir(testRock::SwapDirPointer aStore)
44 {
45 allocate_new_swapdir(&Config.cacheSwap);
46 Config.cacheSwap.swapDirs[Config.cacheSwap.n_configured] = aStore.getRaw();
47 ++Config.cacheSwap.n_configured;
48 }
49
50 void
51 testRock::setUp()
52 {
53 CPPUNIT_NS::TestFixture::setUp();
54
55 if (0 > system ("rm -rf " TESTDIR))
56 throw std::runtime_error("Failed to clean test work directory");
57
58 // use current directory for shared segments (on path-based OSes)
59 Ipc::Mem::Segment::BasePath = getcwd(cwd,MAXPATHLEN);
60 if (Ipc::Mem::Segment::BasePath == NULL)
61 Ipc::Mem::Segment::BasePath = ".";
62
63 Store::Root(new StoreController);
64
65 store = new Rock::SwapDir();
66
67 addSwapDir(store);
68
69 commonInit();
70
71 char *path=xstrdup(TESTDIR);
72
73 char *config_line=xstrdup("10 max-size=16384");
74
75 ConfigParser::SetCfgLine(config_line);
76
77 store->parse(0, path);
78 store_maxobjsize = 1024*1024*2;
79
80 safe_free(path);
81
82 safe_free(config_line);
83
84 /* ok, ready to create */
85 store->create();
86
87 rr = new Rock::SwapDirRr;
88 rr->useConfig();
89 }
90
91 void
92 testRock::tearDown()
93 {
94 CPPUNIT_NS::TestFixture::tearDown();
95
96 Store::Root(NULL);
97
98 store = NULL;
99
100 free_cachedir(&Config.cacheSwap);
101
102 rr->finishShutdown(); // deletes rr
103 rr = NULL;
104
105 // TODO: do this once, or each time.
106 // safe_free(Config.replPolicy->type);
107 // delete Config.replPolicy;
108
109 if (0 > system ("rm -rf " TESTDIR))
110 throw std::runtime_error("Failed to clean test work directory");
111 }
112
113 void
114 testRock::commonInit()
115 {
116 static bool inited = false;
117
118 if (inited)
119 return;
120
121 StoreFileSystem::SetupAllFs();
122
123 Config.Store.avgObjectSize = 1024;
124 Config.Store.objectsPerBucket = 20;
125 Config.Store.maxObjectSize = 2048;
126
127 Config.store_dir_select_algorithm = xstrdup("round-robin");
128
129 Config.replPolicy = new RemovalPolicySettings;
130 Config.replPolicy->type = xstrdup("lru");
131 Config.replPolicy->args = NULL;
132
133 /* garh garh */
134 storeReplAdd("lru", createRemovalPolicy_lru);
135
136 visible_appname_string = xstrdup(APP_FULLNAME);
137
138 Mem::Init();
139
140 comm_init();
141
142 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
143
144 httpReplyInitModule(); /* must go before accepting replies */
145
146 mem_policy = createRemovalPolicy(Config.replPolicy);
147
148 inited = true;
149 }
150
151 void
152 testRock::storeInit()
153 {
154 /* ok, ready to use */
155 Store::Root().init();
156
157 /* rebuild is a scheduled event */
158 StockEventLoop loop;
159
160 /* our swapdir must be scheduled to rebuild */
161 CPPUNIT_ASSERT_EQUAL(2, StoreController::store_dirs_rebuilding);
162
163 loop.run();
164
165 /* cannot use loop.run(); as the loop will never idle: the store-dir
166 * clean() scheduled event prevents it
167 */
168
169 /* nothing left to rebuild */
170 CPPUNIT_ASSERT_EQUAL(0, StoreController::store_dirs_rebuilding);
171 }
172
173 static const char *
174 storeId(const int i)
175 {
176 static char buf[64];
177 snprintf(buf, sizeof(buf), "dummy url %i", i);
178 buf[sizeof(buf) - 1] = '\0';
179 return buf;
180 }
181
182 StoreEntry *
183 testRock::createEntry(const int i)
184 {
185 RequestFlags flags;
186 flags.cachable = true;
187 StoreEntry *const pe =
188 storeCreateEntry(storeId(i), "dummy log url", flags, Http::METHOD_GET);
189 HttpReply *const rep = const_cast<HttpReply *>(pe->getReply());
190 rep->setHeaders(Http::scOkay, "dummy test object", "x-squid-internal/test", 0, -1, squid_curtime + 100000);
191
192 pe->setPublicKey();
193
194 return pe;
195 }
196
197 StoreEntry *
198 testRock::addEntry(const int i)
199 {
200 StoreEntry *const pe = createEntry(i);
201
202 pe->buffer();
203 /* TODO: remove this when the metadata is separated */
204 {
205 Packer p;
206 packerToStoreInit(&p, pe);
207 pe->getReply()->packHeadersInto(&p);
208 packerClean(&p);
209 }
210
211 pe->flush();
212 pe->timestampsSet();
213 pe->complete();
214 pe->swapOut();
215
216 return pe;
217 }
218
219 StoreEntry *
220 testRock::getEntry(const int i)
221 {
222 return storeGetPublic(storeId(i), Http::METHOD_GET);
223 }
224
225 void
226 testRock::testRockCreate()
227 {
228 struct stat sb;
229
230 CPPUNIT_ASSERT_EQUAL(0, ::stat(TESTDIR, &sb));
231
232 /* TODO: check the size */
233
234 /* TODO: test rebuild */
235 }
236
237 void
238 testRock::testRockSwapOut()
239 {
240 storeInit();
241
242 // add few entries to prime the database
243 for (int i = 0; i < 5; ++i) {
244 CPPUNIT_ASSERT_EQUAL((uint64_t)i, store->currentCount());
245
246 StoreEntry *const pe = addEntry(i);
247
248 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING, pe->swap_status);
249 CPPUNIT_ASSERT_EQUAL(0, pe->swap_dirn);
250 CPPUNIT_ASSERT(pe->swap_filen >= 0);
251
252 // Rock::IoState::finishedWriting() schedules an AsyncCall
253 // storeSwapOutFileClosed(). Let it fire.
254 StockEventLoop loop;
255 loop.run();
256
257 CPPUNIT_ASSERT_EQUAL(SWAPOUT_DONE, pe->swap_status);
258
259 pe->unlock("testRock::testRockSwapOut priming");
260 }
261
262 CPPUNIT_ASSERT_EQUAL((uint64_t)5, store->currentCount());
263
264 // try to swap out entry to a used unlocked slot
265 {
266 StoreEntry *const pe = addEntry(4);
267
268 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING, pe->swap_status);
269 CPPUNIT_ASSERT_EQUAL(0, pe->swap_dirn);
270 CPPUNIT_ASSERT(pe->swap_filen >= 0);
271
272 StockEventLoop loop;
273 loop.run();
274
275 CPPUNIT_ASSERT_EQUAL(SWAPOUT_DONE, pe->swap_status);
276
277 pe->unlock("testRock::testRockSwapOut e#4");
278 }
279
280 // try to swap out entry to a used locked slot
281 {
282 StoreEntry *const pe = addEntry(5);
283
284 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING, pe->swap_status);
285 CPPUNIT_ASSERT_EQUAL(0, pe->swap_dirn);
286 CPPUNIT_ASSERT(pe->swap_filen >= 0);
287
288 // the slot is locked here because the async calls have not run yet
289 StoreEntry *const pe2 = addEntry(5);
290 CPPUNIT_ASSERT_EQUAL(SWAPOUT_NONE, pe2->swap_status);
291 CPPUNIT_ASSERT_EQUAL(MemObject::SwapOut::swImpossible, pe2->mem_obj->swapout.decision);
292 CPPUNIT_ASSERT_EQUAL(-1, pe2->swap_dirn);
293 CPPUNIT_ASSERT_EQUAL(-1, pe2->swap_filen);
294
295 StockEventLoop loop;
296 loop.run();
297
298 pe->unlock("testRock::testRockSwapOut e#5.1");
299 pe2->unlock("testRock::testRockSwapOut e#5.2");
300
301 // pe2 has the same public key as pe so it marks old pe for release
302 // here, we add another entry #5 into the now-available slot
303 StoreEntry *const pe3 = addEntry(5);
304 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING, pe3->swap_status);
305 CPPUNIT_ASSERT_EQUAL(0, pe3->swap_dirn);
306 CPPUNIT_ASSERT(pe3->swap_filen >= 0);
307 loop.run();
308 CPPUNIT_ASSERT_EQUAL(SWAPOUT_DONE, pe3->swap_status);
309 pe3->unlock("testRock::testRockSwapOut e#5.3");
310 }
311
312 CPPUNIT_ASSERT_EQUAL((uint64_t)6, store->currentCount());
313
314 // try to get and release all entries
315 for (int i = 0; i < 6; ++i) {
316 StoreEntry *const pe = getEntry(i);
317 CPPUNIT_ASSERT(pe != NULL);
318
319 pe->release(); // destroys pe
320
321 StoreEntry *const pe2 = getEntry(i);
322 CPPUNIT_ASSERT_EQUAL(static_cast<StoreEntry *>(NULL), pe2);
323 }
324 }
325