Commit 798c5262 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

introduced an abstract base class for XfroutClient, introduced a mock derived...

introduced an abstract base class for XfroutClient, introduced a mock derived class of it, and added detailed tests for xfrout using it.


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac221@2317 e5f2f494-b856-4b98-b285-d166d9295462
parent 62c01a67
......@@ -52,7 +52,6 @@
#include <auth/common.h>
#include <auth/auth_srv.h>
#include <auth/asio_link.h>
#include <auth/spec_config.h>
#include <boost/lexical_cast.hpp>
......@@ -75,7 +74,7 @@ private:
AuthSrvImpl(const AuthSrvImpl& source);
AuthSrvImpl& operator=(const AuthSrvImpl& source);
public:
AuthSrvImpl();
AuthSrvImpl(AbstractXfroutClient& xfrout_client);
~AuthSrvImpl();
isc::data::ElementPtr setDbFile(const isc::data::ElementPtr config);
......@@ -99,16 +98,17 @@ public:
isc::cc::Session session_with_xfrin_;
bool is_axfr_connection_established_;
XfroutClient axfr_client_;
AbstractXfroutClient& xfrout_client_;
/// Currently non-configurable, but will be.
static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
};
AuthSrvImpl::AuthSrvImpl() : cs_(NULL), verbose_mode_(false),
is_notify_session_established_(false),
is_axfr_connection_established_(false),
axfr_client_(UNIX_SOCKET_FILE)
AuthSrvImpl::AuthSrvImpl(AbstractXfroutClient& xfrout_client) :
cs_(NULL), verbose_mode_(false),
is_notify_session_established_(false),
is_axfr_connection_established_(false),
xfrout_client_(xfrout_client)
{
// cur_datasrc_ is automatically initialized by the default constructor,
// effectively being an empty (sqlite) data source. once ccsession is up
......@@ -125,13 +125,14 @@ AuthSrvImpl::~AuthSrvImpl() {
}
if (is_axfr_connection_established_) {
axfr_client_.disconnect();
xfrout_client_.disconnect();
is_axfr_connection_established_ = false;
}
}
AuthSrv::AuthSrv() : impl_(new AuthSrvImpl) {
}
AuthSrv::AuthSrv(AbstractXfroutClient& xfrout_client) :
impl_(new AuthSrvImpl(xfrout_client))
{}
AuthSrv::~AuthSrv() {
delete impl_;
......@@ -342,15 +343,20 @@ AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
try {
if (!is_axfr_connection_established_) {
axfr_client_.connect();
xfrout_client_.connect();
is_axfr_connection_established_ = true;
}
axfr_client_.sendXfroutRequestInfo(io_message.getSocket().getNative(),
io_message.getData(),
io_message.getDataSize());
xfrout_client_.sendXfroutRequestInfo(
io_message.getSocket().getNative(),
io_message.getData(),
io_message.getDataSize());
} catch (const XfroutError& err) {
if (is_axfr_connection_established_) {
axfr_client_.disconnect();
// discoonect() may trigger an exception, but since we try it
// only if we've successfully opened it, it shouldn't happen in
// normal condition. Should this occur, we'll propagate it to the
// upper layer.
xfrout_client_.disconnect();
is_axfr_connection_established_ = false;
}
......@@ -360,6 +366,7 @@ AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
}
makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
verbose_mode_);
return (true);
}
return (false);
}
......
......@@ -28,6 +28,10 @@ class InputBuffer;
class Message;
class MessageRenderer;
}
namespace xfr {
class AbstractXfroutClient;
};
}
namespace asio_link {
......@@ -47,7 +51,7 @@ private:
AuthSrv(const AuthSrv& source);
AuthSrv& operator=(const AuthSrv& source);
public:
explicit AuthSrv();
explicit AuthSrv(isc::xfr::AbstractXfroutClient& xfrout_client);
~AuthSrv();
//@}
/// \return \c true if the \message contains a response to be returned;
......
......@@ -39,16 +39,19 @@
#include <cc/data.h>
#include <config/ccsession.h>
#include "spec_config.h"
#include "common.h"
#include "auth_srv.h"
#include "asio_link.h"
#include <xfr/xfrout_client.h>
#include <auth/spec_config.h>
#include <auth/common.h>
#include <auth/auth_srv.h>
#include <auth/asio_link.h>
using namespace std;
using namespace isc::data;
using namespace isc::cc;
using namespace isc::config;
using namespace isc::dns;
using namespace isc::xfr;
namespace {
......@@ -133,6 +136,8 @@ main(int argc, char* argv[]) {
// initialize command channel
int ret = 0;
XfroutClient xfrout_client(UNIX_SOCKET_FILE);
try {
string specfile;
if (getenv("B10_FROM_BUILD")) {
......@@ -142,7 +147,7 @@ main(int argc, char* argv[]) {
specfile = string(AUTH_SPECFILE_LOCATION);
}
auth_server = new AuthSrv;
auth_server = new AuthSrv(xfrout_client);
auth_server->setVerbose(verbose_mode);
io_service = new asio_link::IOService(auth_server, port, use_ipv4,
......
......@@ -14,6 +14,8 @@
// $Id$
#include <config.h>
#include <gtest/gtest.h>
#include <dns/buffer.h>
......@@ -25,6 +27,8 @@
#include <cc/data.h>
#include <xfr/xfrout_client.h>
#include <auth/auth_srv.h>
#include <auth/asio_link.h>
......@@ -34,6 +38,7 @@ using isc::UnitTestUtil;
using namespace std;
using namespace isc::dns;
using namespace isc::data;
using namespace isc::xfr;
using namespace asio_link;
namespace {
......@@ -45,8 +50,30 @@ const char* BADCONFIG_TESTDB =
"{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
class AuthSrvTest : public ::testing::Test {
private:
class MockXfroutClient : public AbstractXfroutClient {
public:
MockXfroutClient() :
is_connected_(false), connect_ok_(true), send_ok_(true),
disconnect_ok_(true)
{}
virtual void connect();
virtual void disconnect();
virtual int sendXfroutRequestInfo(int tcp_sock, const void* msg_data,
uint16_t msg_len);
bool isConnected() const { return (is_connected_); }
void disableConnect() { connect_ok_ = false; }
void disableDisconnect() { disconnect_ok_ = false; }
void enableDisconnect() { disconnect_ok_ = true; }
void disableSend() { send_ok_ = false; }
private:
bool is_connected_;
bool connect_ok_;
bool send_ok_;
bool disconnect_ok_;
};
protected:
AuthSrvTest() : request_message(Message::RENDER),
AuthSrvTest() : server(xfrout), request_message(Message::RENDER),
parse_message(Message::PARSE), default_qid(0x1035),
opcode(Opcode(Opcode::QUERY())), qname("www.example.com"),
qclass(RRClass::IN()), qtype(RRType::A()),
......@@ -58,6 +85,7 @@ protected:
delete io_message;
delete endpoint;
}
MockXfroutClient xfrout;
AuthSrv server;
Message request_message;
Message parse_message;
......@@ -80,6 +108,35 @@ protected:
int protocol);
};
void
AuthSrvTest::MockXfroutClient::connect() {
if (!connect_ok_) {
isc_throw(XfroutError, "xfrout connection disabled for test");
}
is_connected_ = true;
}
void
AuthSrvTest::MockXfroutClient::disconnect() {
if (!disconnect_ok_) {
isc_throw(XfroutError,
"closing xfrout connection is disabled for test");
}
is_connected_ = false;
}
int
AuthSrvTest::MockXfroutClient::sendXfroutRequestInfo(
const int tcp_sock UNUSED_PARAM,
const void* msg_data UNUSED_PARAM,
const uint16_t msg_len UNUSED_PARAM)
{
if (!send_ok_) {
isc_throw(XfroutError, "xfrout connection send for test");
}
return (0);
}
// These are flags to indicate whether the corresponding flag bit of the
// DNS header is to be set in the test cases. (Note that the flag values
// is irrelevant to their wire-format values)
......@@ -102,7 +159,9 @@ AuthSrvTest::createDataFromFile(const char* const datafile,
endpoint = IOEndpoint::create(protocol, IOAddress("192.0.2.1"), 5300);
UnitTestUtil::readWireData(datafile, data);
io_message = new IOMessage(&data[0], data.size(),
IOSocket::getDummyUDPSocket(), *endpoint);
protocol == IPPROTO_UDP ?
IOSocket::getDummyUDPSocket() :
IOSocket::getDummyTCPSocket(), *endpoint);
}
void
......@@ -110,6 +169,7 @@ AuthSrvTest::createRequest(const Opcode& opcode, const Name& request_name,
const RRClass& rrclass, const RRType& rrtype,
const int protocol = IPPROTO_UDP)
{
request_message.clear(Message::RENDER);
request_message.setOpcode(opcode);
request_message.setQid(default_qid);
request_message.addQuestion(Question(request_name, rrclass, rrtype));
......@@ -119,7 +179,9 @@ AuthSrvTest::createRequest(const Opcode& opcode, const Name& request_name,
endpoint = IOEndpoint::create(protocol, IOAddress("192.0.2.1"), 5300);
io_message = new IOMessage(request_renderer.getData(),
request_renderer.getLength(),
IOSocket::getDummyUDPSocket(), *endpoint);
protocol == IPPROTO_UDP ?
IOSocket::getDummyUDPSocket() :
IOSocket::getDummyTCPSocket(), *endpoint);
}
void
......@@ -276,6 +338,67 @@ TEST_F(AuthSrvTest, AXFROverUDP) {
QR_FLAG, 1, 0, 0, 0);
}
TEST_F(AuthSrvTest, AXFRSuccess) {
EXPECT_FALSE(xfrout.isConnected());
createRequest(opcode, Name("example.com"), RRClass::IN(), RRType::AXFR(),
IPPROTO_TCP);
// On success, the AXFR query has been passed to a separate process,
// so we shouldn't have to respond.
EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
response_renderer));
EXPECT_TRUE(xfrout.isConnected());
}
TEST_F(AuthSrvTest, AXFRConnectFail) {
EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
xfrout.disableConnect();
createRequest(opcode, Name("example.com"), RRClass::IN(), RRType::AXFR(),
IPPROTO_TCP);
EXPECT_TRUE(server.processMessage(*io_message, parse_message,
response_renderer));
headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
EXPECT_FALSE(xfrout.isConnected());
}
TEST_F(AuthSrvTest, AXFRSendFail) {
// first send a valid query, making the connection with the xfr process
// open.
createRequest(opcode, Name("example.com"), RRClass::IN(), RRType::AXFR(),
IPPROTO_TCP);
server.processMessage(*io_message, parse_message, response_renderer);
EXPECT_TRUE(xfrout.isConnected());
xfrout.disableSend();
parse_message.clear(Message::PARSE);
response_renderer.clear();
createRequest(opcode, Name("example.com"), RRClass::IN(), RRType::AXFR(),
IPPROTO_TCP);
EXPECT_TRUE(server.processMessage(*io_message, parse_message,
response_renderer));
headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
// The connection should have been closed due to the send failure.
EXPECT_FALSE(xfrout.isConnected());
}
TEST_F(AuthSrvTest, AXFRDisconnectFail) {
// In our usage disconnect() shouldn't fail. So we'll see the exception
// should it be thrown.
xfrout.disableSend();
xfrout.disableDisconnect();
createRequest(opcode, Name("example.com"), RRClass::IN(), RRType::AXFR(),
IPPROTO_TCP);
EXPECT_THROW(server.processMessage(*io_message, parse_message,
response_renderer),
XfroutError);
EXPECT_TRUE(xfrout.isConnected());
// XXX: we need to re-enable disconnect. otherwise an exception would be
// thrown via the destructor of the server.
xfrout.enableDisconnect();
}
TEST_F(AuthSrvTest, notifyInTest) {
createRequest(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
RRType::SOA());
......
......@@ -54,9 +54,8 @@ void
XfroutClient::connect() {
try {
impl_->socket_.connect(stream_protocol::endpoint(impl_->file_path_));
} catch (const asio::system_error &) {
isc_throw(XfroutError,
"socket connect failed");
} catch (const asio::system_error& ex) {
isc_throw(XfroutError, "socket connect failed: " << ex.what());
}
}
......@@ -64,9 +63,8 @@ void
XfroutClient::disconnect() {
try {
impl_->socket_.close();
} catch (const asio::system_error &) {
isc_throw(XfroutError,
"close socket failed");
} catch (const asio::system_error& ex) {
isc_throw(XfroutError, "close socket failed: " << ex.what());
}
}
......
......@@ -34,7 +34,34 @@ public:
isc::Exception(file, line, what) {}
};
class XfroutClient {
/// \brief The AbstractXfroutClient class is an abstract base class that
/// defines the interfaces of XfroutClient.
///
/// The intended primary usage of abstraction is to allow tests for the
/// user class of XfroutClient without requiring actual communication.
class AbstractXfroutClient {
///
/// \name Constructors, Assignment Operator and Destructor.
///
/// Note: The copy constructor and the assignment operator are
/// intentionally defined as private to make it explicit that this is a
/// pure base class.
//@{
private:
AbstractXfroutClient(const AbstractXfroutClient& source);
AbstractXfroutClient& operator=(const AbstractXfroutClient& source);
protected:
AbstractXfroutClient() {}
public:
virtual ~AbstractXfroutClient() {}
//@}
virtual void connect() = 0;
virtual void disconnect() = 0;
virtual int sendXfroutRequestInfo(int tcp_sock, const void* msg_data,
uint16_t msg_len) = 0;
};
class XfroutClient : public AbstractXfroutClient {
public:
XfroutClient(const std::string& file);
~XfroutClient();
......@@ -43,10 +70,10 @@ private:
XfroutClient(const XfroutClient& source);
XfroutClient& operator=(const XfroutClient& source);
public:
void connect();
void disconnect();
int sendXfroutRequestInfo(int tcp_sock, const void* msg_data,
uint16_t msg_len);
virtual void connect();
virtual void disconnect();
virtual int sendXfroutRequestInfo(int tcp_sock, const void* msg_data,
uint16_t msg_len);
private:
XfroutClientImpl* impl_;
};
......
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