/* * test_tcp_loopback — in-process TCP acceptor + client, sends 10 frames. * Runs only under dev (requires Asio). */ #include #include #include #include #include #include #include #include "net/transport.h" using namespace voicecat::net; static int g_failures = 0; #define CHECK(cond) \ do { \ if (!(cond)) { \ std::printf("FAIL [%s:%d]: %s\n", __FILE__, __LINE__, #cond); \ ++g_failures; \ } \ } while (0) int main() { constexpr int kFrameCount = 10; constexpr uint16_t kPort = 19850; std::mutex mtx; std::condition_variable cv; std::vector> received; std::atomic server_connected{false}; // Server io_context + acceptor. asio::io_context server_io; auto work = asio::make_work_guard(server_io); std::thread server_thread([&] { server_io.run(); }); TcpAcceptor acceptor(server_io, kPort, [&](asio::ip::tcp::socket sock) { TcpChannelCallbacks cbs; cbs.on_frame = [&](std::vector frame) { std::lock_guard lk(mtx); received.push_back(std::move(frame)); cv.notify_all(); }; cbs.on_connected = [&] { server_connected.store(true); }; auto conn = std::make_shared(std::move(sock), std::move(cbs)); return conn; }); acceptor.start(); // Client. std::atomic client_connected{false}; TcpChannelCallbacks client_cbs; client_cbs.on_connected = [&] { client_connected.store(true); }; client_cbs.on_connect_error = [](std::error_code ec) { std::printf("connect error: %s\n", ec.message().c_str()); }; TcpControlChannel client(std::move(client_cbs)); client.async_connect("127.0.0.1", kPort); // Wait for connection. auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5); while (!client_connected.load() && std::chrono::steady_clock::now() < deadline) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } CHECK(client_connected.load()); // Send kFrameCount distinct frames. for (int i = 0; i < kFrameCount; ++i) { std::vector payload = {static_cast(i), 0xAB, 0xCD}; client.send_frame(payload); } // Wait for all frames to arrive on the server side. { std::unique_lock lk(mtx); bool ok = cv.wait_for(lk, std::chrono::seconds(5), [&] { return static_cast(received.size()) >= kFrameCount; }); CHECK(ok); } CHECK(static_cast(received.size()) == kFrameCount); for (int i = 0; i < kFrameCount && i < static_cast(received.size()); ++i) { CHECK(received[i].size() == 3); if (!received[i].empty()) CHECK(received[i][0] == static_cast(i)); } // Clean up. client.close(); acceptor.stop(); work.reset(); server_io.stop(); server_thread.join(); if (g_failures == 0) { std::printf("tcp_loopback: all checks passed\n"); return 0; } std::printf("tcp_loopback: %d failure(s)\n", g_failures); return 1; }