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