1 #define SQUID_UNIT_TEST 1
4 #include "ConfigParser.h"
5 #include "DiskIO/DiskIOModule.h"
6 #include "fs/rock/RockSwapDir.h"
8 #include "HttpHeader.h"
11 #include "MemObject.h"
12 #include "RequestFlags.h"
13 #include "SquidConfig.h"
15 #include "StoreFileSystem.h"
16 #include "StoreSearch.h"
19 #include "testStoreSupport.h"
31 #define TESTDIR "testRock_Store"
33 CPPUNIT_TEST_SUITE_REGISTRATION( testRock
);
35 extern REMOVALPOLICYCREATE createRemovalPolicy_lru
;
37 static char cwd
[MAXPATHLEN
];
40 addSwapDir(testRock::SwapDirPointer aStore
)
42 allocate_new_swapdir(&Config
.cacheSwap
);
43 Config
.cacheSwap
.swapDirs
[Config
.cacheSwap
.n_configured
] = aStore
.getRaw();
44 ++Config
.cacheSwap
.n_configured
;
50 CPPUNIT_NS::TestFixture::setUp();
52 if (0 > system ("rm -rf " TESTDIR
))
53 throw std::runtime_error("Failed to clean test work directory");
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
= ".";
60 Store::Root(new StoreController
);
62 store
= new Rock::SwapDir();
68 char *path
=xstrdup(TESTDIR
);
70 char *config_line
=xstrdup("10 max-size=16384");
72 ConfigParser::SetCfgLine(config_line
);
74 store
->parse(0, path
);
75 store_maxobjsize
= 1024*1024*2;
79 safe_free(config_line
);
81 /* ok, ready to create */
84 rr
= new Rock::SwapDirRr
;
85 rr
->run(rrAfterConfig
);
91 CPPUNIT_NS::TestFixture::tearDown();
97 free_cachedir(&Config
.cacheSwap
);
101 // TODO: do this once, or each time.
102 // safe_free(Config.replPolicy->type);
103 // delete Config.replPolicy;
105 if (0 > system ("rm -rf " TESTDIR
))
106 throw std::runtime_error("Failed to clean test work directory");
110 testRock::commonInit()
112 static bool inited
= false;
117 StoreFileSystem::SetupAllFs();
119 Config
.Store
.avgObjectSize
= 1024;
121 Config
.Store
.objectsPerBucket
= 20;
123 Config
.Store
.maxObjectSize
= 2048;
125 Config
.store_dir_select_algorithm
= xstrdup("round-robin");
127 Config
.replPolicy
= new RemovalPolicySettings
;
129 Config
.replPolicy
->type
= xstrdup ("lru");
131 Config
.replPolicy
->args
= NULL
;
134 storeReplAdd("lru", createRemovalPolicy_lru
);
136 visible_appname_string
= xstrdup(APP_FULLNAME
);
142 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
144 httpReplyInitModule(); /* must go before accepting replies */
146 mem_policy
= createRemovalPolicy(Config
.replPolicy
);
152 testRock::storeInit()
154 /* ok, ready to use */
155 Store::Root().init();
157 /* rebuild is a scheduled event */
160 /* our swapdir must be scheduled to rebuild */
161 CPPUNIT_ASSERT_EQUAL(2, StoreController::store_dirs_rebuilding
);
165 /* cannot use loop.run(); as the loop will never idle: the store-dir
166 * clean() scheduled event prevents it
169 /* nothing left to rebuild */
170 CPPUNIT_ASSERT_EQUAL(1, StoreController::store_dirs_rebuilding
);
174 testRock::createEntry(const int i
)
177 flags
.cachable
= true;
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);
192 testRock::addEntry(const int i
)
194 StoreEntry
*const pe
= createEntry(i
);
197 /* TODO: remove this when the metadata is separated */
200 packerToStoreInit(&p
, pe
);
201 pe
->getReply()->packHeadersInto(&p
);
214 testRock::getEntry(const int i
)
216 StoreEntry
*const pe
= createEntry(i
);
217 return store
->get(reinterpret_cast<const cache_key
*>(pe
->key
));
221 testRock::testRockCreate()
225 CPPUNIT_ASSERT_EQUAL(0, ::stat(TESTDIR
, &sb
));
227 /* TODO: check the size */
229 /* TODO: test rebuild */
233 testRock::testRockSwapOut()
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());
241 StoreEntry
*const pe
= addEntry(i
);
243 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING
, pe
->swap_status
);
244 CPPUNIT_ASSERT_EQUAL(0, pe
->swap_dirn
);
245 CPPUNIT_ASSERT(pe
->swap_filen
>= 0);
247 // Rock::IoState::finishedWriting() schedules an AsyncCall
248 // storeSwapOutFileClosed(). Let it fire.
252 CPPUNIT_ASSERT_EQUAL(SWAPOUT_DONE
, pe
->swap_status
);
257 CPPUNIT_ASSERT_EQUAL((uint64_t)5, store
->currentCount());
259 // try to swap out entry to a used unlocked slot
261 StoreEntry
*const pe
= addEntry(4);
263 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING
, pe
->swap_status
);
264 CPPUNIT_ASSERT_EQUAL(0, pe
->swap_dirn
);
265 CPPUNIT_ASSERT(pe
->swap_filen
>= 0);
270 CPPUNIT_ASSERT_EQUAL(SWAPOUT_DONE
, pe
->swap_status
);
273 // try to swap out entry to a used locked slot
275 StoreEntry
*const pe
= addEntry(5);
277 CPPUNIT_ASSERT_EQUAL(SWAPOUT_WRITING
, pe
->swap_status
);
278 CPPUNIT_ASSERT_EQUAL(0, pe
->swap_dirn
);
279 CPPUNIT_ASSERT(pe
->swap_filen
>= 0);
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
);
292 CPPUNIT_ASSERT_EQUAL((uint64_t)6, store
->currentCount());
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
);
301 StoreEntry
*const pe2
= getEntry(i
);
302 CPPUNIT_ASSERT_EQUAL(static_cast<StoreEntry
*>(NULL
), pe2
);