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