Commit c3ac4113 authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot

update EventBaseTest to use precise timing with libevent2

Summary:
Change the EventBaseTest code to request precise timing from libevent.
libevent 2.1+ uses a coarse monotonic clock by default on Linux.
This causes several of folly's timing-related tests for EventBase to fail most
of the time.

This changes the tests to request precise timing from libevent2, using the
`EVENT_PRECISE_TIMER`.  While we can request this programmatically, doing so
portably across libevent versions is awkward, so the environment variable is
the easiest solution for now.

Alternatively we could change the tests to use larger, coarser timeouts to
make them pass reliably.  However, this would make the tests slower.

Differential Revision: D15528322

fbshipit-source-id: 20dc55de36235e63910cf7fb5b67c6f2d509cc15
parent 7bf08cd2
......@@ -22,6 +22,7 @@
#include <folly/io/async/EventHandler.h>
#include <folly/io/async/test/SocketPair.h>
#include <folly/io/async/test/Util.h>
#include <folly/portability/Stdlib.h>
#include <folly/portability/Unistd.h>
#include <folly/futures/Promise.h>
......@@ -55,6 +56,22 @@ using namespace folly;
namespace {
class EventBaseTest : public ::testing::Test {
public:
EventBaseTest() {
// libevent 2.x uses a coarse monotonic timer by default on Linux.
// This timer is imprecise enough to cause several of our tests to fail.
//
// Set an environment variable that causes libevent to use a non-coarse
// timer. This can be controlled programmatically by using the
// EVENT_BASE_FLAG_PRECISE_TIMER flag with event_base_new_with_config().
// However, this would require more compile-time #ifdefs to tell if we are
// using libevent 2.1+ or not. Simply using the environment variable is
// the easiest option for now.
setenv("EVENT_PRECISE_TIMER", "1", 1);
}
};
enum { BUF_SIZE = 4096 };
ssize_t writeToFD(int fd, size_t length) {
......@@ -189,7 +206,7 @@ class TestHandler : public EventHandler {
/**
* Test a READ event
*/
TEST(EventBaseTest, ReadEvent) {
TEST_F(EventBaseTest, ReadEvent) {
EventBase eb;
SocketPair sp;
......@@ -233,7 +250,7 @@ TEST(EventBaseTest, ReadEvent) {
/**
* Test (READ | PERSIST)
*/
TEST(EventBaseTest, ReadPersist) {
TEST_F(EventBaseTest, ReadPersist) {
EventBase eb;
SocketPair sp;
......@@ -279,7 +296,7 @@ TEST(EventBaseTest, ReadPersist) {
/**
* Test registering for READ when the socket is immediately readable
*/
TEST(EventBaseTest, ReadImmediate) {
TEST_F(EventBaseTest, ReadImmediate) {
EventBase eb;
SocketPair sp;
......@@ -328,7 +345,7 @@ TEST(EventBaseTest, ReadImmediate) {
/**
* Test a WRITE event
*/
TEST(EventBaseTest, WriteEvent) {
TEST_F(EventBaseTest, WriteEvent) {
EventBase eb;
SocketPair sp;
......@@ -369,7 +386,7 @@ TEST(EventBaseTest, WriteEvent) {
/**
* Test (WRITE | PERSIST)
*/
TEST(EventBaseTest, WritePersist) {
TEST_F(EventBaseTest, WritePersist) {
EventBase eb;
SocketPair sp;
......@@ -416,7 +433,7 @@ TEST(EventBaseTest, WritePersist) {
/**
* Test registering for WRITE when the socket is immediately writable
*/
TEST(EventBaseTest, WriteImmediate) {
TEST_F(EventBaseTest, WriteImmediate) {
EventBase eb;
SocketPair sp;
......@@ -463,7 +480,7 @@ TEST(EventBaseTest, WriteImmediate) {
/**
* Test (READ | WRITE) when the socket becomes readable first
*/
TEST(EventBaseTest, ReadWrite) {
TEST_F(EventBaseTest, ReadWrite) {
EventBase eb;
SocketPair sp;
......@@ -503,7 +520,7 @@ TEST(EventBaseTest, ReadWrite) {
/**
* Test (READ | WRITE) when the socket becomes writable first
*/
TEST(EventBaseTest, WriteRead) {
TEST_F(EventBaseTest, WriteRead) {
EventBase eb;
SocketPair sp;
......@@ -550,7 +567,7 @@ TEST(EventBaseTest, WriteRead) {
* Test (READ | WRITE) when the socket becomes readable and writable
* at the same time.
*/
TEST(EventBaseTest, ReadWriteSimultaneous) {
TEST_F(EventBaseTest, ReadWriteSimultaneous) {
EventBase eb;
SocketPair sp;
......@@ -590,7 +607,7 @@ TEST(EventBaseTest, ReadWriteSimultaneous) {
/**
* Test (READ | WRITE | PERSIST)
*/
TEST(EventBaseTest, ReadWritePersist) {
TEST_F(EventBaseTest, ReadWritePersist) {
EventBase eb;
SocketPair sp;
......@@ -673,7 +690,7 @@ class PartialReadHandler : public TestHandler {
* When PERSIST is used, make sure the handler gets notified again the next
* time around the loop.
*/
TEST(EventBaseTest, ReadPartial) {
TEST_F(EventBaseTest, ReadPartial) {
EventBase eb;
SocketPair sp;
......@@ -739,7 +756,7 @@ class PartialWriteHandler : public TestHandler {
* becomes writable. When PERSIST is used, make sure the handler gets
* notified again the next time around the loop.
*/
TEST(EventBaseTest, WritePartial) {
TEST_F(EventBaseTest, WritePartial) {
EventBase eb;
SocketPair sp;
......@@ -785,7 +802,7 @@ TEST(EventBaseTest, WritePartial) {
/**
* Test destroying a registered EventHandler
*/
TEST(EventBaseTest, DestroyHandler) {
TEST_F(EventBaseTest, DestroyHandler) {
class DestroyHandler : public AsyncTimeout {
public:
DestroyHandler(EventBase* eb, EventHandler* h)
......@@ -837,7 +854,7 @@ TEST(EventBaseTest, DestroyHandler) {
// Tests for timeout events
///////////////////////////////////////////////////////////////////////////
TEST(EventBaseTest, RunAfterDelay) {
TEST_F(EventBaseTest, RunAfterDelay) {
EventBase eb;
TimePoint timestamp1(false);
......@@ -865,7 +882,7 @@ TEST(EventBaseTest, RunAfterDelay) {
* Test the behavior of tryRunAfterDelay() when some timeouts are
* still scheduled when the EventBase is destroyed.
*/
TEST(EventBaseTest, RunAfterDelayDestruction) {
TEST_F(EventBaseTest, RunAfterDelayDestruction) {
TimePoint timestamp1(false);
TimePoint timestamp2(false);
TimePoint timestamp3(false);
......@@ -917,7 +934,7 @@ class TestTimeout : public AsyncTimeout {
};
} // namespace
TEST(EventBaseTest, BasicTimeouts) {
TEST_F(EventBaseTest, BasicTimeouts) {
EventBase eb;
TestTimeout t1(&eb);
......@@ -971,7 +988,7 @@ class ReschedulingTimeout : public AsyncTimeout {
/**
* Test rescheduling the same timeout multiple times
*/
TEST(EventBaseTest, ReuseTimeout) {
TEST_F(EventBaseTest, ReuseTimeout) {
EventBase eb;
vector<uint32_t> timeouts;
......@@ -1002,7 +1019,7 @@ TEST(EventBaseTest, ReuseTimeout) {
/**
* Test rescheduling a timeout before it has fired
*/
TEST(EventBaseTest, RescheduleTimeout) {
TEST_F(EventBaseTest, RescheduleTimeout) {
EventBase eb;
TestTimeout t1(&eb);
......@@ -1034,7 +1051,7 @@ TEST(EventBaseTest, RescheduleTimeout) {
/**
* Test cancelling a timeout
*/
TEST(EventBaseTest, CancelTimeout) {
TEST_F(EventBaseTest, CancelTimeout) {
EventBase eb;
vector<uint32_t> timeouts;
......@@ -1059,7 +1076,7 @@ TEST(EventBaseTest, CancelTimeout) {
/**
* Test destroying a scheduled timeout object
*/
TEST(EventBaseTest, DestroyTimeout) {
TEST_F(EventBaseTest, DestroyTimeout) {
class DestroyTimeout : public AsyncTimeout {
public:
DestroyTimeout(EventBase* eb, AsyncTimeout* t)
......@@ -1091,7 +1108,7 @@ TEST(EventBaseTest, DestroyTimeout) {
/**
* Test the scheduled executor impl
*/
TEST(EventBaseTest, ScheduledFn) {
TEST_F(EventBaseTest, ScheduledFn) {
EventBase eb;
TimePoint timestamp1(false);
......@@ -1114,7 +1131,7 @@ TEST(EventBaseTest, ScheduledFn) {
T_CHECK_TIMEOUT(start, end, milliseconds(39));
}
TEST(EventBaseTest, ScheduledFnAt) {
TEST_F(EventBaseTest, ScheduledFnAt) {
EventBase eb;
TimePoint timestamp0(false);
......@@ -1185,7 +1202,7 @@ void runInThreadTestFunc(RunInThreadArg* arg) {
} // namespace
TEST(EventBaseTest, RunInThread) {
TEST_F(EventBaseTest, RunInThread) {
constexpr uint32_t numThreads = 50;
constexpr uint32_t opsPerThread = 100;
RunInThreadData data(numThreads, opsPerThread);
......@@ -1251,7 +1268,7 @@ TEST(EventBaseTest, RunInThread) {
// This test simulates some calls, and verifies that the waiting happens by
// triggering what otherwise would be race conditions, and trying to detect
// whether any of the race conditions happened.
TEST(EventBaseTest, RunInEventBaseThreadAndWait) {
TEST_F(EventBaseTest, RunInEventBaseThreadAndWait) {
const size_t c = 256;
vector<unique_ptr<atomic<size_t>>> atoms(c);
for (size_t i = 0; i < c; ++i) {
......@@ -1288,7 +1305,7 @@ TEST(EventBaseTest, RunInEventBaseThreadAndWait) {
EXPECT_EQ(c, sum);
}
TEST(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitCross) {
TEST_F(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitCross) {
EventBase eb;
thread th(&EventBase::loopForever, &eb);
SCOPE_EXIT {
......@@ -1300,7 +1317,7 @@ TEST(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitCross) {
EXPECT_TRUE(mutated);
}
TEST(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitWithin) {
TEST_F(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitWithin) {
EventBase eb;
thread th(&EventBase::loopForever, &eb);
SCOPE_EXIT {
......@@ -1314,7 +1331,7 @@ TEST(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadAndWaitWithin) {
});
}
TEST(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadNotLooping) {
TEST_F(EventBaseTest, RunImmediatelyOrRunInEventBaseThreadNotLooping) {
EventBase eb;
auto mutated = false;
eb.runImmediatelyOrRunInEventBaseThreadAndWait([&] { mutated = true; });
......@@ -1356,7 +1373,7 @@ class CountedLoopCallback : public EventBase::LoopCallback {
// Test that EventBase::loop() doesn't exit while there are
// still LoopCallbacks remaining to be invoked.
TEST(EventBaseTest, RepeatedRunInLoop) {
TEST_F(EventBaseTest, RepeatedRunInLoop) {
EventBase eventBase;
CountedLoopCallback c(&eventBase, 10);
......@@ -1371,7 +1388,7 @@ TEST(EventBaseTest, RepeatedRunInLoop) {
}
// Test that EventBase::loop() works as expected without time measurements.
TEST(EventBaseTest, RunInLoopNoTimeMeasurement) {
TEST_F(EventBaseTest, RunInLoopNoTimeMeasurement) {
EventBase eventBase(false);
CountedLoopCallback c(&eventBase, 10);
......@@ -1386,7 +1403,7 @@ TEST(EventBaseTest, RunInLoopNoTimeMeasurement) {
}
// Test runInLoop() calls with terminateLoopSoon()
TEST(EventBaseTest, RunInLoopStopLoop) {
TEST_F(EventBaseTest, RunInLoopStopLoop) {
EventBase eventBase;
CountedLoopCallback c1(&eventBase, 20);
......@@ -1414,7 +1431,7 @@ TEST(EventBaseTest, RunInLoopStopLoop) {
ASSERT_LE(c1.getCount(), 11);
}
TEST(EventBaseTest, messageAvailableException) {
TEST_F(EventBaseTest, messageAvailableException) {
auto deadManWalking = [] {
EventBase eventBase;
std::thread t([&] {
......@@ -1429,7 +1446,7 @@ TEST(EventBaseTest, messageAvailableException) {
EXPECT_DEATH(deadManWalking(), ".*");
}
TEST(EventBaseTest, TryRunningAfterTerminate) {
TEST_F(EventBaseTest, TryRunningAfterTerminate) {
bool ran = false;
{
EventBase eventBase;
......@@ -1446,7 +1463,7 @@ TEST(EventBaseTest, TryRunningAfterTerminate) {
}
// Test cancelling runInLoop() callbacks
TEST(EventBaseTest, CancelRunInLoop) {
TEST_F(EventBaseTest, CancelRunInLoop) {
EventBase eventBase;
CountedLoopCallback c1(&eventBase, 20);
......@@ -1567,7 +1584,7 @@ class TerminateTestCallback : public EventBase::LoopCallback,
* EventBase::loop() incorrectly exited if there were no more fd handlers
* registered, but a loop callback installed a new fd handler.
*/
TEST(EventBaseTest, LoopTermination) {
TEST_F(EventBaseTest, LoopTermination) {
EventBase eventBase;
// Open a pipe and close the write end,
......@@ -1595,7 +1612,7 @@ TEST(EventBaseTest, LoopTermination) {
close(pipeFds[0]);
}
TEST(EventBaseTest, CallbackOrderTest) {
TEST_F(EventBaseTest, CallbackOrderTest) {
size_t num = 0;
EventBase evb;
......@@ -1620,7 +1637,7 @@ TEST(EventBaseTest, CallbackOrderTest) {
EXPECT_EQ(num, 2);
}
TEST(EventBaseTest, AlwaysEnqueueCallbackOrderTest) {
TEST_F(EventBaseTest, AlwaysEnqueueCallbackOrderTest) {
size_t num = 0;
EventBase evb;
......@@ -1695,7 +1712,7 @@ class IdleTimeTimeoutSeries : public AsyncTimeout {
* later timeout is far enough in the future that the idle time should have
* caused the loop time to decay.
*/
TEST(EventBaseTest, IdleTime) {
TEST_F(EventBaseTest, IdleTime) {
EventBase eventBase;
std::deque<std::size_t> timeouts0(4, 8080);
timeouts0.push_front(8000);
......@@ -1757,7 +1774,7 @@ TEST(EventBaseTest, IdleTime) {
/**
* Test that thisLoop functionality works with terminateLoopSoon
*/
TEST(EventBaseTest, ThisLoop) {
TEST_F(EventBaseTest, ThisLoop) {
bool runInLoop = false;
bool runThisLoop = false;
......@@ -1782,7 +1799,7 @@ TEST(EventBaseTest, ThisLoop) {
ASSERT_TRUE(runInLoop);
}
TEST(EventBaseTest, EventBaseThreadLoop) {
TEST_F(EventBaseTest, EventBaseThreadLoop) {
EventBase base;
bool ran = false;
......@@ -1792,7 +1809,7 @@ TEST(EventBaseTest, EventBaseThreadLoop) {
ASSERT_TRUE(ran);
}
TEST(EventBaseTest, EventBaseThreadName) {
TEST_F(EventBaseTest, EventBaseThreadName) {
EventBase base;
base.setName("foo");
base.loop();
......@@ -1804,7 +1821,7 @@ TEST(EventBaseTest, EventBaseThreadName) {
#endif
}
TEST(EventBaseTest, RunBeforeLoop) {
TEST_F(EventBaseTest, RunBeforeLoop) {
EventBase base;
CountedLoopCallback cb(&base, 1, [&]() { base.terminateLoopSoon(); });
base.runBeforeLoop(&cb);
......@@ -1812,7 +1829,7 @@ TEST(EventBaseTest, RunBeforeLoop) {
ASSERT_EQ(cb.getCount(), 0);
}
TEST(EventBaseTest, RunBeforeLoopWait) {
TEST_F(EventBaseTest, RunBeforeLoopWait) {
EventBase base;
CountedLoopCallback cb(&base, 1);
base.tryRunAfterDelay([&]() { base.terminateLoopSoon(); }, 500);
......@@ -1835,7 +1852,7 @@ class PipeHandler : public EventHandler {
};
} // namespace
TEST(EventBaseTest, StopBeforeLoop) {
TEST_F(EventBaseTest, StopBeforeLoop) {
EventBase evb;
// Give the evb something to do.
......@@ -1858,7 +1875,7 @@ TEST(EventBaseTest, StopBeforeLoop) {
SUCCEED();
}
TEST(EventBaseTest, RunCallbacksOnDestruction) {
TEST_F(EventBaseTest, RunCallbacksOnDestruction) {
bool ran = false;
{
......@@ -1869,7 +1886,7 @@ TEST(EventBaseTest, RunCallbacksOnDestruction) {
ASSERT_TRUE(ran);
}
TEST(EventBaseTest, LoopKeepAlive) {
TEST_F(EventBaseTest, LoopKeepAlive) {
EventBase evb;
bool done = false;
......@@ -1887,7 +1904,7 @@ TEST(EventBaseTest, LoopKeepAlive) {
t.join();
}
TEST(EventBaseTest, LoopKeepAliveInLoop) {
TEST_F(EventBaseTest, LoopKeepAliveInLoop) {
EventBase evb;
bool done = false;
......@@ -1909,7 +1926,7 @@ TEST(EventBaseTest, LoopKeepAliveInLoop) {
t.join();
}
TEST(EventBaseTest, LoopKeepAliveWithLoopForever) {
TEST_F(EventBaseTest, LoopKeepAliveWithLoopForever) {
std::unique_ptr<EventBase> evb = std::make_unique<EventBase>();
bool done = false;
......@@ -1937,7 +1954,7 @@ TEST(EventBaseTest, LoopKeepAliveWithLoopForever) {
ASSERT_TRUE(done);
}
TEST(EventBaseTest, LoopKeepAliveShutdown) {
TEST_F(EventBaseTest, LoopKeepAliveShutdown) {
auto evb = std::make_unique<EventBase>();
bool done = false;
......@@ -1958,7 +1975,7 @@ TEST(EventBaseTest, LoopKeepAliveShutdown) {
t.join();
}
TEST(EventBaseTest, LoopKeepAliveAtomic) {
TEST_F(EventBaseTest, LoopKeepAliveAtomic) {
auto evb = std::make_unique<EventBase>();
static constexpr size_t kNumThreads = 100;
......@@ -2003,12 +2020,12 @@ TEST(EventBaseTest, LoopKeepAliveAtomic) {
}
}
TEST(EventBaseTest, LoopKeepAliveCast) {
TEST_F(EventBaseTest, LoopKeepAliveCast) {
EventBase evb;
Executor::KeepAlive<> keepAlive = getKeepAliveToken(evb);
}
TEST(EventBaseTest, DrivableExecutorTest) {
TEST_F(EventBaseTest, DrivableExecutorTest) {
folly::Promise<bool> p;
auto f = p.getFuture();
EventBase base;
......@@ -2037,14 +2054,14 @@ TEST(EventBaseTest, DrivableExecutorTest) {
t.join();
}
TEST(EventBaseTest, IOExecutorTest) {
TEST_F(EventBaseTest, IOExecutorTest) {
EventBase base;
// Ensure EventBase manages itself as an IOExecutor.
EXPECT_EQ(base.getEventBase(), &base);
}
TEST(EventBaseTest, RequestContextTest) {
TEST_F(EventBaseTest, RequestContextTest) {
EventBase evb;
auto defaultCtx = RequestContext::get();
std::weak_ptr<RequestContext> rctx_weak_ptr;
......@@ -2065,7 +2082,7 @@ TEST(EventBaseTest, RequestContextTest) {
EXPECT_EQ(defaultCtx, RequestContext::get());
}
TEST(EventBaseTest, CancelLoopCallbackRequestContextTest) {
TEST_F(EventBaseTest, CancelLoopCallbackRequestContextTest) {
EventBase evb;
CountedLoopCallback c(&evb, 1);
......@@ -2089,7 +2106,7 @@ TEST(EventBaseTest, CancelLoopCallbackRequestContextTest) {
EXPECT_EQ(defaultCtx, RequestContext::get());
}
TEST(EventBaseTest, TestStarvation) {
TEST_F(EventBaseTest, TestStarvation) {
EventBase evb;
std::promise<void> stopRequested;
std::promise<void> stopScheduled;
......@@ -2122,7 +2139,7 @@ TEST(EventBaseTest, TestStarvation) {
t.join();
}
TEST(EventBaseTest, RunOnDestructionBasic) {
TEST_F(EventBaseTest, RunOnDestructionBasic) {
bool ranOnDestruction = false;
{
EventBase evb;
......@@ -2131,7 +2148,7 @@ TEST(EventBaseTest, RunOnDestructionBasic) {
EXPECT_TRUE(ranOnDestruction);
}
TEST(EventBaseTest, RunOnDestructionCancelled) {
TEST_F(EventBaseTest, RunOnDestructionCancelled) {
struct Callback : EventBase::OnDestructionCallback {
bool ranOnDestruction{false};
......@@ -2150,7 +2167,7 @@ TEST(EventBaseTest, RunOnDestructionCancelled) {
EXPECT_FALSE(cb->cancel());
}
TEST(EventBaseTest, RunOnDestructionAfterHandleDestroyed) {
TEST_F(EventBaseTest, RunOnDestructionAfterHandleDestroyed) {
EventBase evb;
{
bool ranOnDestruction = false;
......@@ -2162,7 +2179,7 @@ TEST(EventBaseTest, RunOnDestructionAfterHandleDestroyed) {
}
}
TEST(EventBaseTest, RunOnDestructionAddCallbackWithinCallback) {
TEST_F(EventBaseTest, RunOnDestructionAddCallbackWithinCallback) {
size_t callbacksCalled = 0;
{
EventBase evb;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment