2 * Copyright (c) 2014, Peter Thorson. All rights reserved.
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.
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.
27 //#define BOOST_TEST_DYN_LINK
28 #define BOOST_TEST_MODULE transport_iostream_connection
29 #include <boost/test/unit_test.hpp>
35 #include <websocketpp/common/memory.hpp>
37 #include <websocketpp/error.hpp>
38 #include <websocketpp/transport/iostream/connection.hpp>
41 #include <websocketpp/concurrency/basic.hpp>
42 #include <websocketpp/logger/basic.hpp>
45 typedef websocketpp::concurrency::basic concurrency_type;
46 typedef websocketpp::log::basic<concurrency_type,
47 websocketpp::log::elevel> elog_type;
48 typedef websocketpp::log::basic<concurrency_type,
49 websocketpp::log::alevel> alog_type;
52 typedef websocketpp::transport::iostream::connection<config> iostream_con;
54 using websocketpp::transport::iostream::error::make_error_code;
56 struct stub_con : public iostream_con {
57 typedef stub_con type;
58 typedef websocketpp::lib::shared_ptr<type> ptr;
59 typedef iostream_con::timer_ptr timer_ptr;
61 stub_con(bool is_server, config::alog_type & a, config::elog_type & e)
62 : iostream_con(is_server,a,e)
63 // Set the error to a known code that is unused by the library
64 // This way we can easily confirm that the handler was run at all.
65 , ec(websocketpp::error::make_error_code(websocketpp::error::test))
69 /// Get a shared pointer to this component
71 return websocketpp::lib::static_pointer_cast<type>(iostream_con::get_shared());
74 void write(std::string msg) {
75 iostream_con::async_write(
78 websocketpp::lib::bind(
81 websocketpp::lib::placeholders::_1
86 void write(std::vector<websocketpp::transport::buffer> & bufs) {
87 iostream_con::async_write(
89 websocketpp::lib::bind(
92 websocketpp::lib::placeholders::_1
97 void async_read_at_least(size_t num_bytes, char *buf, size_t len)
99 iostream_con::async_read_at_least(
103 websocketpp::lib::bind(
104 &stub_con::handle_op,
106 websocketpp::lib::placeholders::_1
111 void handle_op(websocketpp::lib::error_code const & e) {
115 void async_read_indef(size_t num_bytes, char *buf, size_t len)
117 indef_read_size = num_bytes;
118 indef_read_buf = buf;
119 indef_read_len = len;
125 iostream_con::async_read_at_least(
129 websocketpp::lib::bind(
130 &stub_con::handle_indef,
132 websocketpp::lib::placeholders::_1,
133 websocketpp::lib::placeholders::_2
138 void handle_indef(websocketpp::lib::error_code const & e, size_t amt_read) {
140 indef_read_total += amt_read;
146 iostream_con::async_shutdown(
147 websocketpp::lib::bind(
148 &stub_con::handle_async_shutdown,
150 websocketpp::lib::placeholders::_1
155 void handle_async_shutdown(websocketpp::lib::error_code const & e) {
159 websocketpp::lib::error_code ec;
160 size_t indef_read_size;
161 char * indef_read_buf;
162 size_t indef_read_len;
163 size_t indef_read_total;
167 config::alog_type alogger;
168 config::elog_type elogger;
170 BOOST_AUTO_TEST_CASE( const_methods ) {
171 iostream_con::ptr con(new iostream_con(true,alogger,elogger));
173 BOOST_CHECK( !con->is_secure() );
174 BOOST_CHECK_EQUAL( con->get_remote_endpoint(), "iostream transport" );
177 BOOST_AUTO_TEST_CASE( write_before_output_method_set ) {
178 stub_con::ptr con(new stub_con(true,alogger,elogger));
181 BOOST_CHECK( con->ec == make_error_code(websocketpp::transport::iostream::error::output_stream_required) );
183 std::vector<websocketpp::transport::buffer> bufs;
185 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::iostream::error::output_stream_required) );
188 BOOST_AUTO_TEST_CASE( async_write_ostream ) {
189 stub_con::ptr con(new stub_con(true,alogger,elogger));
191 std::stringstream output;
193 con->register_ostream(&output);
197 BOOST_CHECK( !con->ec );
198 BOOST_CHECK_EQUAL( output.str(), "foo" );
201 websocketpp::lib::error_code write_handler(std::string & o, websocketpp::connection_hdl, char const * buf, size_t len) {
202 o += std::string(buf,len);
203 return websocketpp::lib::error_code();
206 websocketpp::lib::error_code vector_write_handler(std::string & o, websocketpp::connection_hdl, std::vector<websocketpp::transport::buffer> const & bufs) {
207 std::vector<websocketpp::transport::buffer>::const_iterator it;
208 for (it = bufs.begin(); it != bufs.end(); it++) {
209 o += std::string((*it).buf, (*it).len);
212 return websocketpp::lib::error_code();
215 websocketpp::lib::error_code write_handler_error(websocketpp::connection_hdl, char const *, size_t) {
216 return make_error_code(websocketpp::transport::error::general);
219 BOOST_AUTO_TEST_CASE( async_write_handler ) {
220 stub_con::ptr con(new stub_con(true,alogger,elogger));
223 con->set_write_handler(websocketpp::lib::bind(
225 websocketpp::lib::ref(output),
226 websocketpp::lib::placeholders::_1,
227 websocketpp::lib::placeholders::_2,
228 websocketpp::lib::placeholders::_3
231 BOOST_CHECK( !con->ec );
232 BOOST_CHECK_EQUAL(output, "foo");
235 BOOST_AUTO_TEST_CASE( async_write_handler_error ) {
236 stub_con::ptr con(new stub_con(true,alogger,elogger));
238 con->set_write_handler(&write_handler_error);
240 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::general) );
243 BOOST_AUTO_TEST_CASE( async_write_vector_0_ostream ) {
244 std::stringstream output;
246 stub_con::ptr con(new stub_con(true,alogger,elogger));
247 con->register_ostream(&output);
249 std::vector<websocketpp::transport::buffer> bufs;
253 BOOST_CHECK( !con->ec );
254 BOOST_CHECK_EQUAL( output.str(), "" );
257 BOOST_AUTO_TEST_CASE( async_write_vector_0_write_handler ) {
260 stub_con::ptr con(new stub_con(true,alogger,elogger));
262 con->set_write_handler(websocketpp::lib::bind(
264 websocketpp::lib::ref(output),
265 websocketpp::lib::placeholders::_1,
266 websocketpp::lib::placeholders::_2,
267 websocketpp::lib::placeholders::_3
270 std::vector<websocketpp::transport::buffer> bufs;
274 BOOST_CHECK( !con->ec );
275 BOOST_CHECK_EQUAL( output, "" );
278 BOOST_AUTO_TEST_CASE( async_write_vector_1_ostream ) {
279 std::stringstream output;
281 stub_con::ptr con(new stub_con(true,alogger,elogger));
282 con->register_ostream(&output);
284 std::vector<websocketpp::transport::buffer> bufs;
286 std::string foo = "foo";
288 bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));
292 BOOST_CHECK( !con->ec );
293 BOOST_CHECK_EQUAL( output.str(), "foo" );
296 BOOST_AUTO_TEST_CASE( async_write_vector_1_write_handler ) {
299 stub_con::ptr con(new stub_con(true,alogger,elogger));
300 con->set_write_handler(websocketpp::lib::bind(
302 websocketpp::lib::ref(output),
303 websocketpp::lib::placeholders::_1,
304 websocketpp::lib::placeholders::_2,
305 websocketpp::lib::placeholders::_3
308 std::vector<websocketpp::transport::buffer> bufs;
310 std::string foo = "foo";
312 bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));
316 BOOST_CHECK( !con->ec );
317 BOOST_CHECK_EQUAL( output, "foo" );
320 BOOST_AUTO_TEST_CASE( async_write_vector_2_ostream ) {
321 std::stringstream output;
323 stub_con::ptr con(new stub_con(true,alogger,elogger));
324 con->register_ostream(&output);
326 std::vector<websocketpp::transport::buffer> bufs;
328 std::string foo = "foo";
329 std::string bar = "bar";
331 bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));
332 bufs.push_back(websocketpp::transport::buffer(bar.data(),bar.size()));
336 BOOST_CHECK( !con->ec );
337 BOOST_CHECK_EQUAL( output.str(), "foobar" );
340 BOOST_AUTO_TEST_CASE( async_write_vector_2_write_handler ) {
343 stub_con::ptr con(new stub_con(true,alogger,elogger));
344 con->set_write_handler(websocketpp::lib::bind(
346 websocketpp::lib::ref(output),
347 websocketpp::lib::placeholders::_1,
348 websocketpp::lib::placeholders::_2,
349 websocketpp::lib::placeholders::_3
352 std::vector<websocketpp::transport::buffer> bufs;
354 std::string foo = "foo";
355 std::string bar = "bar";
357 bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));
358 bufs.push_back(websocketpp::transport::buffer(bar.data(),bar.size()));
362 BOOST_CHECK( !con->ec );
363 BOOST_CHECK_EQUAL( output, "foobar" );
366 BOOST_AUTO_TEST_CASE( async_write_vector_2_vector_write_handler ) {
369 stub_con::ptr con(new stub_con(true,alogger,elogger));
370 con->set_vector_write_handler(websocketpp::lib::bind(
371 &vector_write_handler,
372 websocketpp::lib::ref(output),
373 websocketpp::lib::placeholders::_1,
374 websocketpp::lib::placeholders::_2
377 std::vector<websocketpp::transport::buffer> bufs;
379 std::string foo = "foo";
380 std::string bar = "bar";
382 bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));
383 bufs.push_back(websocketpp::transport::buffer(bar.data(),bar.size()));
387 BOOST_CHECK( !con->ec );
388 BOOST_CHECK_EQUAL( output, "foobar" );
391 BOOST_AUTO_TEST_CASE( async_read_at_least_too_much ) {
392 stub_con::ptr con(new stub_con(true,alogger,elogger));
396 con->async_read_at_least(11,buf,10);
397 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::iostream::error::invalid_num_bytes) );
400 BOOST_AUTO_TEST_CASE( async_read_at_least_double_read ) {
401 stub_con::ptr con(new stub_con(true,alogger,elogger));
405 con->async_read_at_least(5,buf,10);
406 con->async_read_at_least(5,buf,10);
407 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::iostream::error::double_read) );
410 BOOST_AUTO_TEST_CASE( async_read_at_least ) {
411 stub_con::ptr con(new stub_con(true,alogger,elogger));
417 con->async_read_at_least(5,buf,10);
418 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
420 std::stringstream channel;
423 BOOST_CHECK_EQUAL( channel.tellg(), -1 );
424 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
426 std::stringstream channel2;
429 BOOST_CHECK_EQUAL( channel2.tellg(), -1 );
430 BOOST_CHECK( !con->ec );
431 BOOST_CHECK_EQUAL( std::string(buf,10), "abcdexxxxx" );
433 std::stringstream channel3;
436 BOOST_CHECK_EQUAL( channel3.tellg(), 0 );
437 BOOST_CHECK( !con->ec );
438 BOOST_CHECK_EQUAL( std::string(buf,10), "abcdexxxxx" );
439 con->async_read_at_least(1,buf+5,5);
441 BOOST_CHECK_EQUAL( channel3.tellg(), -1 );
442 BOOST_CHECK( !con->ec );
443 BOOST_CHECK_EQUAL( std::string(buf,10), "abcdefxxxx" );
446 BOOST_AUTO_TEST_CASE( async_read_at_least2 ) {
447 stub_con::ptr con(new stub_con(true,alogger,elogger));
453 con->async_read_at_least(5,buf,5);
454 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
456 std::stringstream channel;
457 channel << "abcdefg";
459 BOOST_CHECK_EQUAL( channel.tellg(), 5 );
460 BOOST_CHECK( !con->ec );
461 BOOST_CHECK_EQUAL( std::string(buf,10), "abcdexxxxx" );
463 con->async_read_at_least(1,buf+5,5);
465 BOOST_CHECK_EQUAL( channel.tellg(), -1 );
466 BOOST_CHECK( !con->ec );
467 BOOST_CHECK_EQUAL( std::string(buf,10), "abcdefgxxx" );
470 void timer_callback_stub(websocketpp::lib::error_code const &) {}
472 BOOST_AUTO_TEST_CASE( set_timer ) {
473 stub_con::ptr con(new stub_con(true,alogger,elogger));
475 stub_con::timer_ptr tp = con->set_timer(1000,timer_callback_stub);
480 BOOST_AUTO_TEST_CASE( async_read_at_least_read_some ) {
481 stub_con::ptr con(new stub_con(true,alogger,elogger));
486 con->async_read_at_least(5,buf,5);
487 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
489 char input[10] = "abcdefg";
490 BOOST_CHECK_EQUAL(con->read_some(input,5), 5);
491 BOOST_CHECK( !con->ec );
492 BOOST_CHECK_EQUAL( std::string(buf,10), "abcdexxxxx" );
494 BOOST_CHECK_EQUAL(con->read_some(input+5,2), 0);
495 BOOST_CHECK( !con->ec );
496 BOOST_CHECK_EQUAL( std::string(buf,10), "abcdexxxxx" );
498 con->async_read_at_least(1,buf+5,5);
499 BOOST_CHECK_EQUAL(con->read_some(input+5,2), 2);
500 BOOST_CHECK( !con->ec );
501 BOOST_CHECK_EQUAL( std::string(buf,10), "abcdefgxxx" );
504 BOOST_AUTO_TEST_CASE( async_read_at_least_read_some_indef ) {
505 stub_con::ptr con(new stub_con(true,alogger,elogger));
510 con->async_read_indef(5,buf,5);
511 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
513 // here we expect to return early from read some because the outstanding
514 // read was for 5 bytes and we were called with 10.
515 char input[11] = "aaaaabbbbb";
516 BOOST_CHECK_EQUAL(con->read_some(input,10), 5);
517 BOOST_CHECK( !con->ec );
518 BOOST_CHECK_EQUAL( std::string(buf,10), "aaaaaxxxxx" );
519 BOOST_CHECK_EQUAL( con->indef_read_total, 5 );
521 // A subsequent read should read 5 more because the indef read refreshes
522 // itself. The new read will start again at the beginning of the buffer.
523 BOOST_CHECK_EQUAL(con->read_some(input+5,5), 5);
524 BOOST_CHECK( !con->ec );
525 BOOST_CHECK_EQUAL( std::string(buf,10), "bbbbbxxxxx" );
526 BOOST_CHECK_EQUAL( con->indef_read_total, 10 );
529 BOOST_AUTO_TEST_CASE( async_read_at_least_read_all ) {
530 stub_con::ptr con(new stub_con(true,alogger,elogger));
535 con->async_read_indef(5,buf,5);
536 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
538 char input[11] = "aaaaabbbbb";
539 BOOST_CHECK_EQUAL(con->read_all(input,10), 10);
540 BOOST_CHECK( !con->ec );
541 BOOST_CHECK_EQUAL( std::string(buf,10), "bbbbbxxxxx" );
542 BOOST_CHECK_EQUAL( con->indef_read_total, 10 );
545 BOOST_AUTO_TEST_CASE( eof_flag ) {
546 stub_con::ptr con(new stub_con(true,alogger,elogger));
548 con->async_read_at_least(5,buf,5);
549 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
551 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::eof) );
554 BOOST_AUTO_TEST_CASE( fatal_error_flag ) {
555 stub_con::ptr con(new stub_con(true,alogger,elogger));
557 con->async_read_at_least(5,buf,5);
558 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
560 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::pass_through) );
563 BOOST_AUTO_TEST_CASE( shutdown ) {
564 stub_con::ptr con(new stub_con(true,alogger,elogger));
565 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
567 BOOST_CHECK_EQUAL( con->ec, websocketpp::lib::error_code() );
570 websocketpp::lib::error_code sd_handler(websocketpp::connection_hdl) {
571 return make_error_code(websocketpp::transport::error::general);
574 BOOST_AUTO_TEST_CASE( shutdown_handler ) {
575 stub_con::ptr con(new stub_con(true,alogger,elogger));
577 con->set_shutdown_handler(&sd_handler);
578 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
580 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::general) );
583 BOOST_AUTO_TEST_CASE( shared_pointer_memory_cleanup ) {
584 stub_con::ptr con(new stub_con(true,alogger,elogger));
586 BOOST_CHECK_EQUAL(con.use_count(), 1);
590 con->async_read_at_least(5,buf,5);
591 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
592 BOOST_CHECK_EQUAL(con.use_count(), 2);
594 char input[10] = "foo";
595 con->read_some(input,3);
596 BOOST_CHECK_EQUAL(con.use_count(), 2);
598 con->read_some(input,2);
599 BOOST_CHECK_EQUAL( std::string(buf,10), "foofoxxxxx" );
600 BOOST_CHECK_EQUAL(con.use_count(), 1);
602 con->async_read_at_least(5,buf,5);
603 BOOST_CHECK_EQUAL(con.use_count(), 2);
606 BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::eof) );
607 BOOST_CHECK_EQUAL(con.use_count(), 1);