starpc 0.43.1 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/echo/echo.pb.js +1 -1
- package/dist/mock/mock.pb.js +1 -1
- package/dist/rpcstream/rpcstream.pb.js +1 -1
- package/dist/srpc/rpcproto.pb.js +1 -1
- package/echo/echo.pb.ts +1 -1
- package/echo/echo_e2e_test.cpp +1048 -0
- package/echo/echo_srpc.pb.cpp +125 -0
- package/echo/echo_srpc.pb.hpp +317 -0
- package/go.mod +7 -7
- package/go.sum +14 -14
- package/mock/mock.pb.ts +1 -1
- package/mock/mock_srpc.pb.cpp +45 -0
- package/mock/mock_srpc.pb.hpp +104 -0
- package/package.json +6 -5
- package/srpc/CMakeLists.txt +59 -0
- package/srpc/client-rpc.cpp +106 -0
- package/srpc/client-rpc.hpp +68 -0
- package/srpc/client.cpp +101 -0
- package/srpc/client.hpp +66 -0
- package/srpc/common-rpc.cpp +182 -0
- package/srpc/common-rpc.hpp +109 -0
- package/srpc/errors.hpp +71 -0
- package/srpc/handler.hpp +23 -0
- package/srpc/invoker.hpp +91 -0
- package/srpc/message.hpp +28 -0
- package/srpc/msg-stream.hpp +86 -0
- package/srpc/mux.cpp +109 -0
- package/srpc/mux.hpp +64 -0
- package/srpc/packet.cpp +83 -0
- package/srpc/packet.hpp +56 -0
- package/srpc/rpcproto.pb.ts +1 -1
- package/srpc/server-rpc.cpp +97 -0
- package/srpc/server-rpc.hpp +63 -0
- package/srpc/starpc.hpp +18 -0
- package/srpc/stream.hpp +61 -0
- package/srpc/writer.hpp +60 -0
|
@@ -0,0 +1,1048 @@
|
|
|
1
|
+
// go:build deps_only
|
|
2
|
+
|
|
3
|
+
// Echo end-to-end test for starpc C++ implementation.
|
|
4
|
+
// Tests unary and streaming RPC patterns.
|
|
5
|
+
|
|
6
|
+
#include <atomic>
|
|
7
|
+
#include <cassert>
|
|
8
|
+
#include <iostream>
|
|
9
|
+
#include <memory>
|
|
10
|
+
#include <mutex>
|
|
11
|
+
#include <queue>
|
|
12
|
+
#include <thread>
|
|
13
|
+
|
|
14
|
+
#include "echo/echo_srpc.pb.hpp"
|
|
15
|
+
#include "rpcstream/rpcstream.hpp"
|
|
16
|
+
#include "srpc/rpcproto.pb.h"
|
|
17
|
+
#include "srpc/starpc.hpp"
|
|
18
|
+
|
|
19
|
+
namespace {
|
|
20
|
+
|
|
21
|
+
const char *kTestBody = "hello world via starpc C++ e2e test";
|
|
22
|
+
|
|
23
|
+
// InMemoryTransport provides an in-memory packet transport for testing.
|
|
24
|
+
// Simulates a bidirectional connection between client and server.
|
|
25
|
+
class InMemoryTransport {
|
|
26
|
+
public:
|
|
27
|
+
struct Endpoint {
|
|
28
|
+
std::mutex mtx;
|
|
29
|
+
std::condition_variable cv;
|
|
30
|
+
std::queue<std::string> packets;
|
|
31
|
+
bool closed = false;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
InMemoryTransport()
|
|
35
|
+
: client_endpoint_(std::make_shared<Endpoint>()),
|
|
36
|
+
server_endpoint_(std::make_shared<Endpoint>()) {}
|
|
37
|
+
|
|
38
|
+
// Get writer for client to send to server
|
|
39
|
+
std::shared_ptr<Endpoint> ClientToServer() { return server_endpoint_; }
|
|
40
|
+
// Get writer for server to send to client
|
|
41
|
+
std::shared_ptr<Endpoint> ServerToClient() { return client_endpoint_; }
|
|
42
|
+
// Get reader for client (reads from server)
|
|
43
|
+
std::shared_ptr<Endpoint> ClientReader() { return client_endpoint_; }
|
|
44
|
+
// Get reader for server (reads from client)
|
|
45
|
+
std::shared_ptr<Endpoint> ServerReader() { return server_endpoint_; }
|
|
46
|
+
|
|
47
|
+
static void Send(std::shared_ptr<Endpoint> ep, const std::string &data) {
|
|
48
|
+
std::lock_guard<std::mutex> lock(ep->mtx);
|
|
49
|
+
if (!ep->closed) {
|
|
50
|
+
ep->packets.push(data);
|
|
51
|
+
ep->cv.notify_all();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static bool Recv(std::shared_ptr<Endpoint> ep, std::string *out,
|
|
56
|
+
int timeout_ms = 5000) {
|
|
57
|
+
std::unique_lock<std::mutex> lock(ep->mtx);
|
|
58
|
+
if (!ep->cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), [&ep]() {
|
|
59
|
+
return !ep->packets.empty() || ep->closed;
|
|
60
|
+
})) {
|
|
61
|
+
return false; // timeout
|
|
62
|
+
}
|
|
63
|
+
if (ep->packets.empty()) {
|
|
64
|
+
return false; // closed
|
|
65
|
+
}
|
|
66
|
+
*out = ep->packets.front();
|
|
67
|
+
ep->packets.pop();
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static void Close(std::shared_ptr<Endpoint> ep) {
|
|
72
|
+
std::lock_guard<std::mutex> lock(ep->mtx);
|
|
73
|
+
ep->closed = true;
|
|
74
|
+
ep->cv.notify_all();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private:
|
|
78
|
+
std::shared_ptr<Endpoint> client_endpoint_;
|
|
79
|
+
std::shared_ptr<Endpoint> server_endpoint_;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// InMemoryPacketWriter writes packets to an InMemoryTransport endpoint.
|
|
83
|
+
class InMemoryPacketWriter : public starpc::PacketWriter {
|
|
84
|
+
public:
|
|
85
|
+
explicit InMemoryPacketWriter(std::shared_ptr<InMemoryTransport::Endpoint> ep)
|
|
86
|
+
: endpoint_(ep) {}
|
|
87
|
+
|
|
88
|
+
starpc::Error WritePacket(const srpc::Packet &pkt) override {
|
|
89
|
+
std::string data;
|
|
90
|
+
if (!pkt.SerializeToString(&data)) {
|
|
91
|
+
return starpc::Error::InvalidMessage;
|
|
92
|
+
}
|
|
93
|
+
InMemoryTransport::Send(endpoint_, data);
|
|
94
|
+
return starpc::Error::OK;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
starpc::Error Close() override {
|
|
98
|
+
InMemoryTransport::Close(endpoint_);
|
|
99
|
+
return starpc::Error::OK;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private:
|
|
103
|
+
std::shared_ptr<InMemoryTransport::Endpoint> endpoint_;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// RpcStreamAdapter adapts generated stream classes to implement
|
|
107
|
+
// rpcstream::RpcStream
|
|
108
|
+
class RpcStreamAdapter : public rpcstream::RpcStream {
|
|
109
|
+
public:
|
|
110
|
+
explicit RpcStreamAdapter(echo::SRPCEchoer_RpcStreamStream *strm)
|
|
111
|
+
: strm_(strm) {}
|
|
112
|
+
|
|
113
|
+
starpc::Error Send(const rpcstream::RpcStreamPacket &msg) override {
|
|
114
|
+
return strm_->Send(msg);
|
|
115
|
+
}
|
|
116
|
+
starpc::Error Recv(rpcstream::RpcStreamPacket *msg) override {
|
|
117
|
+
return strm_->Recv(msg);
|
|
118
|
+
}
|
|
119
|
+
starpc::Error CloseSend() override { return starpc::Error::OK; }
|
|
120
|
+
starpc::Error Close() override { return starpc::Error::OK; }
|
|
121
|
+
|
|
122
|
+
private:
|
|
123
|
+
echo::SRPCEchoer_RpcStreamStream *strm_;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// EchoServerImpl implements the echo server.
|
|
127
|
+
class EchoServerImpl : public echo::SRPCEchoerServer {
|
|
128
|
+
public:
|
|
129
|
+
void SetRpcStreamMux(starpc::Mux *mux) { rpc_stream_mux_ = mux; }
|
|
130
|
+
|
|
131
|
+
starpc::Error Echo(const echo::EchoMsg &req, echo::EchoMsg *resp) override {
|
|
132
|
+
resp->set_body(req.body());
|
|
133
|
+
return starpc::Error::OK;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
starpc::Error
|
|
137
|
+
EchoServerStream(const echo::EchoMsg &req,
|
|
138
|
+
echo::SRPCEchoer_EchoServerStreamStream *strm) override {
|
|
139
|
+
// Send 5 copies of the message
|
|
140
|
+
for (int i = 0; i < 5; i++) {
|
|
141
|
+
echo::EchoMsg msg;
|
|
142
|
+
msg.set_body(req.body());
|
|
143
|
+
starpc::Error err = strm->Send(msg);
|
|
144
|
+
if (err != starpc::Error::OK) {
|
|
145
|
+
return err;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return starpc::Error::OK;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
starpc::Error EchoClientStream(echo::SRPCEchoer_EchoClientStreamStream *strm,
|
|
152
|
+
echo::EchoMsg *resp) override {
|
|
153
|
+
// Receive first message and return it
|
|
154
|
+
echo::EchoMsg msg;
|
|
155
|
+
starpc::Error err = strm->Recv(&msg);
|
|
156
|
+
if (err != starpc::Error::OK) {
|
|
157
|
+
return err;
|
|
158
|
+
}
|
|
159
|
+
resp->set_body(msg.body());
|
|
160
|
+
return starpc::Error::OK;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
starpc::Error
|
|
164
|
+
EchoBidiStream(echo::SRPCEchoer_EchoBidiStreamStream *strm) override {
|
|
165
|
+
// Echo back all received messages
|
|
166
|
+
while (true) {
|
|
167
|
+
echo::EchoMsg msg;
|
|
168
|
+
starpc::Error err = strm->Recv(&msg);
|
|
169
|
+
if (err == starpc::Error::EOF_) {
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
if (err != starpc::Error::OK) {
|
|
173
|
+
return err;
|
|
174
|
+
}
|
|
175
|
+
err = strm->Send(msg);
|
|
176
|
+
if (err != starpc::Error::OK) {
|
|
177
|
+
return err;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return starpc::Error::OK;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
starpc::Error RpcStream(echo::SRPCEchoer_RpcStreamStream *strm) override {
|
|
184
|
+
// Wrap stream to implement rpcstream::RpcStream interface
|
|
185
|
+
RpcStreamAdapter adapter(strm);
|
|
186
|
+
return rpcstream::HandleRpcStream(
|
|
187
|
+
&adapter, [this](const std::string &component_id) {
|
|
188
|
+
if (!rpc_stream_mux_) {
|
|
189
|
+
return std::make_tuple(static_cast<starpc::Invoker *>(nullptr),
|
|
190
|
+
std::function<void()>(),
|
|
191
|
+
starpc::Error::Unimplemented);
|
|
192
|
+
}
|
|
193
|
+
return std::make_tuple(
|
|
194
|
+
static_cast<starpc::Invoker *>(rpc_stream_mux_),
|
|
195
|
+
std::function<void()>(), starpc::Error::OK);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
starpc::Error DoNothing(const google::protobuf::Empty &req,
|
|
200
|
+
google::protobuf::Empty *resp) override {
|
|
201
|
+
// Just return OK
|
|
202
|
+
return starpc::Error::OK;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private:
|
|
206
|
+
starpc::Mux *rpc_stream_mux_ = nullptr;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// RunServer runs the server-side packet handling loop.
|
|
210
|
+
void RunServer(InMemoryTransport *transport, starpc::Mux *mux) {
|
|
211
|
+
auto reader = transport->ServerReader();
|
|
212
|
+
auto writer_ep = transport->ServerToClient();
|
|
213
|
+
auto writer = std::make_unique<InMemoryPacketWriter>(writer_ep);
|
|
214
|
+
|
|
215
|
+
auto server_rpc = starpc::NewServerRPC(mux, writer.get());
|
|
216
|
+
|
|
217
|
+
while (true) {
|
|
218
|
+
std::string data;
|
|
219
|
+
if (!InMemoryTransport::Recv(reader, &data)) {
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
starpc::Error err = server_rpc->HandlePacketData(data);
|
|
223
|
+
if (err != starpc::Error::OK && err != starpc::Error::Completed) {
|
|
224
|
+
std::cerr << "Server error: " << starpc::ErrorString(err) << std::endl;
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Test unary RPC
|
|
231
|
+
bool TestUnary() {
|
|
232
|
+
std::cout << "Testing Unary RPC... " << std::flush;
|
|
233
|
+
|
|
234
|
+
InMemoryTransport transport;
|
|
235
|
+
|
|
236
|
+
// Setup server
|
|
237
|
+
auto mux = starpc::NewMux();
|
|
238
|
+
EchoServerImpl server_impl;
|
|
239
|
+
auto [handler, reg_err] = echo::SRPCRegisterEchoer(mux.get(), &server_impl);
|
|
240
|
+
if (reg_err != starpc::Error::OK) {
|
|
241
|
+
std::cerr << "FAILED: Registration error: " << starpc::ErrorString(reg_err)
|
|
242
|
+
<< std::endl;
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Start server thread
|
|
247
|
+
std::thread server_thread(
|
|
248
|
+
[&transport, &mux]() { RunServer(&transport, mux.get()); });
|
|
249
|
+
|
|
250
|
+
// Setup client
|
|
251
|
+
auto client_rpc = starpc::NewClientRPC("echo.Echoer", "Echo");
|
|
252
|
+
auto writer =
|
|
253
|
+
std::make_unique<InMemoryPacketWriter>(transport.ClientToServer());
|
|
254
|
+
|
|
255
|
+
// Start client receive thread
|
|
256
|
+
auto client_reader = transport.ClientReader();
|
|
257
|
+
std::thread client_recv_thread([&client_rpc, &client_reader]() {
|
|
258
|
+
while (true) {
|
|
259
|
+
std::string data;
|
|
260
|
+
if (!InMemoryTransport::Recv(client_reader, &data)) {
|
|
261
|
+
client_rpc->HandleStreamClose(starpc::Error::EOF_);
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
starpc::Error err = client_rpc->HandlePacketData(data);
|
|
265
|
+
if (err != starpc::Error::OK) {
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Send request
|
|
272
|
+
echo::EchoMsg req;
|
|
273
|
+
req.set_body(kTestBody);
|
|
274
|
+
std::string req_data;
|
|
275
|
+
req.SerializeToString(&req_data);
|
|
276
|
+
|
|
277
|
+
starpc::Error err = client_rpc->Start(writer.get(), true, req_data);
|
|
278
|
+
if (err != starpc::Error::OK) {
|
|
279
|
+
std::cerr << "FAILED: Start error: " << starpc::ErrorString(err)
|
|
280
|
+
<< std::endl;
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Read response
|
|
285
|
+
std::string resp_data;
|
|
286
|
+
err = client_rpc->ReadOne(&resp_data);
|
|
287
|
+
if (err != starpc::Error::OK) {
|
|
288
|
+
std::cerr << "FAILED: ReadOne error: " << starpc::ErrorString(err)
|
|
289
|
+
<< std::endl;
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
echo::EchoMsg resp;
|
|
294
|
+
if (!resp.ParseFromString(resp_data)) {
|
|
295
|
+
std::cerr << "FAILED: Parse response error" << std::endl;
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (resp.body() != kTestBody) {
|
|
300
|
+
std::cerr << "FAILED: Expected '" << kTestBody << "' got '" << resp.body()
|
|
301
|
+
<< "'" << std::endl;
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Cleanup
|
|
306
|
+
client_rpc->Close();
|
|
307
|
+
writer->Close();
|
|
308
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
309
|
+
|
|
310
|
+
client_recv_thread.join();
|
|
311
|
+
server_thread.join();
|
|
312
|
+
|
|
313
|
+
std::cout << "PASSED" << std::endl;
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Test server streaming RPC
|
|
318
|
+
bool TestServerStream() {
|
|
319
|
+
std::cout << "Testing ServerStream RPC... " << std::flush;
|
|
320
|
+
|
|
321
|
+
InMemoryTransport transport;
|
|
322
|
+
|
|
323
|
+
// Setup server
|
|
324
|
+
auto mux = starpc::NewMux();
|
|
325
|
+
EchoServerImpl server_impl;
|
|
326
|
+
auto [handler, reg_err] = echo::SRPCRegisterEchoer(mux.get(), &server_impl);
|
|
327
|
+
if (reg_err != starpc::Error::OK) {
|
|
328
|
+
std::cerr << "FAILED: Registration error: " << starpc::ErrorString(reg_err)
|
|
329
|
+
<< std::endl;
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Start server thread
|
|
334
|
+
std::thread server_thread(
|
|
335
|
+
[&transport, &mux]() { RunServer(&transport, mux.get()); });
|
|
336
|
+
|
|
337
|
+
// Setup client
|
|
338
|
+
auto client_rpc = starpc::NewClientRPC("echo.Echoer", "EchoServerStream");
|
|
339
|
+
auto writer =
|
|
340
|
+
std::make_unique<InMemoryPacketWriter>(transport.ClientToServer());
|
|
341
|
+
|
|
342
|
+
// Start client receive thread
|
|
343
|
+
auto client_reader = transport.ClientReader();
|
|
344
|
+
std::atomic<bool> client_done{false};
|
|
345
|
+
std::thread client_recv_thread([&client_rpc, &client_reader, &client_done]() {
|
|
346
|
+
while (!client_done.load()) {
|
|
347
|
+
std::string data;
|
|
348
|
+
if (!InMemoryTransport::Recv(client_reader, &data, 100)) {
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
starpc::Error err = client_rpc->HandlePacketData(data);
|
|
352
|
+
if (err != starpc::Error::OK) {
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Send request
|
|
359
|
+
echo::EchoMsg req;
|
|
360
|
+
req.set_body(kTestBody);
|
|
361
|
+
std::string req_data;
|
|
362
|
+
req.SerializeToString(&req_data);
|
|
363
|
+
|
|
364
|
+
starpc::Error err = client_rpc->Start(writer.get(), true, req_data);
|
|
365
|
+
if (err != starpc::Error::OK) {
|
|
366
|
+
std::cerr << "FAILED: Start error: " << starpc::ErrorString(err)
|
|
367
|
+
<< std::endl;
|
|
368
|
+
client_done.store(true);
|
|
369
|
+
client_recv_thread.join();
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Read 5 responses
|
|
374
|
+
int received = 0;
|
|
375
|
+
for (int i = 0; i < 5; i++) {
|
|
376
|
+
std::string resp_data;
|
|
377
|
+
err = client_rpc->ReadOne(&resp_data);
|
|
378
|
+
if (err != starpc::Error::OK) {
|
|
379
|
+
std::cerr << "FAILED: ReadOne error at message " << i << ": "
|
|
380
|
+
<< starpc::ErrorString(err) << std::endl;
|
|
381
|
+
client_done.store(true);
|
|
382
|
+
client_recv_thread.join();
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
echo::EchoMsg resp;
|
|
387
|
+
if (!resp.ParseFromString(resp_data)) {
|
|
388
|
+
std::cerr << "FAILED: Parse response error at message " << i << std::endl;
|
|
389
|
+
client_done.store(true);
|
|
390
|
+
client_recv_thread.join();
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (resp.body() != kTestBody) {
|
|
395
|
+
std::cerr << "FAILED: Expected '" << kTestBody << "' got '" << resp.body()
|
|
396
|
+
<< "'" << std::endl;
|
|
397
|
+
client_done.store(true);
|
|
398
|
+
client_recv_thread.join();
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
received++;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (received != 5) {
|
|
405
|
+
std::cerr << "FAILED: Expected 5 messages, got " << received << std::endl;
|
|
406
|
+
client_done.store(true);
|
|
407
|
+
client_recv_thread.join();
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Cleanup
|
|
412
|
+
client_rpc->Close();
|
|
413
|
+
writer->Close();
|
|
414
|
+
client_done.store(true);
|
|
415
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
416
|
+
|
|
417
|
+
client_recv_thread.join();
|
|
418
|
+
server_thread.join();
|
|
419
|
+
|
|
420
|
+
std::cout << "PASSED" << std::endl;
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Test client streaming RPC
|
|
425
|
+
bool TestClientStream() {
|
|
426
|
+
std::cout << "Testing ClientStream RPC... " << std::flush;
|
|
427
|
+
|
|
428
|
+
InMemoryTransport transport;
|
|
429
|
+
|
|
430
|
+
// Setup server
|
|
431
|
+
auto mux = starpc::NewMux();
|
|
432
|
+
EchoServerImpl server_impl;
|
|
433
|
+
auto [handler, reg_err] = echo::SRPCRegisterEchoer(mux.get(), &server_impl);
|
|
434
|
+
if (reg_err != starpc::Error::OK) {
|
|
435
|
+
std::cerr << "FAILED: Registration error: " << starpc::ErrorString(reg_err)
|
|
436
|
+
<< std::endl;
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Start server thread
|
|
441
|
+
std::thread server_thread(
|
|
442
|
+
[&transport, &mux]() { RunServer(&transport, mux.get()); });
|
|
443
|
+
|
|
444
|
+
// Setup client
|
|
445
|
+
auto client_rpc = starpc::NewClientRPC("echo.Echoer", "EchoClientStream");
|
|
446
|
+
auto writer =
|
|
447
|
+
std::make_unique<InMemoryPacketWriter>(transport.ClientToServer());
|
|
448
|
+
|
|
449
|
+
// Start client receive thread
|
|
450
|
+
auto client_reader = transport.ClientReader();
|
|
451
|
+
std::atomic<bool> client_done{false};
|
|
452
|
+
std::thread client_recv_thread([&client_rpc, &client_reader, &client_done]() {
|
|
453
|
+
while (!client_done.load()) {
|
|
454
|
+
std::string data;
|
|
455
|
+
if (!InMemoryTransport::Recv(client_reader, &data, 100)) {
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
starpc::Error err = client_rpc->HandlePacketData(data);
|
|
459
|
+
if (err != starpc::Error::OK) {
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Send request (no initial data for streaming)
|
|
466
|
+
starpc::Error err = client_rpc->Start(writer.get(), false, "");
|
|
467
|
+
if (err != starpc::Error::OK) {
|
|
468
|
+
std::cerr << "FAILED: Start error: " << starpc::ErrorString(err)
|
|
469
|
+
<< std::endl;
|
|
470
|
+
client_done.store(true);
|
|
471
|
+
client_recv_thread.join();
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Send first message using WriteCallData
|
|
476
|
+
echo::EchoMsg req;
|
|
477
|
+
req.set_body(kTestBody);
|
|
478
|
+
std::string req_data;
|
|
479
|
+
req.SerializeToString(&req_data);
|
|
480
|
+
|
|
481
|
+
err = client_rpc->WriteCallData(req_data, false, false, starpc::Error::OK);
|
|
482
|
+
if (err != starpc::Error::OK) {
|
|
483
|
+
std::cerr << "FAILED: WriteCallData error: " << starpc::ErrorString(err)
|
|
484
|
+
<< std::endl;
|
|
485
|
+
client_done.store(true);
|
|
486
|
+
client_recv_thread.join();
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Close send side to indicate we're done sending
|
|
491
|
+
err = client_rpc->WriteCallData("", false, true, starpc::Error::OK);
|
|
492
|
+
if (err != starpc::Error::OK) {
|
|
493
|
+
std::cerr << "FAILED: WriteCallData (close) error: "
|
|
494
|
+
<< starpc::ErrorString(err) << std::endl;
|
|
495
|
+
client_done.store(true);
|
|
496
|
+
client_recv_thread.join();
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Read response
|
|
501
|
+
std::string resp_data;
|
|
502
|
+
err = client_rpc->ReadOne(&resp_data);
|
|
503
|
+
if (err != starpc::Error::OK) {
|
|
504
|
+
std::cerr << "FAILED: ReadOne error: " << starpc::ErrorString(err)
|
|
505
|
+
<< std::endl;
|
|
506
|
+
client_done.store(true);
|
|
507
|
+
client_recv_thread.join();
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
echo::EchoMsg resp;
|
|
512
|
+
if (!resp.ParseFromString(resp_data)) {
|
|
513
|
+
std::cerr << "FAILED: Parse response error" << std::endl;
|
|
514
|
+
client_done.store(true);
|
|
515
|
+
client_recv_thread.join();
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (resp.body() != kTestBody) {
|
|
520
|
+
std::cerr << "FAILED: Expected '" << kTestBody << "' got '" << resp.body()
|
|
521
|
+
<< "'" << std::endl;
|
|
522
|
+
client_done.store(true);
|
|
523
|
+
client_recv_thread.join();
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Cleanup
|
|
528
|
+
client_rpc->Close();
|
|
529
|
+
writer->Close();
|
|
530
|
+
client_done.store(true);
|
|
531
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
532
|
+
|
|
533
|
+
client_recv_thread.join();
|
|
534
|
+
server_thread.join();
|
|
535
|
+
|
|
536
|
+
std::cout << "PASSED" << std::endl;
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Test bidirectional streaming RPC
|
|
541
|
+
bool TestBidiStream() {
|
|
542
|
+
std::cout << "Testing BidiStream RPC... " << std::flush;
|
|
543
|
+
|
|
544
|
+
InMemoryTransport transport;
|
|
545
|
+
|
|
546
|
+
// Setup server
|
|
547
|
+
auto mux = starpc::NewMux();
|
|
548
|
+
EchoServerImpl server_impl;
|
|
549
|
+
auto [handler, reg_err] = echo::SRPCRegisterEchoer(mux.get(), &server_impl);
|
|
550
|
+
if (reg_err != starpc::Error::OK) {
|
|
551
|
+
std::cerr << "FAILED: Registration error: " << starpc::ErrorString(reg_err)
|
|
552
|
+
<< std::endl;
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Start server thread
|
|
557
|
+
std::thread server_thread(
|
|
558
|
+
[&transport, &mux]() { RunServer(&transport, mux.get()); });
|
|
559
|
+
|
|
560
|
+
// Setup client
|
|
561
|
+
auto client_rpc = starpc::NewClientRPC("echo.Echoer", "EchoBidiStream");
|
|
562
|
+
auto writer =
|
|
563
|
+
std::make_unique<InMemoryPacketWriter>(transport.ClientToServer());
|
|
564
|
+
|
|
565
|
+
// Start client receive thread
|
|
566
|
+
auto client_reader = transport.ClientReader();
|
|
567
|
+
std::atomic<bool> client_done{false};
|
|
568
|
+
std::thread client_recv_thread([&client_rpc, &client_reader, &client_done]() {
|
|
569
|
+
while (!client_done.load()) {
|
|
570
|
+
std::string data;
|
|
571
|
+
if (!InMemoryTransport::Recv(client_reader, &data, 100)) {
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
starpc::Error err = client_rpc->HandlePacketData(data);
|
|
575
|
+
if (err != starpc::Error::OK) {
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
// Send request (no initial data for bidi streaming)
|
|
582
|
+
starpc::Error err = client_rpc->Start(writer.get(), false, "");
|
|
583
|
+
if (err != starpc::Error::OK) {
|
|
584
|
+
std::cerr << "FAILED: Start error: " << starpc::ErrorString(err)
|
|
585
|
+
<< std::endl;
|
|
586
|
+
client_done.store(true);
|
|
587
|
+
client_recv_thread.join();
|
|
588
|
+
return false;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Send 3 messages and receive 3 responses
|
|
592
|
+
for (int i = 0; i < 3; i++) {
|
|
593
|
+
// Send message
|
|
594
|
+
echo::EchoMsg req;
|
|
595
|
+
req.set_body(kTestBody);
|
|
596
|
+
std::string req_data;
|
|
597
|
+
req.SerializeToString(&req_data);
|
|
598
|
+
|
|
599
|
+
err = client_rpc->WriteCallData(req_data, false, false, starpc::Error::OK);
|
|
600
|
+
if (err != starpc::Error::OK) {
|
|
601
|
+
std::cerr << "FAILED: WriteCallData error at message " << i << ": "
|
|
602
|
+
<< starpc::ErrorString(err) << std::endl;
|
|
603
|
+
client_done.store(true);
|
|
604
|
+
client_recv_thread.join();
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Receive echoed response
|
|
609
|
+
std::string resp_data;
|
|
610
|
+
err = client_rpc->ReadOne(&resp_data);
|
|
611
|
+
if (err != starpc::Error::OK) {
|
|
612
|
+
std::cerr << "FAILED: ReadOne error at message " << i << ": "
|
|
613
|
+
<< starpc::ErrorString(err) << std::endl;
|
|
614
|
+
client_done.store(true);
|
|
615
|
+
client_recv_thread.join();
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
echo::EchoMsg resp;
|
|
620
|
+
if (!resp.ParseFromString(resp_data)) {
|
|
621
|
+
std::cerr << "FAILED: Parse response error at message " << i << std::endl;
|
|
622
|
+
client_done.store(true);
|
|
623
|
+
client_recv_thread.join();
|
|
624
|
+
return false;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (resp.body() != kTestBody) {
|
|
628
|
+
std::cerr << "FAILED: Expected '" << kTestBody << "' got '" << resp.body()
|
|
629
|
+
<< "'" << std::endl;
|
|
630
|
+
client_done.store(true);
|
|
631
|
+
client_recv_thread.join();
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Close send side
|
|
637
|
+
err = client_rpc->WriteCallData("", false, true, starpc::Error::OK);
|
|
638
|
+
if (err != starpc::Error::OK) {
|
|
639
|
+
std::cerr << "FAILED: WriteCallData (close) error: "
|
|
640
|
+
<< starpc::ErrorString(err) << std::endl;
|
|
641
|
+
client_done.store(true);
|
|
642
|
+
client_recv_thread.join();
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Cleanup
|
|
647
|
+
client_rpc->Close();
|
|
648
|
+
writer->Close();
|
|
649
|
+
client_done.store(true);
|
|
650
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
651
|
+
|
|
652
|
+
client_recv_thread.join();
|
|
653
|
+
server_thread.join();
|
|
654
|
+
|
|
655
|
+
std::cout << "PASSED" << std::endl;
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Test DoNothing RPC
|
|
660
|
+
bool TestDoNothing() {
|
|
661
|
+
std::cout << "Testing DoNothing RPC... " << std::flush;
|
|
662
|
+
|
|
663
|
+
InMemoryTransport transport;
|
|
664
|
+
|
|
665
|
+
// Setup server
|
|
666
|
+
auto mux = starpc::NewMux();
|
|
667
|
+
EchoServerImpl server_impl;
|
|
668
|
+
auto [handler, reg_err] = echo::SRPCRegisterEchoer(mux.get(), &server_impl);
|
|
669
|
+
if (reg_err != starpc::Error::OK) {
|
|
670
|
+
std::cerr << "FAILED: Registration error: " << starpc::ErrorString(reg_err)
|
|
671
|
+
<< std::endl;
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// Start server thread
|
|
676
|
+
std::thread server_thread(
|
|
677
|
+
[&transport, &mux]() { RunServer(&transport, mux.get()); });
|
|
678
|
+
|
|
679
|
+
// Setup client
|
|
680
|
+
auto client_rpc = starpc::NewClientRPC("echo.Echoer", "DoNothing");
|
|
681
|
+
auto writer =
|
|
682
|
+
std::make_unique<InMemoryPacketWriter>(transport.ClientToServer());
|
|
683
|
+
|
|
684
|
+
// Start client receive thread
|
|
685
|
+
auto client_reader = transport.ClientReader();
|
|
686
|
+
std::thread client_recv_thread([&client_rpc, &client_reader]() {
|
|
687
|
+
while (true) {
|
|
688
|
+
std::string data;
|
|
689
|
+
if (!InMemoryTransport::Recv(client_reader, &data)) {
|
|
690
|
+
client_rpc->HandleStreamClose(starpc::Error::EOF_);
|
|
691
|
+
break;
|
|
692
|
+
}
|
|
693
|
+
starpc::Error err = client_rpc->HandlePacketData(data);
|
|
694
|
+
if (err != starpc::Error::OK) {
|
|
695
|
+
break;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
// Send request with empty message
|
|
701
|
+
google::protobuf::Empty req;
|
|
702
|
+
std::string req_data;
|
|
703
|
+
req.SerializeToString(&req_data);
|
|
704
|
+
|
|
705
|
+
starpc::Error err = client_rpc->Start(writer.get(), true, req_data);
|
|
706
|
+
if (err != starpc::Error::OK) {
|
|
707
|
+
std::cerr << "FAILED: Start error: " << starpc::ErrorString(err)
|
|
708
|
+
<< std::endl;
|
|
709
|
+
return false;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Read response
|
|
713
|
+
std::string resp_data;
|
|
714
|
+
err = client_rpc->ReadOne(&resp_data);
|
|
715
|
+
if (err != starpc::Error::OK) {
|
|
716
|
+
std::cerr << "FAILED: ReadOne error: " << starpc::ErrorString(err)
|
|
717
|
+
<< std::endl;
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
google::protobuf::Empty resp;
|
|
722
|
+
if (!resp.ParseFromString(resp_data)) {
|
|
723
|
+
std::cerr << "FAILED: Parse response error" << std::endl;
|
|
724
|
+
return false;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Cleanup
|
|
728
|
+
client_rpc->Close();
|
|
729
|
+
writer->Close();
|
|
730
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
731
|
+
|
|
732
|
+
client_recv_thread.join();
|
|
733
|
+
server_thread.join();
|
|
734
|
+
|
|
735
|
+
std::cout << "PASSED" << std::endl;
|
|
736
|
+
return true;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// RpcStreamClientWrapper wraps a generated RpcStream client.
|
|
740
|
+
class RpcStreamClientWrapper : public rpcstream::RpcStream {
|
|
741
|
+
public:
|
|
742
|
+
explicit RpcStreamClientWrapper(echo::SRPCEchoer_RpcStreamClient *client)
|
|
743
|
+
: client_(client) {}
|
|
744
|
+
|
|
745
|
+
starpc::Error Send(const rpcstream::RpcStreamPacket &msg) override {
|
|
746
|
+
return client_->Send(msg);
|
|
747
|
+
}
|
|
748
|
+
starpc::Error Recv(rpcstream::RpcStreamPacket *msg) override {
|
|
749
|
+
return client_->Recv(msg);
|
|
750
|
+
}
|
|
751
|
+
starpc::Error CloseSend() override { return client_->CloseSend(); }
|
|
752
|
+
starpc::Error Close() override { return client_->Close(); }
|
|
753
|
+
|
|
754
|
+
private:
|
|
755
|
+
echo::SRPCEchoer_RpcStreamClient *client_;
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
// TestClientContext holds all resources for a test client with proper lifetime.
|
|
759
|
+
struct TestClientContext {
|
|
760
|
+
std::unique_ptr<starpc::ClientRPC> client_rpc;
|
|
761
|
+
std::unique_ptr<InMemoryPacketWriter> writer;
|
|
762
|
+
std::thread recv_thread;
|
|
763
|
+
std::atomic<bool> done{false};
|
|
764
|
+
|
|
765
|
+
~TestClientContext() {
|
|
766
|
+
done.store(true);
|
|
767
|
+
if (recv_thread.joinable()) {
|
|
768
|
+
recv_thread.join();
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
// CreateTestClient creates a client with a joinable receive thread.
|
|
774
|
+
std::unique_ptr<TestClientContext>
|
|
775
|
+
CreateTestClient(InMemoryTransport &transport, const std::string &service,
|
|
776
|
+
const std::string &method) {
|
|
777
|
+
auto ctx = std::make_unique<TestClientContext>();
|
|
778
|
+
ctx->client_rpc = starpc::NewClientRPC(service, method);
|
|
779
|
+
ctx->writer =
|
|
780
|
+
std::make_unique<InMemoryPacketWriter>(transport.ClientToServer());
|
|
781
|
+
|
|
782
|
+
auto client_reader = transport.ClientReader();
|
|
783
|
+
auto *rpc = ctx->client_rpc.get();
|
|
784
|
+
ctx->recv_thread = std::thread([rpc, client_reader, &done = ctx->done]() {
|
|
785
|
+
while (!done.load()) {
|
|
786
|
+
std::string data;
|
|
787
|
+
if (!InMemoryTransport::Recv(client_reader, &data, 100)) {
|
|
788
|
+
if (done.load())
|
|
789
|
+
break;
|
|
790
|
+
continue;
|
|
791
|
+
}
|
|
792
|
+
starpc::Error err = rpc->HandlePacketData(data);
|
|
793
|
+
if (err != starpc::Error::OK) {
|
|
794
|
+
break;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
rpc->HandleStreamClose(starpc::Error::EOF_);
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
return ctx;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Test RpcStream RPC using OpenRpcStream, HandleRpcStream, and RpcStreamWriter.
|
|
804
|
+
// This test verifies:
|
|
805
|
+
// 1. Client opens an RpcStream to the server
|
|
806
|
+
// 2. Server handles init/ack via HandleRpcStream
|
|
807
|
+
// 3. Client sends Echo call through the RpcStream
|
|
808
|
+
// 4. Server forwards to nested mux and returns response
|
|
809
|
+
bool TestRpcStream() {
|
|
810
|
+
std::cout << "Testing RpcStream RPC... " << std::flush;
|
|
811
|
+
|
|
812
|
+
InMemoryTransport transport;
|
|
813
|
+
|
|
814
|
+
// Setup server with nested mux
|
|
815
|
+
auto mux = starpc::NewMux();
|
|
816
|
+
auto nested_mux = starpc::NewMux();
|
|
817
|
+
EchoServerImpl server_impl;
|
|
818
|
+
server_impl.SetRpcStreamMux(nested_mux.get());
|
|
819
|
+
|
|
820
|
+
// Register echo service on both muxes
|
|
821
|
+
auto [handler, reg_err] = echo::SRPCRegisterEchoer(mux.get(), &server_impl);
|
|
822
|
+
if (reg_err != starpc::Error::OK) {
|
|
823
|
+
std::cerr << "FAILED: Registration error: " << starpc::ErrorString(reg_err)
|
|
824
|
+
<< std::endl;
|
|
825
|
+
return false;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
auto [nested_handler, nested_reg_err] =
|
|
829
|
+
echo::SRPCRegisterEchoer(nested_mux.get(), &server_impl);
|
|
830
|
+
if (nested_reg_err != starpc::Error::OK) {
|
|
831
|
+
std::cerr << "FAILED: Nested registration error: "
|
|
832
|
+
<< starpc::ErrorString(nested_reg_err) << std::endl;
|
|
833
|
+
return false;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// Start server thread
|
|
837
|
+
std::thread server_thread(
|
|
838
|
+
[&transport, &mux]() { RunServer(&transport, mux.get()); });
|
|
839
|
+
|
|
840
|
+
// Create client for RpcStream call
|
|
841
|
+
auto ctx = CreateTestClient(transport, "echo.Echoer", "RpcStream");
|
|
842
|
+
|
|
843
|
+
// Start the RpcStream call (no initial data for bidi stream)
|
|
844
|
+
starpc::Error err = ctx->client_rpc->Start(ctx->writer.get(), false, "");
|
|
845
|
+
if (err != starpc::Error::OK) {
|
|
846
|
+
std::cerr << "FAILED: Start error: " << starpc::ErrorString(err)
|
|
847
|
+
<< std::endl;
|
|
848
|
+
ctx->done.store(true);
|
|
849
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
850
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
851
|
+
server_thread.join();
|
|
852
|
+
return false;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Send init packet
|
|
856
|
+
rpcstream::RpcStreamPacket init_pkt;
|
|
857
|
+
init_pkt.mutable_init()->set_component_id("");
|
|
858
|
+
std::string init_data;
|
|
859
|
+
init_pkt.SerializeToString(&init_data);
|
|
860
|
+
err = ctx->client_rpc->WriteCallData(init_data, false, false,
|
|
861
|
+
starpc::Error::OK);
|
|
862
|
+
if (err != starpc::Error::OK) {
|
|
863
|
+
std::cerr << "FAILED: Send init error: " << starpc::ErrorString(err)
|
|
864
|
+
<< std::endl;
|
|
865
|
+
ctx->done.store(true);
|
|
866
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
867
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
868
|
+
server_thread.join();
|
|
869
|
+
return false;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// Read ack packet
|
|
873
|
+
std::string ack_data;
|
|
874
|
+
err = ctx->client_rpc->ReadOne(&ack_data);
|
|
875
|
+
if (err != starpc::Error::OK) {
|
|
876
|
+
std::cerr << "FAILED: Read ack error: " << starpc::ErrorString(err)
|
|
877
|
+
<< std::endl;
|
|
878
|
+
ctx->done.store(true);
|
|
879
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
880
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
881
|
+
server_thread.join();
|
|
882
|
+
return false;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
rpcstream::RpcStreamPacket ack_pkt;
|
|
886
|
+
if (!ack_pkt.ParseFromString(ack_data) || !ack_pkt.has_ack()) {
|
|
887
|
+
std::cerr << "FAILED: Invalid ack packet" << std::endl;
|
|
888
|
+
ctx->done.store(true);
|
|
889
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
890
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
891
|
+
server_thread.join();
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
if (!ack_pkt.ack().error().empty()) {
|
|
896
|
+
std::cerr << "FAILED: Ack error: " << ack_pkt.ack().error() << std::endl;
|
|
897
|
+
ctx->done.store(true);
|
|
898
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
899
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
900
|
+
server_thread.join();
|
|
901
|
+
return false;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// Create CallStart packet for Echo call
|
|
905
|
+
echo::EchoMsg req;
|
|
906
|
+
req.set_body(kTestBody);
|
|
907
|
+
std::string req_data;
|
|
908
|
+
req.SerializeToString(&req_data);
|
|
909
|
+
auto call_start =
|
|
910
|
+
starpc::NewCallStartPacket("echo.Echoer", "Echo", req_data, true);
|
|
911
|
+
|
|
912
|
+
// Wrap in RpcStreamPacket and send
|
|
913
|
+
std::string call_start_data;
|
|
914
|
+
call_start->SerializeToString(&call_start_data);
|
|
915
|
+
rpcstream::RpcStreamPacket data_pkt;
|
|
916
|
+
data_pkt.set_data(call_start_data);
|
|
917
|
+
std::string pkt_data;
|
|
918
|
+
data_pkt.SerializeToString(&pkt_data);
|
|
919
|
+
err =
|
|
920
|
+
ctx->client_rpc->WriteCallData(pkt_data, false, false, starpc::Error::OK);
|
|
921
|
+
if (err != starpc::Error::OK) {
|
|
922
|
+
std::cerr << "FAILED: Send CallStart error: " << starpc::ErrorString(err)
|
|
923
|
+
<< std::endl;
|
|
924
|
+
ctx->done.store(true);
|
|
925
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
926
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
927
|
+
server_thread.join();
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Read response (RpcStreamPacket containing srpc::Packet with CallData)
|
|
932
|
+
std::string resp_data;
|
|
933
|
+
err = ctx->client_rpc->ReadOne(&resp_data);
|
|
934
|
+
if (err != starpc::Error::OK) {
|
|
935
|
+
std::cerr << "FAILED: Read response error: " << starpc::ErrorString(err)
|
|
936
|
+
<< std::endl;
|
|
937
|
+
ctx->done.store(true);
|
|
938
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
939
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
940
|
+
server_thread.join();
|
|
941
|
+
return false;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
rpcstream::RpcStreamPacket resp_pkt;
|
|
945
|
+
if (!resp_pkt.ParseFromString(resp_data) || !resp_pkt.has_data()) {
|
|
946
|
+
std::cerr << "FAILED: Invalid response packet" << std::endl;
|
|
947
|
+
ctx->done.store(true);
|
|
948
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
949
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
950
|
+
server_thread.join();
|
|
951
|
+
return false;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
srpc::Packet inner_pkt;
|
|
955
|
+
if (!inner_pkt.ParseFromString(resp_pkt.data()) ||
|
|
956
|
+
!inner_pkt.has_call_data()) {
|
|
957
|
+
std::cerr << "FAILED: Invalid inner packet" << std::endl;
|
|
958
|
+
ctx->done.store(true);
|
|
959
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
960
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
961
|
+
server_thread.join();
|
|
962
|
+
return false;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
echo::EchoMsg resp;
|
|
966
|
+
if (!resp.ParseFromString(inner_pkt.call_data().data())) {
|
|
967
|
+
std::cerr << "FAILED: Parse EchoMsg error" << std::endl;
|
|
968
|
+
ctx->done.store(true);
|
|
969
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
970
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
971
|
+
server_thread.join();
|
|
972
|
+
return false;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
if (resp.body() != kTestBody) {
|
|
976
|
+
std::cerr << "FAILED: Expected '" << kTestBody << "' got '" << resp.body()
|
|
977
|
+
<< "'" << std::endl;
|
|
978
|
+
ctx->client_rpc->Close();
|
|
979
|
+
ctx->done.store(true);
|
|
980
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
981
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
982
|
+
server_thread.join();
|
|
983
|
+
return false;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// Close the RPC to signal server we're done
|
|
987
|
+
ctx->client_rpc->Close();
|
|
988
|
+
|
|
989
|
+
// Cleanup
|
|
990
|
+
ctx->done.store(true);
|
|
991
|
+
InMemoryTransport::Close(transport.ClientReader());
|
|
992
|
+
InMemoryTransport::Close(transport.ServerReader());
|
|
993
|
+
server_thread.join();
|
|
994
|
+
|
|
995
|
+
std::cout << "PASSED" << std::endl;
|
|
996
|
+
return true;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
} // namespace
|
|
1000
|
+
|
|
1001
|
+
int main() {
|
|
1002
|
+
std::cout << "=== starpc C++ E2E Tests ===" << std::endl;
|
|
1003
|
+
|
|
1004
|
+
int passed = 0;
|
|
1005
|
+
int failed = 0;
|
|
1006
|
+
|
|
1007
|
+
if (TestUnary()) {
|
|
1008
|
+
passed++;
|
|
1009
|
+
} else {
|
|
1010
|
+
failed++;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
if (TestServerStream()) {
|
|
1014
|
+
passed++;
|
|
1015
|
+
} else {
|
|
1016
|
+
failed++;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
if (TestClientStream()) {
|
|
1020
|
+
passed++;
|
|
1021
|
+
} else {
|
|
1022
|
+
failed++;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
if (TestBidiStream()) {
|
|
1026
|
+
passed++;
|
|
1027
|
+
} else {
|
|
1028
|
+
failed++;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
if (TestDoNothing()) {
|
|
1032
|
+
passed++;
|
|
1033
|
+
} else {
|
|
1034
|
+
failed++;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
if (TestRpcStream()) {
|
|
1038
|
+
passed++;
|
|
1039
|
+
} else {
|
|
1040
|
+
failed++;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
std::cout << std::endl;
|
|
1044
|
+
std::cout << "Results: " << passed << " passed, " << failed << " failed"
|
|
1045
|
+
<< std::endl;
|
|
1046
|
+
|
|
1047
|
+
return failed > 0 ? 1 : 0;
|
|
1048
|
+
}
|