summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2020-04-03 10:38:53 -0400
committerNat Goodspeed <nat@lindenlab.com>2020-04-03 10:38:53 -0400
commitdc07509f296661cf7a4d4bceb88a1a897757de98 (patch)
tree07637f41c8dfbc4cab5cefa65749a8a748603c99
parentb793ab8619d8c52a099aa85fdd831990ca95c6f4 (diff)
DRTVWR-476: Cherry-pick debug aids from commit 77b0c53 (fiber-mutex)
-rw-r--r--indra/llcommon/llerror.h15
-rw-r--r--indra/llcommon/llsingleton.h2
-rw-r--r--indra/llcommon/tests/lleventdispatcher_test.cpp119
-rw-r--r--indra/test/chained_callback.h105
-rw-r--r--indra/test/debug.h40
-rw-r--r--indra/test/print.h42
-rw-r--r--indra/test/test.cpp105
-rw-r--r--indra/viewer_components/login/tests/lllogin_test.cpp1
8 files changed, 320 insertions, 109 deletions
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 48162eca9e..3cdd051ac7 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -191,9 +191,9 @@ namespace LLError
The classes CallSite and Log are used by the logging macros below.
They are not intended for general use.
*/
-
+
struct CallSite;
-
+
class LL_COMMON_API Log
{
public:
@@ -202,8 +202,17 @@ namespace LLError
static void flush(std::ostringstream* out, char* message);
static void flush(std::ostringstream*, const CallSite&);
static std::string demangle(const char* mangled);
+ /// classname<TYPE>()
+ template <typename T>
+ static std::string classname() { return demangle(typeid(T).name()); }
+ /// classname(some_pointer)
+ template <typename T>
+ static std::string classname(const T* ptr) { return demangle(typeid(*ptr).name()); }
+ /// classname(some_reference)
+ template <typename T>
+ static std::string classname(const T& obj) { return demangle(typeid(obj).name()); }
};
-
+
struct LL_COMMON_API CallSite
{
// Represents a specific place in the code where a message is logged
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 27c2ceb3b6..ccd2e48bf2 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -120,6 +120,8 @@ protected:
static void logdebugs(const char* p1, const char* p2="",
const char* p3="", const char* p4="");
static std::string demangle(const char* mangled);
+ // these classname() declarations restate template functions declared in
+ // llerror.h because we avoid #including that here
template <typename T>
static std::string classname() { return demangle(typeid(T).name()); }
template <typename T>
diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp
index efb75951be..9da1ecfd67 100644
--- a/indra/llcommon/tests/lleventdispatcher_test.cpp
+++ b/indra/llcommon/tests/lleventdispatcher_test.cpp
@@ -23,6 +23,7 @@
#include "stringize.h"
#include "tests/wrapllerrs.h"
#include "../test/catch_and_store_what_in.h"
+#include "../test/debug.h"
#include <map>
#include <string>
@@ -46,15 +47,6 @@ using boost::lambda::var;
using namespace llsd;
/*****************************************************************************
-* Output control
-*****************************************************************************/
-#ifdef DEBUG_ON
-using std::cout;
-#else
-static std::ostringstream cout;
-#endif
-
-/*****************************************************************************
* Example data, functions, classes
*****************************************************************************/
// We don't need a whole lot of different arbitrary-params methods, just (no |
@@ -155,13 +147,13 @@ struct Vars
/*------------- no-args (non-const, const, static) methods -------------*/
void method0()
{
- cout << "method0()\n";
+ debug()("method0()");
i = 17;
}
void cmethod0() const
{
- cout << 'c';
+ debug()('c', NONL);
const_cast<Vars*>(this)->method0();
}
@@ -170,13 +162,13 @@ struct Vars
/*------------ Callable (non-const, const, static) methods -------------*/
void method1(const LLSD& obj)
{
- cout << "method1(" << obj << ")\n";
+ debug()("method1(", obj, ")");
llsd = obj;
}
void cmethod1(const LLSD& obj) const
{
- cout << 'c';
+ debug()('c', NONL);
const_cast<Vars*>(this)->method1(obj);
}
@@ -196,12 +188,12 @@ struct Vars
else
vcp = std::string("'") + cp + "'";
- cout << "methodna(" << b
- << ", " << i
- << ", " << f
- << ", " << d
- << ", " << vcp
- << ")\n";
+ debug()("methodna(", b,
+ ", ", i,
+ ", ", f,
+ ", ", d,
+ ", ", vcp,
+ ")");
this->b = b;
this->i = i;
@@ -218,12 +210,12 @@ struct Vars
vbin << std::hex << std::setfill('0') << std::setw(2) << unsigned(byte);
}
- cout << "methodnb(" << "'" << s << "'"
- << ", " << uuid
- << ", " << date
- << ", '" << uri << "'"
- << ", " << vbin.str()
- << ")\n";
+ debug()("methodnb(", "'", s, "'",
+ ", ", uuid,
+ ", ", date,
+ ", '", uri, "'",
+ ", ", vbin.str(),
+ ")");
this->s = s;
this->uuid = uuid;
@@ -234,18 +226,30 @@ struct Vars
void cmethodna(NPARAMSa) const
{
- cout << 'c';
+ debug()('c', NONL);
const_cast<Vars*>(this)->methodna(NARGSa);
}
void cmethodnb(NPARAMSb) const
{
- cout << 'c';
+ debug()('c', NONL);
const_cast<Vars*>(this)->methodnb(NARGSb);
}
static void smethodna(NPARAMSa);
static void smethodnb(NPARAMSb);
+
+ static Debug& debug()
+ {
+ // Lazily initialize this Debug instance so it can notice if main()
+ // has forcibly set LOGTEST. If it were simply a static member, it
+ // would already have examined the environment variable by the time
+ // main() gets around to checking command-line switches. Since we have
+ // a global static Vars instance, the same would be true of a plain
+ // non-static member.
+ static Debug sDebug("Vars");
+ return sDebug;
+ }
};
/*------- Global Vars instance for free functions and static methods -------*/
static Vars g;
@@ -253,25 +257,25 @@ static Vars g;
/*------------ Static Vars method implementations reference 'g' ------------*/
void Vars::smethod0()
{
- cout << "smethod0() -> ";
+ debug()("smethod0() -> ", NONL);
g.method0();
}
void Vars::smethod1(const LLSD& obj)
{
- cout << "smethod1(" << obj << ") -> ";
+ debug()("smethod1(", obj, ") -> ", NONL);
g.method1(obj);
}
void Vars::smethodna(NPARAMSa)
{
- cout << "smethodna(...) -> ";
+ debug()("smethodna(...) -> ", NONL);
g.methodna(NARGSa);
}
void Vars::smethodnb(NPARAMSb)
{
- cout << "smethodnb(...) -> ";
+ debug()("smethodnb(...) -> ", NONL);
g.methodnb(NARGSb);
}
@@ -284,25 +288,25 @@ void clear()
/*------------------- Free functions also reference 'g' --------------------*/
void free0()
{
- cout << "free0() -> ";
+ g.debug()("free0() -> ", NONL);
g.method0();
}
void free1(const LLSD& obj)
{
- cout << "free1(" << obj << ") -> ";
+ g.debug()("free1(", obj, ") -> ", NONL);
g.method1(obj);
}
void freena(NPARAMSa)
{
- cout << "freena(...) -> ";
+ g.debug()("freena(...) -> ", NONL);
g.methodna(NARGSa);
}
void freenb(NPARAMSb)
{
- cout << "freenb(...) -> ";
+ g.debug()("freenb(...) -> ", NONL);
g.methodnb(NARGSb);
}
@@ -313,6 +317,7 @@ namespace tut
{
struct lleventdispatcher_data
{
+ Debug debug{"test"};
WrapLLErrs redirect;
Dispatcher work;
Vars v;
@@ -431,7 +436,12 @@ namespace tut
// Same for freenb() et al.
params = LLSDMap("a", LLSDArray("b")("i")("f")("d")("cp"))
("b", LLSDArray("s")("uuid")("date")("uri")("bin"));
- cout << "params:\n" << params << "\nparams[\"a\"]:\n" << params["a"] << "\nparams[\"b\"]:\n" << params["b"] << std::endl;
+ debug("params:\n",
+ params, "\n"
+ "params[\"a\"]:\n",
+ params["a"], "\n"
+ "params[\"b\"]:\n",
+ params["b"]);
// default LLSD::Binary value
std::vector<U8> binary;
for (size_t ix = 0, h = 0xaa; ix < 6; ++ix, h += 0x11)
@@ -448,7 +458,8 @@ namespace tut
(LLDate::now())
(LLURI("http://www.ietf.org/rfc/rfc3986.txt"))
(binary));
- cout << "dft_array_full:\n" << dft_array_full << std::endl;
+ debug("dft_array_full:\n",
+ dft_array_full);
// Partial defaults arrays.
foreach(LLSD::String a, ab)
{
@@ -457,7 +468,8 @@ namespace tut
llsd_copy_array(dft_array_full[a].beginArray() + partition,
dft_array_full[a].endArray());
}
- cout << "dft_array_partial:\n" << dft_array_partial << std::endl;
+ debug("dft_array_partial:\n",
+ dft_array_partial);
foreach(LLSD::String a, ab)
{
@@ -473,7 +485,10 @@ namespace tut
dft_map_partial[a][params[a][ix].asString()] = dft_array_full[a][ix];
}
}
- cout << "dft_map_full:\n" << dft_map_full << "\ndft_map_partial:\n" << dft_map_partial << '\n';
+ debug("dft_map_full:\n",
+ dft_map_full, "\n"
+ "dft_map_partial:\n",
+ dft_map_partial);
// (Free function | static method) with (no | arbitrary) params,
// map style, no (empty array) defaults
@@ -918,7 +933,12 @@ namespace tut
params[a].endArray()),
dft_array_partial[a]);
}
- cout << "allreq:\n" << allreq << "\nleftreq:\n" << leftreq << "\nrightdft:\n" << rightdft << std::endl;
+ debug("allreq:\n",
+ allreq, "\n"
+ "leftreq:\n",
+ leftreq, "\n"
+ "rightdft:\n",
+ rightdft);
// Generate maps containing parameter names not provided by the
// dft_map_partial maps.
@@ -930,7 +950,8 @@ namespace tut
skipreq[a].erase(me.first);
}
}
- cout << "skipreq:\n" << skipreq << std::endl;
+ debug("skipreq:\n",
+ skipreq);
LLSD groups(LLSDArray // array of groups
@@ -975,7 +996,11 @@ namespace tut
LLSD names(grp[0]);
LLSD required(grp[1][0]);
LLSD optional(grp[1][1]);
- cout << "For " << names << ",\n" << "required:\n" << required << "\noptional:\n" << optional << std::endl;
+ debug("For ", names, ",\n",
+ "required:\n",
+ required, "\n"
+ "optional:\n",
+ optional);
// Loop through 'names'
foreach(LLSD nm, inArray(names))
@@ -1163,7 +1188,7 @@ namespace tut
}
// Adjust expect["a"]["cp"] for special Vars::cp treatment.
expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'";
- cout << "expect: " << expect << '\n';
+ debug("expect: ", expect);
// Use substantially the same logic for args and argsplus
LLSD argsarrays(LLSDArray(args)(argsplus));
@@ -1218,7 +1243,8 @@ namespace tut
{
array_overfull[a].append("bogus");
}
- cout << "array_full: " << array_full << "\narray_overfull: " << array_overfull << std::endl;
+ debug("array_full: ", array_full, "\n"
+ "array_overfull: ", array_overfull);
// We rather hope that LLDate::now() will generate a timestamp
// distinct from the one it generated in the constructor, moments ago.
ensure_not_equals("Timestamps too close",
@@ -1233,7 +1259,8 @@ namespace tut
map_overfull[a] = map_full[a];
map_overfull[a]["extra"] = "ignore";
}
- cout << "map_full: " << map_full << "\nmap_overfull: " << map_overfull << std::endl;
+ debug("map_full: ", map_full, "\n"
+ "map_overfull: ", map_overfull);
LLSD expect(map_full);
// Twiddle the const char* param.
expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'";
@@ -1248,7 +1275,7 @@ namespace tut
// so won't bother returning it. Predict that behavior to match the
// LLSD values.
expect["a"].erase("b");
- cout << "expect: " << expect << std::endl;
+ debug("expect: ", expect);
// For this test, calling functions registered with different sets of
// parameter defaults should make NO DIFFERENCE WHATSOEVER. Every call
// should pass all params.
diff --git a/indra/test/chained_callback.h b/indra/test/chained_callback.h
new file mode 100644
index 0000000000..41a7f7c9fa
--- /dev/null
+++ b/indra/test/chained_callback.h
@@ -0,0 +1,105 @@
+/**
+ * @file chained_callback.h
+ * @author Nat Goodspeed
+ * @date 2020-01-03
+ * @brief Subclass of tut::callback used for chaining callbacks.
+ *
+ * $LicenseInfo:firstyear=2020&license=viewerlgpl$
+ * Copyright (c) 2020, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_CHAINED_CALLBACK_H)
+#define LL_CHAINED_CALLBACK_H
+
+/**
+ * Derive your TUT callback from chained_callback instead of tut::callback to
+ * ensure that multiple such callbacks can coexist in a given test executable.
+ * The relevant callback method will be called for each callback instance in
+ * reverse order of the instance's link() methods being called: the most
+ * recently link()ed callback will be called first, then the previous, and so
+ * forth.
+ *
+ * Obviously, for this to work, all relevant callbacks must be derived from
+ * chained_callback instead of tut::callback. Given that, control should reach
+ * each of them regardless of their construction order. The chain is
+ * guaranteed to stop because the first link() call will link to test_runner's
+ * default_callback, which is simply an instance of the callback() base class.
+ *
+ * The rule for deriving from chained_callback is that you may override any of
+ * its virtual methods, but your override must at some point call the
+ * corresponding chained_callback method.
+ */
+class chained_callback: public tut::callback
+{
+public:
+ /**
+ * Instead of calling tut::test_runner::set_callback(&your_callback), call
+ * your_callback.link();
+ * This uses the canonical instance of tut::test_runner.
+ */
+ void link()
+ {
+ link(tut::runner.get());
+ }
+
+ /**
+ * If for some reason you have a different instance of test_runner...
+ */
+ void link(tut::test_runner& runner)
+ {
+ // Since test_runner's constructor sets a default callback,
+ // get_callback() will always return a reference to a valid callback
+ // instance.
+ mPrev = &runner.get_callback();
+ runner.set_callback(this);
+ }
+
+ /**
+ * Called when new test run started.
+ */
+ virtual void run_started()
+ {
+ mPrev->run_started();
+ }
+
+ /**
+ * Called when a group started
+ * @param name Name of the group
+ */
+ virtual void group_started(const std::string& name)
+ {
+ mPrev->group_started(name);
+ }
+
+ /**
+ * Called when a test finished.
+ * @param tr Test results.
+ */
+ virtual void test_completed(const tut::test_result& tr)
+ {
+ mPrev->test_completed(tr);
+ }
+
+ /**
+ * Called when a group is completed
+ * @param name Name of the group
+ */
+ virtual void group_completed(const std::string& name)
+ {
+ mPrev->group_completed(name);
+ }
+
+ /**
+ * Called when all tests in run completed.
+ */
+ virtual void run_completed()
+ {
+ mPrev->run_completed();
+ }
+
+private:
+ tut::callback* mPrev;
+};
+
+#endif /* ! defined(LL_CHAINED_CALLBACK_H) */
diff --git a/indra/test/debug.h b/indra/test/debug.h
index 33c3ea2d27..76dbb973b2 100644
--- a/indra/test/debug.h
+++ b/indra/test/debug.h
@@ -29,37 +29,59 @@
#if ! defined(LL_DEBUG_H)
#define LL_DEBUG_H
-#include <iostream>
+#include "print.h"
/*****************************************************************************
* Debugging stuff
*****************************************************************************/
-// This class is intended to illuminate entry to a given block, exit from the
-// same block and checkpoints along the way. It also provides a convenient
-// place to turn std::cout output on and off.
+/**
+ * This class is intended to illuminate entry to a given block, exit from the
+ * same block and checkpoints along the way. It also provides a convenient
+ * place to turn std::cerr output on and off.
+ *
+ * If the environment variable LOGTEST is non-empty, each Debug instance will
+ * announce its construction and destruction, presumably at entry and exit to
+ * the block in which it's declared. Moreover, any arguments passed to its
+ * operator()() will be streamed to std::cerr, prefixed by the block
+ * description.
+ *
+ * The variable LOGTEST is used because that's the environment variable
+ * checked by test.cpp, our TUT main() program, to turn on LLError logging. It
+ * is expected that Debug is solely for use in test programs.
+ */
class Debug
{
public:
Debug(const std::string& block):
- mBlock(block)
+ mBlock(block),
+ mLOGTEST(getenv("LOGTEST")),
+ // debug output enabled when LOGTEST is set AND non-empty
+ mEnabled(mLOGTEST && *mLOGTEST)
{
(*this)("entry");
}
+ // non-copyable
+ Debug(const Debug&) = delete;
+
~Debug()
{
(*this)("exit");
}
- void operator()(const std::string& status)
+ template <typename... ARGS>
+ void operator()(ARGS&&... args)
{
-#if defined(DEBUG_ON)
- std::cout << mBlock << ' ' << status << std::endl;
-#endif
+ if (mEnabled)
+ {
+ print(mBlock, ' ', std::forward<ARGS>(args)...);
+ }
}
private:
const std::string mBlock;
+ const char* mLOGTEST;
+ bool mEnabled;
};
// It's often convenient to use the name of the enclosing function as the name
diff --git a/indra/test/print.h b/indra/test/print.h
new file mode 100644
index 0000000000..08e36caddf
--- /dev/null
+++ b/indra/test/print.h
@@ -0,0 +1,42 @@
+/**
+ * @file print.h
+ * @author Nat Goodspeed
+ * @date 2020-01-02
+ * @brief print() function for debugging
+ *
+ * $LicenseInfo:firstyear=2020&license=viewerlgpl$
+ * Copyright (c) 2020, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_PRINT_H)
+#define LL_PRINT_H
+
+#include <iostream>
+
+// print(..., NONL);
+// leaves the output dangling, suppressing the normally appended std::endl
+struct NONL_t {};
+#define NONL (NONL_t())
+
+// normal recursion end
+inline
+void print()
+{
+ std::cerr << std::endl;
+}
+
+// print(NONL) is a no-op
+inline
+void print(NONL_t)
+{
+}
+
+template <typename T, typename... ARGS>
+void print(T&& first, ARGS&&... rest)
+{
+ std::cerr << first;
+ print(std::forward<ARGS>(rest)...);
+}
+
+#endif /* ! defined(LL_PRINT_H) */
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index 6b342ffe89..ea54ba658e 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -37,6 +37,7 @@
#include "linden_common.h"
#include "llerrorcontrol.h"
#include "lltut.h"
+#include "chained_callback.h"
#include "stringize.h"
#include "namedtempfile.h"
#include "lltrace.h"
@@ -71,7 +72,6 @@
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/foreach.hpp>
-#include <boost/lambda/lambda.hpp>
#include <fstream>
@@ -172,8 +172,10 @@ private:
LLError::RecorderPtr mRecorder;
};
-class LLTestCallback : public tut::callback
+class LLTestCallback : public chained_callback
{
+ typedef chained_callback super;
+
public:
LLTestCallback(bool verbose_mode, std::ostream *stream,
boost::shared_ptr<LLReplayLog> replayer) :
@@ -184,7 +186,7 @@ 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, [](std::ostream*){})),
mReplayer(replayer)
{
if (stream)
@@ -205,22 +207,25 @@ public:
~LLTestCallback()
{
- }
+ }
virtual void run_started()
{
//std::cout << "run_started" << std::endl;
LL_INFOS("TestRunner")<<"Test Started"<< LL_ENDL;
+ super::run_started();
}
virtual void group_started(const std::string& name) {
LL_INFOS("TestRunner")<<"Unit test group_started name=" << name << LL_ENDL;
*mStream << "Unit test group_started name=" << name << std::endl;
+ super::group_started(name);
}
virtual void group_completed(const std::string& name) {
LL_INFOS("TestRunner")<<"Unit test group_completed name=" << name << LL_ENDL;
*mStream << "Unit test group_completed name=" << name << std::endl;
+ super::group_completed(name);
}
virtual void test_completed(const tut::test_result& tr)
@@ -282,6 +287,7 @@ public:
*mStream << std::endl;
}
LL_INFOS("TestRunner")<<out.str()<<LL_ENDL;
+ super::test_completed(tr);
}
virtual int getFailedTests() const { return mFailedTests; }
@@ -309,6 +315,7 @@ public:
*mStream << "Please report or fix the problem." << std::endl;
*mStream << "*********************************" << std::endl;
}
+ super::run_completed();
}
protected:
@@ -474,9 +481,8 @@ void stream_usage(std::ostream& s, const char* app)
<< "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";
+ << "--debug is like LOGTEST=DEBUG, but --debug overrides LOGTEST,\n"
+ << "while LOGTEST overrides LOGFAIL.\n\n";
s << "Examples:" << std::endl;
s << " " << app << " --verbose" << std::endl;
@@ -520,35 +526,8 @@ int main(int argc, char **argv)
#ifndef LL_WINDOWS
::testing::InitGoogleMock(&argc, argv);
#endif
- // LOGTEST overrides default, but can be overridden by --debug or LOGFAIL.
- const char* LOGTEST = getenv("LOGTEST");
- if (LOGTEST)
- {
- LLError::initForApplication(".", ".", true /* log to stderr */);
- LLError::setDefaultLevel(LLError::decodeLevel(LOGTEST));
- }
- else
- {
- LLError::initForApplication(".", ".", false /* do not log to stderr */);
- LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
- }
- LLError::setFatalFunction(wouldHaveCrashed);
- std::string test_app_name(argv[0]);
- std::string test_log = test_app_name + ".log";
- LLFile::remove(test_log);
- LLError::logToFile(test_log);
-
-#ifdef CTYPE_WORKAROUND
- ctype_workaround();
-#endif
ll_init_apr();
-
- if (!sMasterThreadRecorder)
- {
- sMasterThreadRecorder = new LLTrace::ThreadRecorder();
- LLTrace::set_master_thread_recorder(sMasterThreadRecorder);
- }
apr_getopt_t* os = NULL;
if(APR_SUCCESS != apr_getopt_init(&os, gAPRPoolp, argc, argv))
{
@@ -562,7 +541,13 @@ int main(int argc, char **argv)
std::string test_group;
std::string suite_name;
- // values use for options parsing
+ // LOGTEST overrides default, but can be overridden by --debug.
+ const char* LOGTEST = getenv("LOGTEST");
+
+ // DELETE
+ LOGTEST = "DEBUG";
+
+ // values used for options parsing
apr_status_t apr_err;
const char* opt_arg = NULL;
int opt_id = 0;
@@ -611,10 +596,7 @@ int main(int argc, char **argv)
wait_at_exit = true;
break;
case 'd':
- // this is what LLError::initForApplication() does internally
- // when you pass log_to_stderr=true
- LLError::logToStderr();
- LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ LOGTEST = "DEBUG";
break;
case 'x':
suite_name.assign(opt_arg);
@@ -626,22 +608,44 @@ int main(int argc, char **argv)
}
}
- // run the tests
-
+ // set up logging
const char* LOGFAIL = getenv("LOGFAIL");
- boost::shared_ptr<LLReplayLog> replayer;
- // As described in stream_usage(), LOGFAIL overrides both --debug and
- // LOGTEST. But allow user to set LOGFAIL empty to revert to LOGTEST
- // and/or --debug.
- if (LOGFAIL && *LOGFAIL)
+ boost::shared_ptr<LLReplayLog> replayer{boost::make_shared<LLReplayLog>()};
+
+ // Testing environment variables for both 'set' and 'not empty' allows a
+ // user to suppress a pre-existing environment variable by forcing empty.
+ if (LOGTEST && *LOGTEST)
{
- LLError::ELevel level = LLError::decodeLevel(LOGFAIL);
- replayer.reset(new LLReplayLogReal(level, gAPRPoolp));
+ LLError::initForApplication(".", ".", true /* log to stderr */);
+ LLError::setDefaultLevel(LLError::decodeLevel(LOGTEST));
}
else
{
- replayer.reset(new LLReplayLog());
+ LLError::initForApplication(".", ".", false /* do not log to stderr */);
+ LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+ if (LOGFAIL && *LOGFAIL)
+ {
+ LLError::ELevel level = LLError::decodeLevel(LOGFAIL);
+ replayer.reset(new LLReplayLogReal(level, gAPRPoolp));
+ }
}
+ LLError::setFatalFunction(wouldHaveCrashed);
+ std::string test_app_name(argv[0]);
+ std::string test_log = test_app_name + ".log";
+ LLFile::remove(test_log);
+ LLError::logToFile(test_log);
+
+#ifdef CTYPE_WORKAROUND
+ ctype_workaround();
+#endif
+
+ if (!sMasterThreadRecorder)
+ {
+ sMasterThreadRecorder = new LLTrace::ThreadRecorder();
+ LLTrace::set_master_thread_recorder(sMasterThreadRecorder);
+ }
+
+ // run the tests
LLTestCallback* mycallback;
if (getenv("TEAMCITY_PROJECT_NAME"))
@@ -653,7 +657,8 @@ int main(int argc, char **argv)
mycallback = new LLTestCallback(verbose_mode, output.get(), replayer);
}
- tut::runner.get().set_callback(mycallback);
+ // a chained_callback subclass must be linked with previous
+ mycallback->link();
if(test_group.empty())
{
diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp
index 0255e10e53..0d933a3d64 100644
--- a/indra/viewer_components/login/tests/lllogin_test.cpp
+++ b/indra/viewer_components/login/tests/lllogin_test.cpp
@@ -43,7 +43,6 @@
#include "llsd.h"
#include "../../../test/lltut.h"
#include "../../../test/lltestapp.h"
-//#define DEBUG_ON
#include "../../../test/debug.h"
#include "llevents.h"
#include "lleventcoro.h"