Reduce occurrences of sporadic PerfLog unit test failures

This commit is contained in:
Scott Schurr
2018-05-19 20:15:33 -07:00
committed by Mike Ellery
parent 833fae57db
commit 6a74d771ee

View File

@@ -49,8 +49,7 @@ class PerfLog_test : public beast::unit_test::suite
beast::Journal j_ {env_.app().journal ("PerfLog_test")}; beast::Journal j_ {env_.app().journal ("PerfLog_test")};
// Use this to make calls to random_shuffle() less predictable. // Use this to make calls to random_shuffle() less predictable.
std::random_device rd_; std::default_random_engine shuffler_ {std::random_device{}()};
std::default_random_engine shuffler_ {rd_()};
// A PerfLog needs a Parent that is a Stoppable and a function to // A PerfLog needs a Parent that is a Stoppable and a function to
// call if it wants to shutdown the system. This class provides both. // call if it wants to shutdown the system. This class provides both.
@@ -158,6 +157,8 @@ class PerfLog_test : public beast::unit_test::suite
} }
}; };
//------------------------------------------------------------------------------
// Convenience function to return a PerfLog // Convenience function to return a PerfLog
std::unique_ptr<perf::PerfLog> getPerfLog ( std::unique_ptr<perf::PerfLog> getPerfLog (
PerfLogParent& parent, WithFile withFile) PerfLogParent& parent, WithFile withFile)
@@ -166,13 +167,17 @@ class PerfLog_test : public beast::unit_test::suite
[&parent] () { return parent.signalStop(); }); [&parent] () { return parent.signalStop(); });
} }
//------------------------------------------------------------------------------
// Convenience function to return a uint64 given a Json::Value containing // Convenience function to return a uint64 given a Json::Value containing
// a string. // a string.
std::uint64_t jsonToUint64 (Json::Value const& jsonUintAsString) static std::uint64_t jsonToUint64 (Json::Value const& jsonUintAsString)
{ {
return std::stoull (jsonUintAsString.asString()); return std::stoull (jsonUintAsString.asString());
} }
//------------------------------------------------------------------------------
// The PerfLog's current state is easier to sort by duration if the // The PerfLog's current state is easier to sort by duration if the
// duration is converted from string to integer. The following struct // duration is converted from string to integer. The following struct
// is a way to think about the converted entry. // is a way to think about the converted entry.
@@ -190,7 +195,7 @@ class PerfLog_test : public beast::unit_test::suite
// A convenience function to convert JSON to Cur and sort. The sort // A convenience function to convert JSON to Cur and sort. The sort
// goes from longest to shortest duration. That way stuff that was started // goes from longest to shortest duration. That way stuff that was started
// earlier goes to the front. // earlier goes to the front.
std::vector<Cur> getSortedCurrent (Json::Value const& currentJson) static std::vector<Cur> getSortedCurrent (Json::Value const& currentJson)
{ {
std::vector<Cur> currents; std::vector<Cur> currents;
currents.reserve (currentJson.size()); currents.reserve (currentJson.size());
@@ -214,6 +219,38 @@ class PerfLog_test : public beast::unit_test::suite
return currents; return currents;
} }
//------------------------------------------------------------------------------
// Helper function that checks the size of the PerfLog file and then
// returns when the file gets bigger. This indicates that the PerfLog
// has written new values to the file and _should_ have the latest
// update.
static void waitForFileUpdate (PerfLogParent const& parent)
{
using namespace boost::filesystem;
auto const path = parent.getPerfLogPath() / parent.getPerfLogFileName();
if (!exists (path))
return;
// We wait for the file to change size twice. The first file size
// change may have been in process while we arrived.
std::uintmax_t const firstSize {file_size (path)};
std::uintmax_t secondSize {firstSize};
do
{
std::this_thread::sleep_for (parent.getLogInterval());
secondSize = file_size (path);
} while (firstSize >= secondSize);
do
{
std::this_thread::sleep_for (parent.getLogInterval());
} while (secondSize >= file_size (path));
}
//------------------------------------------------------------------------------
public: public:
void testFileCreation() void testFileCreation()
{ {
@@ -259,7 +296,7 @@ public:
// to not be able to write to its file. That should cause no // to not be able to write to its file. That should cause no
// problems. // problems.
parent.doStart(); parent.doStart();
std::this_thread::sleep_for (parent.getLogInterval() * 3); std::this_thread::sleep_for (parent.getLogInterval() * 10);
parent.doStop(); parent.doStop();
// Remove the file. // Remove the file.
@@ -312,7 +349,7 @@ public:
// to not be able to write to its file. That should cause no // to not be able to write to its file. That should cause no
// problems. // problems.
parent.doStart(); parent.doStart();
std::this_thread::sleep_for (parent.getLogInterval() * 3); std::this_thread::sleep_for (parent.getLogInterval() * 10);
parent.doStop(); parent.doStop();
// Fix file permissions so the file can be cleaned up. // Fix file permissions so the file can be cleaned up.
@@ -483,7 +520,7 @@ public:
validateFinalCurrent (perfLog->currentJson()); validateFinalCurrent (perfLog->currentJson());
// Give the PerfLog enough time to flush it's state to the file. // Give the PerfLog enough time to flush it's state to the file.
std::this_thread::sleep_for (parent.getLogInterval() * 3); waitForFileUpdate (parent);
// Politely stop the PerfLog. // Politely stop the PerfLog.
parent.doStop(); parent.doStop();
@@ -829,7 +866,7 @@ public:
validateFinalCurrent (perfLog->currentJson()); validateFinalCurrent (perfLog->currentJson());
// Give the PerfLog enough time to flush it's state to the file. // Give the PerfLog enough time to flush it's state to the file.
std::this_thread::sleep_for (parent.getLogInterval() * 3); waitForFileUpdate (parent);
// Politely stop the PerfLog. // Politely stop the PerfLog.
parent.doStop(); parent.doStop();
@@ -929,7 +966,7 @@ public:
} }
}; };
// Lambda to validate currentJson (always empty) fore this test. // Lambda to validate currentJson (always empty) for this test.
auto verifyEmptyCurrent = [this] (Json::Value const& currentJson) auto verifyEmptyCurrent = [this] (Json::Value const& currentJson)
{ {
BEAST_EXPECT(currentJson.isObject()); BEAST_EXPECT(currentJson.isObject());
@@ -969,7 +1006,7 @@ public:
verifyEmptyCurrent (perfLog->currentJson()); verifyEmptyCurrent (perfLog->currentJson());
// Give the PerfLog enough time to flush it's state to the file. // Give the PerfLog enough time to flush it's state to the file.
std::this_thread::sleep_for (parent.getLogInterval() * 3); waitForFileUpdate (parent);
// Politely stop the PerfLog. // Politely stop the PerfLog.
parent.doStop(); parent.doStop();
@@ -1038,7 +1075,7 @@ public:
// Start PerfLog and wait long enough for PerfLog::report() // Start PerfLog and wait long enough for PerfLog::report()
// to write to its file. // to write to its file.
parent.doStart(); parent.doStart();
std::this_thread::sleep_for (parent.getLogInterval() * 3); waitForFileUpdate (parent);
decltype (file_size (fullPath)) firstFileSize {0}; decltype (file_size (fullPath)) firstFileSize {0};
if (withFile == WithFile::no) if (withFile == WithFile::no)
@@ -1053,7 +1090,7 @@ public:
// Rotate and then wait to make sure more stuff is written to the file. // Rotate and then wait to make sure more stuff is written to the file.
perfLog->rotate(); perfLog->rotate();
std::this_thread::sleep_for (parent.getLogInterval() * 3); waitForFileUpdate (parent);
parent.doStop(); parent.doStop();