---
configure.ac | 1 +
src/Makefile.am | 118 ++++++++++++++++
src/fs/rock/RockSwapDir.cc | 23 +---
src/fs/rock/RockSwapDir.h | 18 ++-
src/tests/stub_store_rebuild.cc | 4 +-
src/tests/stub_tools.cc | 5 +-
src/tests/testRock.cc | 288 +++++++++++++++++++++++++++++++++++++++
src/tests/testRock.h | 37 +++++
8 files changed, 470 insertions(+), 24 deletions(-)
create mode 100644 src/tests/testRock.cc
create mode 100644 src/tests/testRock.h
diff --git configure.ac configure.ac
index 273d89c..586864c 100644
--- configure.ac
+++ configure.ac
@@ -769,40 +769,41 @@ for fs in $squid_storeio_module_candidates none; do
aufs)
if test "x$squid_disk_module_candidates_Blocking" != "xyes" -a \
"$squid_disk_module_candidates_DiskThreads" != "yes" ; then
AC_MSG_ERROR([Storage module aufs requires DiskIO module: Blocking or DiskThreads])
fi
;;
coss)
AC_MSG_WARN([COSS Support is not stable yet in Squid-3. Please do not use.])
if ! test "x$squid_disk_module_candidates_AIO" = "xyes"; then
AC_MSG_ERROR([COSS requires POSIX AIO which is not available.])
fi
# Automake on MinGW needs explicit exe extension
# for STORE_TESTS substition
STORE_TESTS="$STORE_TESTS tests/testCoss$EXEEXT"
;;
rock)
if test "x$squid_disk_module_candidates_IpcIo" != "xyes" -a \
"x$squid_disk_module_candidates_Blocking" != "xyes"; then
AC_MSG_ERROR([Storage module Rock requires IpcIo or Blocking DiskIO module])
fi
+ STORE_TESTS="$STORE_TESTS tests/testRock$EXEEXT"
;;
ufs)
STORE_TESTS="$STORE_TESTS tests/testUfs$EXEEXT"
esac
done
dnl hack: need to define those even if not used in the build system to
dnl make sure that global FS objects are linked to the squid binary.
AH_TEMPLATE(HAVE_FS_UFS, "Define to 1 if ufs filesystem module is build")
AH_TEMPLATE(HAVE_FS_AUFS, "Define to 1 if aufs filesystem module is build")
AH_TEMPLATE(HAVE_FS_DISKD, "Define to 1 if diskd filesystem module is build")
AH_TEMPLATE(HAVE_FS_COSS, "Define to 1 if coss filesystem module is build")
AH_TEMPLATE(HAVE_FS_ROCK, "Define to 1 if rock filesystem module is build")
dnl got final squid_storeio_module_candidates, build library lists
dnl This list will not be needed when each fs library has its own Makefile
STORE_LIBS_TO_BUILD=
dnl File system libraries to link executables with.
dnl These are the same as STORE_LIBS_TO_BUILD, but with a path
diff --git src/Makefile.am src/Makefile.am
index 8d80a0e..96072e2 100644
--- src/Makefile.am
+++ src/Makefile.am
@@ -169,40 +169,41 @@ AIO_WIN32_SOURCES =
endif
if USE_AIOPS_WIN32
AIOPS_SOURCE = DiskIO/DiskThreads/aiops_win32.cc
else
AIOPS_SOURCE = DiskIO/DiskThreads/aiops.cc
endif
EXTRA_LIBRARIES = libAIO.a libBlocking.a libDiskDaemon.a libDiskThreads.a \
libMmapped.a libIpcIo.a
noinst_LIBRARIES = $(DISK_LIBS)
noinst_LTLIBRARIES = libsquid.la
EXTRA_PROGRAMS = \
DiskIO/DiskDaemon/diskd \
unlinkd \
dnsserver \
recv-announce \
tests/testUfs \
tests/testCoss \
+ tests/testRock \
tests/testNull \
ufsdump
## cfgen is used when building squid
## ufsdump is a debug utility, it is possibly useful for end users with cache
## corruption, but at this point we do not install it.
noinst_PROGRAMS = \
cf_gen
sbin_PROGRAMS = \
squid
bin_PROGRAMS =
libexec_PROGRAMS = \
$(DNSSERVER) \
$(DISK_PROGRAMS) \
$(UNLINKD)
@@ -2612,40 +2613,157 @@ tests_testUfs_LDADD = \
$(DISK_LIBS) \
$(DISK_OS_LIBS) \
acl/libapi.la \
ipc/libipc.la \
$(SSL_LIBS) \
comm/libcomm.la \
base/libbase.la \
ip/libip.la \
$(top_builddir)/lib/libmisccontainers.la \
$(top_builddir)/lib/libmiscencoding.la \
$(top_builddir)/lib/libmiscutil.la \
$(REGEXLIB) \
$(SQUID_CPPUNIT_LIBS) \
$(SSLLIB) \
$(COMPAT_LIB) \
$(XTRA_LIBS)
tests_testUfs_LDFLAGS = $(LIBADD_DL)
tests_testUfs_DEPENDENCIES = \
$(SWAP_TEST_DS)
+tests_testRock_SOURCES = \
+ cbdata.cc \
+ CacheDigest.cc \
+ ConfigOption.cc \
+ ConfigParser.cc \
+ disk.cc \
+ ETag.cc \
+ EventLoop.cc \
+ event.cc \
+ fd.cc \
+ HttpBody.cc \
+ HttpHdrCc.cc \
+ HttpHdrContRange.cc \
+ HttpHdrRange.cc \
+ HttpHdrSc.cc \
+ HttpHdrScTarget.cc \
+ HttpHeader.cc \
+ HttpHeaderTools.cc \
+ HttpMsg.cc \
+ HttpReply.cc \
+ HttpRequestMethod.cc \
+ HttpStatusLine.cc \
+ int.cc \
+ mem.cc \
+ MemBuf.cc \
+ MemObject.cc \
+ mem_node.cc \
+ Packer.cc \
+ Parsing.cc \
+ RemovalPolicy.cc \
+ StatHist.cc \
+ stmem.cc \
+ store.cc \
+ StoreFileSystem.cc \
+ StoreIOState.cc \
+ StoreMeta.cc \
+ StoreMetaMD5.cc \
+ StoreMetaSTD.cc \
+ StoreMetaSTDLFS.cc \
+ StoreMetaURL.cc \
+ StoreMetaUnpacker.cc \
+ StoreMetaVary.cc \
+ store_dir.cc \
+ store_io.cc \
+ store_key_md5.cc \
+ store_swapmeta.cc \
+ store_swapout.cc \
+ String.cc \
+ SwapDir.cc \
+ tests/testRock.cc \
+ tests/testMain.cc \
+ tests/testRock.h \
+ tests/testStoreSupport.cc \
+ tests/testStoreSupport.h \
+ tests/stub_access_log.cc \
+ tests/stub_cache_cf.cc \
+ tests/stub_cache_manager.cc \
+ tests/stub_client_db.cc \
+ tests/stub_client_side_request.cc \
+ tests/stub_debug.cc \
+ tests/stub_errorpage.cc \
+ tests/stub_HelperChildConfig.cc \
+ tests/stub_http.cc \
+ tests/stub_HttpRequest.cc \
+ tests/stub_ipc.cc \
+ tests/stub_MemStore.cc \
+ tests/stub_mime.cc \
+ tests/stub_Port.cc \
+ tests/stub_pconn.cc \
+ tests/stub_store_client.cc \
+ tests/stub_store_rebuild.cc \
+ tests/stub_tools.cc \
+ tests/stub_UdsOp.cc \
+ time.cc \
+ url.cc \
+ URLScheme.cc \
+ wordlist.cc \
+ $(DELAY_POOL_SOURCE) \
+ $(DISKIO_SOURCE) \
+ $(UNLINKDSOURCE)
+nodist_tests_testRock_SOURCES = \
+ $(DISKIO_GEN_SOURCE) \
+ swap_log_op.cc \
+ SquidMath.cc \
+ SquidMath.h \
+ $(TESTSOURCES)
+tests_testRock_LDADD = \
+ anyp/libanyp.la \
+ libsquid.la \
+ comm/libcomm.la \
+ ip/libip.la \
+ fs/libfs.la \
+ $(AUTH_LIBS) \
+ $(COMMON_LIBS) \
+ $(REPL_OBJS) \
+ $(DISK_LIBS) \
+ $(DISK_OS_LIBS) \
+ acl/libacls.la \
+ acl/libapi.la \
+ acl/libstate.la \
+ eui/libeui.la \
+ ipc/libipc.la \
+ mgr/libmgr.la \
+ base/libbase.la \
+ $(SSL_LIBS) \
+ $(top_builddir)/lib/libmisccontainers.la \
+ $(top_builddir)/lib/libmiscencoding.la \
+ $(top_builddir)/lib/libmiscutil.la \
+ $(REGEXLIB) \
+ $(SQUID_CPPUNIT_LIBS) \
+ $(SSLLIB) \
+ $(COMPAT_LIB) \
+ $(XTRA_LIBS)
+tests_testRock_LDFLAGS = $(LIBADD_DL)
+tests_testRock_DEPENDENCIES = \
+ $(SWAP_TEST_DS)
+
tests_testCoss_SOURCES = \
tests/testCoss.cc \
tests/testMain.cc \
tests/testCoss.h \
tests/stub_cache_manager.cc \
tests/stub_client_db.cc \
tests/stub_debug.cc \
tests/stub_HelperChildConfig.cc \
tests/stub_internal.cc \
tests/stub_ipc.cc \
tests/stub_pconn.cc \
tests/stub_store_rebuild.cc \
fd.cc \
disk.cc \
filemap.cc \
HttpBody.cc \
HttpReply.cc \
HttpStatusLine.cc \
int.cc \
list.cc \
diff --git src/fs/rock/RockSwapDir.cc src/fs/rock/RockSwapDir.cc
index 9673712..600f143 100644
--- src/fs/rock/RockSwapDir.cc
+++ src/fs/rock/RockSwapDir.cc
@@ -1,28 +1,27 @@
/*
* $Id$
*
* DEBUG: section 47 Store Directory Routines
*/
#include "config.h"
-#include "base/RunnersRegistry.h"
#include "ConfigOption.h"
#include "DiskIO/DiskIOModule.h"
#include "DiskIO/DiskIOStrategy.h"
#include "DiskIO/ReadRequest.h"
#include "DiskIO/WriteRequest.h"
#include "fs/rock/RockSwapDir.h"
#include "fs/rock/RockIoState.h"
#include "fs/rock/RockIoRequests.h"
#include "fs/rock/RockRebuild.h"
#include "ipc/mem/Pages.h"
#include "MemObject.h"
#include "Parsing.h"
#include "SquidMath.h"
#include <iomanip>
const int64_t Rock::SwapDir::HeaderSize = 16*1024;
Rock::SwapDir::SwapDir(): ::SwapDir("rock"), filePath(NULL), io(NULL), map(NULL)
{
}
@@ -753,55 +752,43 @@ Rock::SwapDir::statfs(StoreEntry &e) const
}
}
}
storeAppendPrintf(&e, "Pending operations: %d out of %d\n",
store_open_disk_fd, Config.max_open_disk_fds);
storeAppendPrintf(&e, "Flags:");
if (flags.selected)
storeAppendPrintf(&e, " SELECTED");
if (flags.read_only)
storeAppendPrintf(&e, " READ-ONLY");
storeAppendPrintf(&e, "\n");
}
-/// initializes shared memory segments used by Rock::SwapDir
-class RockSwapDirRr: public Ipc::Mem::RegisteredRunner
+namespace Rock
{
-public:
- /* RegisteredRunner API */
- virtual ~RockSwapDirRr();
-
-protected:
- virtual void create(const RunnerRegistry &);
-
-private:
- Vector<Rock::SwapDir::DirMap::Owner *> owners;
-};
-
-RunnerRegistrationEntry(rrAfterConfig, RockSwapDirRr);
-
+ RunnerRegistrationEntry(rrAfterConfig, SwapDirRr);
+}
-void RockSwapDirRr::create(const RunnerRegistry &)
+void Rock::SwapDirRr::create(const RunnerRegistry &)
{
Must(owners.empty());
for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
if (const Rock::SwapDir *const sd = dynamic_cast<Rock::SwapDir *>(INDEXSD(i))) {
// TODO: check whether entryLimitAllowed() has map here
Rock::SwapDir::DirMap::Owner *const owner =
Rock::SwapDir::DirMap::Init(sd->path, sd->entryLimitAllowed());
owners.push_back(owner);
}
}
}
-RockSwapDirRr::~RockSwapDirRr()
+Rock::SwapDirRr::~SwapDirRr()
{
for (size_t i = 0; i < owners.size(); ++i)
delete owners[i];
}
diff --git src/fs/rock/RockSwapDir.h src/fs/rock/RockSwapDir.h
index 4e56c42..b89927b 100644
--- src/fs/rock/RockSwapDir.h
+++ src/fs/rock/RockSwapDir.h
@@ -16,84 +16,98 @@ namespace Rock
class Rebuild;
/// \ingroup Rock
class SwapDir: public ::SwapDir, public IORequestor
{
public:
SwapDir();
virtual ~SwapDir();
/* public ::SwapDir API */
virtual void reconfigure();
virtual StoreSearch *search(String const url, HttpRequest *);
virtual StoreEntry *get(const cache_key *key);
virtual void get(String const, STOREGETCLIENT, void * cbdata);
virtual void disconnect(StoreEntry &e);
virtual uint64_t currentSize() const;
virtual uint64_t currentCount() const;
virtual bool doReportStat() const;
virtual void swappedOut(const StoreEntry &e);
+ virtual void create();
+ virtual void parse(int index, char *path);
int64_t entryLimitHigh() const { return SwapFilenMax; } ///< Core limit
int64_t entryLimitAllowed() const;
typedef Ipc::StoreMapWithExtras<DbCellHeader> DirMap;
protected:
/* protected ::SwapDir API */
virtual bool needsDiskStrand() const;
- virtual void create();
virtual void init();
virtual ConfigOption *getOptionTree() const;
virtual bool allowOptionReconfigure(const char *const option) const;
virtual bool canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const;
virtual StoreIOState::Pointer createStoreIO(StoreEntry &, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *);
virtual StoreIOState::Pointer openStoreIO(StoreEntry &, StoreIOState::STFNCB *, StoreIOState::STIOCB *, void *);
virtual void maintain();
virtual void diskFull();
virtual void reference(StoreEntry &e);
virtual bool dereference(StoreEntry &e);
virtual void unlink(StoreEntry &e);
virtual void statfs(StoreEntry &e) const;
/* IORequestor API */
virtual void ioCompletedNotification();
virtual void closeCompleted();
virtual void readCompleted(const char *buf, int len, int errflag, RefCount< ::ReadRequest>);
virtual void writeCompleted(int errflag, size_t len, RefCount< ::WriteRequest>);
- virtual void parse(int index, char *path);
void parseSize(const bool reconfiguring); ///< parses anonymous cache_dir size option
void validateOptions(); ///< warns of configuration problems; may quit
bool parseTimeOption(char const *option, const char *value, int reconfiguring);
void dumpTimeOption(StoreEntry * e) const;
void rebuild(); ///< starts loading and validating stored entry metadata
///< used to add entries successfully loaded during rebuild
bool addEntry(const int fileno, const DbCellHeader &header, const StoreEntry &from);
bool full() const; ///< no more entries can be stored without purging
void trackReferences(StoreEntry &e); ///< add to replacement policy scope
void ignoreReferences(StoreEntry &e); ///< delete from repl policy scope
int64_t diskOffset(int filen) const;
int64_t diskOffsetLimit() const;
int entryLimit() const { return map->entryLimit(); }
friend class Rebuild;
const char *filePath; ///< location of cache storage file inside path/
private:
DiskIOStrategy *io;
RefCount<DiskFile> theFile; ///< cache storage for this cache_dir
DirMap *map;
/* configurable options */
DiskFile::Config fileConfig; ///< file-level configuration options
static const int64_t HeaderSize; ///< on-disk db header size
};
+/// initializes shared memory segments used by Rock::SwapDir
+class SwapDirRr: public Ipc::Mem::RegisteredRunner
+{
+public:
+ /* RegisteredRunner API */
+ virtual ~SwapDirRr();
+
+protected:
+ virtual void create(const RunnerRegistry &);
+
+private:
+ Vector<SwapDir::DirMap::Owner *> owners;
+};
+
} // namespace Rock
#endif /* SQUID_FS_ROCK_SWAP_DIR_H */
diff --git src/tests/stub_store_rebuild.cc src/tests/stub_store_rebuild.cc
index 22c567a..608cbdd 100644
--- src/tests/stub_store_rebuild.cc
+++ src/tests/stub_store_rebuild.cc
@@ -19,43 +19,41 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*
*/
#include "squid.h"
void
storeRebuildProgress(int sd_index, int total, int sofar)
-{
- fatal ("Not implemented");
-}
+{}
void
storeRebuildComplete(struct _store_rebuild_data *dc)
{}
bool
storeRebuildLoadEntry(int, int, MemBuf&, _store_rebuild_data&)
{
return false;
}
bool
storeRebuildKeepEntry(const StoreEntry &tmpe, const cache_key *key,
struct _store_rebuild_data &counts)
{
return false;
}
bool
diff --git src/tests/stub_tools.cc src/tests/stub_tools.cc
index f86d0d7..27afd55 100644
--- src/tests/stub_tools.cc
+++ src/tests/stub_tools.cc
@@ -55,41 +55,44 @@ xmemset(void* dst, int val, size_t sz)
}
bool
IamWorkerProcess()
{
fprintf(stderr, "Not implemented");
return true;
}
bool
IamDiskProcess()
{
fprintf(stderr, "Not implemented");
return false;
}
bool
IamMasterProcess()
{
fprintf(stderr, "Not implemented");
- return false;
+ // Since most tests run as a single process, this is the best default.
+ // TODO: If some test case uses multiple processes and cares about
+ // its role, we may need to parameterize or remove this stub.
+ return true;
}
bool
InDaemonMode()
{
fprintf(stderr, "Not implemented");
return false;
}
bool
UsingSmp()
{
fprintf(stderr, "Not implemented");
return false;
}
void
logsFlush(void)
{
fatal("tools.cc required");
diff --git src/tests/testRock.cc src/tests/testRock.cc
new file mode 100644
index 0000000..4fbd233
--- /dev/null
+++ src/tests/testRock.cc
@@ -0,0 +1,288 @@
+#define SQUID_UNIT_TEST 1
+#include "config.h"
+
+#include "DiskIO/DiskIOModule.h"
+#include "HttpHeader.h"
+#include "HttpReply.h"
+#include "Mem.h"
+#include "MemObject.h"
+#include "Store.h"
+#include "StoreFileSystem.h"
+#include "StoreSearch.h"
+#include "SwapDir.h"
+#include "fs/rock/RockSwapDir.h"
+#include "testRock.h"
+#include "testStoreSupport.h"
+
+#if HAVE_STDEXCEPT
+#include <stdexcept>
+#endif
+
+#define TESTDIR "testRock__testRockSearch"
+
+CPPUNIT_TEST_SUITE_REGISTRATION( testRock );
+
+extern REMOVALPOLICYCREATE createRemovalPolicy_lru;
+
+static void
+addSwapDir(testRock::SwapDirPointer aStore)
+{
+ allocate_new_swapdir(&Config.cacheSwap);
+ Config.cacheSwap.swapDirs[Config.cacheSwap.n_configured] = aStore.getRaw();
+ ++Config.cacheSwap.n_configured;
+}
+
+void
+testRock::setUp()
+{
+ CPPUNIT_NS::TestFixture::setUp();
+
+ if (0 > system ("rm -rf " TESTDIR))
+ throw std::runtime_error("Failed to clean test work directory");
+
+ Store::Root(new StoreController);
+
+ store = new Rock::SwapDir();
+
+ addSwapDir(store);
+
+ commonInit();
+
+ char *path=xstrdup(TESTDIR);
+
+ char *config_line=xstrdup("foo 100 max-size=16384");
+
+ strtok(config_line, w_space);
+
+ store->parse(0, path);
+
+ safe_free(path);
+
+ safe_free(config_line);
+
+ /* ok, ready to create */
+ store->create();
+
+ rr = new Rock::SwapDirRr;
+ rr->run(rrAfterConfig);
+}
+
+void
+testRock::tearDown()
+{
+ CPPUNIT_NS::TestFixture::tearDown();
+
+ Store::Root(NULL);
+
+ store = NULL;
+
+ free_cachedir(&Config.cacheSwap);
+
+ delete rr;
+
+ // TODO: do this once, or each time.
+ // safe_free(Config.replPolicy->type);
+ // delete Config.replPolicy;
+
+ if (0 > system ("rm -rf " TESTDIR))
+ throw std::runtime_error("Failed to clean test work directory");
+}
+
+void
+testRock::commonInit()
+{
+ static bool inited = false;
+
+ if (inited)
+ return;
+
+ StoreFileSystem::SetupAllFs();
+
+ Config.Store.avgObjectSize = 1024;
+
+ Config.Store.objectsPerBucket = 20;
+
+ Config.Store.maxObjectSize = 2048;
+
+ Config.store_dir_select_algorithm = xstrdup("round-robin");
+
+ Config.replPolicy = new RemovalPolicySettings;
+
+ Config.replPolicy->type = xstrdup ("lru");
+
+ Config.replPolicy->args = NULL;
+
+ /* garh garh */
+ storeReplAdd("lru", createRemovalPolicy_lru);
+
+ visible_appname_string = xstrdup(APP_FULLNAME);
+
+ Mem::Init();
+
+ comm_init();
+
+ httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
+
+ httpReplyInitModule(); /* must go before accepting replies */
+
+ mem_policy = createRemovalPolicy(Config.replPolicy);
+
+ inited = true;
+}
+
+void
+testRock::storeInit()
+{
+ /* ok, ready to use */
+ Store::Root().init();
+
+ /* rebuild is a scheduled event */
+ StockEventLoop loop;
+
+ /* our swapdir must be scheduled to rebuild */
+ CPPUNIT_ASSERT_EQUAL(2, StoreController::store_dirs_rebuilding);
+
+ loop.run();
+
+ /* cannot use loop.run(); as the loop will never idle: the store-dir
+ * clean() scheduled event prevents it
+ */
+
+ /* nothing left to rebuild */
+ CPPUNIT_ASSERT_EQUAL(1, StoreController::store_dirs_rebuilding);
+}
+
+StoreEntry *
+testRock::createEntry(const int i)
+{
+ request_flags flags;
+ flags.cachable = 1;
+ char url[64];
+ snprintf(url, sizeof(url), "dummy url %i", i);
+ url[sizeof(url) - 1] = '\0';
+ StoreEntry *const pe =
+ storeCreateEntry(url, "dummy log url", flags, METHOD_GET);
+ HttpReply *const rep = const_cast<HttpReply *>(pe->getReply());
+ rep->setHeaders(HTTP_OK, "dummy test object", "x-squid-internal/test",
+ -1, -1, squid_curtime + 100000);
+
+ pe->setPublicKey();
+
+ return pe;
+}
+
+StoreEntry *
+testRock::addEntry(const int i)
+{
+ StoreEntry *const pe = createEntry(i);
+
+ pe->buffer();
+ /* TODO: remove this when the metadata is separated */
+ {
+ Packer p;
+ packerToStoreInit(&p, pe);
+ pe->getReply()->packHeadersInto(&p);
+ packerClean(&p);
+ }
+
+ pe->flush();
+ pe->timestampsSet();
+ pe->complete();
+ pe->swapOut();
+
+ return pe;
+}
+
+StoreEntry *
+testRock::getEntry(const int i)
+{
+ StoreEntry *const pe = createEntry(i);
+ return store->get(reinterpret_cast<const cache_key *>(pe->key));
+}
+
+void
+testRock::testRockCreate()
+{
+ struct stat sb;
+
+ CPPUNIT_ASSERT(::stat(TESTDIR, &sb) == 0);
+
+ /* TODO: check the size */
+
+ /* TODO: test rebuild */
+}
+
+void
+testRock::testRockSwapOut()
+{
+ storeInit();
+
+ // add few entries to prime the database
+ for (int i = 0; i < 5; ++i) {
+ CPPUNIT_ASSERT_EQUAL((uint64_t)i, store->currentCount());
+
+ StoreEntry *const pe = addEntry(i);
+
+ CPPUNIT_ASSERT(pe->swap_status == SWAPOUT_WRITING);
+ CPPUNIT_ASSERT(pe->swap_dirn == 0);
+ CPPUNIT_ASSERT(pe->swap_filen >= 0);
+
+ // Rock::IoState::finishedWriting() schedules an AsyncCall
+ // storeSwapOutFileClosed(). Let it fire.
+ StockEventLoop loop;
+ loop.run();
+
+ CPPUNIT_ASSERT(pe->swap_status == SWAPOUT_DONE);
+
+ pe->unlock();
+ }
+
+ CPPUNIT_ASSERT_EQUAL((uint64_t)5, store->currentCount());
+
+ // try to swap out entry to a used unlocked slot
+ {
+ StoreEntry *const pe = addEntry(4);
+
+ CPPUNIT_ASSERT(pe->swap_status == SWAPOUT_WRITING);
+ CPPUNIT_ASSERT(pe->swap_dirn == 0);
+ CPPUNIT_ASSERT(pe->swap_filen >= 0);
+
+ StockEventLoop loop;
+ loop.run();
+
+ CPPUNIT_ASSERT(pe->swap_status == SWAPOUT_DONE);
+ }
+
+ // try to swap out entry to a used locked slot
+ {
+ StoreEntry *const pe = addEntry(5);
+
+ CPPUNIT_ASSERT(pe->swap_status == SWAPOUT_WRITING);
+ CPPUNIT_ASSERT(pe->swap_dirn == 0);
+ CPPUNIT_ASSERT(pe->swap_filen >= 0);
+
+ // the slot is locked here because the async calls have not run yet
+ StoreEntry *const pe2 = addEntry(5);
+ CPPUNIT_ASSERT(pe2->swap_status == SWAPOUT_NONE);
+ CPPUNIT_ASSERT(pe2->mem_obj->swapout.decision ==
+ MemObject::SwapOut::swImpossible);
+ CPPUNIT_ASSERT(pe2->swap_dirn == -1);
+ CPPUNIT_ASSERT(pe2->swap_filen == -1);
+
+ StockEventLoop loop;
+ loop.run();
+ }
+
+ CPPUNIT_ASSERT_EQUAL((uint64_t)6, store->currentCount());
+
+ // try to get and unlink entries
+ for (int i = 0; i < 6; ++i) {
+ StoreEntry *const pe = getEntry(i);
+ CPPUNIT_ASSERT(pe != NULL);
+
+ pe->unlink();
+
+ StoreEntry *const pe2 = getEntry(i);
+ CPPUNIT_ASSERT(pe2 == NULL);
+ }
+}
diff --git src/tests/testRock.h src/tests/testRock.h
new file mode 100644
index 0000000..2951d8f
--- /dev/null
+++ src/tests/testRock.h
@@ -0,0 +1,37 @@
+#ifndef SQUID_SRC_TEST_TESTROCK_H
+#define SQUID_SRC_TEST_TESTROCK_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+/*
+ * test the store framework
+ */
+
+class testRock : public CPPUNIT_NS::TestFixture
+{
+ CPPUNIT_TEST_SUITE( testRock );
+ CPPUNIT_TEST( testRockCreate );
+ CPPUNIT_TEST( testRockSwapOut );
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ virtual void setUp();
+ virtual void tearDown();
+
+ typedef RefCount<Rock::SwapDir> SwapDirPointer;
+
+protected:
+ void commonInit();
+ void storeInit();
+ StoreEntry *createEntry(const int i);
+ StoreEntry *addEntry(const int i);
+ StoreEntry *getEntry(const int i);
+ void testRockCreate();
+ void testRockSwapOut();
+
+private:
+ SwapDirPointer store;
+ Rock::SwapDirRr *rr;
+};
+
+#endif /* SQUID_SRC_TEST_TESTROCK_H */