Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
integration.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014, Peter Thorson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of the WebSocket++ Project nor the
12 * names of its contributors may be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27//#define BOOST_TEST_DYN_LINK
28#define BOOST_TEST_MODULE transport_integration
29#include <boost/test/unit_test.hpp>
30
32
40
42 typedef config type;
44
46
49
53
56
58
68
71
72 //static const websocketpp::log::level elog_level = websocketpp::log::elevel::all;
73 //static const websocketpp::log::level alog_level = websocketpp::log::alevel::all;
74
76 static const long timeout_open_handshake = 500;
78 static const long timeout_close_handshake = 500;
80 static const long timeout_pong = 500;
81};
82
124
127
130
133
134using websocketpp::lib::placeholders::_1;
135using websocketpp::lib::placeholders::_2;
136using websocketpp::lib::bind;
137
138template <typename T>
140 sleep(timeout);
141
142 websocketpp::lib::error_code ec;
143 e.close(hdl,websocketpp::close::status::normal,"",ec);
144 BOOST_CHECK(!ec);
145}
146
147void run_server(server * s, int port, bool log = false) {
148 if (log) {
149 s->set_access_channels(websocketpp::log::alevel::all);
150 s->set_error_channels(websocketpp::log::elevel::all);
151 } else {
152 s->clear_access_channels(websocketpp::log::alevel::all);
153 s->clear_error_channels(websocketpp::log::elevel::all);
154 }
155
156 s->init_asio();
157 s->set_reuse_addr(true);
158
159 s->listen(port);
160 s->start_accept();
161 s->run();
162}
163
164void run_client(client & c, std::string uri, bool log = false) {
165 if (log) {
168 } else {
171 }
172 websocketpp::lib::error_code ec;
173 c.init_asio(ec);
174 c.set_reuse_addr(true);
175 BOOST_CHECK(!ec);
176
178 BOOST_CHECK( !ec );
179 c.connect(con);
180
181 c.run();
182}
183
184void run_client_and_mark(client * c, bool * flag, websocketpp::lib::mutex * mutex) {
185 c->run();
186 BOOST_CHECK( true );
187 websocketpp::lib::lock_guard<websocketpp::lib::mutex> lock(*mutex);
188 *flag = true;
189 BOOST_CHECK( true );
190}
191
192void run_time_limited_client(client & c, std::string uri, long timeout,
193 bool log)
194{
195 if (log) {
198 } else {
201 }
202 c.init_asio();
203
204 websocketpp::lib::error_code ec;
206 BOOST_CHECK( !ec );
207 c.connect(con);
208
209 websocketpp::lib::thread tthread(websocketpp::lib::bind(
211 websocketpp::lib::ref(c),
212 con->get_handle(),
213 timeout
214 ));
215 tthread.detach();
216
217 c.run();
218}
219
220void run_dummy_server(int port) {
221 using boost::asio::ip::tcp;
222
223 try {
224 boost::asio::io_service io_service;
225 tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v6(), port));
226 tcp::socket socket(io_service);
227
228 acceptor.accept(socket);
229 for (;;) {
230 char data[512];
231 boost::system::error_code ec;
232 socket.read_some(boost::asio::buffer(data), ec);
233 if (ec == boost::asio::error::eof) {
234 break;
235 } else if (ec) {
236 // other error
237 throw ec;
238 }
239 }
240 } catch (std::exception & e) {
241 std::cout << e.what() << std::endl;
242 } catch (boost::system::error_code & ec) {
243 std::cout << ec.message() << std::endl;
244 }
245}
246
247void run_dummy_client(std::string port) {
248 using boost::asio::ip::tcp;
249
250 try {
251 boost::asio::io_service io_service;
252 tcp::resolver resolver(io_service);
253 tcp::resolver::query query("localhost", port);
254 tcp::resolver::iterator iterator = resolver.resolve(query);
255 tcp::socket socket(io_service);
256
257 boost::asio::connect(socket, iterator);
258 for (;;) {
259 char data[512];
260 boost::system::error_code ec;
261 socket.read_some(boost::asio::buffer(data), ec);
262 if (ec == boost::asio::error::eof) {
263 break;
264 } else if (ec) {
265 // other error
266 throw ec;
267 }
268 }
269 } catch (std::exception & e) {
270 std::cout << e.what() << std::endl;
271 } catch (boost::system::error_code & ec) {
272 std::cout << ec.message() << std::endl;
273 }
274}
275
277 s->get_alog().write(websocketpp::log::alevel::app,"got ping");
278 return false;
279}
280
282 s->stop_listening();
283}
284
286 server::connection_ptr con = s->get_con_from_hdl(hdl);
287 //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal );
288 //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal );
289 s->stop();
290}
291
292template <typename T>
293void ping_on_open(T * c, std::string payload, websocketpp::connection_hdl hdl) {
294 typename T::connection_ptr con = c->get_con_from_hdl(hdl);
295 websocketpp::lib::error_code ec;
296 con->ping(payload,ec);
297 BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code());
298}
299
301 BOOST_FAIL( "expected no pong handler" );
302}
303
305 BOOST_FAIL( "expected no pong timeout" );
306}
307
308void req_pong(std::string expected_payload, websocketpp::connection_hdl,
309 std::string payload)
310{
311 BOOST_CHECK_EQUAL( expected_payload, payload );
312}
313
315 BOOST_FAIL( "expected no open handler" );
316}
317
318void delay(websocketpp::connection_hdl, long duration) {
319 sleep(duration);
320}
321
322template <typename T>
323void check_ec(T * c, websocketpp::lib::error_code ec,
325{
326 typename T::connection_ptr con = c->get_con_from_hdl(hdl);
327 BOOST_CHECK_EQUAL( con->get_ec(), ec );
328 //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal );
329 //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal );
330}
331
332template <typename T>
333void check_ec_and_stop(T * e, websocketpp::lib::error_code ec,
335{
336 typename T::connection_ptr con = e->get_con_from_hdl(hdl);
337 BOOST_CHECK_EQUAL( con->get_ec(), ec );
338 //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal );
339 //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal );
340 e->stop();
341}
342
343template <typename T>
344void req_pong_timeout(T * c, std::string expected_payload,
345 websocketpp::connection_hdl hdl, std::string payload)
346{
347 typename T::connection_ptr con = c->get_con_from_hdl(hdl);
348 BOOST_CHECK_EQUAL( payload, expected_payload );
349 con->close(websocketpp::close::status::normal,"");
350}
351
352template <typename T>
354 e->get_con_from_hdl(hdl)->close(websocketpp::close::status::normal,"");
355}
356
357// Wait for the specified time period then fail the test
359 sleep(value);
360 BOOST_FAIL( "Test timed out" );
361}
362
363BOOST_AUTO_TEST_CASE( pong_no_timeout ) {
364 server s;
365 client c;
366
367 s.set_close_handler(bind(&stop_on_close,&s,::_1));
368
369 // send a ping when the connection is open
370 c.set_open_handler(bind(&ping_on_open<client>,&c,"foo",::_1));
371 // require that a pong with matching payload is received
372 c.set_pong_handler(bind(&req_pong,"foo",::_1,::_2));
373 // require that a pong timeout is NOT received
375
376 websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
377
378 // Run a client that closes the connection after 1 seconds
379 run_time_limited_client(c, "http://localhost:9005", 1, false);
380
381 sthread.join();
382}
383
384BOOST_AUTO_TEST_CASE( pong_timeout ) {
385 server s;
386 client c;
387
388 s.set_ping_handler(bind(&on_ping, &s,::_1,::_2));
389 s.set_close_handler(bind(&stop_on_close,&s,::_1));
390
392 websocketpp::lib::error_code(),::_1));
393
394 c.set_pong_handler(bind(&fail_on_pong,::_1,::_2));
395 c.set_open_handler(bind(&ping_on_open<client>,&c,"foo",::_1));
396 c.set_pong_timeout_handler(bind(&req_pong_timeout<client>,&c,"foo",::_1,::_2));
398 websocketpp::lib::error_code(),::_1));
399
400 websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
401 websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
402 tthread.detach();
403
404 run_client(c, "http://localhost:9005",false);
405
406 sthread.join();
407}
408
409BOOST_AUTO_TEST_CASE( client_open_handshake_timeout ) {
410 client c;
411
412 // set open handler to fail test
413 c.set_open_handler(bind(&fail_on_open,::_1));
414 // set fail hander to test for the right fail error code
417
418 websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_dummy_server,9005));
419 websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
420 sthread.detach();
421 tthread.detach();
422
423 run_client(c, "http://localhost:9005");
424}
425
426BOOST_AUTO_TEST_CASE( server_open_handshake_timeout ) {
427 server s;
428
429 // set open handler to fail test
430 s.set_open_handler(bind(&fail_on_open,::_1));
431 // set fail hander to test for the right fail error code
432 s.set_fail_handler(bind(&check_ec_and_stop<server>,&s,
434
435 websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
436 websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
437 tthread.detach();
438
439 run_dummy_client("9005");
440
441 sthread.join();
442}
443
444BOOST_AUTO_TEST_CASE( client_self_initiated_close_handshake_timeout ) {
445 server s;
446 client c;
447
448 // on open server sleeps for longer than the timeout
449 // on open client sends close handshake
450 // client handshake timer should be triggered
451 s.set_open_handler(bind(&delay,::_1,1));
452 s.set_close_handler(bind(&stop_on_close,&s,::_1));
453
454 c.set_open_handler(bind(&close<client>,&c,::_1));
457
458 websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
459 websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
460 tthread.detach();
461
462 run_client(c, "http://localhost:9005", false);
463
464 sthread.join();
465}
466
467BOOST_AUTO_TEST_CASE( client_peer_initiated_close_handshake_timeout ) {
468 // on open server sends close
469 // client should ack normally and then wait
470 // server leaves TCP connection open
471 // client handshake timer should be triggered
472
473 // TODO: how to make a mock server that leaves the TCP connection open?
474}
475
476BOOST_AUTO_TEST_CASE( server_self_initiated_close_handshake_timeout ) {
477 server s;
478 client c;
479
480 // on open server sends close
481 // on open client sleeps for longer than the timeout
482 // server handshake timer should be triggered
483
484 s.set_open_handler(bind(&close<server>,&s,::_1));
485 s.set_close_handler(bind(&check_ec_and_stop<server>,&s,
487
488 c.set_open_handler(bind(&delay,::_1,1));
489
490 websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
491 websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,10));
492 tthread.detach();
493
494 run_client(c, "http://localhost:9005",false);
495
496 sthread.join();
497}
498
499BOOST_AUTO_TEST_CASE( client_runs_out_of_work ) {
500 client c;
501
502 websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,3));
503 tthread.detach();
504
505 websocketpp::lib::error_code ec;
506 c.init_asio(ec);
507 BOOST_CHECK(!ec);
508
509 c.run();
510
511 // This test checks that an io_service with no work ends immediately.
512 BOOST_CHECK(true);
513}
514
515
516
517
518BOOST_AUTO_TEST_CASE( client_is_perpetual ) {
519 client c;
520 bool flag = false;
521 websocketpp::lib::mutex mutex;
522
523 websocketpp::lib::error_code ec;
524 c.init_asio(ec);
525 BOOST_CHECK(!ec);
526
527 c.start_perpetual();
528
529 websocketpp::lib::thread cthread(websocketpp::lib::bind(&run_client_and_mark,&c,&flag,&mutex));
530
531 sleep(1);
532
533 {
534 // Checks that the thread hasn't exited yet
535 websocketpp::lib::lock_guard<websocketpp::lib::mutex> lock(mutex);
536 BOOST_CHECK( !flag );
537 }
538
539 c.stop_perpetual();
540
541 sleep(1);
542
543 {
544 // Checks that the thread has exited
545 websocketpp::lib::lock_guard<websocketpp::lib::mutex> lock(mutex);
546 BOOST_CHECK( flag );
547 }
548
549 cthread.join();
550}
551
552BOOST_AUTO_TEST_CASE( client_failed_connection ) {
553 client c;
554
555 run_time_limited_client(c,"http://localhost:9005", 5, false);
556}
557
558BOOST_AUTO_TEST_CASE( stop_listening ) {
559 server s;
560 client c;
561
562 // the first connection stops the server from listening
563 s.set_open_handler(bind(&cancel_on_open,&s,::_1));
564
565 // client immediately closes after opening a connection
566 c.set_open_handler(bind(&close<client>,&c,::_1));
567
568 websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false));
569 websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,5));
570 tthread.detach();
571
572 run_client(c, "http://localhost:9005",false);
573
574 sthread.join();
575}
576
577BOOST_AUTO_TEST_CASE( pause_reading ) {
579 std::string handshake = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n";
580 char buffer[2] = { char(0x81), char(0x80) };
581
582 // suppress output (it needs a place to go to avoid error but we don't care what it is)
583 std::stringstream null_output;
584 s.register_ostream(&null_output);
585
587 con->start();
588
589 // read handshake, should work
590 BOOST_CHECK_EQUAL( con->read_some(handshake.data(), handshake.length()), handshake.length());
591
592 // pause reading and try again. The first read should work, the second should return 0
593 // the first read was queued already after the handshake so it will go through because
594 // reading wasn't paused when it was queued. The byte it reads wont be enough to
595 // complete the frame so another read will be requested. This one wont actually happen
596 // because the connection is paused now.
597 con->pause_reading();
598 BOOST_CHECK_EQUAL( con->read_some(buffer, 1), 1);
599 BOOST_CHECK_EQUAL( con->read_some(buffer+1, 1), 0);
600 // resume reading and try again. Should work this time because the resume should have
601 // re-queued a read.
602 con->resume_reading();
603 BOOST_CHECK_EQUAL( con->read_some(buffer+1, 1), 1);
604}
605
606
607BOOST_AUTO_TEST_CASE( server_connection_cleanup ) {
609}
610
611#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
612BOOST_AUTO_TEST_CASE( move_construct_transport ) {
613 server s1;
614
615 server s2(std::move(s1));
616}
617#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
base::response_type response_type
base::endpoint_msg_manager_type endpoint_msg_manager_type
websocketpp::config::asio base
base::request_type request_type
static const long timeout_pong
Length of time to wait for a pong after a ping.
base::alog_type alog_type
base::rng_type rng_type
websocketpp::transport::asio::endpoint< transport_config > transport_type
static const long timeout_open_handshake
Length of time before an opening handshake is aborted.
static const long timeout_close_handshake
Length of time before a closing handshake is aborted.
config type
base::message_type message_type
base::concurrency_type concurrency_type
base::elog_type elog_type
base::con_msg_manager_type con_msg_manager_type
Client endpoint role based on the given config.
connection_ptr connect(connection_ptr con)
Begin the connection process for the given connection.
connection_ptr get_connection(uri_ptr location, lib::error_code &ec)
Get a new connection.
Concurrency policy that uses std::mutex / boost::mutex.
Definition basic.hpp:37
Stub concurrency policy that implements the interface using no-ops.
Definition none.hpp:60
void set_pong_timeout_handler(pong_timeout_handler h)
Definition endpoint.hpp:302
void set_fail_handler(fail_handler h)
Definition endpoint.hpp:287
alog_type & get_alog()
Get reference to access logger.
Definition endpoint.hpp:261
void clear_access_channels(log::level channels)
Clear Access logging channels.
Definition endpoint.hpp:231
void set_open_handler(open_handler h)
Definition endpoint.hpp:277
void set_access_channels(log::level channels)
Set Access logging channel.
Definition endpoint.hpp:220
void set_error_channels(log::level channels)
Set Error logging channel.
Definition endpoint.hpp:242
void set_pong_handler(pong_handler h)
Definition endpoint.hpp:297
void clear_error_channels(log::level channels)
Clear Error logging channels.
Definition endpoint.hpp:253
void set_close_handler(close_handler h)
Definition endpoint.hpp:282
void set_ping_handler(ping_handler h)
Definition endpoint.hpp:292
Stores, parses, and manipulates HTTP requests.
Definition request.hpp:50
Stores, parses, and manipulates HTTP responses.
Definition response.hpp:57
Basic logger that outputs to an ostream.
Definition basic.hpp:59
Stub logger that ignores all input.
Definition stub.hpp:41
Represents a buffer for a single WebSocket message.
Definition pool.hpp:101
Thread safe stub "random" integer generator.
Definition none.hpp:46
Server endpoint role based on the given config.
connection_ptr get_connection()
Create and initialize a new connection.
Basic ASIO endpoint socket component.
Definition none.hpp:314
Asio based endpoint transport component.
Definition endpoint.hpp:53
void stop_on_close(server *s, websocketpp::connection_hdl hdl)
void req_pong_timeout(T *c, std::string expected_payload, websocketpp::connection_hdl hdl, std::string payload)
void run_client(client &c, std::string uri, bool log=false)
websocketpp::client< websocketpp::config::core_client > iostream_client
void run_test_timer(long value)
BOOST_AUTO_TEST_CASE(pong_no_timeout)
void close_after_timeout(T &e, websocketpp::connection_hdl hdl, long timeout)
void fail_on_open(websocketpp::connection_hdl)
void cancel_on_open(server *s, websocketpp::connection_hdl)
void check_ec(T *c, websocketpp::lib::error_code ec, websocketpp::connection_hdl hdl)
websocketpp::server< config_tls > server_tls
websocketpp::client< config_tls > client_tls
void ping_on_open(T *c, std::string payload, websocketpp::connection_hdl hdl)
void delay(websocketpp::connection_hdl, long duration)
websocketpp::server< config > server
websocketpp::server< websocketpp::config::core > iostream_server
void run_dummy_client(std::string port)
void run_server(server *s, int port, bool log=false)
bool on_ping(server *s, websocketpp::connection_hdl, std::string)
void fail_on_pong_timeout(websocketpp::connection_hdl, std::string)
void run_time_limited_client(client &c, std::string uri, long timeout, bool log)
void check_ec_and_stop(T *e, websocketpp::lib::error_code ec, websocketpp::connection_hdl hdl)
void run_dummy_server(int port)
void run_client_and_mark(client *c, bool *flag, websocketpp::lib::mutex *mutex)
void fail_on_pong(websocketpp::connection_hdl, std::string)
void close(T *e, websocketpp::connection_hdl hdl)
void req_pong(std::string expected_payload, websocketpp::connection_hdl, std::string payload)
websocketpp::client< config > client
@ close_handshake_timeout
WebSocket close handshake timed out.
Definition error.hpp:117
@ open_handshake_timeout
WebSocket opening handshake timed out.
Definition error.hpp:114
lib::weak_ptr< void > connection_hdl
A handle to uniquely identify a connection.
#define value
Definition pkcs11.h:157
#define T(meth, val, expected)
type::concurrency_type concurrency_type
websocketpp::transport::asio::basic_socket::endpoint socket_type
type::request_type request_type
type::alog_type alog_type
type::elog_type elog_type
type::response_type response_type
websocketpp::transport::asio::basic_socket::endpoint socket_type
type::response_type response_type
type::concurrency_type concurrency_type
type::request_type request_type
static const long timeout_open_handshake
Length of time before an opening handshake is aborted.
base::endpoint_msg_manager_type endpoint_msg_manager_type
base::response_type response_type
static const long timeout_close_handshake
Length of time before a closing handshake is aborted.
base::concurrency_type concurrency_type
base::alog_type alog_type
base::con_msg_manager_type con_msg_manager_type
websocketpp::config::asio base
websocketpp::transport::asio::endpoint< transport_config > transport_type
base::elog_type elog_type
base::rng_type rng_type
static const long timeout_pong
Length of time to wait for a pong after a ping.
base::message_type message_type
base::request_type request_type
Client config with asio transport and TLS disabled.
Client config with asio transport and TLS enabled.
Server config with asio transport and TLS disabled.
static level const all
Special aggregate value representing "all levels".
Definition levels.hpp:152
static level const app
Special channel for application specific logs. Not used by the library.
Definition levels.hpp:143
static level const all
Special aggregate value representing "all levels".
Definition levels.hpp:80
void lock()
char * s