]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tests/testRock.cc
Merged from trunk 13172.
[thirdparty/squid.git] / src / tests / testRock.cc
1 #define SQUID_UNIT_TEST 1
2 #include "squid.h"
3
4 #include "ConfigParser.h"
5 #include "DiskIO/DiskIOModule.h"
6 #include "fs/rock/RockSwapDir.h"
7 #include "globals.h"
8 #include "HttpHeader.h"
9 #include "HttpReply.h"
10 #include "Mem.h"
11 #include "MemObject.h"
12 #include "RequestFlags.h"
13 #include "SquidConfig.h"
14 #include "Store.h"
15 #include "StoreFileSystem.h"
16 #include "StoreSearch.h"
17 #include "SwapDir.h"
18 #include "testRock.h"
19 #include "testStoreSupport.h"
20
21 #if HAVE_SYS_STAT_H
22 #include <sys/stat.h>
23 #endif
24 #if HAVE_STDEXCEPT
25 #include <stdexcept>
26 #endif
27 #if HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #define TESTDIR "testRock_Store"
32
33 CPPUNIT_TEST_SUITE_REGISTRATION( testRock );
34
35 extern REMOVALPOLICYCREATE createRemovalPolicy_lru;
36
37 static char cwd[MAXPATHLEN];
38
39 static void
40 addSwapDir(testRock::SwapDirPointer aStore)
41 {
42 allocate_new_swapdir(&Config.cacheSwap);
43 Config.cacheSwap.swapDirs[Config.cacheSwap.n_configured] = aStore.getRaw();
44 ++Config.cacheSwap.n_configured;
45 }
46
47 void
48 testRock::setUp()
49 {
50 CPPUNIT_NS::TestFixture::setUp();
51
52 if (0 > system ("rm -rf " TESTDIR))
53 throw std::runtime_error("Failed to clean test work directory");
54
55 // use current directory for shared segments (on path-based OSes)
56 Ipc::Mem::Segment::BasePath = getcwd(cwd,MAXPATHLEN);
57 if (Ipc::Mem::Segment::BasePath == NULL)
58 Ipc::Mem::Segment::BasePath = ".";
59
60 Store::Root(new StoreController);
61
62 store = new Rock::SwapDir();
63
64 addSwapDir(store);
65
66 commonInit();
67
68 char *path=xstrdup(TESTDIR);
69
70 char *config_line=xstrdup("10 max-size=16384");
71
72 ConfigParser::SetCfgLine(config_line);
73
74 store->parse(0, path);
75 store_maxobjsize = 1024*1024*2;
76
77 safe_free(path);
78
79 safe_free(config_line);
80
81 /* ok, ready to create */
82 store->create();
83
84 rr = new Rock::SwapDirRr;
85 rr->run(rrAfterConfig);
86 }
87
88 void
89 testRock::tearDown()
90 {
91 CPPUNIT_NS::TestFixture::tearDown();
92
93 Store::Root(NULL);
94
95 store = NULL;
96
97 free_cachedir(&Config.cacheSwap);
98
99 delete rr;
100
101 // TODO: do this once, or each time.
102 // safe_free(Config.replPolicy->type);
103 // delete Config.replPolicy;
104
105 if (0 > system ("rm -rf " TESTDIR))
106 throw std::runtime_error("Failed to clean test work directory");
107 }
108
109 void
110 testRock::commonInit()
111 {
112 static bool inited = false;
113
114 if (inited)
115 return;
116
117 StoreFileSystem::SetupAllFs();
118
119 Config.Store.avgObjectSize = 1024;
120
121 Config.Store.objectsPerBucket = 20;
122
123 Config.Store.maxObjectSize = 2048;
124
125 Config.store_dir_select_algorithm = xstrdup("round-robin");
126
127 Config.replPolicy = new RemovalPolicySettings;
128
129 Config.replPolicy->type = xstrdup ("lru");
130
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(1, StoreController::store_dirs_rebuilding);
171 }
172
173 StoreEntry *
174 testRock::createEntry(const int i)
175 {
176 RequestFlags flags;
177 flags.cachable = true;
178 char url[64];
179 snprintf(url, sizeof(url), "dummy url %i", i);
180 url[sizeof(url) - 1] = '\0';
181 StoreEntry *const pe =
182 storeCreateEntry(url, "dummy log url", flags, Http::METHOD_GET);
183 HttpReply *const rep = const_cast<HttpReply *>(pe->getReply());
184 rep->setHeaders(Http::scOkay, "dummy test object", "x-squid-internal/test", 0, -1, squid_curtime + 100000);
185
186 pe->setPublicKey();
187
188 return pe;
189 }
190
191 StoreEntry *
192 testRock::addEntry(const int i)
193 {
194 StoreEntry *const pe = createEntry(i);
195
196 pe->buffer();
197 /* TODO: remove this when the metadata is separated */
198 {
199 Packer p;
200 packerToStoreInit(&p, pe);
201 pe->getReply()->packHeadersInto(&p);
202 packerClean(&p);
203 }
204
205 pe->flush();
206 pe->timestampsSet();
207 pe->complete();
208 pe->swapOut();
209
210 return pe;
211 }
212
213 StoreEntry *
214 testRock::getEntry(const int i)
215 {
216 StoreEntry *const pe = createEntry(i);
217 return store->get(reinterpret_cast<const cache_key *>(pe->key));
218 }
219
220 void
221 testRock::testRockCreate()
222 {
223 struct stat sb;
224
225 CPPUNIT_ASSERT_EQUAL(0, ::stat(TESTDIR, &sb));
226
227 /* TODO: check the size */
228
229 /* TODO: test rebuild */
230 }
231
232 void
233 testRock::testRockSwapOut()
234 {
235 storeInit();
236
237 // add few entries to prime the database
238 for (int i = 0; i < 5; ++i) {
239 CPPUNIT_ASSERT_EQUAL((uint64_t)i, store->currentCount());
240
241 StoreEntry *const pe = addEntry(i);
242
243 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING, pe->swap_status);
244 CPPUNIT_ASSERT_EQUAL(0, pe->swap_dirn);
245 CPPUNIT_ASSERT(pe->swap_filen >= 0);
246
247 // Rock::IoState::finishedWriting() schedules an AsyncCall
248 // storeSwapOutFileClosed(). Let it fire.
249 StockEventLoop loop;
250 loop.run();
251
252 CPPUNIT_ASSERT_EQUAL(SWAPOUT_DONE, pe->swap_status);
253
254 pe->unlock();
255 }
256
257 CPPUNIT_ASSERT_EQUAL((uint64_t)5, store->currentCount());
258
259 // try to swap out entry to a used unlocked slot
260 {
261 StoreEntry *const pe = addEntry(4);
262
263 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING, pe->swap_status);
264 CPPUNIT_ASSERT_EQUAL(0, pe->swap_dirn);
265 CPPUNIT_ASSERT(pe->swap_filen >= 0);
266
267 StockEventLoop loop;
268 loop.run();
269
270 CPPUNIT_ASSERT_EQUAL(SWAPOUT_DONE, pe->swap_status);
271 }
272
273 // try to swap out entry to a used locked slot
274 {
275 StoreEntry *const pe = addEntry(5);
276
277 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING, pe->swap_status);
278 CPPUNIT_ASSERT_EQUAL(0, pe->swap_dirn);
279 CPPUNIT_ASSERT(pe->swap_filen >= 0);
280
281 // the slot is locked here because the async calls have not run yet
282 StoreEntry *const pe2 = addEntry(5);
283 CPPUNIT_ASSERT_EQUAL(SWAPOUT_NONE, pe2->swap_status);
284 CPPUNIT_ASSERT_EQUAL(MemObject::SwapOut::swImpossible, pe2->mem_obj->swapout.decision);
285 CPPUNIT_ASSERT_EQUAL(-1, pe2->swap_dirn);
286 CPPUNIT_ASSERT_EQUAL(-1, pe2->swap_filen);
287
288 StockEventLoop loop;
289 loop.run();
290 }
291
292 CPPUNIT_ASSERT_EQUAL((uint64_t)6, store->currentCount());
293
294 // try to get and unlink entries
295 for (int i = 0; i < 6; ++i) {
296 StoreEntry *const pe = getEntry(i);
297 CPPUNIT_ASSERT(pe != NULL);
298
299 pe->unlink();
300
301 StoreEntry *const pe2 = getEntry(i);
302 CPPUNIT_ASSERT_EQUAL(static_cast<StoreEntry *>(NULL), pe2);
303 }
304 }