yams/tests/unit/cli/daemon_helpers_pool_catch2_test.cpp
Trevon 7df64b1161
perf(search): bound topology routing and harden runtime paths (#59)
* fix: address review build issues

* perf(search): bound topology routing

Cache route membership, shortlist centroids with static ANN, and route SPQ through explicit allowed-document budgets.

* test(xplan): measure routed vector work

Pin benchmark binary identity and export route, cache, and phase costs for repeated equal-budget comparisons.

* test(search): use portable jthread wrapper

* fix(daemon): serialize detached cancellation

* fix(cli): honor pinned daemon sockets

* fix(xplan): support Windows contract imports

* fix(list): apply metadata filters before paging

* docs(prompts): require memory hydration

Treat search results as candidates and hydrate selected artifacts before use. Quote argument hints for strict YAML loaders.

* test(cli): keep add on pinned daemon

* test(metadata): isolate performance timing

* fix(graph): tolerate stale snippet ranges

Source files may change before persisted symbol metadata is refreshed. Omit stale snippets instead of aborting graph exploration.

* test(daemon): await request readiness

Reuse the retrying list probe before asserting post-shutdown error quality under sanitizer load.

* ci(release): use hosted cmake

Resolve Conan CMake tool requirements from PATH so cold ARM64 caches do not depend on cmake.org. Default BUILD_DIR for failure cleanup.
2026-07-19 14:53:10 -04:00

88 lines
3.5 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <algorithm>
#include <chrono>
#include <memory>
#include <thread>
#include <yams/cli/daemon_helpers.h>
#include <yams/daemon/client/sandbox_probe.h>
#include "../../common/test_helpers_catch2.h"
using namespace std::chrono_literals;
TEST_CASE("DaemonClientPool pruning thread exits promptly on shutdown", "[cli][daemon][pool]") {
yams::daemon::ClientConfig clientCfg;
clientCfg.transportMode = yams::daemon::ClientTransportMode::InProcess;
yams::cli::DaemonClientPool::Config poolCfg;
poolCfg.min_clients = 1;
poolCfg.max_clients = 1;
poolCfg.idle_timeout = std::chrono::seconds(60);
poolCfg.client_config = clientCfg;
std::chrono::milliseconds worst{0};
for (int i = 0; i < 3; ++i) {
auto pool = std::make_unique<yams::cli::DaemonClientPool>(poolCfg);
// Let the pruning thread enter its wait state before destruction.
std::this_thread::sleep_for(80ms);
const auto start = std::chrono::steady_clock::now();
pool.reset();
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start);
worst = std::max(worst, elapsed);
}
CHECK(worst < 1100ms);
}
TEST_CASE("is_transport_failure classifies 'Daemon not ready yet' as transport",
"[cli][daemon][transport]") {
using yams::Error;
using yams::ErrorCode;
yams::Error notReady{ErrorCode::InvalidState,
"Daemon not ready yet for list (status=initializing)"};
CHECK(yams::cli::is_transport_failure(notReady));
yams::Error timeout{ErrorCode::Timeout, "deadline exceeded"};
CHECK(yams::cli::is_transport_failure(timeout));
yams::Error otherInvalid{ErrorCode::InvalidState, "unrelated invalid state"};
CHECK_FALSE(yams::cli::is_transport_failure(otherInvalid));
yams::Error notFound{ErrorCode::NotFound, "missing key"};
CHECK_FALSE(yams::cli::is_transport_failure(notFound));
}
TEST_CASE("Explicit pinned socket bypasses the generic sandbox probe", "[cli][daemon][transport]") {
struct ProbeReset {
~ProbeReset() { yams::daemon::set_unix_socket_probe_for_tests(nullptr); }
} probeReset;
yams::daemon::set_unix_socket_probe_for_tests([] { return false; });
yams::test::ScopedEnvVar embedded("YAMS_EMBEDDED", std::nullopt);
yams::test::ScopedEnvVar inDaemon("YAMS_IN_DAEMON", std::nullopt);
yams::test::ScopedEnvVar config(
"YAMS_CONFIG", std::string("/nonexistent/yams-daemon-helper-test-config.toml"));
yams::test::ScopedEnvVar socketPath("YAMS_DAEMON_SOCKET_PATH",
std::string("/tmp/yams-pinned-test.sock"));
yams::test::ScopedEnvVar legacySocket("YAMS_DAEMON_SOCKET", std::nullopt);
yams::test::ScopedEnvVar noAutoStart("YAMS_CLI_DISABLE_DAEMON_AUTOSTART", std::string("1"));
yams::daemon::ClientConfig configRequest;
auto plan = yams::cli::prepare_cli_daemon_client_plan(
configRequest, yams::cli::CliDaemonAccessPolicy::AllowInProcessFallback);
REQUIRE(plan);
const auto& resolved = plan.value();
CHECK(resolved.resolvedMode == yams::daemon::ClientTransportMode::Socket);
CHECK(resolved.config.transportMode == yams::daemon::ClientTransportMode::Socket);
CHECK(resolved.config.socketPath == "/tmp/yams-pinned-test.sock");
CHECK(resolved.requireSocket);
CHECK_FALSE(resolved.allowInProcessFallback);
CHECK_FALSE(resolved.config.autoStart);
}