blob: c6f25da7b5acf7cce063be00928144af9b4049ce [file] [log] [blame]
Davide Pesavento22fba352017-10-17 15:53:51 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesaventoe422f9e2022-06-03 01:30:23 -04003 * Copyright (c) 2014-2022, Regents of the University of California,
Davide Pesavento22fba352017-10-17 15:53:51 -04004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#ifndef NFD_TESTS_DAEMON_FACE_WEBSOCKET_TRANSPORT_FIXTURE_HPP
27#define NFD_TESTS_DAEMON_FACE_WEBSOCKET_TRANSPORT_FIXTURE_HPP
28
29#include "face/websocket-transport.hpp"
30#include "face/face.hpp"
31
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040032#include "tests/test-common.hpp"
Davide Pesavento3dade002019-03-19 11:29:56 -060033#include "tests/daemon/limited-io.hpp"
Davide Pesaventoa8098582019-03-31 15:48:02 -040034#include "tests/daemon/face/dummy-link-service.hpp"
Davide Pesavento279af1c2022-08-29 20:18:32 -040035#include "tests/daemon/face/transport-test-common.hpp"
Davide Pesavento22fba352017-10-17 15:53:51 -040036
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040037namespace nfd::tests {
Davide Pesavento22fba352017-10-17 15:53:51 -040038
Davide Pesavento22fba352017-10-17 15:53:51 -040039namespace ip = boost::asio::ip;
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040040using face::WebSocketTransport;
Davide Pesavento22fba352017-10-17 15:53:51 -040041
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040042/** \brief A fixture that accepts a single WebSocket connection from a client.
Davide Pesavento22fba352017-10-17 15:53:51 -040043 */
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040044class WebSocketTransportFixture : public GlobalIoFixture
Davide Pesavento22fba352017-10-17 15:53:51 -040045{
46protected:
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040047 /** \brief Initialize server and start listening.
Davide Pesavento22fba352017-10-17 15:53:51 -040048 */
49 void
50 serverListen(const ip::tcp::endpoint& ep,
Davide Pesavento14e71f02019-03-28 17:35:25 -040051 const time::milliseconds& pongTimeout = 1_s)
Davide Pesavento22fba352017-10-17 15:53:51 -040052 {
53 server.clear_access_channels(websocketpp::log::alevel::all);
54 server.clear_error_channels(websocketpp::log::elevel::all);
55
56 server.init_asio(&g_io);
Davide Pesavento412c9822021-07-02 00:21:05 -040057 server.set_open_handler(std::bind(&WebSocketTransportFixture::serverHandleOpen, this, _1));
58 server.set_close_handler(std::bind(&WebSocketTransportFixture::serverHandleClose, this));
59 server.set_message_handler(std::bind(&WebSocketTransportFixture::serverHandleMessage, this, _2));
60 server.set_pong_handler(std::bind(&WebSocketTransportFixture::serverHandlePong, this));
61 server.set_pong_timeout_handler(std::bind(&WebSocketTransportFixture::serverHandlePongTimeout, this));
Davide Pesavento22fba352017-10-17 15:53:51 -040062 server.set_pong_timeout(pongTimeout.count());
63
64 server.set_reuse_addr(true);
65
66 server.listen(ep);
67 server.start_accept();
68 }
69
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040070 /** \brief Initialize client and connect to server.
Davide Pesavento22fba352017-10-17 15:53:51 -040071 */
72 void
73 clientConnect(const std::string& uri)
74 {
75 client.clear_access_channels(websocketpp::log::alevel::all);
76 client.clear_error_channels(websocketpp::log::elevel::all);
77
78 client.init_asio(&g_io);
Davide Pesavento412c9822021-07-02 00:21:05 -040079 client.set_open_handler(std::bind(&WebSocketTransportFixture::clientHandleOpen, this, _1));
80 client.set_message_handler(std::bind(&WebSocketTransportFixture::clientHandleMessage, this, _2));
81 client.set_ping_handler(std::bind(&WebSocketTransportFixture::clientHandlePing, this));
Davide Pesavento22fba352017-10-17 15:53:51 -040082
83 websocketpp::lib::error_code ec;
84 auto con = client.get_connection(uri, ec);
85 BOOST_REQUIRE_EQUAL(ec, websocketpp::lib::error_code());
86
87 client.connect(con);
88 }
89
Davide Pesavento279af1c2022-08-29 20:18:32 -040090 /**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040091 * \brief Initialize both server and client, and have each other connected, create Transport.
Davide Pesavento22fba352017-10-17 15:53:51 -040092 */
93 void
Davide Pesavento279af1c2022-08-29 20:18:32 -040094 initialize(const shared_ptr<const ndn::net::NetworkInterface>&,
95 const ip::address& address,
Davide Pesavento14e71f02019-03-28 17:35:25 -040096 time::milliseconds pingInterval = 10_s,
97 time::milliseconds pongTimeout = 1_s)
Davide Pesavento22fba352017-10-17 15:53:51 -040098 {
99 ip::tcp::endpoint ep(address, 20070);
100 serverListen(ep, pongTimeout);
101 clientConnect(FaceUri(ep, "ws").toString());
102
103 BOOST_REQUIRE_EQUAL(limitedIo.run(2, // serverHandleOpen, clientHandleOpen
Davide Pesavento14e71f02019-03-28 17:35:25 -0400104 1_s), LimitedIo::EXCEED_OPS);
Davide Pesavento22fba352017-10-17 15:53:51 -0400105
Davide Pesaventoa8098582019-03-31 15:48:02 -0400106 face = make_unique<Face>(make_unique<DummyLinkService>(),
Alexander Afanasyeva6bd7da2019-04-25 17:26:11 -0400107 make_unique<WebSocketTransport>(serverHdl, server, pingInterval));
Davide Pesavento22fba352017-10-17 15:53:51 -0400108 transport = static_cast<WebSocketTransport*>(face->getTransport());
Davide Pesaventoa8098582019-03-31 15:48:02 -0400109 serverReceivedPackets = &static_cast<DummyLinkService*>(face->getLinkService())->receivedPackets;
Davide Pesavento22fba352017-10-17 15:53:51 -0400110
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400111 BOOST_REQUIRE_EQUAL(transport->getState(), face::TransportState::UP);
Davide Pesavento22fba352017-10-17 15:53:51 -0400112 }
113
114private:
115 void
116 serverHandleOpen(websocketpp::connection_hdl hdl)
117 {
118 websocketpp::lib::error_code ec;
119 auto con = server.get_con_from_hdl(hdl, ec);
120 BOOST_REQUIRE_EQUAL(ec, websocketpp::lib::error_code());
121 BOOST_REQUIRE(con);
122 remoteEp = con->get_socket().remote_endpoint();
123
124 serverHdl = hdl;
125 limitedIo.afterOp();
126 }
127
128 void
129 serverHandleClose()
130 {
131 if (transport == nullptr) {
132 return;
133 }
134
135 transport->close();
136 limitedIo.afterOp();
137 }
138
139 void
140 serverHandleMessage(websocket::Server::message_ptr msg)
141 {
142 if (transport == nullptr) {
143 return;
144 }
145
146 transport->receiveMessage(msg->get_payload());
147 limitedIo.afterOp();
148 }
149
150 void
151 serverHandlePong()
152 {
153 if (transport == nullptr) {
154 return;
155 }
156
157 transport->handlePong();
158 limitedIo.afterOp();
159 }
160
161 void
162 serverHandlePongTimeout()
163 {
164 if (transport == nullptr) {
165 return;
166 }
167
168 transport->handlePongTimeout();
169 limitedIo.afterOp();
170 }
171
172 void
173 clientHandleOpen(websocketpp::connection_hdl hdl)
174 {
175 clientHdl = hdl;
176 limitedIo.afterOp();
177 }
178
179 void
180 clientHandleMessage(websocket::Client::message_ptr msg)
181 {
182 clientReceivedMessages.push_back(msg->get_payload());
183 limitedIo.afterOp();
184 }
185
186 bool
187 clientHandlePing()
188 {
189 limitedIo.afterOp();
190 return clientShouldPong;
191 }
192
193protected:
194 LimitedIo limitedIo;
195
196 websocket::Server server;
197 websocketpp::connection_hdl serverHdl;
198 ip::tcp::endpoint remoteEp;
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400199 WebSocketTransport* transport = nullptr;
200 std::vector<RxPacket>* serverReceivedPackets = nullptr;
Davide Pesavento22fba352017-10-17 15:53:51 -0400201
202 websocket::Client client;
203 websocketpp::connection_hdl clientHdl;
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400204 bool clientShouldPong = true;
Davide Pesavento22fba352017-10-17 15:53:51 -0400205 std::vector<std::string> clientReceivedMessages;
206
207private:
208 unique_ptr<Face> face;
209};
210
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400211} // namespace nfd::tests
Davide Pesavento22fba352017-10-17 15:53:51 -0400212
213#endif // NFD_TESTS_DAEMON_FACE_WEBSOCKET_TRANSPORT_FIXTURE_HPP