changeset 822:5120b9793d1f

tests: add common server error tests
author David Demelier <markand@malikania.fr>
date Fri, 30 Nov 2018 14:06:13 +0100
parents 6532414a9cbd
children d76699e13156
files tests/src/libirccd-daemon/CMakeLists.txt tests/src/libirccd-daemon/server/CMakeLists.txt tests/src/libirccd-daemon/server/main.cpp
diffstat 3 files changed, 247 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/tests/src/libirccd-daemon/CMakeLists.txt	Fri Nov 30 21:57:36 2018 +0100
+++ b/tests/src/libirccd-daemon/CMakeLists.txt	Fri Nov 30 14:06:13 2018 +0100
@@ -49,4 +49,5 @@
 add_subdirectory(logger)
 add_subdirectory(rules)
 add_subdirectory(rule-util)
+add_subdirectory(server)
 add_subdirectory(server-util)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-daemon/server/CMakeLists.txt	Fri Nov 30 14:06:13 2018 +0100
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+	NAME server
+	SOURCES main.cpp
+	LIBRARIES libirccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/src/libirccd-daemon/server/main.cpp	Fri Nov 30 14:06:13 2018 +0100
@@ -0,0 +1,223 @@
+/*
+ * main.cpp -- test server object
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "server"
+#include <boost/test/unit_test.hpp>
+
+#include <cassert>
+#include <ostream>
+#include <string>
+#include <system_error>
+
+#include <irccd/daemon/server.hpp>
+
+using std::errc;
+using std::error_code;
+using std::make_shared;
+using std::move;
+using std::ostream;
+using std::shared_ptr;
+using std::string;
+using std::system_error;
+
+using boost::asio::io_context;
+using boost::asio::ip::tcp;
+using boost::asio::streambuf;
+
+using irccd::daemon::server;
+
+BOOST_TEST_DONT_PRINT_LOG_VALUE(errc)
+BOOST_TEST_DONT_PRINT_LOG_VALUE(server::state)
+
+namespace irccd {
+
+namespace {
+
+class fixture {
+protected:
+	io_context context_;
+	streambuf output_;
+	tcp::acceptor acceptor_{context_};
+	tcp::socket socket_{context_};
+	shared_ptr<server> server_;
+
+	fixture();
+
+	void accept();
+	void feed(string);
+	void pair();
+};
+
+void fixture::accept()
+{
+	acceptor_.async_accept(socket_, [] (auto code) {
+		if (code)
+			throw system_error(move(code));
+	});
+}
+
+void fixture::feed(string data)
+{
+	assert(server_->get_state() != server::state::disconnected);
+
+	ostream out(&output_);
+
+	out << data;
+	out << std::flush;
+
+	async_write(socket_, output_, [] (auto code, auto) {
+		if (code)
+			throw system_error(move(code));
+	});
+}
+
+void fixture::pair()
+{
+	accept();
+
+	server_->connect([] (auto code) {
+		if (code)
+			throw system_error(move(code));
+	});
+
+	context_.run();
+	context_.reset();
+
+	BOOST_TEST(server_->get_state() == server::state::identifying);
+}
+
+fixture::fixture()
+{
+	acceptor_.open(tcp::v4());
+	acceptor_.bind(tcp::endpoint(tcp::v4(), 0U));
+	acceptor_.listen(1);
+
+	server_ = make_shared<server>(context_, "test", "127.0.0.1");
+	server_->set_port(acceptor_.local_endpoint().port());
+	server_->set_options(server::options::ipv4);
+	server_->set_ping_timeout(3);
+}
+
+BOOST_FIXTURE_TEST_SUITE(fixture_suite, fixture)
+
+BOOST_AUTO_TEST_SUITE(interrupts)
+
+/*
+ * This test checks that interrupting any pending operations will never
+ * trigger the handlers.
+ */
+BOOST_AUTO_TEST_CASE(not_connected_yet)
+{
+	accept();
+
+	server_->connect([] (auto code) {
+		BOOST_FAIL("handler called (not expected");
+	});
+	server_->disconnect();
+
+	context_.run();
+}
+
+/*
+ * This test checks that interrupting a connected server will never trigger
+ * handlers.
+ */
+BOOST_AUTO_TEST_CASE(connected)
+{
+	pair();
+
+	server_->recv([] (auto, auto) {
+		BOOST_FAIL("handler called (not expected");
+	});
+	server_->disconnect();
+
+	context_.run();
+}
+
+/*
+ * This test checks that interrupting the wait timer will never trigger
+ * handlers.
+ */
+BOOST_AUTO_TEST_CASE(waiting)
+{
+	server_->wait([] (auto) {
+		BOOST_FAIL("handler called (not expected");
+	});
+	server_->disconnect();
+
+	context_.run();
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(errors)
+
+BOOST_AUTO_TEST_CASE(timeout)
+{
+	pair();
+
+	error_code result;
+
+	server_->recv([&] (auto code, auto) {
+		result = move(code);
+	});
+
+	context_.run();
+
+	BOOST_TEST(result == errc::timed_out);
+}
+
+BOOST_AUTO_TEST_CASE(connection_reset)
+{
+	pair();
+
+	error_code result;
+
+	server_->recv([&] (auto code, auto) {
+		result = move(code);
+	});
+	socket_.close();
+
+	context_.run();
+
+	BOOST_TEST(result == errc::connection_reset);
+}
+
+BOOST_AUTO_TEST_CASE(argument_list_too_long)
+{
+	pair();
+	feed(string(2048, 'a'));
+
+	error_code result;
+
+	server_->recv([&] (auto code, auto) {
+		result = move(code);
+	});
+
+	context_.run();
+
+	BOOST_TEST(result == errc::argument_list_too_long);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // !namespace
+
+} // !irccd