/* * Copyright (C) 1996-2018 The Squid Software Foundation and contributors * * Squid software is distributed under GPLv2+ license and includes * contributions from numerous individuals and organizations. * Please see the COPYING and CONTRIBUTORS files for details. */ #include "squid.h" #include "DiskIO/DiskIOModule.h" #include "fs/ufs/UFSSwapDir.h" #include "globals.h" #include "HttpHeader.h" #include "HttpReply.h" #include "Mem.h" #include "MemObject.h" #include "RequestFlags.h" #include "SquidConfig.h" #include "Store.h" #include "SwapDir.h" #include "testStoreSupport.h" #include "testUfs.h" #include "unitTestMain.h" #include #define TESTDIR "testUfs_Store" CPPUNIT_TEST_SUITE_REGISTRATION( testUfs ); typedef RefCount SwapDirPointer; extern REMOVALPOLICYCREATE createRemovalPolicy_lru; /* XXX fails with --enable-removal-policies=heap */ static void addSwapDir(SwapDirPointer aStore) { allocate_new_swapdir(&Config.cacheSwap); Config.cacheSwap.swapDirs[Config.cacheSwap.n_configured] = aStore.getRaw(); ++Config.cacheSwap.n_configured; } /* TODO make this a cbdata class */ static bool cbcalled; static void searchCallback(void *cbdata) { cbcalled = true; } void testUfs::commonInit() { static bool inited = false; if (inited) return; 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"); /* garh garh */ storeReplAdd("lru", createRemovalPolicy_lru); Mem::Init(); comm_init(); httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */ inited = true; } void testUfs::testUfsSearch() { /* test sequence * make a valid working ufs swapdir * put two entries in it and sync logs * search the ufs dir * check the entries we find are what we want */ if (0 > system ("rm -rf " TESTDIR)) throw std::runtime_error("Failed to clean test work directory"); Store::Root(new StoreController); SwapDirPointer aStore (new Fs::Ufs::UFSSwapDir("ufs", "Blocking")); aStore->IO = new Fs::Ufs::UFSStrategy(DiskIOModule::Find("Blocking")->createStrategy()); addSwapDir(aStore); commonInit(); mem_policy = createRemovalPolicy(Config.replPolicy); char *path=xstrdup(TESTDIR); char *config_line=xstrdup("100 1 1"); visible_appname_string = xstrdup(PACKAGE "/" VERSION); ConfigParser::SetCfgLine(config_line); aStore->parse(0, path); store_maxobjsize = 1024*1024*2; safe_free(path); safe_free(config_line); /* ok, ready to create */ aStore->create(); /* ok, ready to use - inits store & hash too */ Store::Root().init(); /* our swapdir must be scheduled to rebuild */ CPPUNIT_ASSERT_EQUAL(2, StoreController::store_dirs_rebuilding); /* rebuild is a scheduled event */ StockEventLoop loop; while (StoreController::store_dirs_rebuilding) loop.runOnce(); /* 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(0, StoreController::store_dirs_rebuilding); /* add an entry */ { /* Create "vary" base object */ RequestFlags flags; flags.cachable = true; StoreEntry *pe = storeCreateEntry("dummy url", "dummy log url", flags, Http::METHOD_GET); HttpReply *rep = (HttpReply *) pe->getReply(); // bypass const rep->setHeaders(Http::scOkay, "dummy test object", "x-squid-internal/test", 0, -1, squid_curtime + 100000); pe->setPublicKey(); 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(); CPPUNIT_ASSERT_EQUAL(0, pe->swap_dirn); CPPUNIT_ASSERT_EQUAL(0, pe->swap_filen); pe->unlock("testUfs::testUfsSearch vary"); } storeDirWriteCleanLogs(0); /* here we cheat: we know that UFSSwapDirs search off disk. If we did an init call to a new * swapdir instance, we'd not be testing a clean build. */ StoreSearchPointer search = aStore->search (NULL, NULL); /* search for everything in the store */ /* nothing should be immediately available */ #if 0 CPPUNIT_ASSERT_EQUAL(false, search->next()); #endif CPPUNIT_ASSERT_EQUAL(false, search->error()); CPPUNIT_ASSERT_EQUAL(false, search->isDone()); CPPUNIT_ASSERT_EQUAL(static_cast(NULL), search->currentItem()); /* trigger a callback */ cbcalled = false; search->next(searchCallback, NULL); CPPUNIT_ASSERT_EQUAL(true, cbcalled); /* we should have access to a entry now, that matches the entry we had before */ //CPPUNIT_ASSERT_EQUAL(false, search->next()); CPPUNIT_ASSERT_EQUAL(false, search->error()); CPPUNIT_ASSERT_EQUAL(false, search->isDone()); CPPUNIT_ASSERT(search->currentItem() != NULL); /* trigger another callback */ cbcalled = false; search->next(searchCallback, NULL); CPPUNIT_ASSERT_EQUAL(true, cbcalled); /* now we should have no error, we should have finished and have no current item */ //CPPUNIT_ASSERT_EQUAL(false, search->next()); CPPUNIT_ASSERT_EQUAL(false, search->error()); CPPUNIT_ASSERT_EQUAL(true, search->isDone()); CPPUNIT_ASSERT_EQUAL(static_cast(NULL), search->currentItem()); Store::Root(NULL); free_cachedir(&Config.cacheSwap); /* todo: here we should test a dirty rebuild */ safe_free(Config.replPolicy->type); delete Config.replPolicy; if (0 > system ("rm -rf " TESTDIR)) throw std::runtime_error("Failed to clean test work directory"); } /* The UFS store should always configure an IO engine even if none is * supplied on the configuration line. */ void testUfs::testUfsDefaultEngine() { /* boring common test boilerplate */ if (0 > system ("rm -rf " TESTDIR)) throw std::runtime_error("Failed to clean test work directory"); // This assertion may fail if previous test cases fail. // Apparently, CPPUNIT_ASSERT* failure may prevent destructors of local // objects such as "StorePointer aRoot" from being called. CPPUNIT_ASSERT(!store_table); // or StoreHashIndex ctor will abort below Store::Root(new StoreController); SwapDirPointer aStore (new Fs::Ufs::UFSSwapDir("ufs", "Blocking")); addSwapDir(aStore); commonInit(); Config.replPolicy = new RemovalPolicySettings; Config.replPolicy->type = xstrdup("lru"); mem_policy = createRemovalPolicy(Config.replPolicy); char *path=xstrdup(TESTDIR); char *config_line=xstrdup("100 1 1"); ConfigParser::SetCfgLine(config_line); aStore->parse(0, path); safe_free(path); safe_free(config_line); CPPUNIT_ASSERT(aStore->IO->io != NULL); Store::Root(NULL); free_cachedir(&Config.cacheSwap); safe_free(Config.replPolicy->type); delete Config.replPolicy; if (0 > system ("rm -rf " TESTDIR)) throw std::runtime_error("Failed to clean test work directory"); }