Path: blob/master/Utilities/cmcppdap/src/session_test.cpp
3153 views
// Copyright 2019 Google LLC1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// https://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314#include "dap/session.h"15#include "dap/io.h"16#include "dap/protocol.h"1718#include "chan.h"1920#include "gmock/gmock.h"21#include "gtest/gtest.h"2223#include <array>24#include <atomic>25#include <condition_variable>26#include <mutex>27#include <thread>2829namespace dap {3031struct TestResponse : public Response {32boolean b;33integer i;34number n;35array<integer> a;36object o;37string s;38optional<integer> o1;39optional<integer> o2;40};4142DAP_STRUCT_TYPEINFO(TestResponse,43"test-response",44DAP_FIELD(b, "res_b"),45DAP_FIELD(i, "res_i"),46DAP_FIELD(n, "res_n"),47DAP_FIELD(a, "res_a"),48DAP_FIELD(o, "res_o"),49DAP_FIELD(s, "res_s"),50DAP_FIELD(o1, "res_o1"),51DAP_FIELD(o2, "res_o2"));5253struct TestRequest : public Request {54using Response = TestResponse;5556boolean b;57integer i;58number n;59array<integer> a;60object o;61string s;62optional<integer> o1;63optional<integer> o2;64};6566DAP_STRUCT_TYPEINFO(TestRequest,67"test-request",68DAP_FIELD(b, "req_b"),69DAP_FIELD(i, "req_i"),70DAP_FIELD(n, "req_n"),71DAP_FIELD(a, "req_a"),72DAP_FIELD(o, "req_o"),73DAP_FIELD(s, "req_s"),74DAP_FIELD(o1, "req_o1"),75DAP_FIELD(o2, "req_o2"));7677struct TestEvent : public Event {78boolean b;79integer i;80number n;81array<integer> a;82object o;83string s;84optional<integer> o1;85optional<integer> o2;86};8788DAP_STRUCT_TYPEINFO(TestEvent,89"test-event",90DAP_FIELD(b, "evt_b"),91DAP_FIELD(i, "evt_i"),92DAP_FIELD(n, "evt_n"),93DAP_FIELD(a, "evt_a"),94DAP_FIELD(o, "evt_o"),95DAP_FIELD(s, "evt_s"),96DAP_FIELD(o1, "evt_o1"),97DAP_FIELD(o2, "evt_o2"));9899}; // namespace dap100101namespace {102103dap::TestRequest createRequest() {104dap::TestRequest request;105request.b = false;106request.i = 72;107request.n = 9.87;108request.a = {2, 5, 7, 8};109request.o = {110std::make_pair("a", dap::integer(1)),111std::make_pair("b", dap::number(2)),112std::make_pair("c", dap::string("3")),113};114request.s = "request";115request.o2 = 42;116return request;117}118119dap::TestResponse createResponse() {120dap::TestResponse response;121response.b = true;122response.i = 99;123response.n = 123.456;124response.a = {5, 4, 3, 2, 1};125response.o = {126std::make_pair("one", dap::integer(1)),127std::make_pair("two", dap::number(2)),128std::make_pair("three", dap::string("3")),129};130response.s = "ROGER";131response.o1 = 50;132return response;133}134135dap::TestEvent createEvent() {136dap::TestEvent event;137event.b = false;138event.i = 72;139event.n = 9.87;140event.a = {2, 5, 7, 8};141event.o = {142std::make_pair("a", dap::integer(1)),143std::make_pair("b", dap::number(2)),144std::make_pair("c", dap::string("3")),145};146event.s = "event";147event.o2 = 42;148return event;149}150151} // anonymous namespace152153class SessionTest : public testing::Test {154public:155void bind() {156auto client2server = dap::pipe();157auto server2client = dap::pipe();158client->bind(server2client, client2server);159server->bind(client2server, server2client);160}161162std::unique_ptr<dap::Session> client = dap::Session::create();163std::unique_ptr<dap::Session> server = dap::Session::create();164};165166TEST_F(SessionTest, Request) {167dap::TestRequest received;168server->registerHandler([&](const dap::TestRequest& req) {169received = req;170return createResponse();171});172173bind();174175auto request = createRequest();176client->send(request).get();177178// Check request was received correctly.179ASSERT_EQ(received.b, request.b);180ASSERT_EQ(received.i, request.i);181ASSERT_EQ(received.n, request.n);182ASSERT_EQ(received.a, request.a);183ASSERT_EQ(received.o.size(), 3U);184ASSERT_EQ(received.o["a"].get<dap::integer>(),185request.o["a"].get<dap::integer>());186ASSERT_EQ(received.o["b"].get<dap::number>(),187request.o["b"].get<dap::number>());188ASSERT_EQ(received.o["c"].get<dap::string>(),189request.o["c"].get<dap::string>());190ASSERT_EQ(received.s, request.s);191ASSERT_EQ(received.o1, request.o1);192ASSERT_EQ(received.o2, request.o2);193}194195TEST_F(SessionTest, RequestResponseSuccess) {196server->registerHandler(197[&](const dap::TestRequest&) { return createResponse(); });198199bind();200201auto request = createRequest();202auto response = client->send(request);203204auto got = response.get();205206// Check response was received correctly.207ASSERT_EQ(got.error, false);208ASSERT_EQ(got.response.b, dap::boolean(true));209ASSERT_EQ(got.response.i, dap::integer(99));210ASSERT_EQ(got.response.n, dap::number(123.456));211ASSERT_EQ(got.response.a, dap::array<dap::integer>({5, 4, 3, 2, 1}));212ASSERT_EQ(got.response.o.size(), 3U);213ASSERT_EQ(got.response.o["one"].get<dap::integer>(), dap::integer(1));214ASSERT_EQ(got.response.o["two"].get<dap::number>(), dap::number(2));215ASSERT_EQ(got.response.o["three"].get<dap::string>(), dap::string("3"));216ASSERT_EQ(got.response.s, "ROGER");217ASSERT_EQ(got.response.o1, dap::optional<dap::integer>(50));218ASSERT_FALSE(got.response.o2.has_value());219}220221TEST_F(SessionTest, BreakPointRequestResponseSuccess) {222server->registerHandler([&](const dap::SetBreakpointsRequest&) {223dap::SetBreakpointsResponse response;224dap::Breakpoint bp;225bp.line = 2;226response.breakpoints.emplace_back(std::move(bp));227return response;228});229230bind();231232auto got = client->send(dap::SetBreakpointsRequest{}).get();233234// Check response was received correctly.235ASSERT_EQ(got.error, false);236ASSERT_EQ(got.response.breakpoints.size(), 1U);237}238239TEST_F(SessionTest, RequestResponseOrError) {240server->registerHandler(241[&](const dap::TestRequest&) -> dap::ResponseOrError<dap::TestResponse> {242return dap::Error("Oh noes!");243});244245bind();246247auto response = client->send(createRequest());248249auto got = response.get();250251// Check response was received correctly.252ASSERT_EQ(got.error, true);253ASSERT_EQ(got.error.message, "Oh noes!");254}255256TEST_F(SessionTest, RequestResponseError) {257server->registerHandler(258[&](const dap::TestRequest&) { return dap::Error("Oh noes!"); });259260bind();261262auto response = client->send(createRequest());263264auto got = response.get();265266// Check response was received correctly.267ASSERT_EQ(got.error, true);268ASSERT_EQ(got.error.message, "Oh noes!");269}270271TEST_F(SessionTest, RequestCallbackResponse) {272using ResponseCallback = std::function<void(dap::SetBreakpointsResponse)>;273274server->registerHandler(275[&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {276dap::SetBreakpointsResponse response;277dap::Breakpoint bp;278bp.line = 2;279response.breakpoints.emplace_back(std::move(bp));280callback(response);281});282283bind();284285auto got = client->send(dap::SetBreakpointsRequest{}).get();286287// Check response was received correctly.288ASSERT_EQ(got.error, false);289ASSERT_EQ(got.response.breakpoints.size(), 1U);290}291292TEST_F(SessionTest, RequestCallbackResponseOrError) {293using ResponseCallback =294std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;295296server->registerHandler(297[&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {298dap::SetBreakpointsResponse response;299dap::Breakpoint bp;300bp.line = 2;301response.breakpoints.emplace_back(std::move(bp));302callback(response);303});304305bind();306307auto got = client->send(dap::SetBreakpointsRequest{}).get();308309// Check response was received correctly.310ASSERT_EQ(got.error, false);311ASSERT_EQ(got.response.breakpoints.size(), 1U);312}313314TEST_F(SessionTest, RequestCallbackError) {315using ResponseCallback =316std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;317318server->registerHandler(319[&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {320callback(dap::Error("Oh noes!"));321});322323bind();324325auto got = client->send(dap::SetBreakpointsRequest{}).get();326327// Check response was received correctly.328ASSERT_EQ(got.error, true);329ASSERT_EQ(got.error.message, "Oh noes!");330}331332TEST_F(SessionTest, RequestCallbackSuccessAfterReturn) {333using ResponseCallback =334std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;335336ResponseCallback callback;337std::mutex mutex;338std::condition_variable cv;339340server->registerHandler(341[&](const dap::SetBreakpointsRequest&, const ResponseCallback& cb) {342std::unique_lock<std::mutex> lock(mutex);343callback = cb;344cv.notify_all();345});346347bind();348349auto future = client->send(dap::SetBreakpointsRequest{});350351{352dap::SetBreakpointsResponse response;353dap::Breakpoint bp;354bp.line = 2;355response.breakpoints.emplace_back(std::move(bp));356357// Wait for the handler to be called.358std::unique_lock<std::mutex> lock(mutex);359cv.wait(lock, [&] { return static_cast<bool>(callback); });360361// Issue the callback362callback(response);363}364365auto got = future.get();366367// Check response was received correctly.368ASSERT_EQ(got.error, false);369ASSERT_EQ(got.response.breakpoints.size(), 1U);370}371372TEST_F(SessionTest, RequestCallbackErrorAfterReturn) {373using ResponseCallback =374std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;375376ResponseCallback callback;377std::mutex mutex;378std::condition_variable cv;379380server->registerHandler(381[&](const dap::SetBreakpointsRequest&, const ResponseCallback& cb) {382std::unique_lock<std::mutex> lock(mutex);383callback = cb;384cv.notify_all();385});386387bind();388389auto future = client->send(dap::SetBreakpointsRequest{});390391{392// Wait for the handler to be called.393std::unique_lock<std::mutex> lock(mutex);394cv.wait(lock, [&] { return static_cast<bool>(callback); });395396// Issue the callback397callback(dap::Error("Oh noes!"));398}399400auto got = future.get();401402// Check response was received correctly.403ASSERT_EQ(got.error, true);404ASSERT_EQ(got.error.message, "Oh noes!");405}406407TEST_F(SessionTest, ResponseSentHandlerSuccess) {408const auto response = createResponse();409410dap::Chan<dap::ResponseOrError<dap::TestResponse>> chan;411server->registerHandler([&](const dap::TestRequest&) { return response; });412server->registerSentHandler(413[&](const dap::ResponseOrError<dap::TestResponse> r) { chan.put(r); });414415bind();416417client->send(createRequest());418419auto got = chan.take().value();420ASSERT_EQ(got.error, false);421ASSERT_EQ(got.response.b, dap::boolean(true));422ASSERT_EQ(got.response.i, dap::integer(99));423ASSERT_EQ(got.response.n, dap::number(123.456));424ASSERT_EQ(got.response.a, dap::array<dap::integer>({5, 4, 3, 2, 1}));425ASSERT_EQ(got.response.o.size(), 3U);426ASSERT_EQ(got.response.o["one"].get<dap::integer>(), dap::integer(1));427ASSERT_EQ(got.response.o["two"].get<dap::number>(), dap::number(2));428ASSERT_EQ(got.response.o["three"].get<dap::string>(), dap::string("3"));429ASSERT_EQ(got.response.s, "ROGER");430ASSERT_EQ(got.response.o1, dap::optional<dap::integer>(50));431ASSERT_FALSE(got.response.o2.has_value());432}433434TEST_F(SessionTest, ResponseSentHandlerError) {435dap::Chan<dap::ResponseOrError<dap::TestResponse>> chan;436server->registerHandler(437[&](const dap::TestRequest&) { return dap::Error("Oh noes!"); });438server->registerSentHandler(439[&](const dap::ResponseOrError<dap::TestResponse> r) { chan.put(r); });440441bind();442443client->send(createRequest());444445auto got = chan.take().value();446ASSERT_EQ(got.error, true);447ASSERT_EQ(got.error.message, "Oh noes!");448}449450TEST_F(SessionTest, Event) {451dap::Chan<dap::TestEvent> received;452server->registerHandler([&](const dap::TestEvent& e) { received.put(e); });453454bind();455456auto event = createEvent();457client->send(event);458459// Check event was received correctly.460auto got = received.take().value();461462ASSERT_EQ(got.b, event.b);463ASSERT_EQ(got.i, event.i);464ASSERT_EQ(got.n, event.n);465ASSERT_EQ(got.a, event.a);466ASSERT_EQ(got.o.size(), 3U);467ASSERT_EQ(got.o["a"].get<dap::integer>(), event.o["a"].get<dap::integer>());468ASSERT_EQ(got.o["b"].get<dap::number>(), event.o["b"].get<dap::number>());469ASSERT_EQ(got.o["c"].get<dap::string>(), event.o["c"].get<dap::string>());470ASSERT_EQ(got.s, event.s);471ASSERT_EQ(got.o1, event.o1);472ASSERT_EQ(got.o2, event.o2);473}474475TEST_F(SessionTest, RegisterHandlerFunction) {476struct S {477static dap::TestResponse requestA(const dap::TestRequest&) { return {}; }478static dap::Error requestB(const dap::TestRequest&) { return {}; }479static dap::ResponseOrError<dap::TestResponse> requestC(480const dap::TestRequest&) {481return dap::Error();482}483static void event(const dap::TestEvent&) {}484static void sent(const dap::ResponseOrError<dap::TestResponse>&) {}485};486client->registerHandler(&S::requestA);487client->registerHandler(&S::requestB);488client->registerHandler(&S::requestC);489client->registerHandler(&S::event);490client->registerSentHandler(&S::sent);491}492493TEST_F(SessionTest, SendRequestNoBind) {494bool errored = false;495client->onError([&](const std::string&) { errored = true; });496auto res = client->send(createRequest()).get();497ASSERT_TRUE(errored);498ASSERT_TRUE(res.error);499}500501TEST_F(SessionTest, SendEventNoBind) {502bool errored = false;503client->onError([&](const std::string&) { errored = true; });504client->send(createEvent());505ASSERT_TRUE(errored);506}507508TEST_F(SessionTest, SingleThread) {509server->registerHandler(510[&](const dap::TestRequest&) { return createResponse(); });511512// Explicitly connect and process request on this test thread instead of513// calling bind() which inturn starts processing messages immediately on a new514// thread.515auto client2server = dap::pipe();516auto server2client = dap::pipe();517client->connect(server2client, client2server);518server->connect(client2server, server2client);519520auto request = createRequest();521auto response = client->send(request);522523// Process request and response on this thread524if (auto payload = server->getPayload()) {525payload();526}527if (auto payload = client->getPayload()) {528payload();529}530531auto got = response.get();532// Check response was received correctly.533ASSERT_EQ(got.error, false);534ASSERT_EQ(got.response.b, dap::boolean(true));535ASSERT_EQ(got.response.i, dap::integer(99));536ASSERT_EQ(got.response.n, dap::number(123.456));537ASSERT_EQ(got.response.a, dap::array<dap::integer>({5, 4, 3, 2, 1}));538ASSERT_EQ(got.response.o.size(), 3U);539ASSERT_EQ(got.response.o["one"].get<dap::integer>(), dap::integer(1));540ASSERT_EQ(got.response.o["two"].get<dap::number>(), dap::number(2));541ASSERT_EQ(got.response.o["three"].get<dap::string>(), dap::string("3"));542ASSERT_EQ(got.response.s, "ROGER");543ASSERT_EQ(got.response.o1, dap::optional<dap::integer>(50));544ASSERT_FALSE(got.response.o2.has_value());545}546547TEST_F(SessionTest, Concurrency) {548std::atomic<int> numEventsHandled = {0};549std::atomic<bool> done = {false};550551server->registerHandler(552[](const dap::TestRequest&) { return dap::TestResponse(); });553554server->registerHandler([&](const dap::TestEvent&) {555if (numEventsHandled++ > 10000) {556done = true;557}558});559560bind();561562constexpr int numThreads = 32;563std::array<std::thread, numThreads> threads;564565for (int i = 0; i < numThreads; i++) {566threads[i] = std::thread([&] {567while (!done) {568client->send(createEvent());569client->send(createRequest());570}571});572}573574for (int i = 0; i < numThreads; i++) {575threads[i].join();576}577578client.reset();579server.reset();580}581582TEST_F(SessionTest, OnClientClosed) {583std::mutex mutex;584std::condition_variable cv;585bool clientClosed = false;586587auto client2server = dap::pipe();588auto server2client = dap::pipe();589590client->bind(server2client, client2server);591server->bind(client2server, server2client, [&] {592std::unique_lock<std::mutex> lock(mutex);593clientClosed = true;594cv.notify_all();595});596597client.reset();598599// Wait for the client closed handler to be called.600std::unique_lock<std::mutex> lock(mutex);601cv.wait(lock, [&] { return static_cast<bool>(clientClosed); });602}603604TEST_F(SessionTest, OnServerClosed) {605std::mutex mutex;606std::condition_variable cv;607bool serverClosed = false;608609auto client2server = dap::pipe();610auto server2client = dap::pipe();611612client->bind(server2client, client2server, [&] {613std::unique_lock<std::mutex> lock(mutex);614serverClosed = true;615cv.notify_all();616});617server->bind(client2server, server2client);618619server.reset();620621// Wait for the client closed handler to be called.622std::unique_lock<std::mutex> lock(mutex);623cv.wait(lock, [&] { return static_cast<bool>(serverClosed); });624}625626627