mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-20 11:45:53 +00:00
@@ -114,8 +114,6 @@ target_sources(
|
||||
rpc/RPCHelpersTests.cpp
|
||||
rpc/WorkQueueTests.cpp
|
||||
test_data/SslCert.cpp
|
||||
util/AccountUtilsTests.cpp
|
||||
util/AssertTests.cpp
|
||||
# Async framework
|
||||
util/async/AnyExecutionContextTests.cpp
|
||||
util/async/AnyOperationTests.cpp
|
||||
@@ -140,6 +138,10 @@ target_sources(
|
||||
util/requests/RequestBuilderTests.cpp
|
||||
util/requests/SslContextTests.cpp
|
||||
util/requests/WsConnectionTests.cpp
|
||||
# Common utils
|
||||
util/AccountUtilsTests.cpp
|
||||
util/AssertTests.cpp
|
||||
util/MoveTrackerTests.cpp
|
||||
util/RandomTests.cpp
|
||||
util/RetryTests.cpp
|
||||
util/RepeatTests.cpp
|
||||
|
||||
68
tests/unit/util/MoveTrackerTests.cpp
Normal file
68
tests/unit/util/MoveTrackerTests.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2025, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "util/MoveTracker.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
struct MoveMe : util::MoveTracker {
|
||||
using MoveTracker::wasMoved; // expose as public for tests
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(MoveTrackerTests, SimpleChecks)
|
||||
{
|
||||
auto moveMe = MoveMe();
|
||||
EXPECT_FALSE(moveMe.wasMoved());
|
||||
|
||||
auto other = std::move(moveMe);
|
||||
EXPECT_TRUE(moveMe.wasMoved());
|
||||
EXPECT_FALSE(other.wasMoved());
|
||||
}
|
||||
|
||||
TEST(MoveTrackerTests, SupportReuse)
|
||||
{
|
||||
auto original = MoveMe();
|
||||
auto other = std::move(original);
|
||||
|
||||
original = std::move(other);
|
||||
EXPECT_FALSE(original.wasMoved());
|
||||
EXPECT_TRUE(other.wasMoved());
|
||||
}
|
||||
|
||||
TEST(MoveTrackerTests, SelfMove)
|
||||
{
|
||||
auto original = MoveMe();
|
||||
[&](MoveMe& from) { original = std::move(from); }(original); // avoids the compiler catching self-move
|
||||
|
||||
EXPECT_FALSE(original.wasMoved());
|
||||
}
|
||||
|
||||
TEST(MoveTrackerTests, SelfMoveAfterWasMoved)
|
||||
{
|
||||
auto original = MoveMe();
|
||||
[[maybe_unused]] auto fake = std::move(original);
|
||||
|
||||
[&](MoveMe& from) { original = std::move(from); }(original); // avoids the compiler catching self-move
|
||||
|
||||
EXPECT_TRUE(original.wasMoved());
|
||||
}
|
||||
@@ -34,8 +34,6 @@
|
||||
using namespace util::async;
|
||||
using ::testing::Types;
|
||||
|
||||
using ExecutionContextTypes = Types<CoroExecutionContext, PoolExecutionContext, SyncExecutionContext>;
|
||||
|
||||
template <typename T>
|
||||
struct ExecutionContextTests : public ::testing::Test {
|
||||
using ExecutionContextType = T;
|
||||
@@ -48,7 +46,15 @@ struct ExecutionContextTests : public ::testing::Test {
|
||||
}
|
||||
};
|
||||
|
||||
// Suite for tests to be ran against all context types but SyncExecutionContext
|
||||
template <typename T>
|
||||
using AsyncExecutionContextTests = ExecutionContextTests<T>;
|
||||
|
||||
using ExecutionContextTypes = Types<CoroExecutionContext, PoolExecutionContext, SyncExecutionContext>;
|
||||
using AsyncExecutionContextTypes = Types<CoroExecutionContext, PoolExecutionContext>;
|
||||
|
||||
TYPED_TEST_CASE(ExecutionContextTests, ExecutionContextTypes);
|
||||
TYPED_TEST_CASE(AsyncExecutionContextTests, AsyncExecutionContextTypes);
|
||||
|
||||
TYPED_TEST(ExecutionContextTests, move)
|
||||
{
|
||||
@@ -149,6 +155,26 @@ TYPED_TEST(ExecutionContextTests, timerCancel)
|
||||
EXPECT_EQ(value, 42);
|
||||
}
|
||||
|
||||
TYPED_TEST(ExecutionContextTests, timerAutoCancels)
|
||||
{
|
||||
auto value = 0;
|
||||
std::binary_semaphore sem{0};
|
||||
{
|
||||
auto res = this->ctx.scheduleAfter(
|
||||
std::chrono::milliseconds(1),
|
||||
[&value, &sem]([[maybe_unused]] auto stopRequested, auto cancelled) {
|
||||
if (cancelled)
|
||||
value = 42;
|
||||
|
||||
sem.release();
|
||||
}
|
||||
);
|
||||
} // res goes out of scope and cancels the timer
|
||||
|
||||
sem.acquire();
|
||||
EXPECT_EQ(value, 42);
|
||||
}
|
||||
|
||||
TYPED_TEST(ExecutionContextTests, timerStdException)
|
||||
{
|
||||
auto res =
|
||||
@@ -247,6 +273,46 @@ TYPED_TEST(ExecutionContextTests, strandWithTimeout)
|
||||
EXPECT_EQ(res.get().value(), 42);
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncExecutionContextTests, executeAutoAborts)
|
||||
{
|
||||
auto value = 0;
|
||||
std::binary_semaphore sem{0};
|
||||
|
||||
{
|
||||
auto res = this->ctx.execute([&](auto stopRequested) {
|
||||
while (not stopRequested)
|
||||
;
|
||||
value = 42;
|
||||
sem.release();
|
||||
});
|
||||
} // res goes out of scope and aborts operation
|
||||
|
||||
sem.acquire();
|
||||
EXPECT_EQ(value, 42);
|
||||
}
|
||||
|
||||
TYPED_TEST(AsyncExecutionContextTests, repeatingOperationAutoAborts)
|
||||
{
|
||||
auto const repeatDelay = std::chrono::milliseconds{1};
|
||||
auto const timeout = std::chrono::milliseconds{15};
|
||||
auto callCount = 0uz;
|
||||
auto timeSpentMs = 0u;
|
||||
|
||||
{
|
||||
auto res = this->ctx.executeRepeatedly(repeatDelay, [&] { ++callCount; });
|
||||
timeSpentMs = util::timed([timeout] { std::this_thread::sleep_for(timeout); }); // calculate actual time spent
|
||||
} // res goes out of scope and automatically aborts the repeating operation
|
||||
|
||||
// double the delay so that if abort did not happen we will fail below expectations
|
||||
std::this_thread::sleep_for(timeout);
|
||||
|
||||
auto const expectedPureCalls = timeout.count() / repeatDelay.count();
|
||||
auto const expectedActualCount = timeSpentMs / repeatDelay.count();
|
||||
|
||||
EXPECT_GE(callCount, expectedPureCalls / 2u); // expect at least half of the scheduled calls
|
||||
EXPECT_LE(callCount, expectedActualCount); // never should be called more times than possible before timeout
|
||||
}
|
||||
|
||||
using NoErrorHandlerSyncExecutionContext = BasicExecutionContext<
|
||||
impl::SameThreadContext,
|
||||
impl::BasicStopSource,
|
||||
|
||||
Reference in New Issue
Block a user