]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testRock.cc
Make packerClean() the destructor actions for Packer class
[thirdparty/squid.git] / src / tests / testRock.cc
1 /*
2 * Copyright (C) 1996-2015 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 #include "unitTestMain.h"
26
27 #include <stdexcept>
28 #if HAVE_SYS_STAT_H
29 #include <sys/stat.h>
30 #endif
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #define TESTDIR "testRock_Store"
36
37 CPPUNIT_TEST_SUITE_REGISTRATION( testRock );
38
39 extern REMOVALPOLICYCREATE createRemovalPolicy_lru;
40
41 static char cwd[MAXPATHLEN];
42
43 static void
44 addSwapDir(testRock::SwapDirPointer aStore)
45 {
46 allocate_new_swapdir(&Config.cacheSwap);
47 Config.cacheSwap.swapDirs[Config.cacheSwap.n_configured] = aStore.getRaw();
48 ++Config.cacheSwap.n_configured;
49 }
50
51 void
52 testRock::setUp()
53 {
54 CPPUNIT_NS::TestFixture::setUp();
55
56 if (0 > system ("rm -rf " TESTDIR))
57 throw std::runtime_error("Failed to clean test work directory");
58
59 // use current directory for shared segments (on path-based OSes)
60 Ipc::Mem::Segment::BasePath = getcwd(cwd,MAXPATHLEN);
61 if (Ipc::Mem::Segment::BasePath == NULL)
62 Ipc::Mem::Segment::BasePath = ".";
63
64 Store::Root(new StoreController);
65
66 store = new Rock::SwapDir();
67
68 addSwapDir(store);
69
70 commonInit();
71
72 char *path=xstrdup(TESTDIR);
73
74 char *config_line=xstrdup("10 max-size=16384");
75
76 ConfigParser::SetCfgLine(config_line);
77
78 store->parse(0, path);
79 store_maxobjsize = 1024*1024*2;
80
81 safe_free(path);
82
83 safe_free(config_line);
84
85 /* ok, ready to create */
86 store->create();
87
88 rr = new Rock::SwapDirRr;
89 rr->useConfig();
90 }
91
92 void
93 testRock::tearDown()
94 {
95 CPPUNIT_NS::TestFixture::tearDown();
96
97 Store::Root(NULL);
98
99 store = NULL;
100
101 free_cachedir(&Config.cacheSwap);
102
103 rr->finishShutdown(); // deletes rr
104 rr = NULL;
105
106 // TODO: do this once, or each time.
107 // safe_free(Config.replPolicy->type);
108 // delete Config.replPolicy;
109
110 if (0 > system ("rm -rf " TESTDIR))
111 throw std::runtime_error("Failed to clean test work directory");
112 }
113
114 void
115 testRock::commonInit()
116 {
117 static bool inited = false;
118
119 if (inited)
120 return;
121
122 StoreFileSystem::SetupAllFs();
123
124 Config.Store.avgObjectSize = 1024;
125 Config.Store.objectsPerBucket = 20;
126 Config.Store.maxObjectSize = 2048;
127
128 Config.store_dir_select_algorithm = xstrdup("round-robin");
129
130 Config.replPolicy = new RemovalPolicySettings;
131 Config.replPolicy->type = xstrdup("lru");
132 Config.replPolicy->args = NULL;
133
134 /* garh garh */
135 storeReplAdd("lru", createRemovalPolicy_lru);
136
137 visible_appname_string = xstrdup(APP_FULLNAME);
138
139 Mem::Init();
140
141 comm_init();
142
143 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
144
145 httpReplyInitModule(); /* must go before accepting replies */
146
147 mem_policy = createRemovalPolicy(Config.replPolicy);
148
149 inited = true;
150 }
151
152 void
153 testRock::storeInit()
154 {
155 /* ok, ready to use */
156 Store::Root().init();
157
158 /* rebuild is a scheduled event */
159 StockEventLoop loop;
160
161 /* our swapdir must be scheduled to rebuild */
162 CPPUNIT_ASSERT_EQUAL(2, StoreController::store_dirs_rebuilding);
163
164 loop.run();
165
166 /* cannot use loop.run(); as the loop will never idle: the store-dir
167 * clean() scheduled event prevents it
168 */
169
170 /* nothing left to rebuild */
171 CPPUNIT_ASSERT_EQUAL(0, StoreController::store_dirs_rebuilding);
172 }
173
174 static const char *
175 storeId(const int i)
176 {
177 static char buf[64];
178 snprintf(buf, sizeof(buf), "dummy url %i", i);
179 buf[sizeof(buf) - 1] = '\0';
180 return buf;
181 }
182
183 StoreEntry *
184 testRock::createEntry(const int i)
185 {
186 RequestFlags flags;
187 flags.cachable = true;
188 StoreEntry *const pe =
189 storeCreateEntry(storeId(i), "dummy log url", flags, Http::METHOD_GET);
190 HttpReply *const rep = const_cast<HttpReply *>(pe->getReply());
191 rep->setHeaders(Http::scOkay, "dummy test object", "x-squid-internal/test", 0, -1, squid_curtime + 100000);
192
193 pe->setPublicKey();
194
195 return pe;
196 }
197
198 StoreEntry *
199 testRock::addEntry(const int i)
200 {
201 StoreEntry *const pe = createEntry(i);
202
203 pe->buffer();
204 /* TODO: remove this when the metadata is separated */
205 {
206 Packer p;
207 packerToStoreInit(&p, pe);
208 pe->getReply()->packHeadersInto(&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