diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2012-05-09 22:33:04 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2012-05-09 22:33:04 -0400 |
commit | a5b0147df4c489b90b3e281ea93b595431094478 (patch) | |
tree | 0671efae966a304126d1d0329137be22acfe6447 /indra/test/test.cpp | |
parent | d6569db3520f7e0ce2d93febb6f4e26b48c08a3d (diff) | |
parent | d29f920c22ca67b13f42680c432b689b80909f42 (diff) |
Automated merge with http://hg.secondlife.com/viewer-release
Diffstat (limited to 'indra/test/test.cpp')
-rw-r--r-- | indra/test/test.cpp | 134 |
1 files changed, 120 insertions, 14 deletions
diff --git a/indra/test/test.cpp b/indra/test/test.cpp index e58e7293fb..48f20b2e79 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -37,7 +37,9 @@ #include "linden_common.h" #include "llerrorcontrol.h" #include "lltut.h" +#include "tests/wrapllerrs.h" // RecorderProxy #include "stringize.h" +#include "namedtempfile.h" #include "apr_pools.h" #include "apr_getopt.h" @@ -64,23 +66,87 @@ #pragma warning (pop) #endif -#include <boost/scoped_ptr.hpp> #include <boost/shared_ptr.hpp> #include <boost/make_shared.hpp> #include <boost/foreach.hpp> #include <boost/lambda/lambda.hpp> +#include <fstream> + +void wouldHaveCrashed(const std::string& message); + namespace tut { std::string sSourceDir; - - test_runner_singleton runner; + + test_runner_singleton runner; } +class LLReplayLog +{ +public: + LLReplayLog() {} + virtual ~LLReplayLog() {} + + virtual void reset() {} + virtual void replay(std::ostream&) {} +}; + +class LLReplayLogReal: public LLReplayLog, public LLError::Recorder, public boost::noncopyable +{ +public: + LLReplayLogReal(LLError::ELevel level, apr_pool_t* pool): + mOldSettings(LLError::saveAndResetSettings()), + mProxy(new RecorderProxy(this)), + mTempFile("log", "", pool), // create file + mFile(mTempFile.getName().c_str()) // open it + { + LLError::setFatalFunction(wouldHaveCrashed); + LLError::setDefaultLevel(level); + LLError::addRecorder(mProxy); + } + + virtual ~LLReplayLogReal() + { + LLError::removeRecorder(mProxy); + delete mProxy; + LLError::restoreSettings(mOldSettings); + } + + virtual void recordMessage(LLError::ELevel level, const std::string& message) + { + mFile << message << std::endl; + } + + virtual void reset() + { + mFile.close(); + mFile.open(mTempFile.getName().c_str()); + } + + virtual void replay(std::ostream& out) + { + mFile.close(); + std::ifstream inf(mTempFile.getName().c_str()); + std::string line; + while (std::getline(inf, line)) + { + out << line << std::endl; + } + } + +private: + LLError::Settings* mOldSettings; + LLError::Recorder* mProxy; + NamedTempFile mTempFile; + std::ofstream mFile; +}; + class LLTestCallback : public tut::callback { public: - LLTestCallback(bool verbose_mode, std::ostream *stream) : + LLTestCallback(bool verbose_mode, std::ostream *stream, + boost::shared_ptr<LLReplayLog> replayer) : mVerboseMode(verbose_mode), mTotalTests(0), mPassedTests(0), @@ -88,8 +154,10 @@ public: mSkippedTests(0), // By default, capture a shared_ptr to std::cout, with a no-op "deleter" // so that destroying the shared_ptr makes no attempt to delete std::cout. - mStream(boost::shared_ptr<std::ostream>(&std::cout, boost::lambda::_1)) - { + mStream(boost::shared_ptr<std::ostream>(&std::cout, boost::lambda::_1)), + mReplayer(replayer) + if (stream) + { if (stream) { // We want a boost::iostreams::tee_device that will stream to two @@ -126,6 +194,16 @@ public: virtual void test_completed(const tut::test_result& tr) { ++mTotalTests; + + // If this test failed, dump requested log messages BEFORE stating the + // test result. + if (tr.result != tut::test_result::ok && tr.result != tut::test_result::skip) + { + mReplayer->replay(*mStream); + } + // Either way, clear stored messages in preparation for next test. + mReplayer->reset(); + std::ostringstream out; out << "[" << tr.group << ", " << tr.test; if (! tr.name.empty()) @@ -206,6 +284,7 @@ protected: int mFailedTests; int mSkippedTests; boost::shared_ptr<std::ostream> mStream; + boost::shared_ptr<LLReplayLog> mReplayer; }; // TeamCity specific class which emits service messages @@ -214,8 +293,9 @@ protected: class LLTCTestCallback : public LLTestCallback { public: - LLTCTestCallback(bool verbose_mode, std::ostream *stream) : - LLTestCallback(verbose_mode, stream) + LLTCTestCallback(bool verbose_mode, std::ostream *stream, + boost::shared_ptr<LLReplayLog> replayer) : + LLTestCallback(verbose_mode, stream, replayer) { } @@ -356,6 +436,14 @@ void stream_usage(std::ostream& s, const char* app) ++option; } + s << app << " is also sensitive to environment variables:\n" + << "LOGTEST=level : for all tests, emit log messages at level 'level'\n" + << "LOGFAIL=level : only for failed tests, emit log messages at level 'level'\n" + << "where 'level' is one of ALL, DEBUG, INFO, WARN, ERROR, NONE.\n" + << "--debug is like LOGTEST=DEBUG, but --debug overrides LOGTEST.\n" + << "Setting LOGFAIL overrides both LOGTEST and --debug: the only log\n" + << "messages you will see will be for failed tests.\n\n"; + s << "Examples:" << std::endl; s << " " << app << " --verbose" << std::endl; s << "\tRun all the tests and report all results." << std::endl; @@ -392,8 +480,14 @@ int main(int argc, char **argv) LLError::initForApplication("."); LLError::setFatalFunction(wouldHaveCrashed); LLError::setDefaultLevel(LLError::LEVEL_ERROR); - //< *TODO: should come from error config file. Note that we - // have a command line option that sets this to debug. + // ^ possibly overridden by --debug, LOGTEST or LOGFAIL + + // LOGTEST overrides default, but can be overridden by --debug or LOGFAIL. + const char* LOGTEST = getenv("LOGTEST"); + if (LOGTEST) + { + LLError::setDefaultLevel(LLError::decodeLevel(LOGTEST)); + } #ifdef CTYPE_WORKAROUND ctype_workaround(); @@ -468,8 +562,6 @@ int main(int argc, char **argv) wait_at_exit = true; break; case 'd': - // *TODO: should come from error config file. We set it to - // ERROR by default, so this allows full debug levels. LLError::setDefaultLevel(LLError::LEVEL_DEBUG); break; case 'x': @@ -484,14 +576,28 @@ int main(int argc, char **argv) // run the tests + const char* LOGFAIL = getenv("LOGFAIL"); + boost::shared_ptr<LLReplayLog> replayer; + // As described in stream_usage(), LOGFAIL overrides both --debug and + // LOGTEST. + if (LOGFAIL) + { + LLError::ELevel level = LLError::decodeLevel(LOGFAIL); + replayer.reset(new LLReplayLogReal(level, pool)); + } + else + { + replayer.reset(new LLReplayLog()); + } + LLTestCallback* mycallback; if (getenv("TEAMCITY_PROJECT_NAME")) { - mycallback = new LLTCTestCallback(verbose_mode, output.get()); + mycallback = new LLTCTestCallback(verbose_mode, output, replayer); } else { - mycallback = new LLTestCallback(verbose_mode, output.get()); + mycallback = new LLTestCallback(verbose_mode, output, replayer); } tut::runner.get().set_callback(mycallback); |