TestBase.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/test/TestBase.cpp#21 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2005-2009 SQLstream, Inc.
00006 // Copyright (C) 2005-2009 LucidEra, Inc.
00007 // Portions Copyright (C) 1999-2009 John V. Sichi
00008 //
00009 // This program is free software; you can redistribute it and/or modify it
00010 // under the terms of the GNU General Public License as published by the Free
00011 // Software Foundation; either version 2 of the License, or (at your option)
00012 // any later version approved by The Eigenbase Project.
00013 //
00014 // This program is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU General Public License
00020 // along with this program; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 */
00023 
00024 #include "fennel/common/CommonPreamble.h"
00025 #include "fennel/test/TestBase.h"
00026 #include "fennel/common/FileSystem.h"
00027 #include "fennel/common/Backtrace.h"
00028 #include "boost/test/test_tools.hpp"
00029 
00030 using namespace fennel;
00031 using boost::unit_test::test_unit;
00032 
00033 ConfigMap TestBase::configMap;
00034 bool TestBase::runAll = false;
00035 std::string TestBase::runSingle;
00036 
00037 ParamName TestBase::paramTestSuiteName = "testSuiteNameBoost";
00038 ParamName TestBase::paramTraceFileName = "testTraceFileName";
00039 ParamName TestBase::paramDictionaryFileName = "testDictionaryFileName";
00040 ParamName TestBase::paramTraceLevel = "testTraceLevel";
00041 ParamName TestBase::paramStatsFileName = "testStatsFileName";
00042 ParamName TestBase::paramTraceStdout = "testTraceStdout";
00043 ParamName TestBase::paramDegreeOfParallelism = "degreeOfParallelism";
00044 
00045 TestBase::TestBase()
00046     : statsTarget(
00047         configMap.getStringParam(paramStatsFileName,"/tmp/fennel.stats")),
00048       statsTimer(statsTarget,500),
00049       defaultTests(),
00050       extraTests()
00051 {
00052     pTestObj.reset(this);
00053     testName = configMap.getStringParam(paramTestSuiteName);
00054     traceLevel = static_cast<TraceLevel>(
00055         configMap.getIntParam(paramTraceLevel,TRACE_CONFIG));
00056     std::string traceStdoutParam =
00057         configMap.getStringParam(paramTraceStdout,"");
00058     traceStdout = ((traceStdoutParam.length() == 0) ? false : true);
00059 
00060     std::string defaultTraceFileName;
00061     const char *fennelHome = getenv("FENNEL_HOME");
00062     if (fennelHome) {
00063         defaultTraceFileName += fennelHome;
00064         defaultTraceFileName += "/trace/";
00065     }
00066     defaultTraceFileName += testName + "_trace.log";
00067     std::string traceFileName =
00068         configMap.getStringParam(
00069             paramTraceFileName,
00070             defaultTraceFileName);
00071 
00072     traceFile = false;
00073     if (traceFileName == "-") {
00074         traceStdout = true;
00075     } else if (traceFileName != "none") {
00076         if (!traceFileName.empty()) {
00077             traceStream.open(traceFileName.c_str());
00078             if (traceStream.good()) {
00079                 traceFile = true;
00080             }
00081         }
00082     }
00083 
00084     // NOTE jvs 25-Nov-2008:  This is to make sure we trace any
00085     // configuration access in the derived class constructor.
00086     // There's a matching call to disableTracing in
00087     // the definition for FENNEL_UNIT_TEST_SUITE after
00088     // the constructor returns.
00089     configMap.initTraceSource(shared_from_this(), "testConfig");
00090 }
00091 
00092 TestBase::~TestBase()
00093 {
00094     traceStream.close();
00095     configMap.clear();
00096 }
00097 
00098 
00107 
00108 void TestBase::readParams(int argc,char **argv)
00109 {
00110     bool verbose = false;
00111     ConfigMap adhocMap;
00112 
00113     for (int i = 1; i < argc; ++i) {
00114         std::string arg = argv[i];
00115         if (argv[i][0] == '-') {
00116             if (arg == "-v") {
00117                 verbose = true;
00118             } else if (arg == "-") {
00119                 configMap.readParams(std::cin);
00120             } else if (arg == "-all") {
00121                 runAll = true;
00122             } else if (arg == "-t") {   // -t TEST
00123                 permAssert(i + 1 < argc);
00124                 runSingle = argv[++i];
00125             } else if (arg[1] == 't') { // allow -tTEST
00126                 runSingle = arg.substr(2);
00127             }
00128         } else {
00129             int i = arg.find("=");
00130             if ((0 < i) && (i < arg.size())) {
00131                 // an ad hoc parameter
00132                 std::string key = arg.substr(0,i);
00133                 std::string val = arg.substr(i + 1);
00134                 adhocMap.setStringParam(key,val);
00135             } else {
00136                 // a config file name
00137                 std::ifstream configFile(arg.c_str());
00138                 assert(configFile.good());
00139                 configMap.readParams(configFile);
00140             }
00141         }
00142     }
00143     configMap.mergeFrom(adhocMap);
00144 
00145     // set a default dictionary file location for use by tests that need a
00146     // small non-random sorted data set
00147     if (!configMap.isParamSet(paramDictionaryFileName)) {
00148         std::string dictFileName = "dictWords";
00149         configMap.setStringParam(paramDictionaryFileName,dictFileName);
00150     }
00151 
00152     if (verbose) {
00153         configMap.dumpParams(std::cout);
00154     }
00155 }
00156 
00157 TestSuite *TestBase::releaseTestSuite()
00158 {
00159     assert(pTestObj);
00160     assert(pTestObj.use_count() > 1);
00161 
00162     // release self-reference now that all test cases have been registered
00163     pTestObj.reset();
00164 
00165     TestSuite* pTestSuite = BOOST_TEST_SUITE(testName.c_str());
00166 
00167     if (runSingle.size()) {
00168         test_unit *p =  defaultTests.findTest(runSingle);
00169         if (!p) {
00170             p = extraTests.findTest(runSingle);
00171         }
00172         if (!p) {
00173             std::cerr << "test " << runSingle << " not found\n";
00174             exit(2);
00175         }
00176         pTestSuite->add(p);
00177     } else {
00178         defaultTests.addAllToTestSuite(pTestSuite);
00179         if (runAll) {
00180             extraTests.addAllToTestSuite(pTestSuite);
00181         }
00182     }
00183     return pTestSuite;
00184 }
00185 
00186 void TestBase::TestCaseGroup::addTest(std::string name, test_unit *tu)
00187 {
00188     items.push_back(Item(name, tu));
00189 }
00190 
00191 test_unit*
00192 TestBase::TestCaseGroup::findTest(std::string name) const
00193 {
00194     for (std::vector<Item>::const_iterator p = items.begin();
00195          p != items.end(); ++p)
00196     {
00197         if (name == p->name) {
00198             return p->tu;
00199         }
00200     }
00201     return 0;
00202 }
00203 
00204 void TestBase::TestCaseGroup::addAllToTestSuite(TestSuite *suite) const
00205 {
00206     for (std::vector<Item>::const_iterator p = items.begin();
00207          p != items.end(); ++p)
00208     {
00209         suite->add(p->tu);
00210     }
00211 }
00212 
00213 
00214 void TestBase::beforeTestCase(std::string testCaseName)
00215 {
00216     notifyTrace(testName,TRACE_INFO,"ENTER:  " + testCaseName);
00217 
00218     // Install the AutoBacktrace signal handler now, after
00219     // boost::execution_monitor::catch_signals() has installed its own, so that
00220     // on SIGABRT AutoBacktrace goes first, prints the backtrace, then chains
00221     // to boost, which handles the error.
00222     AutoBacktrace::setOutputStream();
00223     AutoBacktrace::setTraceTarget(shared_from_this());
00224     AutoBacktrace::install();
00225     configMap.initTraceSource(shared_from_this(), "testConfig");
00226 }
00227 
00228 void TestBase::afterTestCase(std::string testCaseName)
00229 {
00230     AutoBacktrace::setTraceTarget();
00231     configMap.disableTracing();
00232     notifyTrace(testName,TRACE_INFO,"LEAVE:  " + testCaseName);
00233 }
00234 
00235 void TestBase::testCaseSetUp()
00236 {
00237 }
00238 
00239 void TestBase::testCaseTearDown()
00240 {
00241 }
00242 
00243 void TestBase::notifyTrace(std::string source,TraceLevel,std::string message)
00244 {
00245     if (traceFile || traceStdout) {
00246         StrictMutexGuard traceMutexGuard(traceMutex);
00247         if (traceFile) {
00248             traceStream << "[" << source << "] " << message << std::endl;
00249             traceStream.flush();
00250         }
00251         if (traceStdout) {
00252             std::cout << "[" << source << "] " << message << std::endl;
00253             std::cout.flush();
00254         }
00255     }
00256 }
00257 
00258 TraceLevel TestBase::getSourceTraceLevel(std::string)
00259 {
00260     return traceLevel;
00261 }
00262 
00263 void TestBase::snooze(uint nSeconds)
00264 {
00265 #ifdef __MSVC__
00266     ::_sleep(nSeconds*1000);
00267 #else
00268     ::sleep(nSeconds);
00269 #endif
00270 }
00271 
00272 // End TestBase.cpp

Generated on Mon Jun 22 04:00:21 2009 for Fennel by  doxygen 1.5.1