yams/tests/unit/metadata/connection_pool_catch2_test.cpp

151 lines
4.6 KiB
C++

// Catch2 migration of connection pool tests
// Migration: yams-3s4 / yams-aqc (metadata tests)
// Covers:
// - connection_pool_maintenance_smoke_test.cpp
// - connection_pool_waiting_guard_test.cpp
#include <catch2/catch_test_macros.hpp>
#include <chrono>
#include <filesystem>
#include <thread>
#include <yams/metadata/connection_pool.h>
using namespace std::chrono_literals;
using namespace yams::metadata;
namespace {
std::filesystem::path make_db_path(const std::string& prefix) {
const char* t = std::getenv("YAMS_TEST_TMPDIR");
auto base = (t && *t) ? std::filesystem::path(t) : std::filesystem::temp_directory_path();
std::error_code ec;
std::filesystem::create_directories(base, ec);
auto ts = std::chrono::steady_clock::now().time_since_epoch().count();
auto p = base / (prefix + std::to_string(ts) + ".db");
std::filesystem::remove(p, ec);
return p;
}
} // namespace
// ============================================================================
// ConnectionPoolMaintenance - pruneIdleConnections
// ============================================================================
TEST_CASE("Connection pool prunes idle connections to min", "[metadata][connection_pool][slow]") {
ConnectionPoolConfig cfg;
cfg.minConnections = 1;
cfg.maxConnections = 4;
cfg.idleTimeout = std::chrono::seconds(1);
cfg.enableWAL = false;
ConnectionPool pool(make_db_path("pool_mt_").string(), cfg);
REQUIRE(pool.initialize().has_value());
// Acquire and release to create extra connections
{
auto c1 = pool.acquire();
REQUIRE(c1.has_value());
}
{
auto c2 = pool.acquire();
REQUIRE(c2.has_value());
}
// Let them become idle
std::this_thread::sleep_for(1500ms);
pool.pruneIdleConnections();
auto stats = pool.getStats();
// After prune, available connections should not exceed minConnections by much
CHECK(stats.availableConnections <= cfg.minConnections);
pool.shutdown();
}
// ============================================================================
// ConnectionPoolWaitingGuard - timeout behavior
// ============================================================================
TEST_CASE("Connection pool waiting counter resets on timeout", "[metadata][connection_pool]") {
ConnectionPoolConfig cfg;
cfg.minConnections = 1;
cfg.maxConnections = 1;
cfg.enableWAL = false;
cfg.busyTimeout = 50ms;
ConnectionPool pool(make_db_path("pool_wait_guard_").string(), cfg);
REQUIRE(pool.initialize().has_value());
auto first = pool.acquire();
REQUIRE(first.has_value());
auto second = pool.acquire(100ms);
REQUIRE_FALSE(second.has_value());
auto stats = pool.getStats();
CHECK(stats.waitingRequests == 0u);
CHECK(stats.maxObservedWaiting >= 1u);
CHECK(stats.totalWaitMicros > 0u);
CHECK(stats.timeoutCount == 1u);
pool.shutdown();
}
TEST_CASE("Connection pool immediate acquire does not count waiting",
"[metadata][connection_pool]") {
ConnectionPoolConfig cfg;
cfg.minConnections = 1;
cfg.maxConnections = 2;
cfg.enableWAL = false;
ConnectionPool pool(make_db_path("pool_wait_guard_").string(), cfg);
REQUIRE(pool.initialize().has_value());
{
auto conn = pool.acquire();
REQUIRE(conn.has_value());
}
auto stats = pool.getStats();
CHECK(stats.waitingRequests == 0u);
CHECK(stats.maxObservedWaiting == 0u);
CHECK(stats.totalWaitMicros == 0u);
CHECK(stats.timeoutCount == 0u);
pool.shutdown();
}
TEST_CASE("Connection pool histograms holder durations and warns on slow holds",
"[metadata][connection_pool]") {
ConnectionPoolConfig cfg;
cfg.minConnections = 1;
cfg.maxConnections = 1;
cfg.enableWAL = false;
ConnectionPool pool(make_db_path("pool_holder_hist_").string(), cfg);
REQUIRE(pool.initialize().has_value());
pool.setSlowHolderThreshold(std::chrono::milliseconds(20));
{
auto conn =
pool.acquire(std::chrono::milliseconds(1000), ConnectionPriority::Normal, "fast_path");
REQUIRE(conn.has_value());
}
{
auto conn =
pool.acquire(std::chrono::milliseconds(1000), ConnectionPriority::Normal, "slow_path");
REQUIRE(conn.has_value());
std::this_thread::sleep_for(std::chrono::milliseconds(60));
}
auto stats = pool.getStats();
std::uint64_t total = 0;
for (auto v : stats.holderDurationBuckets) {
total += v;
}
CHECK(total >= 2u);
CHECK(stats.slowHolderCount >= 1u);
CHECK(stats.maxHolderMicros >= 50'000u);
pool.shutdown();
}