diff options
Diffstat (limited to 'indra/test')
-rw-r--r-- | indra/test/debug.h | 79 | ||||
-rw-r--r-- | indra/test/hexdump.h | 97 | ||||
-rw-r--r-- | indra/test/io.cpp | 40 | ||||
-rw-r--r-- | indra/test/lltut.h | 2 | ||||
-rw-r--r-- | indra/test/print.h | 6 |
5 files changed, 83 insertions, 141 deletions
diff --git a/indra/test/debug.h b/indra/test/debug.h index 1579bb9c86..2f6a114761 100644 --- a/indra/test/debug.h +++ b/indra/test/debug.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-05-28 * @brief Debug output for unit test code - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,43 +30,56 @@ #define LL_DEBUG_H #include "print.h" +#include "stringize.h" +#include <exception> // std::uncaught_exceptions() /***************************************************************************** * 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::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. + * Return true if the environment variable LOGTEST is non-empty. * * 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. */ +inline +bool LOGTEST_enabled() +{ + auto LOGTEST{ getenv("LOGTEST") }; + // debug output enabled when LOGTEST is set AND non-empty + return LOGTEST && *LOGTEST; +} + +/** + * 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 enabled, 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. + */ class Debug { public: - Debug(const std::string& block): - mBlock(block), - mLOGTEST(getenv("LOGTEST")), - // debug output enabled when LOGTEST is set AND non-empty - mEnabled(mLOGTEST && *mLOGTEST) + template <typename... ARGS> + Debug(ARGS&&... args): + mBlock(stringize(std::forward<ARGS>(args)...)), + mEnabled(LOGTEST_enabled()) { (*this)("entry"); } // non-copyable Debug(const Debug&) = delete; + Debug& operator=(const Debug&) = delete; ~Debug() { - (*this)("exit"); + auto exceptional{ std::uncaught_exceptions()? "exceptional " : "" }; + (*this)(exceptional, "exit"); } template <typename... ARGS> @@ -80,7 +93,6 @@ public: private: const std::string mBlock; - const char* mLOGTEST; bool mEnabled; }; @@ -88,20 +100,19 @@ private: // of the Debug block. #define DEBUG Debug debug(LL_PRETTY_FUNCTION) -// These BEGIN/END macros are specifically for debugging output -- please -// don't assume you must use such for coroutines in general! They only help to -// make control flow (as well as exception exits) explicit. -#define BEGIN \ -{ \ - DEBUG; \ - try +/// If enabled, debug_expr(expression) gives you output concerning an inline +/// expression such as a class member initializer. +#define debug_expr(expr) debug_expr_(#expr, [&](){ return expr; }) -#define END \ - catch (...) \ - { \ - debug("*** exceptional "); \ - throw; \ - } \ +template <typename EXPR> +inline auto debug_expr_(const char* strexpr, EXPR&& lambda) +{ + if (! LOGTEST_enabled()) + return std::forward<EXPR>(lambda)(); + print("Before: ", strexpr); + auto result{ std::forward<EXPR>(lambda)() }; + print(strexpr, " -> ", result); + return result; } #endif /* ! defined(LL_DEBUG_H) */ diff --git a/indra/test/hexdump.h b/indra/test/hexdump.h deleted file mode 100644 index 95f1e297c3..0000000000 --- a/indra/test/hexdump.h +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file hexdump.h - * @author Nat Goodspeed - * @date 2023-09-08 - * @brief Provide hexdump() and hexmix() ostream formatters - * - * $LicenseInfo:firstyear=2023&license=viewerlgpl$ - * Copyright (c) 2023, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_HEXDUMP_H) -#define LL_HEXDUMP_H - -#include <cctype> -#include <iomanip> -#include <iostream> -#include <string_view> - -// Format a given byte string as 2-digit hex values, no separators -// Usage: std::cout << hexdump(somestring) << ... -class hexdump -{ -public: - hexdump(const std::string_view& data): - hexdump(data.data(), data.length()) - {} - - hexdump(const char* data, size_t len): - hexdump(reinterpret_cast<const unsigned char*>(data), len) - {} - - hexdump(const unsigned char* data, size_t len): - mData(data, data + len) - {} - - friend std::ostream& operator<<(std::ostream& out, const hexdump& self) - { - auto oldfmt{ out.flags() }; - auto oldfill{ out.fill() }; - out.setf(std::ios_base::hex, std::ios_base::basefield); - out.fill('0'); - for (auto c : self.mData) - { - out << std::setw(2) << unsigned(c); - } - out.setf(oldfmt, std::ios_base::basefield); - out.fill(oldfill); - return out; - } - -private: - std::vector<unsigned char> mData; -}; - -// Format a given byte string as a mix of printable characters and, for each -// non-printable character, "\xnn" -// Usage: std::cout << hexmix(somestring) << ... -class hexmix -{ -public: - hexmix(const std::string_view& data): - mData(data) - {} - - hexmix(const char* data, size_t len): - mData(data, len) - {} - - friend std::ostream& operator<<(std::ostream& out, const hexmix& self) - { - auto oldfmt{ out.flags() }; - auto oldfill{ out.fill() }; - out.setf(std::ios_base::hex, std::ios_base::basefield); - out.fill('0'); - for (auto c : self.mData) - { - // std::isprint() must be passed an unsigned char! - if (std::isprint(static_cast<unsigned char>(c))) - { - out << c; - } - else - { - out << "\\x" << std::setw(2) << unsigned(c); - } - } - out.setf(oldfmt, std::ios_base::basefield); - out.fill(oldfill); - return out; - } - -private: - std::string mData; -}; - -#endif /* ! defined(LL_HEXDUMP_H) */ diff --git a/indra/test/io.cpp b/indra/test/io.cpp index 412f9ca1d2..5bc169fd78 100644 --- a/indra/test/io.cpp +++ b/indra/test/io.cpp @@ -45,6 +45,7 @@ #include "llcommon.h" #include "lluuid.h" #include "llinstantmessage.h" +#include "stringize.h" namespace tut { @@ -1116,6 +1117,9 @@ namespace tut template<> template<> void fitness_test_object::test<5>() { + skip("Test is strongly timing dependent, " + "and on slow CI machines it fails way too often."); + const int retries = 100; // Set up the server LLPumpIO::chain_t chain; typedef LLCloneIOFactory<LLIOSleeper> sleeper_t; @@ -1129,9 +1133,12 @@ namespace tut chain.push_back(LLIOPipe::ptr_t(server)); mPump->addChain(chain, NEVER_CHAIN_EXPIRY_SECS); // We need to tickle the pump a little to set up the listen() - pump_loop(mPump, 0.1f); + for (int retry = 0; mPump->runningChains() < 1 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } U32 count = mPump->runningChains(); - ensure_equals("server chain onboard", count, 1); + ensure_equals("server chain 1 onboard", count, 1); LL_DEBUGS() << "** Server is up." << LL_ENDL; // Set up the client @@ -1140,9 +1147,12 @@ namespace tut bool connected = client->blockingConnect(server_host); ensure("Connected to server", connected); LL_DEBUGS() << "connected" << LL_ENDL; - pump_loop(mPump,0.1f); + for (int retry = 0; mPump->runningChains() < 2 && retry < retries; ++retry) + { + pump_loop(mPump,0.1f); + } count = mPump->runningChains(); - ensure_equals("server chain onboard", count, 2); + ensure_equals("server chain 2 onboard", count, 2); LL_DEBUGS() << "** Client is connected." << LL_ENDL; // We have connected, since the socket reader does not block, @@ -1156,20 +1166,32 @@ namespace tut chain.clear(); // pump for a bit and make sure all 3 chains are running - pump_loop(mPump,0.1f); + for (int retry = 0; mPump->runningChains() < 3 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } count = mPump->runningChains(); - // ensure_equals("client chain onboard", count, 3); commented out because it fails frequently - appears to be timing sensitive + ensure_equals("client chain onboard", count, 3); LL_DEBUGS() << "** request should have been sent." << LL_ENDL; // pump for long enough the the client socket closes, and the // server socket should not be closed yet. - pump_loop(mPump,0.2f); + for (int retry = 0; mPump->runningChains() == 3 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } + // We used to test for count == 2 here, but on a slow test machine it + // can happen that not just one but two chains close before we reach + // this point. count = mPump->runningChains(); - ensure_equals("client chain timed out ", count, 2); + ensure(stringize("client chain timed out: count ", count), count < 3); LL_DEBUGS() << "** client chain should be closed." << LL_ENDL; // At this point, the socket should be closed by the timeout - pump_loop(mPump,1.0f); + for (int retry = 0; mPump->runningChains() > 1 && retry < retries; ++retry) + { + pump_loop(mPump, 0.1f); + } count = mPump->runningChains(); ensure_equals("accepted socked close", count, 1); LL_DEBUGS() << "** Sleeper should have timed out.." << LL_ENDL; diff --git a/indra/test/lltut.h b/indra/test/lltut.h index e56b4e8d1c..fbf60444be 100644 --- a/indra/test/lltut.h +++ b/indra/test/lltut.h @@ -31,6 +31,8 @@ #include "is_approx_equal_fraction.h" // instead of llmath.h #include <cstring> +#include <string> +#include <vector> class LLDate; class LLSD; diff --git a/indra/test/print.h b/indra/test/print.h index 7577698cc8..749603907e 100644 --- a/indra/test/print.h +++ b/indra/test/print.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2020-01-02 * @brief print() function for debugging - * + * * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Copyright (c) 2020, Linden Research, Inc. * $/LicenseInfo$ @@ -23,7 +23,9 @@ struct NONL_t {}; inline void print() { +#ifdef LL_TEST std::cerr << std::endl; +#endif } // print(NONL) is a no-op @@ -35,8 +37,10 @@ void print(NONL_t) template <typename T, typename... ARGS> void print(T&& first, ARGS&&... rest) { +#ifdef LL_TEST std::cerr << first; print(std::forward<ARGS>(rest)...); +#endif } #endif /* ! defined(LL_PRINT_H) */ |