// The CLI's Client against a real in-process daemon RPC server. #include #include #include #include #include #include "check.hpp" #include "client.hpp" #include "rpc/dispatcher.hpp" #include "rpc/event_loop.hpp" #include "rpc/uds_server.hpp" namespace rpc = velox::daemon::rpc; using velox::cli::CallError; using velox::cli::Client; void run() { // connect() with no daemon -> a kConnect error, not a crash. { ::setenv("XDG_RUNTIME_DIR", "/tmp/velox-cli-test-nonexistent-xyz", 1); Client c; auto err = c.connect(); CHECK(err.has_value()); if (err) CHECK_EQ(err->code, CallError::kConnect); } // Point XDG_RUNTIME_DIR at a fresh temp dir; the client derives // /velox/velox.sock and the server binds exactly that. char tmpl[] = "/tmp/velox-cli-test-XXXXXX"; const char* xdg = ::mkdtemp(tmpl); CHECK(xdg != nullptr); if (xdg == nullptr) return; ::setenv("XDG_RUNTIME_DIR", xdg, 1); const std::string velox_dir = std::string(xdg) + "/velox"; ::mkdir(velox_dir.c_str(), 0700); const std::string server_sock = velox_dir + "/velox.sock"; rpc::EventLoop loop; rpc::VeloxDispatcher dispatcher; rpc::UdsServer server(loop, dispatcher, server_sock); const auto ec = server.start(); CHECK(!ec); if (ec) return; std::thread th([&loop] { loop.run(); }); { Client c; auto err = c.connect(); CHECK(!err.has_value()); if (err) { loop.stop(); th.join(); return; } CHECK_EQ(c.hello_result().value("transport", ""), std::string("uds")); auto ls = c.call("download.list", nlohmann::json::object()); CHECK(ls.has_value()); if (ls) { CHECK_EQ(ls->value("total", -1), 0); CHECK(ls->at("items").is_array()); } // A not-yet-implemented method surfaces the daemon's error, not a transport error. auto add = c.call("download.add", {{"url", "https://example.com/x"}}); CHECK(!add.has_value()); if (!add) CHECK_EQ(add.error().code, -32603); } loop.stop(); th.join(); ::unlink(server_sock.c_str()); } TEST_MAIN()