Adversarial review on test porting plan

This commit is contained in:
2026-06-13 17:59:06 -04:00
parent a29c779f6e
commit 2f31e9a034
7 changed files with 593 additions and 173 deletions
+121 -21
View File
@@ -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 &registry)
sscl::tests::CancelableDeadlineTimerRegistry &registry,
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 &registry)
sscl::tests::CancelableDeadlineTimerRegistry &registry,
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(),
[&registry](
[&registry, &trace](
std::exception_ptr &exceptionPtr,
std::function<void()> completion)
{
return runGroupTimerCancelLongAfterAwaitFirst(
exceptionPtr,
std::move(completion),
registry);
registry,
trace);
}));
assertTimerTraceCrossedThreads(trace);
}