mirror of
https://github.com/latentPrion/libspinscale.git
synced 2026-06-24 03:48:34 +00:00
Adversarial review on test porting plan
This commit is contained in:
+121
-21
@@ -1,8 +1,11 @@
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -36,19 +39,77 @@ using CalleeIntInvoker =
|
||||
using Clock = std::chrono::steady_clock;
|
||||
using Ms = std::chrono::milliseconds;
|
||||
|
||||
CalleeIntInvoker waitDeadlineTimer(int timerLabelMilliseconds)
|
||||
class GroupTimerThreadTrace
|
||||
{
|
||||
public:
|
||||
void recordTimerCompletionThread(int timerLabelMilliseconds)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
timerCompletionThreads[timerLabelMilliseconds] =
|
||||
std::this_thread::get_id();
|
||||
}
|
||||
|
||||
void recordAwaitFirstResumeThread()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
awaitFirstResumeThread = std::this_thread::get_id();
|
||||
}
|
||||
|
||||
void recordAwaitAllResumeThread()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
awaitAllResumeThread = std::this_thread::get_id();
|
||||
}
|
||||
|
||||
std::thread::id timerCompletionThread(int timerLabelMilliseconds) const
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
const auto iterator =
|
||||
timerCompletionThreads.find(timerLabelMilliseconds);
|
||||
|
||||
if (iterator == timerCompletionThreads.end()) {
|
||||
throw std::runtime_error("Missing timer completion thread trace");
|
||||
}
|
||||
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
std::thread::id awaitFirstThread() const
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
return awaitFirstResumeThread;
|
||||
}
|
||||
|
||||
std::thread::id awaitAllThread() const
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
return awaitAllResumeThread;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::mutex mutex;
|
||||
std::map<int, std::thread::id> timerCompletionThreads;
|
||||
std::thread::id awaitFirstResumeThread;
|
||||
std::thread::id awaitAllResumeThread;
|
||||
};
|
||||
|
||||
CalleeIntInvoker waitDeadlineTimer(
|
||||
int timerLabelMilliseconds,
|
||||
GroupTimerThreadTrace &trace)
|
||||
{
|
||||
const boost::system::error_code waitError =
|
||||
co_await sscl::tests::DeadlineTimerAwaiter{
|
||||
sscl::ComponentThread::getSelf()->getIoContext(),
|
||||
timerLabelMilliseconds};
|
||||
sscl::tests::throwIfTimerWaitFailed(waitError);
|
||||
trace.recordTimerCompletionThread(timerLabelMilliseconds);
|
||||
co_return timerLabelMilliseconds;
|
||||
}
|
||||
|
||||
CalleeIntInvoker waitCancelableDeadlineTimer(
|
||||
int timerLabelMilliseconds,
|
||||
sscl::tests::CancelableDeadlineTimerRegistry ®istry)
|
||||
sscl::tests::CancelableDeadlineTimerRegistry ®istry,
|
||||
GroupTimerThreadTrace &trace)
|
||||
{
|
||||
const boost::system::error_code waitError =
|
||||
co_await sscl::tests::RegisteredDeadlineTimerAwaiter{
|
||||
@@ -58,10 +119,12 @@ CalleeIntInvoker waitCancelableDeadlineTimer(
|
||||
registry};
|
||||
|
||||
if (sscl::tests::timerWasCanceled(waitError)) {
|
||||
trace.recordTimerCompletionThread(timerLabelMilliseconds);
|
||||
co_return timerLabelMilliseconds;
|
||||
}
|
||||
|
||||
sscl::tests::throwIfTimerWaitFailed(waitError);
|
||||
trace.recordTimerCompletionThread(timerLabelMilliseconds);
|
||||
co_return timerLabelMilliseconds;
|
||||
}
|
||||
|
||||
@@ -89,15 +152,19 @@ void throwIfElapsedTooShort(
|
||||
|
||||
CallerDriver runGroupTimerRace(
|
||||
std::exception_ptr &exceptionPtr,
|
||||
std::function<void()> completion)
|
||||
std::function<void()> completion,
|
||||
GroupTimerThreadTrace &trace)
|
||||
{
|
||||
(void)exceptionPtr;
|
||||
(void)completion;
|
||||
|
||||
sscl::co::Group group;
|
||||
CalleeIntInvoker invokerShort = waitDeadlineTimer(timerDelayShortMs);
|
||||
CalleeIntInvoker invokerMedium = waitDeadlineTimer(timerDelayMediumMs);
|
||||
CalleeIntInvoker invokerLong = waitDeadlineTimer(timerDelayLongMs);
|
||||
CalleeIntInvoker invokerShort =
|
||||
waitDeadlineTimer(timerDelayShortMs, trace);
|
||||
CalleeIntInvoker invokerMedium =
|
||||
waitDeadlineTimer(timerDelayMediumMs, trace);
|
||||
CalleeIntInvoker invokerLong =
|
||||
waitDeadlineTimer(timerDelayLongMs, trace);
|
||||
|
||||
group.add(invokerShort);
|
||||
group.add(invokerMedium);
|
||||
@@ -107,6 +174,7 @@ CallerDriver runGroupTimerRace(
|
||||
|
||||
auto awaitFirst = group.getAwaitFirstSettlementInvoker();
|
||||
auto [firstSettlement, allSettlementsAfterFirst] = co_await awaitFirst;
|
||||
trace.recordAwaitFirstResumeThread();
|
||||
|
||||
const auto firstElapsedMs =
|
||||
std::chrono::duration_cast<Ms>(Clock::now() - testStart);
|
||||
@@ -125,6 +193,7 @@ CallerDriver runGroupTimerRace(
|
||||
|
||||
auto awaitAll = group.getAwaitAllSettlementsInvoker();
|
||||
auto &allSettlements = co_await awaitAll;
|
||||
trace.recordAwaitAllResumeThread();
|
||||
|
||||
const auto allElapsedMs =
|
||||
std::chrono::duration_cast<Ms>(Clock::now() - testStart);
|
||||
@@ -137,16 +206,16 @@ CallerDriver runGroupTimerRace(
|
||||
throw std::runtime_error("expected three settlements");
|
||||
}
|
||||
|
||||
sscl::tests::expectCompletedIntSettlement<CalleeIntInvoker>(
|
||||
sscl::tests::requireCompletedIntSettlement<CalleeIntInvoker>(
|
||||
firstSettlement,
|
||||
timerDelayShortMs);
|
||||
sscl::tests::expectCompletedIntSettlement<CalleeIntInvoker>(
|
||||
sscl::tests::requireCompletedIntSettlement<CalleeIntInvoker>(
|
||||
allSettlementsAfterFirst[0],
|
||||
timerDelayShortMs);
|
||||
sscl::tests::expectCompletedIntSettlement<CalleeIntInvoker>(
|
||||
sscl::tests::requireCompletedIntSettlement<CalleeIntInvoker>(
|
||||
allSettlementsAfterFirst[1],
|
||||
timerDelayMediumMs);
|
||||
sscl::tests::expectCompletedIntSettlement<CalleeIntInvoker>(
|
||||
sscl::tests::requireCompletedIntSettlement<CalleeIntInvoker>(
|
||||
allSettlementsAfterFirst[2],
|
||||
timerDelayLongMs);
|
||||
|
||||
@@ -156,18 +225,19 @@ CallerDriver runGroupTimerRace(
|
||||
CallerDriver runGroupTimerCancelLongAfterAwaitFirst(
|
||||
std::exception_ptr &exceptionPtr,
|
||||
std::function<void()> completion,
|
||||
sscl::tests::CancelableDeadlineTimerRegistry ®istry)
|
||||
sscl::tests::CancelableDeadlineTimerRegistry ®istry,
|
||||
GroupTimerThreadTrace &trace)
|
||||
{
|
||||
(void)exceptionPtr;
|
||||
(void)completion;
|
||||
|
||||
sscl::co::Group group;
|
||||
CalleeIntInvoker invokerShort =
|
||||
waitCancelableDeadlineTimer(timerDelayShortMs, registry);
|
||||
waitCancelableDeadlineTimer(timerDelayShortMs, registry, trace);
|
||||
CalleeIntInvoker invokerMedium =
|
||||
waitCancelableDeadlineTimer(timerDelayMediumMs, registry);
|
||||
waitCancelableDeadlineTimer(timerDelayMediumMs, registry, trace);
|
||||
CalleeIntInvoker invokerLong =
|
||||
waitCancelableDeadlineTimer(timerDelayLongMs, registry);
|
||||
waitCancelableDeadlineTimer(timerDelayLongMs, registry, trace);
|
||||
|
||||
group.add(invokerShort);
|
||||
group.add(invokerMedium);
|
||||
@@ -177,6 +247,7 @@ CallerDriver runGroupTimerCancelLongAfterAwaitFirst(
|
||||
|
||||
auto awaitFirst = group.getAwaitFirstSettlementInvoker();
|
||||
auto [firstSettlement, allSettlementsAfterFirst] = co_await awaitFirst;
|
||||
trace.recordAwaitFirstResumeThread();
|
||||
|
||||
if (&firstSettlement.invokerAs<CalleeIntInvoker>() != &invokerShort) {
|
||||
throw std::runtime_error("cancel test first settlement mismatch");
|
||||
@@ -190,6 +261,7 @@ CallerDriver runGroupTimerCancelLongAfterAwaitFirst(
|
||||
|
||||
auto awaitAll = group.getAwaitAllSettlementsInvoker();
|
||||
auto &allSettlements = co_await awaitAll;
|
||||
trace.recordAwaitAllResumeThread();
|
||||
|
||||
const auto allElapsedMs =
|
||||
std::chrono::duration_cast<Ms>(Clock::now() - testStart);
|
||||
@@ -207,13 +279,13 @@ CallerDriver runGroupTimerCancelLongAfterAwaitFirst(
|
||||
throw std::runtime_error("cancel test expected three settlements");
|
||||
}
|
||||
|
||||
sscl::tests::expectCompletedIntSettlement<CalleeIntInvoker>(
|
||||
sscl::tests::requireCompletedIntSettlement<CalleeIntInvoker>(
|
||||
allSettlements[0],
|
||||
timerDelayShortMs);
|
||||
sscl::tests::expectCompletedIntSettlement<CalleeIntInvoker>(
|
||||
sscl::tests::requireCompletedIntSettlement<CalleeIntInvoker>(
|
||||
allSettlements[1],
|
||||
timerDelayMediumMs);
|
||||
sscl::tests::expectCompletedIntSettlement<CalleeIntInvoker>(
|
||||
sscl::tests::requireCompletedIntSettlement<CalleeIntInvoker>(
|
||||
allSettlements[2],
|
||||
timerDelayLongMs);
|
||||
|
||||
@@ -229,6 +301,25 @@ class GroupTimerTest
|
||||
: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void assertTimerTraceCrossedThreads(
|
||||
const GroupTimerThreadTrace &trace)
|
||||
{
|
||||
EXPECT_EQ(
|
||||
trace.timerCompletionThread(timerDelayShortMs),
|
||||
threads.callee().osThreadId());
|
||||
EXPECT_EQ(
|
||||
trace.timerCompletionThread(timerDelayMediumMs),
|
||||
threads.callee().osThreadId());
|
||||
EXPECT_EQ(
|
||||
trace.timerCompletionThread(timerDelayLongMs),
|
||||
threads.callee().osThreadId());
|
||||
EXPECT_EQ(trace.awaitFirstThread(), threads.caller().osThreadId());
|
||||
EXPECT_EQ(trace.awaitAllThread(), threads.caller().osThreadId());
|
||||
EXPECT_NE(
|
||||
trace.timerCompletionThread(timerDelayShortMs),
|
||||
trace.awaitFirstThread());
|
||||
}
|
||||
|
||||
sscl::tests::PostingThreadSet threads;
|
||||
};
|
||||
|
||||
@@ -236,33 +327,42 @@ protected:
|
||||
|
||||
TEST_F(GroupTimerTest, AwaitFirstReturnsShortestTimerAndAwaitAllWaitsForLongest)
|
||||
{
|
||||
GroupTimerThreadTrace trace;
|
||||
|
||||
ASSERT_NO_THROW(
|
||||
sscl::tests::runNonViralPostingTask(
|
||||
threads.caller(),
|
||||
[](
|
||||
[&trace](
|
||||
std::exception_ptr &exceptionPtr,
|
||||
std::function<void()> completion)
|
||||
{
|
||||
return runGroupTimerRace(
|
||||
exceptionPtr,
|
||||
std::move(completion));
|
||||
std::move(completion),
|
||||
trace);
|
||||
}));
|
||||
|
||||
assertTimerTraceCrossedThreads(trace);
|
||||
}
|
||||
|
||||
TEST_F(GroupTimerTest, CancelLongTimerAfterAwaitFirst)
|
||||
{
|
||||
sscl::tests::CancelableDeadlineTimerRegistry registry;
|
||||
GroupTimerThreadTrace trace;
|
||||
|
||||
ASSERT_NO_THROW(
|
||||
sscl::tests::runNonViralPostingTask(
|
||||
threads.caller(),
|
||||
[®istry](
|
||||
[®istry, &trace](
|
||||
std::exception_ptr &exceptionPtr,
|
||||
std::function<void()> completion)
|
||||
{
|
||||
return runGroupTimerCancelLongAfterAwaitFirst(
|
||||
exceptionPtr,
|
||||
std::move(completion),
|
||||
registry);
|
||||
registry,
|
||||
trace);
|
||||
}));
|
||||
|
||||
assertTimerTraceCrossedThreads(trace);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user