summaryrefslogtreecommitdiff
path: root/indra/test/setenv.h
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2020-04-02 13:14:31 -0400
committerNat Goodspeed <nat@lindenlab.com>2020-04-03 10:46:17 -0400
commit962ccb4f01f220850fea35e32c3d92a718d35631 (patch)
tree44e1b62b50c0677754253ab6858f38885b885d48 /indra/test/setenv.h
parentdc07509f296661cf7a4d4bceb88a1a897757de98 (diff)
DRTVWR-476: Facilitate debugging test programs with logging.
On Mac, even if you run a test program with --debug or set LOGTEST=DEBUG, it won't log to stderr if you're filtering build output or running the build in an emacs compile buffer. This is because, on Mac, a viewer launched by mouse rather than from the command line is passed a stderr stream that ultimately gets logged to the system Console. The shouldLogToStderr() function is intended to avoid spamming the Console with the (voluminous) viewer log output. It tests whether stderr isatty() and, if not, suppresses calling LLError::logToStderr(). This makes debugging test programs using log output trickier than necessary. Change shouldLogToStderr() to permit logging when either stderr isatty() or is a pipe. The original intention is preserved in that empirically, a viewer launched by mouse is passed a stderr stream identified as a character device rather than as a pipe. Also introduce SetEnv, a class that facilitates setting (e.g.) LOGTEST=DEBUG for specific test programs without setting it for all test programs in the build. Using the constructor for a static object means you can set environment variables before main() is entered, which is important because it's the main() function in test.cpp that acts on the LOGTEST and LOGFAIL environment variables. These changes make it unnecessary to retain the temporary change in test.cpp to force LOGTEST to DEBUG.
Diffstat (limited to 'indra/test/setenv.h')
-rw-r--r--indra/test/setenv.h66
1 files changed, 66 insertions, 0 deletions
diff --git a/indra/test/setenv.h b/indra/test/setenv.h
new file mode 100644
index 0000000000..ed2de9ccca
--- /dev/null
+++ b/indra/test/setenv.h
@@ -0,0 +1,66 @@
+/**
+ * @file setenv.h
+ * @author Nat Goodspeed
+ * @date 2020-04-01
+ * @brief Provide a way for a particular test program to alter the
+ * environment before entry to main().
+ *
+ * $LicenseInfo:firstyear=2020&license=viewerlgpl$
+ * Copyright (c) 2020, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_SETENV_H)
+#define LL_SETENV_H
+
+#include <stdlib.h> // setenv()
+
+/**
+ * Our test.cpp main program responds to environment variables LOGTEST and
+ * LOGFAIL. But if you set (e.g.) LOGTEST=DEBUG before a viewer build, @em
+ * every test program in the build emits debug log output. This can be so
+ * voluminous as to slow down the build.
+ *
+ * With an integration test program, you can specifically build (e.g.) the
+ * INTEGRATION_TEST_llstring target, and set any environment variables you
+ * want for that. But with a unit test program, since executing the program is
+ * a side effect rather than an explicit target, specifically building (e.g.)
+ * PROJECT_lllogin_TEST_lllogin only builds the executable without running it.
+ *
+ * To set an environment variable for a particular test program, declare a
+ * static instance of SetEnv in its .cpp file. SetEnv's constructor takes
+ * pairs of strings, e.g.
+ *
+ * @code
+ * static SetEnv sLOGGING("LOGTEST", "INFO");
+ * @endcode
+ *
+ * Declaring a static instance of SetEnv is important because that ensures
+ * that the environment variables are set before main() is entered, since it
+ * is main() that examines LOGTEST and LOGFAIL.
+ */
+struct SetEnv
+{
+ // degenerate constructor, terminate recursion
+ SetEnv() {}
+
+ /**
+ * SetEnv() accepts an arbitrary number of pairs of strings: variable
+ * name, value, variable name, value ... Entering the constructor sets
+ * those variables in the process environment using Posix setenv(),
+ * overriding any previous value. If static SetEnv declarations in
+ * different translation units specify overlapping sets of variable names,
+ * it is indeterminate which instance will "win."
+ */
+ template <typename VAR, typename VAL, typename... ARGS>
+ SetEnv(VAR&& var, VAL&& val, ARGS&&... rest):
+ // constructor forwarding handles the tail of the list
+ SetEnv(std::forward<ARGS>(rest)...)
+ {
+ // set just the first (variable, value) pair
+ // 1 means override previous value if any
+ setenv(std::forward<VAR>(var), std::forward<VAL>(val), 1);
+ }
+};
+
+#endif /* ! defined(LL_SETENV_H) */