Make test.cpp support LOGFAIL env var: only failed tests show log.
Set LOGFAIL= one of ALL, DEBUG, INFO, WARN, ERROR, NONE. A passing test will run silently, as now; but a failing test will replay log output at the specified level or higher. While at it, support LOGTEST environment variable, same values. This is like setting --debug (or -d), but allows specifying an arbitrary level -- and, unlike --debug, can be set for a TeamCity build config without modifying any scripts or code. Publish LLError::decodeLevel(std::string), previously private to llerror.cpp.meow-7.2.2
parent
b3b51f012f
commit
f02ded46fe
|
|
@ -654,9 +654,7 @@ namespace LLError
|
|||
g.invalidateCallSites();
|
||||
s.tagLevelMap[tag_name] = level;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
LLError::ELevel decodeLevel(std::string name)
|
||||
{
|
||||
static LevelMap level_names;
|
||||
|
|
@ -681,7 +679,9 @@ namespace {
|
|||
|
||||
return i->second;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level)
|
||||
{
|
||||
LLSD::array_const_iterator i, end;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ namespace LLError
|
|||
LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel);
|
||||
LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel);
|
||||
LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel);
|
||||
|
||||
|
||||
LL_COMMON_API LLError::ELevel decodeLevel(std::string name);
|
||||
LL_COMMON_API void configure(const LLSD&);
|
||||
// the LLSD can configure all of the settings
|
||||
// usually read automatically from the live errorlog.xml file
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "llerrorcontrol.h"
|
||||
#include "lltut.h"
|
||||
#include "stringize.h"
|
||||
#include "namedtempfile.h"
|
||||
|
||||
#include "apr_pools.h"
|
||||
#include "apr_getopt.h"
|
||||
|
|
@ -69,17 +70,79 @@
|
|||
#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:
|
||||
LLReplayLogReal(LLError::ELevel level, apr_pool_t* pool):
|
||||
mOldSettings(LLError::saveAndResetSettings()),
|
||||
mTempFile("log", "", pool), // create file
|
||||
mFile(mTempFile.getName().c_str()) // open it
|
||||
{
|
||||
LLError::setFatalFunction(wouldHaveCrashed);
|
||||
LLError::setDefaultLevel(level);
|
||||
LLError::addRecorder(this);
|
||||
}
|
||||
|
||||
virtual ~LLReplayLogReal()
|
||||
{
|
||||
LLError::removeRecorder(this);
|
||||
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;
|
||||
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),
|
||||
|
|
@ -87,7 +150,8 @@ 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)
|
||||
{
|
||||
|
|
@ -125,6 +189,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())
|
||||
|
|
@ -205,6 +279,7 @@ protected:
|
|||
int mFailedTests;
|
||||
int mSkippedTests;
|
||||
boost::shared_ptr<std::ostream> mStream;
|
||||
boost::shared_ptr<LLReplayLog> mReplayer;
|
||||
};
|
||||
|
||||
// TeamCity specific class which emits service messages
|
||||
|
|
@ -213,8 +288,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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -355,6 +431,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;
|
||||
|
|
@ -391,8 +475,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();
|
||||
|
|
@ -467,8 +557,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':
|
||||
|
|
@ -483,14 +571,28 @@ int main(int argc, char **argv)
|
|||
|
||||
// run the tests
|
||||
|
||||
LLTestCallback* mycallback;
|
||||
if (getenv("TEAMCITY_PROJECT_NAME"))
|
||||
const char* LOGFAIL = getenv("LOGFAIL");
|
||||
boost::shared_ptr<LLReplayLog> replayer;
|
||||
// As described in stream_usage(), LOGFAIL overrides both --debug and
|
||||
// LOGTEST.
|
||||
if (LOGFAIL)
|
||||
{
|
||||
mycallback = new LLTCTestCallback(verbose_mode, output);
|
||||
LLError::ELevel level = LLError::decodeLevel(LOGFAIL);
|
||||
replayer.reset(new LLReplayLogReal(level, pool));
|
||||
}
|
||||
else
|
||||
{
|
||||
mycallback = new LLTestCallback(verbose_mode, output);
|
||||
replayer.reset(new LLReplayLog());
|
||||
}
|
||||
|
||||
LLTestCallback* mycallback;
|
||||
if (getenv("TEAMCITY_PROJECT_NAME"))
|
||||
{
|
||||
mycallback = new LLTCTestCallback(verbose_mode, output, replayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
mycallback = new LLTestCallback(verbose_mode, output, replayer);
|
||||
}
|
||||
|
||||
tut::runner.get().set_callback(mycallback);
|
||||
|
|
|
|||
Loading…
Reference in New Issue