Commit aa79e7e9 authored by Jelte Jansen's avatar Jelte Jansen
Browse files

sync for merge 2


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac296@2760 e5f2f494-b856-4b98-b285-d166d9295462
parent 3cc58b3f
// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
//
// 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 ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC 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.
// $Id: data_unittests.cc 1899 2010-05-21 12:03:59Z jelte $
#include <config.h>
// for some IPC/network system calls in asio/detail/pipe_select_interrupter.hpp
#include <unistd.h>
// XXX: the ASIO header must be included before others. See session.cc.
#include <asio.hpp>
#include <gtest/gtest.h>
#include <session.h>
#include <cc/data.h>
#include <exceptions/exceptions.h>
#include <boost/bind.hpp>
#include <session_unittests_config.h>
using namespace isc::cc;
TEST(AsioSession, establish) {
asio::io_service io_service_;
Session sess(io_service_);
EXPECT_THROW(
sess.establish("/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
"/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
"/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
"/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
"/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
"/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
"/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
"/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
"/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
"/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
), SessionError
);
}
// This class sets up a domain socket for the session to connect to
// it will impersonate the msgq a tiny bit (if setSendLname() has
// been called, it will send an 'answer' to the lname query that is
// sent in the initialization of Session objects)
class TestDomainSocket {
public:
TestDomainSocket(asio::io_service& io_service, const char* file) :
io_service_(io_service),
ep_(file),
acceptor_(io_service_, ep_),
socket_(io_service_)
{
acceptor_.async_accept(socket_,
boost::bind(&TestDomainSocket::acceptHandler,
this, _1));
}
~TestDomainSocket() {
socket_.close();
unlink(BIND10_TEST_SOCKET_FILE);
}
void
acceptHandler(const asio::error_code& error UNUSED_PARAM) {
}
void
sendmsg(isc::data::ElementPtr& env, isc::data::ElementPtr& msg) {
const std::string header_wire = env->toWire();
const std::string body_wire = msg->toWire();
const unsigned int length = 2 + header_wire.length() +
body_wire.length();
const unsigned int length_net = htonl(length);
const unsigned short header_length = header_wire.length();
const unsigned short header_length_net = htons(header_length);
socket_.send(asio::buffer(&length_net, sizeof(length_net)));
socket_.send(asio::buffer(&header_length_net,
sizeof(header_length_net)));
socket_.send(asio::buffer(header_wire.data(), header_length));
socket_.send(asio::buffer(body_wire.data(), body_wire.length()));
}
void
sendLname() {
isc::data::ElementPtr lname_answer1 =
isc::data::Element::fromJSON("{ \"type\": \"lname\" }");
isc::data::ElementPtr lname_answer2 =
isc::data::Element::fromJSON("{ \"lname\": \"foobar\" }");
sendmsg(lname_answer1, lname_answer2);
}
void
setSendLname() {
// ignore whatever data we get, send back an lname
asio::async_read(socket_, asio::buffer(data_buf, 0),
boost::bind(&TestDomainSocket::sendLname, this));
}
private:
asio::io_service& io_service_;
asio::local::stream_protocol::endpoint ep_;
asio::local::stream_protocol::acceptor acceptor_;
asio::local::stream_protocol::socket socket_;
char data_buf[1024];
};
class SessionTest : public ::testing::Test {
protected:
SessionTest() : sess(my_io_service), work(my_io_service) {
// The TestDomainSocket is held as a 'new'-ed pointer,
// so we can call unlink() first.
unlink(BIND10_TEST_SOCKET_FILE);
tds = new TestDomainSocket(my_io_service, BIND10_TEST_SOCKET_FILE);
}
~SessionTest() {
delete tds;
}
public:
// used in the handler test
// This handler first reads (and ignores) whatever message caused
// it to be invoked. Then it calls group_recv for a second message.
// If this message is { "command": "stop" } it'll tell the
// io_service it is done. Otherwise it'll re-register this handler
void someHandler() {
isc::data::ElementPtr env, msg;
sess.group_recvmsg(env, msg, false, -1);
sess.group_recvmsg(env, msg, false, -1);
if (msg && msg->contains("command") &&
msg->get("command")->stringValue() == "stop") {
my_io_service.stop();
} else {
sess.startRead(boost::bind(&SessionTest::someHandler, this));
}
}
protected:
asio::io_service my_io_service;
TestDomainSocket* tds;
Session sess;
// Keep run() from stopping right away by informing it it has work to do
asio::io_service::work work;
};
TEST_F(SessionTest, timeout_on_connect) {
// set to a short timeout so the test doesn't take too long
EXPECT_EQ(4000, sess.getTimeout());
sess.setTimeout(100);
EXPECT_EQ(100, sess.getTimeout());
// no answer, should timeout
EXPECT_THROW(sess.establish(BIND10_TEST_SOCKET_FILE), SessionTimeout);
}
TEST_F(SessionTest, connect_ok) {
tds->setSendLname();
sess.establish(BIND10_TEST_SOCKET_FILE);
}
TEST_F(SessionTest, connect_ok_no_timeout) {
tds->setSendLname();
sess.setTimeout(0);
sess.establish(BIND10_TEST_SOCKET_FILE);
}
TEST_F(SessionTest, connect_ok_connection_reset) {
tds->setSendLname();
sess.establish(BIND10_TEST_SOCKET_FILE);
// Close the session again, so the next recv() should throw
sess.disconnect();
isc::data::ElementPtr env, msg;
EXPECT_THROW(sess.group_recvmsg(env, msg, false, -1), SessionError);
}
TEST_F(SessionTest, run_with_handler) {
tds->setSendLname();
sess.establish(BIND10_TEST_SOCKET_FILE);
sess.startRead(boost::bind(&SessionTest::someHandler, this));
isc::data::ElementPtr env = isc::data::Element::fromJSON("{ \"to\": \"me\" }");
isc::data::ElementPtr msg = isc::data::Element::fromJSON("{ \"some\": \"message\" }");
tds->sendmsg(env, msg);
msg = isc::data::Element::fromJSON("{ \"another\": \"message\" }");
tds->sendmsg(env, msg);
msg = isc::data::Element::fromJSON("{ \"a third\": \"message\" }");
tds->sendmsg(env, msg);
msg = isc::data::Element::fromJSON("{ \"command\": \"stop\" }");
tds->sendmsg(env, msg);
size_t count = my_io_service.run();
ASSERT_EQ(2, count);
}
TEST_F(SessionTest, run_with_handler_timeout) {
tds->setSendLname();
sess.establish(BIND10_TEST_SOCKET_FILE);
sess.startRead(boost::bind(&SessionTest::someHandler, this));
sess.setTimeout(100);
isc::data::ElementPtr env = isc::data::Element::fromJSON("{ \"to\": \"me\" }");
isc::data::ElementPtr msg = isc::data::Element::fromJSON("{ \"some\": \"message\" }");
tds->sendmsg(env, msg);
msg = isc::data::Element::fromJSON("{ \"another\": \"message\" }");
tds->sendmsg(env, msg);
msg = isc::data::Element::fromJSON("{ \"a third\": \"message\" }");
tds->sendmsg(env, msg);
// No followup message, should time out.
ASSERT_THROW(my_io_service.run(), SessionTimeout);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment