#include // Validates multiplexing over a single socket does not hang #include #include #include #include #include // Ensure Boost.Asio awaitable/co_spawn are visible before including client header #include #include #include #include "integration/daemon/test_daemon_harness.h" #include #include using namespace yams; using namespace yams::daemon; TEST_CASE("MCPSocketStressTest.ManyConcurrentRequestsSingleSocket", "[stress][mcpsocketstresstest]") { yams::test::DaemonHarness harness; INFO("Failed to start daemon harness"); REQUIRE(harness.start()); ClientConfig cfg; cfg.socketPath = harness.socketPath(); cfg.singleUseConnections = false; cfg.maxInflight = 256; cfg.requestTimeout = std::chrono::milliseconds(10000); cfg.headerTimeout = std::chrono::milliseconds(5000); cfg.bodyTimeout = std::chrono::milliseconds(15000); cfg.autoStart = false; DaemonClient client(cfg); // Fire a burst of concurrent lightweight requests over the single socket const int concurrency = 64; const int rounds = 3; for (int r = 0; r < rounds; ++r) { auto results = std::make_shared>>>(concurrency); std::vector> futs; futs.reserve(concurrency); for (int i = 0; i < concurrency; ++i) { futs.emplace_back(boost::asio::co_spawn( GlobalIOContext::instance().get_io_context(), [&client, results, i]() -> boost::asio::awaitable { auto res = co_await client.status(); (*results)[i] = std::move(res); co_return; }, boost::asio::use_future)); } for (auto& f : futs) f.get(); int ok = 0; for (auto& v : *results) if (v && v->has_value()) ++ok; spdlog::info("MCPSocketStress round {}: {}/{} OK", r, ok, concurrency); REQUIRE(ok == concurrency); } }