starpc 0.44.0 → 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/echo/echo_e2e_test.cpp +794 -35
- package/echo/echo_srpc.pb.cpp +40 -28
- package/echo/echo_srpc.pb.hpp +131 -106
- package/go.mod +2 -2
- package/go.sum +4 -4
- package/mock/mock_srpc.pb.cpp +13 -10
- package/mock/mock_srpc.pb.hpp +34 -28
- package/package.json +5 -4
- package/srpc/client-rpc.cpp +21 -19
- package/srpc/client-rpc.hpp +14 -11
- package/srpc/client.cpp +12 -16
- package/srpc/client.hpp +17 -25
- package/srpc/common-rpc.cpp +13 -14
- package/srpc/common-rpc.hpp +13 -11
- package/srpc/errors.hpp +33 -20
- package/srpc/handler.hpp +3 -3
- package/srpc/invoker.hpp +26 -29
- package/srpc/message.hpp +4 -6
- package/srpc/msg-stream.hpp +13 -11
- package/srpc/mux.cpp +19 -18
- package/srpc/mux.hpp +15 -14
- package/srpc/packet.cpp +25 -27
- package/srpc/packet.hpp +14 -17
- package/srpc/server-rpc.cpp +22 -22
- package/srpc/server-rpc.hpp +15 -13
- package/srpc/starpc.hpp +1 -1
- package/srpc/stream.hpp +18 -16
- package/srpc/writer.hpp +15 -12
package/echo/echo_e2e_test.cpp
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//go:build deps_only
|
|
1
|
+
// go:build deps_only
|
|
2
2
|
|
|
3
3
|
// Echo end-to-end test for starpc C++ implementation.
|
|
4
4
|
// Tests unary and streaming RPC patterns.
|
|
@@ -12,17 +12,18 @@
|
|
|
12
12
|
#include <thread>
|
|
13
13
|
|
|
14
14
|
#include "echo/echo_srpc.pb.hpp"
|
|
15
|
+
#include "rpcstream/rpcstream.hpp"
|
|
15
16
|
#include "srpc/rpcproto.pb.h"
|
|
16
17
|
#include "srpc/starpc.hpp"
|
|
17
18
|
|
|
18
19
|
namespace {
|
|
19
20
|
|
|
20
|
-
const char*
|
|
21
|
+
const char *kTestBody = "hello world via starpc C++ e2e test";
|
|
21
22
|
|
|
22
23
|
// InMemoryTransport provides an in-memory packet transport for testing.
|
|
23
24
|
// Simulates a bidirectional connection between client and server.
|
|
24
25
|
class InMemoryTransport {
|
|
25
|
-
|
|
26
|
+
public:
|
|
26
27
|
struct Endpoint {
|
|
27
28
|
std::mutex mtx;
|
|
28
29
|
std::condition_variable cv;
|
|
@@ -30,8 +31,9 @@ class InMemoryTransport {
|
|
|
30
31
|
bool closed = false;
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
InMemoryTransport()
|
|
34
|
-
|
|
34
|
+
InMemoryTransport()
|
|
35
|
+
: client_endpoint_(std::make_shared<Endpoint>()),
|
|
36
|
+
server_endpoint_(std::make_shared<Endpoint>()) {}
|
|
35
37
|
|
|
36
38
|
// Get writer for client to send to server
|
|
37
39
|
std::shared_ptr<Endpoint> ClientToServer() { return server_endpoint_; }
|
|
@@ -42,7 +44,7 @@ class InMemoryTransport {
|
|
|
42
44
|
// Get reader for server (reads from client)
|
|
43
45
|
std::shared_ptr<Endpoint> ServerReader() { return server_endpoint_; }
|
|
44
46
|
|
|
45
|
-
static void Send(std::shared_ptr<Endpoint> ep, const std::string&
|
|
47
|
+
static void Send(std::shared_ptr<Endpoint> ep, const std::string &data) {
|
|
46
48
|
std::lock_guard<std::mutex> lock(ep->mtx);
|
|
47
49
|
if (!ep->closed) {
|
|
48
50
|
ep->packets.push(data);
|
|
@@ -50,15 +52,16 @@ class InMemoryTransport {
|
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
static bool Recv(std::shared_ptr<Endpoint> ep, std::string*
|
|
55
|
+
static bool Recv(std::shared_ptr<Endpoint> ep, std::string *out,
|
|
56
|
+
int timeout_ms = 5000) {
|
|
54
57
|
std::unique_lock<std::mutex> lock(ep->mtx);
|
|
55
58
|
if (!ep->cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), [&ep]() {
|
|
56
59
|
return !ep->packets.empty() || ep->closed;
|
|
57
60
|
})) {
|
|
58
|
-
return false;
|
|
61
|
+
return false; // timeout
|
|
59
62
|
}
|
|
60
63
|
if (ep->packets.empty()) {
|
|
61
|
-
return false;
|
|
64
|
+
return false; // closed
|
|
62
65
|
}
|
|
63
66
|
*out = ep->packets.front();
|
|
64
67
|
ep->packets.pop();
|
|
@@ -71,18 +74,18 @@ class InMemoryTransport {
|
|
|
71
74
|
ep->cv.notify_all();
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
private:
|
|
75
78
|
std::shared_ptr<Endpoint> client_endpoint_;
|
|
76
79
|
std::shared_ptr<Endpoint> server_endpoint_;
|
|
77
80
|
};
|
|
78
81
|
|
|
79
82
|
// InMemoryPacketWriter writes packets to an InMemoryTransport endpoint.
|
|
80
83
|
class InMemoryPacketWriter : public starpc::PacketWriter {
|
|
81
|
-
|
|
84
|
+
public:
|
|
82
85
|
explicit InMemoryPacketWriter(std::shared_ptr<InMemoryTransport::Endpoint> ep)
|
|
83
86
|
: endpoint_(ep) {}
|
|
84
87
|
|
|
85
|
-
starpc::Error WritePacket(const srpc::Packet&
|
|
88
|
+
starpc::Error WritePacket(const srpc::Packet &pkt) override {
|
|
86
89
|
std::string data;
|
|
87
90
|
if (!pkt.SerializeToString(&data)) {
|
|
88
91
|
return starpc::Error::InvalidMessage;
|
|
@@ -96,20 +99,43 @@ class InMemoryPacketWriter : public starpc::PacketWriter {
|
|
|
96
99
|
return starpc::Error::OK;
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
|
|
102
|
+
private:
|
|
100
103
|
std::shared_ptr<InMemoryTransport::Endpoint> endpoint_;
|
|
101
104
|
};
|
|
102
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
|
+
|
|
103
126
|
// EchoServerImpl implements the echo server.
|
|
104
127
|
class EchoServerImpl : public echo::SRPCEchoerServer {
|
|
105
|
-
|
|
106
|
-
starpc::
|
|
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 {
|
|
107
132
|
resp->set_body(req.body());
|
|
108
133
|
return starpc::Error::OK;
|
|
109
134
|
}
|
|
110
135
|
|
|
111
|
-
starpc::Error
|
|
112
|
-
|
|
136
|
+
starpc::Error
|
|
137
|
+
EchoServerStream(const echo::EchoMsg &req,
|
|
138
|
+
echo::SRPCEchoer_EchoServerStreamStream *strm) override {
|
|
113
139
|
// Send 5 copies of the message
|
|
114
140
|
for (int i = 0; i < 5; i++) {
|
|
115
141
|
echo::EchoMsg msg;
|
|
@@ -122,8 +148,8 @@ class EchoServerImpl : public echo::SRPCEchoerServer {
|
|
|
122
148
|
return starpc::Error::OK;
|
|
123
149
|
}
|
|
124
150
|
|
|
125
|
-
starpc::Error EchoClientStream(echo::SRPCEchoer_EchoClientStreamStream*
|
|
126
|
-
|
|
151
|
+
starpc::Error EchoClientStream(echo::SRPCEchoer_EchoClientStreamStream *strm,
|
|
152
|
+
echo::EchoMsg *resp) override {
|
|
127
153
|
// Receive first message and return it
|
|
128
154
|
echo::EchoMsg msg;
|
|
129
155
|
starpc::Error err = strm->Recv(&msg);
|
|
@@ -134,7 +160,8 @@ class EchoServerImpl : public echo::SRPCEchoerServer {
|
|
|
134
160
|
return starpc::Error::OK;
|
|
135
161
|
}
|
|
136
162
|
|
|
137
|
-
starpc::Error
|
|
163
|
+
starpc::Error
|
|
164
|
+
EchoBidiStream(echo::SRPCEchoer_EchoBidiStreamStream *strm) override {
|
|
138
165
|
// Echo back all received messages
|
|
139
166
|
while (true) {
|
|
140
167
|
echo::EchoMsg msg;
|
|
@@ -153,19 +180,34 @@ class EchoServerImpl : public echo::SRPCEchoerServer {
|
|
|
153
180
|
return starpc::Error::OK;
|
|
154
181
|
}
|
|
155
182
|
|
|
156
|
-
starpc::Error RpcStream(echo::SRPCEchoer_RpcStreamStream*
|
|
157
|
-
//
|
|
158
|
-
|
|
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
|
+
});
|
|
159
197
|
}
|
|
160
198
|
|
|
161
|
-
starpc::Error DoNothing(const google::protobuf::Empty&
|
|
199
|
+
starpc::Error DoNothing(const google::protobuf::Empty &req,
|
|
200
|
+
google::protobuf::Empty *resp) override {
|
|
162
201
|
// Just return OK
|
|
163
202
|
return starpc::Error::OK;
|
|
164
203
|
}
|
|
204
|
+
|
|
205
|
+
private:
|
|
206
|
+
starpc::Mux *rpc_stream_mux_ = nullptr;
|
|
165
207
|
};
|
|
166
208
|
|
|
167
209
|
// RunServer runs the server-side packet handling loop.
|
|
168
|
-
void RunServer(InMemoryTransport*
|
|
210
|
+
void RunServer(InMemoryTransport *transport, starpc::Mux *mux) {
|
|
169
211
|
auto reader = transport->ServerReader();
|
|
170
212
|
auto writer_ep = transport->ServerToClient();
|
|
171
213
|
auto writer = std::make_unique<InMemoryPacketWriter>(writer_ep);
|
|
@@ -196,18 +238,19 @@ bool TestUnary() {
|
|
|
196
238
|
EchoServerImpl server_impl;
|
|
197
239
|
auto [handler, reg_err] = echo::SRPCRegisterEchoer(mux.get(), &server_impl);
|
|
198
240
|
if (reg_err != starpc::Error::OK) {
|
|
199
|
-
std::cerr << "FAILED: Registration error: " << starpc::ErrorString(reg_err)
|
|
241
|
+
std::cerr << "FAILED: Registration error: " << starpc::ErrorString(reg_err)
|
|
242
|
+
<< std::endl;
|
|
200
243
|
return false;
|
|
201
244
|
}
|
|
202
245
|
|
|
203
246
|
// Start server thread
|
|
204
|
-
std::thread server_thread(
|
|
205
|
-
|
|
206
|
-
});
|
|
247
|
+
std::thread server_thread(
|
|
248
|
+
[&transport, &mux]() { RunServer(&transport, mux.get()); });
|
|
207
249
|
|
|
208
250
|
// Setup client
|
|
209
251
|
auto client_rpc = starpc::NewClientRPC("echo.Echoer", "Echo");
|
|
210
|
-
auto writer =
|
|
252
|
+
auto writer =
|
|
253
|
+
std::make_unique<InMemoryPacketWriter>(transport.ClientToServer());
|
|
211
254
|
|
|
212
255
|
// Start client receive thread
|
|
213
256
|
auto client_reader = transport.ClientReader();
|
|
@@ -233,7 +276,8 @@ bool TestUnary() {
|
|
|
233
276
|
|
|
234
277
|
starpc::Error err = client_rpc->Start(writer.get(), true, req_data);
|
|
235
278
|
if (err != starpc::Error::OK) {
|
|
236
|
-
std::cerr << "FAILED: Start error: " << starpc::ErrorString(err)
|
|
279
|
+
std::cerr << "FAILED: Start error: " << starpc::ErrorString(err)
|
|
280
|
+
<< std::endl;
|
|
237
281
|
return false;
|
|
238
282
|
}
|
|
239
283
|
|
|
@@ -241,7 +285,8 @@ bool TestUnary() {
|
|
|
241
285
|
std::string resp_data;
|
|
242
286
|
err = client_rpc->ReadOne(&resp_data);
|
|
243
287
|
if (err != starpc::Error::OK) {
|
|
244
|
-
std::cerr << "FAILED: ReadOne error: " << starpc::ErrorString(err)
|
|
288
|
+
std::cerr << "FAILED: ReadOne error: " << starpc::ErrorString(err)
|
|
289
|
+
<< std::endl;
|
|
245
290
|
return false;
|
|
246
291
|
}
|
|
247
292
|
|
|
@@ -252,7 +297,430 @@ bool TestUnary() {
|
|
|
252
297
|
}
|
|
253
298
|
|
|
254
299
|
if (resp.body() != kTestBody) {
|
|
255
|
-
std::cerr << "FAILED: Expected '" << kTestBody << "' got '" << resp.body()
|
|
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;
|
|
256
724
|
return false;
|
|
257
725
|
}
|
|
258
726
|
|
|
@@ -268,7 +736,267 @@ bool TestUnary() {
|
|
|
268
736
|
return true;
|
|
269
737
|
}
|
|
270
738
|
|
|
271
|
-
|
|
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
|
|
272
1000
|
|
|
273
1001
|
int main() {
|
|
274
1002
|
std::cout << "=== starpc C++ E2E Tests ===" << std::endl;
|
|
@@ -282,8 +1010,39 @@ int main() {
|
|
|
282
1010
|
failed++;
|
|
283
1011
|
}
|
|
284
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
|
+
|
|
285
1043
|
std::cout << std::endl;
|
|
286
|
-
std::cout << "Results: " << passed << " passed, " << failed << " failed"
|
|
1044
|
+
std::cout << "Results: " << passed << " passed, " << failed << " failed"
|
|
1045
|
+
<< std::endl;
|
|
287
1046
|
|
|
288
1047
|
return failed > 0 ? 1 : 0;
|
|
289
1048
|
}
|