1 #define SQUID_UNIT_TEST 1
4 #include "DiskIO/DiskIOModule.h"
5 #include "fs/rock/RockSwapDir.h"
7 #include "HttpHeader.h"
10 #include "MemObject.h"
11 #include "RequestFlags.h"
12 #include "SquidConfig.h"
14 #include "StoreFileSystem.h"
15 #include "StoreSearch.h"
18 #include "testStoreSupport.h"
30 #define TESTDIR "testRock_Store"
32 CPPUNIT_TEST_SUITE_REGISTRATION( testRock
);
34 extern REMOVALPOLICYCREATE createRemovalPolicy_lru
;
36 static char cwd
[MAXPATHLEN
];
39 addSwapDir(testRock::SwapDirPointer aStore
)
41 allocate_new_swapdir(&Config
.cacheSwap
);
42 Config
.cacheSwap
.swapDirs
[Config
.cacheSwap
.n_configured
] = aStore
.getRaw();
43 ++Config
.cacheSwap
.n_configured
;
49 CPPUNIT_NS::TestFixture::setUp();
51 if (0 > system ("rm -rf " TESTDIR
))
52 throw std::runtime_error("Failed to clean test work directory");
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
= ".";
59 Store::Root(new StoreController
);
61 store
= new Rock::SwapDir();
67 char *path
=xstrdup(TESTDIR
);
69 char *config_line
=xstrdup("foo 10 max-size=16384");
71 strtok(config_line
, w_space
);
73 store
->parse(0, path
);
74 store_maxobjsize
= 1024*1024*2;
78 safe_free(config_line
);
80 /* ok, ready to create */
83 rr
= new Rock::SwapDirRr
;
84 rr
->run(rrAfterConfig
);
90 CPPUNIT_NS::TestFixture::tearDown();
96 free_cachedir(&Config
.cacheSwap
);
100 // TODO: do this once, or each time.
101 // safe_free(Config.replPolicy->type);
102 // delete Config.replPolicy;
104 if (0 > system ("rm -rf " TESTDIR
))
105 throw std::runtime_error("Failed to clean test work directory");
109 testRock::commonInit()
111 static bool inited
= false;
116 StoreFileSystem::SetupAllFs();
118 Config
.Store
.avgObjectSize
= 1024;
120 Config
.Store
.objectsPerBucket
= 20;
122 Config
.Store
.maxObjectSize
= 2048;
124 Config
.store_dir_select_algorithm
= xstrdup("round-robin");
126 Config
.replPolicy
= new RemovalPolicySettings
;
128 Config
.replPolicy
->type
= xstrdup ("lru");
130 Config
.replPolicy
->args
= NULL
;
133 storeReplAdd("lru", createRemovalPolicy_lru
);
135 visible_appname_string
= xstrdup(APP_FULLNAME
);
141 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
143 httpReplyInitModule(); /* must go before accepting replies */
145 mem_policy
= createRemovalPolicy(Config
.replPolicy
);
151 testRock::storeInit()
153 /* ok, ready to use */
154 Store::Root().init();
156 /* rebuild is a scheduled event */
159 /* our swapdir must be scheduled to rebuild */
160 CPPUNIT_ASSERT_EQUAL(2, StoreController::store_dirs_rebuilding
);
164 /* cannot use loop.run(); as the loop will never idle: the store-dir
165 * clean() scheduled event prevents it
168 /* nothing left to rebuild */
169 CPPUNIT_ASSERT_EQUAL(1, StoreController::store_dirs_rebuilding
);
173 testRock::createEntry(const int i
)
176 flags
.cachable
= true;
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);
191 testRock::addEntry(const int i
)
193 StoreEntry
*const pe
= createEntry(i
);
196 /* TODO: remove this when the metadata is separated */
199 packerToStoreInit(&p
, pe
);
200 pe
->getReply()->packHeadersInto(&p
);
213 testRock::getEntry(const int i
)
215 StoreEntry
*const pe
= createEntry(i
);
216 return store
->get(reinterpret_cast<const cache_key
*>(pe
->key
));
220 testRock::testRockCreate()
224 CPPUNIT_ASSERT(::stat(TESTDIR
, &sb
) == 0);
226 /* TODO: check the size */
228 /* TODO: test rebuild */
232 testRock::testRockSwapOut()
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());
240 StoreEntry
*const pe
= addEntry(i
);
242 CPPUNIT_ASSERT(pe
->swap_status
== SWAPOUT_WRITING
);
243 CPPUNIT_ASSERT(pe
->swap_dirn
== 0);
244 CPPUNIT_ASSERT(pe
->swap_filen
>= 0);
246 // Rock::IoState::finishedWriting() schedules an AsyncCall
247 // storeSwapOutFileClosed(). Let it fire.
251 CPPUNIT_ASSERT(pe
->swap_status
== SWAPOUT_DONE
);
256 CPPUNIT_ASSERT_EQUAL((uint64_t)5, store
->currentCount());
258 // try to swap out entry to a used unlocked slot
260 StoreEntry
*const pe
= addEntry(4);
262 CPPUNIT_ASSERT(pe
->swap_status
== SWAPOUT_WRITING
);
263 CPPUNIT_ASSERT(pe
->swap_dirn
== 0);
264 CPPUNIT_ASSERT(pe
->swap_filen
>= 0);
269 CPPUNIT_ASSERT(pe
->swap_status
== SWAPOUT_DONE
);
272 // try to swap out entry to a used locked slot
274 StoreEntry
*const pe
= addEntry(5);
276 CPPUNIT_ASSERT(pe
->swap_status
== SWAPOUT_WRITING
);
277 CPPUNIT_ASSERT(pe
->swap_dirn
== 0);
278 CPPUNIT_ASSERT(pe
->swap_filen
>= 0);
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);
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(pe2
== NULL
);