Merge pull request #44 from jagerman/apple-test-tweaks

Tweak test timers to deal with Apple's shitty thread scheduling
This commit is contained in:
Jason Rhinelander 2021-08-04 20:02:59 -03:00 committed by GitHub
commit 29cd543af9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 24 additions and 13 deletions

View File

@ -1,7 +1,7 @@
set(LIBZMQ_PREFIX ${CMAKE_BINARY_DIR}/libzmq)
set(ZeroMQ_VERSION 4.3.3)
set(ZeroMQ_VERSION 4.3.4)
set(LIBZMQ_URL https://github.com/zeromq/libzmq/releases/download/v${ZeroMQ_VERSION}/zeromq-${ZeroMQ_VERSION}.tar.gz)
set(LIBZMQ_HASH SHA512=4c18d784085179c5b1fcb753a93813095a12c8d34970f2e1bfca6499be6c9d67769c71c68b7ca54ff181b20390043170e89733c22f76ff1ea46494814f7095b1)
set(LIBZMQ_HASH SHA512=e198ef9f82d392754caadd547537666d4fba0afd7d027749b3adae450516bcf284d241d4616cad3cb4ad9af8c10373d456de92dc6d115b037941659f141e7c0e)
message(${LIBZMQ_URL})

View File

@ -5,6 +5,16 @@
using namespace oxenmq;
// Apple's mutexes, thread scheduling, and IO handling are garbage and it shows up with lots of
// spurious failures in this test suite (because it expects a system to not suck that badly), so we
// multiply the time-sensitive bits by this factor as a hack to make the test suite work.
constexpr int TIME_DILATION =
#ifdef __APPLE__
5;
#else
1;
#endif
static auto startup = std::chrono::steady_clock::now();
/// Returns a localhost connection string to listen on. It can be considered random, though in
@ -30,7 +40,7 @@ inline void wait_for(Func f) {
for (int i = 0; i < 20; i++) {
if (f())
break;
std::this_thread::sleep_for(10ms);
std::this_thread::sleep_for(10ms * TIME_DILATION);
}
auto lock = catch_lock();
UNSCOPED_INFO("done waiting after " << (std::chrono::steady_clock::now() - start).count() << "ns");
@ -43,7 +53,7 @@ inline void wait_for_conn(std::atomic<bool> &c) {
}
/// Waits enough time for us to receive a reply from a localhost remote.
inline void reply_sleep() { std::this_thread::sleep_for(10ms); }
inline void reply_sleep() { std::this_thread::sleep_for(10ms * TIME_DILATION); }
inline OxenMQ::Logger get_logger(std::string prefix = "") {
std::string me = "tests/common.h";

View File

@ -470,7 +470,7 @@ TEST_CASE("deferred replies", "[commands][send][deferred]") {
std::string msg = m.data.empty() ? ""s : std::string{m.data.front()};
std::thread t{[send=m.send_later(), msg=std::move(msg)] {
{ auto lock = catch_lock(); UNSCOPED_INFO("sleeping"); }
std::this_thread::sleep_for(50ms);
std::this_thread::sleep_for(50ms * TIME_DILATION);
{ auto lock = catch_lock(); UNSCOPED_INFO("sending"); }
send.reply(msg);
}};
@ -516,7 +516,7 @@ TEST_CASE("deferred replies", "[commands][send][deferred]") {
auto lock = catch_lock();
REQUIRE( replies.size() == 0 ); // The server waits 50ms before sending, so we shouldn't have any reply yet
}
std::this_thread::sleep_for(60ms); // We're at least 70ms in now so the 50ms-delayed server responses should have arrived
std::this_thread::sleep_for(60ms * TIME_DILATION); // We're at least 70ms in now so the 50ms-delayed server responses should have arrived
{
std::lock_guard lq{reply_mut};
auto lock = catch_lock();

View File

@ -279,7 +279,7 @@ TEST_CASE("SN disconnections", "[connect][disconnect]") {
lmq[2]->send(pubkey[1], "sn.hi");
lmq[1]->send(pubkey[0], "BYE");
lmq[0]->send(pubkey[2], "sn.hi");
std::this_thread::sleep_for(50ms);
std::this_thread::sleep_for(50ms * TIME_DILATION);
auto lock = catch_lock();
REQUIRE(his == 5);

View File

@ -15,9 +15,10 @@ TEST_CASE("timer test", "[timer][basic]") {
auto start = std::chrono::steady_clock::now();
wait_for([&] { return ticks.load() > 3; });
{
auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
auto lock = catch_lock();
REQUIRE( ticks.load() > 3 );
REQUIRE( std::chrono::steady_clock::now() - start < 40ms );
REQUIRE( elapsed_ms < 50 * TIME_DILATION );
}
}
@ -35,13 +36,13 @@ TEST_CASE("timer squelch", "[timer][squelch]") {
// finishes, by which point we set `done` and so should get exactly 1 tick.
auto timer = omq.add_timer([&] {
if (first.exchange(false)) {
std::this_thread::sleep_for(30ms);
std::this_thread::sleep_for(30ms * TIME_DILATION);
ticks++;
done = true;
} else if (!done) {
ticks++;
}
}, 5ms, true /* squelch */);
}, 5ms * TIME_DILATION, true /* squelch */);
omq.start();
wait_for([&] { return done.load(); });
@ -58,7 +59,7 @@ TEST_CASE("timer squelch", "[timer][squelch]") {
std::atomic<int> ticks2 = 0;
auto timer2 = omq.add_timer([&] {
if (first2.exchange(false)) {
std::this_thread::sleep_for(30ms);
std::this_thread::sleep_for(40ms);
done2 = true;
} else if (!done2) {
ticks2++;
@ -82,13 +83,13 @@ TEST_CASE("timer cancel", "[timer][cancel]") {
std::atomic<int> ticks = 0;
// We set up *and cancel* this timer before omq starts, so it should never fire
auto notimer = omq.add_timer([&] { ticks += 1000; }, 5ms);
auto notimer = omq.add_timer([&] { ticks += 1000; }, 5ms * TIME_DILATION);
omq.cancel_timer(notimer);
TimerID timer = omq.add_timer([&] {
if (++ticks == 3)
omq.cancel_timer(timer);
}, 5ms);
}, 5ms * TIME_DILATION);
omq.start();