[svn] commit: r2317 - in /branches/trac221/src: bin/auth/auth_srv.cc bin/auth/auth_srv.h bin/auth/main.cc bin/auth/tests/auth_srv_unittest.cc lib/xfr/xfrout_client.cc lib/xfr/xfrout_client.h
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Jun 29 01:45:42 UTC 2010
Author: jinmei
Date: Tue Jun 29 01:45:41 2010
New Revision: 2317
Log:
introduced an abstract base class for XfroutClient, introduced a mock derived class of it, and added detailed tests for xfrout using it.
Modified:
branches/trac221/src/bin/auth/auth_srv.cc
branches/trac221/src/bin/auth/auth_srv.h
branches/trac221/src/bin/auth/main.cc
branches/trac221/src/bin/auth/tests/auth_srv_unittest.cc
branches/trac221/src/lib/xfr/xfrout_client.cc
branches/trac221/src/lib/xfr/xfrout_client.h
Modified: branches/trac221/src/bin/auth/auth_srv.cc
==============================================================================
--- branches/trac221/src/bin/auth/auth_srv.cc (original)
+++ branches/trac221/src/bin/auth/auth_srv.cc Tue Jun 29 01:45:41 2010
@@ -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 @@
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 @@
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 @@
}
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 @@
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 @@
}
makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
verbose_mode_);
+ return (true);
}
return (false);
}
Modified: branches/trac221/src/bin/auth/auth_srv.h
==============================================================================
--- branches/trac221/src/bin/auth/auth_srv.h (original)
+++ branches/trac221/src/bin/auth/auth_srv.h Tue Jun 29 01:45:41 2010
@@ -28,6 +28,10 @@
class Message;
class MessageRenderer;
}
+
+namespace xfr {
+class AbstractXfroutClient;
+};
}
namespace asio_link {
@@ -47,7 +51,7 @@
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;
Modified: branches/trac221/src/bin/auth/main.cc
==============================================================================
--- branches/trac221/src/bin/auth/main.cc (original)
+++ branches/trac221/src/bin/auth/main.cc Tue Jun 29 01:45:41 2010
@@ -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 @@
// initialize command channel
int ret = 0;
+
+ XfroutClient xfrout_client(UNIX_SOCKET_FILE);
try {
string specfile;
if (getenv("B10_FROM_BUILD")) {
@@ -142,7 +147,7 @@
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,
Modified: branches/trac221/src/bin/auth/tests/auth_srv_unittest.cc
==============================================================================
--- branches/trac221/src/bin/auth/tests/auth_srv_unittest.cc (original)
+++ branches/trac221/src/bin/auth/tests/auth_srv_unittest.cc Tue Jun 29 01:45:41 2010
@@ -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 namespace std;
using namespace isc::dns;
using namespace isc::data;
+using namespace isc::xfr;
using namespace asio_link;
namespace {
@@ -45,8 +50,30 @@
"{ \"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 @@
delete io_message;
delete endpoint;
}
+ MockXfroutClient xfrout;
AuthSrv server;
Message request_message;
Message parse_message;
@@ -80,6 +108,35 @@
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 @@
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 @@
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 @@
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 @@
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());
Modified: branches/trac221/src/lib/xfr/xfrout_client.cc
==============================================================================
--- branches/trac221/src/lib/xfr/xfrout_client.cc (original)
+++ branches/trac221/src/lib/xfr/xfrout_client.cc Tue Jun 29 01:45:41 2010
@@ -54,9 +54,8 @@
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 @@
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());
}
}
Modified: branches/trac221/src/lib/xfr/xfrout_client.h
==============================================================================
--- branches/trac221/src/lib/xfr/xfrout_client.h (original)
+++ branches/trac221/src/lib/xfr/xfrout_client.h Tue Jun 29 01:45:41 2010
@@ -34,7 +34,34 @@
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 @@
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_;
};
More information about the bind10-changes
mailing list