Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmcppdap/src/session_test.cpp
3153 views
1
// Copyright 2019 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "dap/session.h"
16
#include "dap/io.h"
17
#include "dap/protocol.h"
18
19
#include "chan.h"
20
21
#include "gmock/gmock.h"
22
#include "gtest/gtest.h"
23
24
#include <array>
25
#include <atomic>
26
#include <condition_variable>
27
#include <mutex>
28
#include <thread>
29
30
namespace dap {
31
32
struct TestResponse : public Response {
33
boolean b;
34
integer i;
35
number n;
36
array<integer> a;
37
object o;
38
string s;
39
optional<integer> o1;
40
optional<integer> o2;
41
};
42
43
DAP_STRUCT_TYPEINFO(TestResponse,
44
"test-response",
45
DAP_FIELD(b, "res_b"),
46
DAP_FIELD(i, "res_i"),
47
DAP_FIELD(n, "res_n"),
48
DAP_FIELD(a, "res_a"),
49
DAP_FIELD(o, "res_o"),
50
DAP_FIELD(s, "res_s"),
51
DAP_FIELD(o1, "res_o1"),
52
DAP_FIELD(o2, "res_o2"));
53
54
struct TestRequest : public Request {
55
using Response = TestResponse;
56
57
boolean b;
58
integer i;
59
number n;
60
array<integer> a;
61
object o;
62
string s;
63
optional<integer> o1;
64
optional<integer> o2;
65
};
66
67
DAP_STRUCT_TYPEINFO(TestRequest,
68
"test-request",
69
DAP_FIELD(b, "req_b"),
70
DAP_FIELD(i, "req_i"),
71
DAP_FIELD(n, "req_n"),
72
DAP_FIELD(a, "req_a"),
73
DAP_FIELD(o, "req_o"),
74
DAP_FIELD(s, "req_s"),
75
DAP_FIELD(o1, "req_o1"),
76
DAP_FIELD(o2, "req_o2"));
77
78
struct TestEvent : public Event {
79
boolean b;
80
integer i;
81
number n;
82
array<integer> a;
83
object o;
84
string s;
85
optional<integer> o1;
86
optional<integer> o2;
87
};
88
89
DAP_STRUCT_TYPEINFO(TestEvent,
90
"test-event",
91
DAP_FIELD(b, "evt_b"),
92
DAP_FIELD(i, "evt_i"),
93
DAP_FIELD(n, "evt_n"),
94
DAP_FIELD(a, "evt_a"),
95
DAP_FIELD(o, "evt_o"),
96
DAP_FIELD(s, "evt_s"),
97
DAP_FIELD(o1, "evt_o1"),
98
DAP_FIELD(o2, "evt_o2"));
99
100
}; // namespace dap
101
102
namespace {
103
104
dap::TestRequest createRequest() {
105
dap::TestRequest request;
106
request.b = false;
107
request.i = 72;
108
request.n = 9.87;
109
request.a = {2, 5, 7, 8};
110
request.o = {
111
std::make_pair("a", dap::integer(1)),
112
std::make_pair("b", dap::number(2)),
113
std::make_pair("c", dap::string("3")),
114
};
115
request.s = "request";
116
request.o2 = 42;
117
return request;
118
}
119
120
dap::TestResponse createResponse() {
121
dap::TestResponse response;
122
response.b = true;
123
response.i = 99;
124
response.n = 123.456;
125
response.a = {5, 4, 3, 2, 1};
126
response.o = {
127
std::make_pair("one", dap::integer(1)),
128
std::make_pair("two", dap::number(2)),
129
std::make_pair("three", dap::string("3")),
130
};
131
response.s = "ROGER";
132
response.o1 = 50;
133
return response;
134
}
135
136
dap::TestEvent createEvent() {
137
dap::TestEvent event;
138
event.b = false;
139
event.i = 72;
140
event.n = 9.87;
141
event.a = {2, 5, 7, 8};
142
event.o = {
143
std::make_pair("a", dap::integer(1)),
144
std::make_pair("b", dap::number(2)),
145
std::make_pair("c", dap::string("3")),
146
};
147
event.s = "event";
148
event.o2 = 42;
149
return event;
150
}
151
152
} // anonymous namespace
153
154
class SessionTest : public testing::Test {
155
public:
156
void bind() {
157
auto client2server = dap::pipe();
158
auto server2client = dap::pipe();
159
client->bind(server2client, client2server);
160
server->bind(client2server, server2client);
161
}
162
163
std::unique_ptr<dap::Session> client = dap::Session::create();
164
std::unique_ptr<dap::Session> server = dap::Session::create();
165
};
166
167
TEST_F(SessionTest, Request) {
168
dap::TestRequest received;
169
server->registerHandler([&](const dap::TestRequest& req) {
170
received = req;
171
return createResponse();
172
});
173
174
bind();
175
176
auto request = createRequest();
177
client->send(request).get();
178
179
// Check request was received correctly.
180
ASSERT_EQ(received.b, request.b);
181
ASSERT_EQ(received.i, request.i);
182
ASSERT_EQ(received.n, request.n);
183
ASSERT_EQ(received.a, request.a);
184
ASSERT_EQ(received.o.size(), 3U);
185
ASSERT_EQ(received.o["a"].get<dap::integer>(),
186
request.o["a"].get<dap::integer>());
187
ASSERT_EQ(received.o["b"].get<dap::number>(),
188
request.o["b"].get<dap::number>());
189
ASSERT_EQ(received.o["c"].get<dap::string>(),
190
request.o["c"].get<dap::string>());
191
ASSERT_EQ(received.s, request.s);
192
ASSERT_EQ(received.o1, request.o1);
193
ASSERT_EQ(received.o2, request.o2);
194
}
195
196
TEST_F(SessionTest, RequestResponseSuccess) {
197
server->registerHandler(
198
[&](const dap::TestRequest&) { return createResponse(); });
199
200
bind();
201
202
auto request = createRequest();
203
auto response = client->send(request);
204
205
auto got = response.get();
206
207
// Check response was received correctly.
208
ASSERT_EQ(got.error, false);
209
ASSERT_EQ(got.response.b, dap::boolean(true));
210
ASSERT_EQ(got.response.i, dap::integer(99));
211
ASSERT_EQ(got.response.n, dap::number(123.456));
212
ASSERT_EQ(got.response.a, dap::array<dap::integer>({5, 4, 3, 2, 1}));
213
ASSERT_EQ(got.response.o.size(), 3U);
214
ASSERT_EQ(got.response.o["one"].get<dap::integer>(), dap::integer(1));
215
ASSERT_EQ(got.response.o["two"].get<dap::number>(), dap::number(2));
216
ASSERT_EQ(got.response.o["three"].get<dap::string>(), dap::string("3"));
217
ASSERT_EQ(got.response.s, "ROGER");
218
ASSERT_EQ(got.response.o1, dap::optional<dap::integer>(50));
219
ASSERT_FALSE(got.response.o2.has_value());
220
}
221
222
TEST_F(SessionTest, BreakPointRequestResponseSuccess) {
223
server->registerHandler([&](const dap::SetBreakpointsRequest&) {
224
dap::SetBreakpointsResponse response;
225
dap::Breakpoint bp;
226
bp.line = 2;
227
response.breakpoints.emplace_back(std::move(bp));
228
return response;
229
});
230
231
bind();
232
233
auto got = client->send(dap::SetBreakpointsRequest{}).get();
234
235
// Check response was received correctly.
236
ASSERT_EQ(got.error, false);
237
ASSERT_EQ(got.response.breakpoints.size(), 1U);
238
}
239
240
TEST_F(SessionTest, RequestResponseOrError) {
241
server->registerHandler(
242
[&](const dap::TestRequest&) -> dap::ResponseOrError<dap::TestResponse> {
243
return dap::Error("Oh noes!");
244
});
245
246
bind();
247
248
auto response = client->send(createRequest());
249
250
auto got = response.get();
251
252
// Check response was received correctly.
253
ASSERT_EQ(got.error, true);
254
ASSERT_EQ(got.error.message, "Oh noes!");
255
}
256
257
TEST_F(SessionTest, RequestResponseError) {
258
server->registerHandler(
259
[&](const dap::TestRequest&) { return dap::Error("Oh noes!"); });
260
261
bind();
262
263
auto response = client->send(createRequest());
264
265
auto got = response.get();
266
267
// Check response was received correctly.
268
ASSERT_EQ(got.error, true);
269
ASSERT_EQ(got.error.message, "Oh noes!");
270
}
271
272
TEST_F(SessionTest, RequestCallbackResponse) {
273
using ResponseCallback = std::function<void(dap::SetBreakpointsResponse)>;
274
275
server->registerHandler(
276
[&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {
277
dap::SetBreakpointsResponse response;
278
dap::Breakpoint bp;
279
bp.line = 2;
280
response.breakpoints.emplace_back(std::move(bp));
281
callback(response);
282
});
283
284
bind();
285
286
auto got = client->send(dap::SetBreakpointsRequest{}).get();
287
288
// Check response was received correctly.
289
ASSERT_EQ(got.error, false);
290
ASSERT_EQ(got.response.breakpoints.size(), 1U);
291
}
292
293
TEST_F(SessionTest, RequestCallbackResponseOrError) {
294
using ResponseCallback =
295
std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
296
297
server->registerHandler(
298
[&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {
299
dap::SetBreakpointsResponse response;
300
dap::Breakpoint bp;
301
bp.line = 2;
302
response.breakpoints.emplace_back(std::move(bp));
303
callback(response);
304
});
305
306
bind();
307
308
auto got = client->send(dap::SetBreakpointsRequest{}).get();
309
310
// Check response was received correctly.
311
ASSERT_EQ(got.error, false);
312
ASSERT_EQ(got.response.breakpoints.size(), 1U);
313
}
314
315
TEST_F(SessionTest, RequestCallbackError) {
316
using ResponseCallback =
317
std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
318
319
server->registerHandler(
320
[&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {
321
callback(dap::Error("Oh noes!"));
322
});
323
324
bind();
325
326
auto got = client->send(dap::SetBreakpointsRequest{}).get();
327
328
// Check response was received correctly.
329
ASSERT_EQ(got.error, true);
330
ASSERT_EQ(got.error.message, "Oh noes!");
331
}
332
333
TEST_F(SessionTest, RequestCallbackSuccessAfterReturn) {
334
using ResponseCallback =
335
std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
336
337
ResponseCallback callback;
338
std::mutex mutex;
339
std::condition_variable cv;
340
341
server->registerHandler(
342
[&](const dap::SetBreakpointsRequest&, const ResponseCallback& cb) {
343
std::unique_lock<std::mutex> lock(mutex);
344
callback = cb;
345
cv.notify_all();
346
});
347
348
bind();
349
350
auto future = client->send(dap::SetBreakpointsRequest{});
351
352
{
353
dap::SetBreakpointsResponse response;
354
dap::Breakpoint bp;
355
bp.line = 2;
356
response.breakpoints.emplace_back(std::move(bp));
357
358
// Wait for the handler to be called.
359
std::unique_lock<std::mutex> lock(mutex);
360
cv.wait(lock, [&] { return static_cast<bool>(callback); });
361
362
// Issue the callback
363
callback(response);
364
}
365
366
auto got = future.get();
367
368
// Check response was received correctly.
369
ASSERT_EQ(got.error, false);
370
ASSERT_EQ(got.response.breakpoints.size(), 1U);
371
}
372
373
TEST_F(SessionTest, RequestCallbackErrorAfterReturn) {
374
using ResponseCallback =
375
std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
376
377
ResponseCallback callback;
378
std::mutex mutex;
379
std::condition_variable cv;
380
381
server->registerHandler(
382
[&](const dap::SetBreakpointsRequest&, const ResponseCallback& cb) {
383
std::unique_lock<std::mutex> lock(mutex);
384
callback = cb;
385
cv.notify_all();
386
});
387
388
bind();
389
390
auto future = client->send(dap::SetBreakpointsRequest{});
391
392
{
393
// Wait for the handler to be called.
394
std::unique_lock<std::mutex> lock(mutex);
395
cv.wait(lock, [&] { return static_cast<bool>(callback); });
396
397
// Issue the callback
398
callback(dap::Error("Oh noes!"));
399
}
400
401
auto got = future.get();
402
403
// Check response was received correctly.
404
ASSERT_EQ(got.error, true);
405
ASSERT_EQ(got.error.message, "Oh noes!");
406
}
407
408
TEST_F(SessionTest, ResponseSentHandlerSuccess) {
409
const auto response = createResponse();
410
411
dap::Chan<dap::ResponseOrError<dap::TestResponse>> chan;
412
server->registerHandler([&](const dap::TestRequest&) { return response; });
413
server->registerSentHandler(
414
[&](const dap::ResponseOrError<dap::TestResponse> r) { chan.put(r); });
415
416
bind();
417
418
client->send(createRequest());
419
420
auto got = chan.take().value();
421
ASSERT_EQ(got.error, false);
422
ASSERT_EQ(got.response.b, dap::boolean(true));
423
ASSERT_EQ(got.response.i, dap::integer(99));
424
ASSERT_EQ(got.response.n, dap::number(123.456));
425
ASSERT_EQ(got.response.a, dap::array<dap::integer>({5, 4, 3, 2, 1}));
426
ASSERT_EQ(got.response.o.size(), 3U);
427
ASSERT_EQ(got.response.o["one"].get<dap::integer>(), dap::integer(1));
428
ASSERT_EQ(got.response.o["two"].get<dap::number>(), dap::number(2));
429
ASSERT_EQ(got.response.o["three"].get<dap::string>(), dap::string("3"));
430
ASSERT_EQ(got.response.s, "ROGER");
431
ASSERT_EQ(got.response.o1, dap::optional<dap::integer>(50));
432
ASSERT_FALSE(got.response.o2.has_value());
433
}
434
435
TEST_F(SessionTest, ResponseSentHandlerError) {
436
dap::Chan<dap::ResponseOrError<dap::TestResponse>> chan;
437
server->registerHandler(
438
[&](const dap::TestRequest&) { return dap::Error("Oh noes!"); });
439
server->registerSentHandler(
440
[&](const dap::ResponseOrError<dap::TestResponse> r) { chan.put(r); });
441
442
bind();
443
444
client->send(createRequest());
445
446
auto got = chan.take().value();
447
ASSERT_EQ(got.error, true);
448
ASSERT_EQ(got.error.message, "Oh noes!");
449
}
450
451
TEST_F(SessionTest, Event) {
452
dap::Chan<dap::TestEvent> received;
453
server->registerHandler([&](const dap::TestEvent& e) { received.put(e); });
454
455
bind();
456
457
auto event = createEvent();
458
client->send(event);
459
460
// Check event was received correctly.
461
auto got = received.take().value();
462
463
ASSERT_EQ(got.b, event.b);
464
ASSERT_EQ(got.i, event.i);
465
ASSERT_EQ(got.n, event.n);
466
ASSERT_EQ(got.a, event.a);
467
ASSERT_EQ(got.o.size(), 3U);
468
ASSERT_EQ(got.o["a"].get<dap::integer>(), event.o["a"].get<dap::integer>());
469
ASSERT_EQ(got.o["b"].get<dap::number>(), event.o["b"].get<dap::number>());
470
ASSERT_EQ(got.o["c"].get<dap::string>(), event.o["c"].get<dap::string>());
471
ASSERT_EQ(got.s, event.s);
472
ASSERT_EQ(got.o1, event.o1);
473
ASSERT_EQ(got.o2, event.o2);
474
}
475
476
TEST_F(SessionTest, RegisterHandlerFunction) {
477
struct S {
478
static dap::TestResponse requestA(const dap::TestRequest&) { return {}; }
479
static dap::Error requestB(const dap::TestRequest&) { return {}; }
480
static dap::ResponseOrError<dap::TestResponse> requestC(
481
const dap::TestRequest&) {
482
return dap::Error();
483
}
484
static void event(const dap::TestEvent&) {}
485
static void sent(const dap::ResponseOrError<dap::TestResponse>&) {}
486
};
487
client->registerHandler(&S::requestA);
488
client->registerHandler(&S::requestB);
489
client->registerHandler(&S::requestC);
490
client->registerHandler(&S::event);
491
client->registerSentHandler(&S::sent);
492
}
493
494
TEST_F(SessionTest, SendRequestNoBind) {
495
bool errored = false;
496
client->onError([&](const std::string&) { errored = true; });
497
auto res = client->send(createRequest()).get();
498
ASSERT_TRUE(errored);
499
ASSERT_TRUE(res.error);
500
}
501
502
TEST_F(SessionTest, SendEventNoBind) {
503
bool errored = false;
504
client->onError([&](const std::string&) { errored = true; });
505
client->send(createEvent());
506
ASSERT_TRUE(errored);
507
}
508
509
TEST_F(SessionTest, SingleThread) {
510
server->registerHandler(
511
[&](const dap::TestRequest&) { return createResponse(); });
512
513
// Explicitly connect and process request on this test thread instead of
514
// calling bind() which inturn starts processing messages immediately on a new
515
// thread.
516
auto client2server = dap::pipe();
517
auto server2client = dap::pipe();
518
client->connect(server2client, client2server);
519
server->connect(client2server, server2client);
520
521
auto request = createRequest();
522
auto response = client->send(request);
523
524
// Process request and response on this thread
525
if (auto payload = server->getPayload()) {
526
payload();
527
}
528
if (auto payload = client->getPayload()) {
529
payload();
530
}
531
532
auto got = response.get();
533
// Check response was received correctly.
534
ASSERT_EQ(got.error, false);
535
ASSERT_EQ(got.response.b, dap::boolean(true));
536
ASSERT_EQ(got.response.i, dap::integer(99));
537
ASSERT_EQ(got.response.n, dap::number(123.456));
538
ASSERT_EQ(got.response.a, dap::array<dap::integer>({5, 4, 3, 2, 1}));
539
ASSERT_EQ(got.response.o.size(), 3U);
540
ASSERT_EQ(got.response.o["one"].get<dap::integer>(), dap::integer(1));
541
ASSERT_EQ(got.response.o["two"].get<dap::number>(), dap::number(2));
542
ASSERT_EQ(got.response.o["three"].get<dap::string>(), dap::string("3"));
543
ASSERT_EQ(got.response.s, "ROGER");
544
ASSERT_EQ(got.response.o1, dap::optional<dap::integer>(50));
545
ASSERT_FALSE(got.response.o2.has_value());
546
}
547
548
TEST_F(SessionTest, Concurrency) {
549
std::atomic<int> numEventsHandled = {0};
550
std::atomic<bool> done = {false};
551
552
server->registerHandler(
553
[](const dap::TestRequest&) { return dap::TestResponse(); });
554
555
server->registerHandler([&](const dap::TestEvent&) {
556
if (numEventsHandled++ > 10000) {
557
done = true;
558
}
559
});
560
561
bind();
562
563
constexpr int numThreads = 32;
564
std::array<std::thread, numThreads> threads;
565
566
for (int i = 0; i < numThreads; i++) {
567
threads[i] = std::thread([&] {
568
while (!done) {
569
client->send(createEvent());
570
client->send(createRequest());
571
}
572
});
573
}
574
575
for (int i = 0; i < numThreads; i++) {
576
threads[i].join();
577
}
578
579
client.reset();
580
server.reset();
581
}
582
583
TEST_F(SessionTest, OnClientClosed) {
584
std::mutex mutex;
585
std::condition_variable cv;
586
bool clientClosed = false;
587
588
auto client2server = dap::pipe();
589
auto server2client = dap::pipe();
590
591
client->bind(server2client, client2server);
592
server->bind(client2server, server2client, [&] {
593
std::unique_lock<std::mutex> lock(mutex);
594
clientClosed = true;
595
cv.notify_all();
596
});
597
598
client.reset();
599
600
// Wait for the client closed handler to be called.
601
std::unique_lock<std::mutex> lock(mutex);
602
cv.wait(lock, [&] { return static_cast<bool>(clientClosed); });
603
}
604
605
TEST_F(SessionTest, OnServerClosed) {
606
std::mutex mutex;
607
std::condition_variable cv;
608
bool serverClosed = false;
609
610
auto client2server = dap::pipe();
611
auto server2client = dap::pipe();
612
613
client->bind(server2client, client2server, [&] {
614
std::unique_lock<std::mutex> lock(mutex);
615
serverClosed = true;
616
cv.notify_all();
617
});
618
server->bind(client2server, server2client);
619
620
server.reset();
621
622
// Wait for the client closed handler to be called.
623
std::unique_lock<std::mutex> lock(mutex);
624
cv.wait(lock, [&] { return static_cast<bool>(serverClosed); });
625
}
626
627